From da9a07ba8ff12644c31297e377ea8c876c1f30f7 Mon Sep 17 00:00:00 2001 From: Peter Marheine Date: Tue, 13 Apr 2021 10:21:52 +1000 Subject: [PATCH] FuUdevDevice: add get_siblings_with_subsystem function This function returns a list of sibling devices that have a chosen subsystem, allowing callers to perform a limited walk of the device tree to locate related devices. --- libfwupdplugin/fu-udev-device.c | 44 +++++++++++++++++++++++++++++++++ libfwupdplugin/fu-udev-device.h | 2 ++ libfwupdplugin/fwupdplugin.map | 1 + 3 files changed, 47 insertions(+) diff --git a/libfwupdplugin/fu-udev-device.c b/libfwupdplugin/fu-udev-device.c index 472345a2e..9c15f72a0 100644 --- a/libfwupdplugin/fu-udev-device.c +++ b/libfwupdplugin/fu-udev-device.c @@ -1747,6 +1747,50 @@ fu_udev_device_get_devtype (FuUdevDevice *self) #endif } +/** + * fu_udev_device_get_siblings_with_subsystem + * @self: a #FuUdevDevice + * @subsystem: the name of a udev subsystem + * + * Get a list of devices that are siblings of self and have the + * provided subsystem. + * + * Returns (element-type FuUdevDevice) (transfer full): devices + * + * Since: 1.6.0 + */ +GPtrArray * +fu_udev_device_get_siblings_with_subsystem (FuUdevDevice *self, + const gchar *const subsystem) +{ + g_autoptr(GPtrArray) out = g_ptr_array_new_with_free_func (g_object_unref); + +#ifdef HAVE_GUDEV + FuUdevDevicePrivate *priv = GET_PRIVATE (self); + g_autoptr(GUdevDevice) udev_parent = g_udev_device_get_parent (priv->udev_device); + const gchar *udev_parent_path = g_udev_device_get_sysfs_path (udev_parent); + g_autoptr(GUdevClient) udev_client = g_udev_client_new (NULL); + + g_autoptr(GList) enumerated = g_udev_client_query_by_subsystem (udev_client, subsystem); + for (GList *element = enumerated; element != NULL; element = element->next) { + g_autoptr(GUdevDevice) enumerated_device = element->data; + g_autoptr(GUdevDevice) enumerated_parent = + g_udev_device_get_parent (enumerated_device); + const gchar *enumerated_parent_path = + g_udev_device_get_sysfs_path (enumerated_parent); + + /* if the sysfs path of self's parent is the same as that of the + * located device's parent, they are siblings */ + if (g_strcmp0 (udev_parent_path, enumerated_parent_path) == 0) { + g_ptr_array_add (out, + fu_udev_device_new (g_steal_pointer (&enumerated_device))); + } + } +#endif + + return g_steal_pointer(&out); +} + static void fu_udev_device_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) diff --git a/libfwupdplugin/fu-udev-device.h b/libfwupdplugin/fu-udev-device.h index 99ab7005c..764291e7a 100644 --- a/libfwupdplugin/fu-udev-device.h +++ b/libfwupdplugin/fu-udev-device.h @@ -118,3 +118,5 @@ gboolean fu_udev_device_write_sysfs (FuUdevDevice *self, GError **error) G_GNUC_WARN_UNUSED_RESULT; const gchar *fu_udev_device_get_devtype (FuUdevDevice *self); +GPtrArray *fu_udev_device_get_siblings_with_subsystem (FuUdevDevice *self, + const gchar *subsystem); diff --git a/libfwupdplugin/fwupdplugin.map b/libfwupdplugin/fwupdplugin.map index 7f7fe0354..7c2482e95 100644 --- a/libfwupdplugin/fwupdplugin.map +++ b/libfwupdplugin/fwupdplugin.map @@ -781,6 +781,7 @@ LIBFWUPDPLUGIN_1.6.0 { fu_firmware_write_chunk; fu_ihex_firmware_set_padding_value; fu_plugin_get_context; + fu_udev_device_get_siblings_with_subsystem; fu_xmlb_builder_insert_kb; fu_xmlb_builder_insert_kv; fu_xmlb_builder_insert_kx;