From c9aa12c8438c6cf88ab7d0e6aee9df032d52056e Mon Sep 17 00:00:00 2001 From: Matthias Klumpp Date: Mon, 16 Jan 2023 00:20:35 +0100 Subject: [PATCH] sysinfo: Fall back to hwdb to resolve modalias to device info --- meson.build | 4 +- meson_options.txt | 5 ++ src/as-system-info.c | 161 +++++++++++++++++++++++++++++-------- src/as-system-info.h | 19 +++++ src/as-utils.h | 2 +- src/meson.build | 3 +- tests/meson.build | 7 +- tests/test-basics.c | 14 +++- tools/ascli-actions-misc.c | 16 ++-- 9 files changed, 186 insertions(+), 45 deletions(-) diff --git a/meson.build b/meson.build index 58463f973..8c36cc999 100644 --- a/meson.build +++ b/meson.build @@ -51,6 +51,7 @@ conf.set('_DEFAULT_SOURCE', true) conf.set('HAVE_APT_SUPPORT', get_option('apt-support')) conf.set('HAVE_STEMMING', get_option('stemming')) conf.set('HAVE_UDEV', get_option('udev')) +conf.set('HAVE_SYSTEMD', get_option('systemd')) conf.set('HAVE_SVG_SUPPORT', get_option('svg-support')) configure_file(output: 'config.h', configuration: conf) @@ -162,7 +163,8 @@ xml2_dep = dependency('libxml-2.0') yaml_dep = dependency('yaml-0.1') xmlb_dep = dependency('xmlb', version: '>= 0.3.6', fallback: ['libxmlb', 'libxmlb_dep'], default_options: ['gtkdoc=false']) -udev_dep = dependency('libudev', required: get_option('udev')) +libudev_dep = dependency('libudev', required: get_option('udev')) +libsystemd_dep = dependency('libsystemd', required: get_option('systemd')) if get_option ('gir') # ensure we have a version of GIR that isn't broken with Meson diff --git a/meson_options.txt b/meson_options.txt index b110cbf4e..6bf42f032 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -8,6 +8,11 @@ option('udev', value : true, description : 'Build with udev support' ) +option('systemd', + type : 'boolean', + value : true, + description : 'Build with systemd support' +) option('vapi', type : 'boolean', value : false, diff --git a/src/as-system-info.c b/src/as-system-info.c index c73d8a669..1eba34707 100644 --- a/src/as-system-info.c +++ b/src/as-system-info.c @@ -51,6 +51,9 @@ #ifdef HAVE_UDEV #include #endif +#ifdef HAVE_SYSTEMD +#include +#endif #include "as-utils-private.h" @@ -74,11 +77,23 @@ typedef struct #ifdef HAVE_UDEV struct udev *udev; #endif +#ifdef HAVE_SYSTEMD + sd_hwdb *hwdb; +#endif } AsSystemInfoPrivate; G_DEFINE_TYPE_WITH_PRIVATE (AsSystemInfo, as_system_info, G_TYPE_OBJECT) #define GET_PRIVATE(o) (as_system_info_get_instance_private (o)) +/** + * as_system_info_error_quark: + * + * Return value: An error quark. + * + * Since: 0.16.0 + **/ +G_DEFINE_QUARK (as-system-info-error-quark, as_system_info_error) + static void as_system_info_init (AsSystemInfo *sysinfo) { @@ -107,7 +122,12 @@ as_system_info_finalize (GObject *object) g_ptr_array_unref (priv->modaliases); g_hash_table_unref (priv->modalias_to_sysfs); #ifdef HAVE_UDEV - udev_unref (priv->udev); + if (priv->udev != NULL) + udev_unref (priv->udev); +#endif +#ifdef HAVE_SYSTEMD + if (priv->hwdb != NULL) + sd_hwdb_unref (priv->hwdb); #endif G_OBJECT_CLASS (as_system_info_parent_class)->finalize (object); @@ -491,50 +511,35 @@ as_system_info_modalias_to_syspath (AsSystemInfo *sysinfo, const gchar *modalias } /** - * as_system_info_get_device_name_for_modalias: - * @sysinfo: a #AsSystemInfo instance. - * @modalias: the modalias value to resolve. - * @error: a #GError - * - * Return a human readable device name for the given modalias. - * Will return the modalias again if no device name could be found, - * and returns %NULL on error. - * - * Returns: a human-readable device name, or %NULL on error. + * as_system_info_get_device_name_from_syspath: */ -gchar* -as_system_info_get_device_name_for_modalias (AsSystemInfo *sysinfo, const gchar *modalias, GError **error) +static gchar* +as_system_info_get_device_name_from_syspath (AsSystemInfo *sysinfo, + const gchar *syspath, + const gchar *modalias, + gboolean allow_fallback, + GError **error) { - AsSystemInfoPrivate *priv = GET_PRIVATE (sysinfo); #ifdef HAVE_UDEV + AsSystemInfoPrivate *priv = GET_PRIVATE (sysinfo); struct udev_device *device; struct udev_list_entry *entry, *e; const gchar *device_vendor = NULL; const gchar *device_model = NULL; const gchar *usb_class = NULL; const gchar *driver = NULL; - const gchar *syspath = NULL; gchar *result = NULL; - syspath = g_hash_table_lookup (priv->modalias_to_sysfs, modalias); - if (syspath == NULL) { - g_set_error (error, - AS_UTILS_ERROR, - AS_UTILS_ERROR_FAILED, - "No path found for device with modalias '%s'.", modalias); - return NULL; - } - if (priv->udev == NULL) priv->udev = udev_new (); device = udev_device_new_from_syspath (priv->udev, syspath); if (device == NULL) { g_set_error (error, - AS_UTILS_ERROR, - AS_UTILS_ERROR_FAILED, + AS_SYSTEM_INFO_ERROR, + AS_SYSTEM_INFO_ERROR_FAILED, "Failure to read device information for %s: %s", - modalias, g_strerror (errno)); + syspath, g_strerror (errno)); return NULL; } @@ -558,23 +563,113 @@ as_system_info_get_device_name_for_modalias (AsSystemInfo *sysinfo, const gchar result = g_strdup_printf ("%s - %s", device_vendor, usb_class); } if (result == NULL) { - if (driver != NULL) - result = g_strdup (driver); - else - result = g_strdup (modalias); + if (allow_fallback) { + if (driver != NULL) + result = g_strdup (driver); + else + result = g_strdup (modalias); + } else { + g_set_error (error, + AS_SYSTEM_INFO_ERROR, + AS_SYSTEM_INFO_ERROR_NOT_FOUND, + "Unable to find good human-readable description for device %s", + modalias); + } } udev_device_unref (device); return result; #else g_set_error_literal (error, - AS_UTILS_ERROR, - AS_UTILS_ERROR_FAILED, + AS_SYSTEM_INFO_ERROR, + AS_SYSTEM_INFO_ERROR_FAILED, "Unable to determine device name: AppStream was built without udev support."); return NULL; #endif } +/** + * as_system_info_get_device_name_from_hwdb: + */ +static gchar* +as_system_info_get_device_name_from_hwdb (AsSystemInfo *sysinfo, const gchar *modalias_glob, gboolean allow_fallback, GError **error) +{ +#ifdef HAVE_SYSTEMD + AsSystemInfoPrivate *priv = GET_PRIVATE (sysinfo); + gint ret = 0; + const gchar *device_vendor = NULL; + const gchar *device_model = NULL; + + if (priv->hwdb == NULL) { + ret = sd_hwdb_new(&priv->hwdb); + if (ret < 0) { + g_set_error (error, + AS_SYSTEM_INFO_ERROR, + AS_SYSTEM_INFO_ERROR_FAILED, + "Unable to open hardware database: %s", + g_strerror (ret)); + return NULL; + } + } + + sd_hwdb_get (priv->hwdb, modalias_glob, "ID_VENDOR_FROM_DATABASE", &device_vendor); + sd_hwdb_get (priv->hwdb, modalias_glob, "ID_MODEL_FROM_DATABASE", &device_model); + + if (device_vendor != NULL && device_model != NULL) + return g_strdup_printf ("%s - %s", device_vendor, device_model); + if (allow_fallback) + return g_strdup (modalias_glob); + + g_set_error (error, + AS_SYSTEM_INFO_ERROR, + AS_SYSTEM_INFO_ERROR_NOT_FOUND, + "Unable to find good human-readable description for device %s", + modalias_glob); + return NULL; +#else + g_set_error_literal (error, + AS_SYSTEM_INFO_ERROR, + AS_SYSTEM_INFO_ERROR_FAILED, + "Unable to determine device name: AppStream was built without systemd-hwdb support."); + return NULL; +#endif +} + +/** + * as_system_info_get_device_name_for_modalias: + * @sysinfo: a #AsSystemInfo instance. + * @modalias: the modalias value to resolve (may contain wildcards). + * @allow_fallback: fall back to low-quality data if no better information is available + * @error: a #GError + * + * Return a human readable device name for the given modalias. + * Will return the modalias again if no device name could be found, + * and returns %NULL on error. + * If @allow_fallback is set to %FALSE, this function will return %NULL and error + * %AS_SYSTEM_INFO_ERROR_NOT_FOUND in case no suitable description could be found. + * + * Returns: a human-readable device name, or %NULL on error. + */ +gchar* +as_system_info_get_device_name_for_modalias (AsSystemInfo *sysinfo, const gchar *modalias, gboolean allow_fallback, GError **error) +{ + AsSystemInfoPrivate *priv = GET_PRIVATE (sysinfo); + const gchar *syspath; + + syspath = g_hash_table_lookup (priv->modalias_to_sysfs, modalias); + if (syspath == NULL) + return as_system_info_get_device_name_from_hwdb (sysinfo, + modalias, + allow_fallback, + error); + else + return as_system_info_get_device_name_from_syspath (sysinfo, + syspath, + modalias, + allow_fallback, + error); +} + /** diff --git a/src/as-system-info.h b/src/as-system-info.h index 64c5c3666..ae8485472 100644 --- a/src/as-system-info.h +++ b/src/as-system-info.h @@ -44,6 +44,24 @@ struct _AsSystemInfoClass void (*_as_reserved6) (void); }; +/** + * AsSystemInfoError: + * @AS_SYSTEM_INFO_ERROR_FAILED: Generic failure + * @AS_SYSTEM_INFO_ERROR_NOT_FOUND: Information was not found. + * + * The error type. + **/ +typedef enum { + AS_SYSTEM_INFO_ERROR_FAILED, + AS_SYSTEM_INFO_ERROR_NOT_FOUND, + /*< private >*/ + AS_SYSTEM_INFO_ERROR_LAST +} AsSystemInfoError; + +#define AS_SYSTEM_INFO_ERROR as_system_info_error_quark () + +GQuark as_system_info_error_quark (void); + AsSystemInfo *as_system_info_new (void); const gchar *as_system_info_get_os_id (AsSystemInfo *sysinfo); @@ -63,6 +81,7 @@ const gchar *as_system_info_modalias_to_syspath (AsSystemInfo *sysinfo, gchar *as_system_info_get_device_name_for_modalias (AsSystemInfo *sysinfo, const gchar *modalias, + gboolean allow_fallback, GError **error); gchar *as_get_current_distro_component_id (void); diff --git a/src/as-utils.h b/src/as-utils.h index 80977b4d6..ba19cc7f6 100644 --- a/src/as-utils.h +++ b/src/as-utils.h @@ -32,7 +32,7 @@ G_BEGIN_DECLS /** * AsUtilsError: - * @AS_UTILS_ERROR_FAILED: Generic failure + * @AS_UTILS_ERROR_FAILED: Generic failure * * The error type. **/ diff --git a/src/meson.build b/src/meson.build index c67a4707e..947fe1e44 100644 --- a/src/meson.build +++ b/src/meson.build @@ -176,7 +176,8 @@ aslib_deps = [glib_dep, xmlb_dep, xml2_dep, yaml_dep, - udev_dep] + libudev_dep, + libsystemd_dep] if get_option ('stemming') aslib_deps += [stemmer_lib] endif diff --git a/tests/meson.build b/tests/meson.build index 88279e0e9..f17104554 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -21,6 +21,7 @@ as_test_basic_exe = executable ('as-test_basic', dependencies: [appstream_dep, gio_dep, xml2_dep], + include_directories: [root_inc_dir] ) test ('as-test_basic', as_test_basic_exe, @@ -35,11 +36,12 @@ as_test_xml_exe = executable ('as-test_xml', dependencies: [appstream_dep, gio_dep, xml2_dep], + include_directories: [root_inc_dir] ) test ('as-test_xml', as_test_xml_exe, args: as_test_args, - env: as_test_env + env: as_test_env, ) # YAML read/write @@ -49,6 +51,7 @@ as_test_yaml_exe = executable ('as-test_yaml', dependencies: [appstream_dep, gio_dep, xml2_dep], + include_directories: [root_inc_dir] ) test ('as-test_yaml', as_test_yaml_exe, @@ -79,6 +82,7 @@ as_test_validate_exe = executable ('as-test_validate', dependencies: [appstream_dep, gio_dep, xml2_dep], + include_directories: [root_inc_dir] ) test ('as-test_validate', as_test_validate_exe, @@ -108,6 +112,7 @@ as_test_misc_exe = executable ('as-test_misc', dependencies: [appstream_dep, gio_dep, xml2_dep], + include_directories: [root_inc_dir] ) test ('as-test_misc', as_test_misc_exe, diff --git a/tests/test-basics.c b/tests/test-basics.c index 9585ae544..b5fcd2364 100644 --- a/tests/test-basics.c +++ b/tests/test-basics.c @@ -18,6 +18,7 @@ * along with this library. If not, see . */ +#include #include #include "appstream.h" #include "as-component-private.h" @@ -722,8 +723,10 @@ test_version_compare (void) static void test_system_info (void) { - g_autofree gchar *osrelease_fname = NULL; g_autoptr(AsSystemInfo) sysinfo = as_system_info_new (); + g_autofree gchar *osrelease_fname = NULL; + g_autofree gchar *dev_name = NULL; + g_autoptr(GError) error = NULL; osrelease_fname = g_build_filename (datadir, "os-release-1", NULL); @@ -740,6 +743,15 @@ test_system_info (void) g_assert_nonnull (as_system_info_get_kernel_version (sysinfo)); g_assert_cmpint (as_system_info_get_memory_total (sysinfo), >=, 128); + + dev_name = as_system_info_get_device_name_for_modalias (sysinfo, "usb:v1130p0202d*", FALSE, &error); +#ifdef HAVE_SYSTEMD + g_assert_no_error (error); + g_assert_cmpstr (dev_name, ==, "Tenx Technology, Inc. - Rocket Launcher"); +#else + if (error != NULL) + g_error_free (g_steal_pointer (&error)); +#endif } /** diff --git a/tools/ascli-actions-misc.c b/tools/ascli-actions-misc.c index acef84951..13bcf4407 100644 --- a/tools/ascli-actions-misc.c +++ b/tools/ascli-actions-misc.c @@ -569,17 +569,19 @@ ascli_show_sysinfo (const gchar *cachepath, gboolean no_cache, gboolean detailed g_autofree gchar *dev_name = NULL; const gchar *modalias = (const gchar*) g_ptr_array_index (modaliases, i); - dev_name = as_system_info_get_device_name_for_modalias (sysinfo, modalias, &tmp_error); - if (dev_name == NULL) { + dev_name = as_system_info_get_device_name_for_modalias (sysinfo, modalias, FALSE, &tmp_error); + if (dev_name == NULL && !g_error_matches (tmp_error, AS_SYSTEM_INFO_ERROR, AS_SYSTEM_INFO_ERROR_NOT_FOUND)) { g_warning ("Unable to read device info: %s", tmp_error->message); continue; } - if (g_strcmp0 (dev_name, modalias) == 0) { - continue; - } else { - ascli_print_stdout (" • %s", dev_name); - if (detailed) + + if (detailed) { + ascli_print_stdout (" • %s", dev_name? dev_name : modalias); + if (dev_name != NULL) ascli_print_stdout (" %s", modalias); + } else { + if (dev_name != NULL) + ascli_print_stdout (" • %s", dev_name); } } }