Skip to content

Commit

Permalink
sysinfo: Fall back to hwdb to resolve modalias to device info
Browse files Browse the repository at this point in the history
  • Loading branch information
ximion committed Jan 15, 2023
1 parent 298fbca commit c9aa12c
Show file tree
Hide file tree
Showing 9 changed files with 186 additions and 45 deletions.
4 changes: 3 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions meson_options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
161 changes: 128 additions & 33 deletions src/as-system-info.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@
#ifdef HAVE_UDEV
#include <libudev.h>
#endif
#ifdef HAVE_SYSTEMD
#include <systemd/sd-hwdb.h>
#endif

#include "as-utils-private.h"

Expand All @@ -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)
{
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}

Expand All @@ -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);
}



/**
Expand Down
19 changes: 19 additions & 0 deletions src/as-system-info.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/as-utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ G_BEGIN_DECLS

/**
* AsUtilsError:
* @AS_UTILS_ERROR_FAILED: Generic failure
* @AS_UTILS_ERROR_FAILED: Generic failure
*
* The error type.
**/
Expand Down
3 changes: 2 additions & 1 deletion src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 6 additions & 1 deletion tests/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
14 changes: 13 additions & 1 deletion tests/test-basics.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/

#include <config.h>
#include <glib.h>
#include "appstream.h"
#include "as-component-private.h"
Expand Down Expand Up @@ -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);

Expand All @@ -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
}

/**
Expand Down
Loading

0 comments on commit c9aa12c

Please sign in to comment.