From fadcc1222949ed57ca2ce143f2eb9b93ea0dab1b Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 26 Jun 2020 15:29:43 +0900 Subject: [PATCH 1/3] sd-device: make FOREACH_DEVICE_SYSATTR() list attributes in subdirectories Then, `udevadm info -a` can show subdir attributes. Closes #12191. --- src/libsystemd/sd-device/sd-device.c | 71 +++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 13 deletions(-) diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index 24f34dc182..05e3a54c10 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -1564,34 +1564,64 @@ _public_ const char *sd_device_get_property_next(sd_device *device, const char * return key; } -static int device_sysattrs_read_all(sd_device *device) { +static int device_sysattrs_read_all_internal(sd_device *device, const char *subdir) { + _cleanup_free_ char *path_dir = NULL; _cleanup_closedir_ DIR *dir = NULL; - const char *syspath; struct dirent *dent; + const char *syspath; int r; - assert(device); - - if (device->sysattrs_read) - return 0; - r = sd_device_get_syspath(device, &syspath); if (r < 0) return r; - dir = opendir(syspath); + if (subdir) { + _cleanup_free_ char *p = NULL; + + p = path_join(syspath, subdir, "uevent"); + if (!p) + return -ENOMEM; + + if (access(p, F_OK) >= 0) + /* this is a child device, skipping */ + return 0; + + path_dir = path_join(syspath, subdir); + if (!path_dir) + return -ENOMEM; + } + + dir = opendir(path_dir ?: syspath); if (!dir) return -errno; FOREACH_DIRENT_ALL(dent, dir, return -errno) { - _cleanup_free_ char *path = NULL; + _cleanup_free_ char *path = NULL, *p = NULL; struct stat statbuf; - /* only handle symlinks and regular files */ - if (!IN_SET(dent->d_type, DT_LNK, DT_REG)) + if (dot_or_dot_dot(dent->d_name)) continue; - path = path_join(syspath, dent->d_name); + /* only handle symlinks, regular files, and directories */ + if (!IN_SET(dent->d_type, DT_LNK, DT_REG, DT_DIR)) + continue; + + if (subdir) { + p = path_join(subdir, dent->d_name); + if (!p) + return -ENOMEM; + } + + if (dent->d_type == DT_DIR) { + /* read subdirectory */ + r = device_sysattrs_read_all_internal(device, p ?: dent->d_name); + if (r < 0) + return r; + + continue; + } + + path = path_join(syspath, p ?: dent->d_name); if (!path) return -ENOMEM; @@ -1601,11 +1631,26 @@ static int device_sysattrs_read_all(sd_device *device) { if (!(statbuf.st_mode & S_IRUSR)) continue; - r = set_put_strdup(&device->sysattrs, dent->d_name); + r = set_put_strdup(&device->sysattrs, p ?: dent->d_name); if (r < 0) return r; } + return 0; +} + +static int device_sysattrs_read_all(sd_device *device) { + int r; + + assert(device); + + if (device->sysattrs_read) + return 0; + + r = device_sysattrs_read_all_internal(device, NULL); + if (r < 0) + return r; + device->sysattrs_read = true; return 0; From 21df146501fd812f07731e93e6c01873232b80fd Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 26 Jun 2020 15:44:41 +0900 Subject: [PATCH 2/3] udevadm: sort entries in `udevadm info -a` by attribute name --- src/udev/udevadm-info.c | 77 ++++++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 25 deletions(-) diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c index 1debdf2b31..b1209e6baf 100644 --- a/src/udev/udevadm-info.c +++ b/src/udev/udevadm-info.c @@ -17,6 +17,7 @@ #include "device-util.h" #include "dirent-util.h" #include "fd-util.h" +#include "sort-util.h" #include "string-table.h" #include "string-util.h" #include "udev-util.h" @@ -56,9 +57,36 @@ static bool skip_attribute(const char *name) { return string_table_lookup(skip, ELEMENTSOF(skip), name) >= 0; } -static void print_all_attributes(sd_device *device, const char *key) { +typedef struct SysAttr { + const char *name; + const char *value; +} SysAttr; + +static int sysattr_compare(const SysAttr *a, const SysAttr *b) { + return strcmp(a->name, b->name); +} + +static int print_all_attributes(sd_device *device, bool is_parent) { + _cleanup_free_ SysAttr *sysattrs = NULL; + size_t n_items = 0, n_allocated = 0; const char *name, *value; + value = NULL; + (void) sd_device_get_devpath(device, &value); + printf(" looking at %sdevice '%s':\n", is_parent ? "parent " : "", strempty(value)); + + value = NULL; + (void) sd_device_get_sysname(device, &value); + printf(" %s==\"%s\"\n", is_parent ? "KERNELS" : "KERNEL", strempty(value)); + + value = NULL; + (void) sd_device_get_subsystem(device, &value); + printf(" %s==\"%s\"\n", is_parent ? "SUBSYSTEMS" : "SUBSYSTEM", strempty(value)); + + value = NULL; + (void) sd_device_get_driver(device, &value); + printf(" %s==\"%s\"\n", is_parent ? "DRIVERS" : "DRIVER", strempty(value)); + FOREACH_DEVICE_SYSATTR(device, name) { size_t len; @@ -79,14 +107,29 @@ static void print_all_attributes(sd_device *device, const char *key) { if (len > 0) continue; - printf(" %s{%s}==\"%s\"\n", key, name, value); + if (!GREEDY_REALLOC(sysattrs, n_allocated, n_items + 1)) + return log_oom(); + + sysattrs[n_items] = (SysAttr) { + .name = name, + .value = value, + }; + n_items++; } + + typesafe_qsort(sysattrs, n_items, sysattr_compare); + + for (size_t i = 0; i < n_items; i++) + printf(" %s{%s}==\"%s\"\n", is_parent ? "ATTRS" : "ATTR", sysattrs[i].name, sysattrs[i].value); + puts(""); + + return 0; } static int print_device_chain(sd_device *device) { sd_device *child, *parent; - const char *str; + int r; printf("\n" "Udevadm info starts with the device specified by the devpath and then\n" @@ -96,30 +139,14 @@ static int print_device_chain(sd_device *device) { "and the attributes from one single parent device.\n" "\n"); - (void) sd_device_get_devpath(device, &str); - printf(" looking at device '%s':\n", str); - (void) sd_device_get_sysname(device, &str); - printf(" KERNEL==\"%s\"\n", str); - if (sd_device_get_subsystem(device, &str) < 0) - str = ""; - printf(" SUBSYSTEM==\"%s\"\n", str); - if (sd_device_get_driver(device, &str) < 0) - str = ""; - printf(" DRIVER==\"%s\"\n", str); - print_all_attributes(device, "ATTR"); + r = print_all_attributes(device, false); + if (r < 0) + return r; for (child = device; sd_device_get_parent(child, &parent) >= 0; child = parent) { - (void) sd_device_get_devpath(parent, &str); - printf(" looking at parent device '%s':\n", str); - (void) sd_device_get_sysname(parent, &str); - printf(" KERNELS==\"%s\"\n", str); - if (sd_device_get_subsystem(parent, &str) < 0) - str = ""; - printf(" SUBSYSTEMS==\"%s\"\n", str); - if (sd_device_get_driver(parent, &str) < 0) - str = ""; - printf(" DRIVERS==\"%s\"\n", str); - print_all_attributes(parent, "ATTRS"); + r = print_all_attributes(parent, true); + if (r < 0) + return r; } return 0; From 21c7fe6d125f8af6ad6b305d2a615be626a2a9f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Sun, 5 Jul 2020 10:55:18 +0200 Subject: [PATCH 3/3] sd-device: be more defensive in FOREACH_DEVICE_SYSATTR Follow-up for fadcc1222949ed57ca2ce143f2eb9b93ea0dab1b. --- src/libsystemd/sd-device/sd-device.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index 05e3a54c10..13596f2303 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -1585,6 +1585,10 @@ static int device_sysattrs_read_all_internal(sd_device *device, const char *subd if (access(p, F_OK) >= 0) /* this is a child device, skipping */ return 0; + if (errno != ENOENT) { + log_debug_errno(errno, "Failed to stat %s, ignoring subdir: %m", p); + return 0; + } path_dir = path_join(syspath, subdir); if (!path_dir)