From d4df6ce2154caa4e1f2fc2df818cd32b523a96ab Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 4 Apr 2022 15:20:01 +0200 Subject: [PATCH 1/6] sd-device: rename return parameter of sd_device_get_devpath() to ret --- src/libsystemd/sd-device/sd-device.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index 4f413880eb..bf9217b649 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -1047,14 +1047,15 @@ _public_ int sd_device_get_driver(sd_device *device, const char **ret) { return 0; } -_public_ int sd_device_get_devpath(sd_device *device, const char **devpath) { +_public_ int sd_device_get_devpath(sd_device *device, const char **ret) { assert_return(device, -EINVAL); assert(device->devpath); assert(device->devpath[0] == '/'); - if (devpath) - *devpath = device->devpath; + if (ret) + *ret = device->devpath; + return 0; } From 1ce0d040593c92adebceed29618f170faaee0839 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 4 Apr 2022 15:18:57 +0200 Subject: [PATCH 2/6] sd-device: actually read diskseq if told so sd_device_get_diskseq() actually called device_read_uevent_file() but that function didn't actually parse DISKSEQ= so far. Fix that. --- src/libsystemd/sd-device/device-internal.h | 1 + src/libsystemd/sd-device/device-private.c | 22 --------------- src/libsystemd/sd-device/sd-device.c | 33 +++++++++++++++++++++- 3 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/libsystemd/sd-device/device-internal.h b/src/libsystemd/sd-device/device-internal.h index 49d0f0fd1f..7ea964acf9 100644 --- a/src/libsystemd/sd-device/device-internal.h +++ b/src/libsystemd/sd-device/device-internal.h @@ -109,6 +109,7 @@ int device_set_devname(sd_device *device, const char *devname); int device_set_devtype(sd_device *device, const char *devtype); int device_set_devnum(sd_device *device, const char *major, const char *minor); int device_set_subsystem(sd_device *device, const char *subsystem); +int device_set_diskseq(sd_device *device, const char *str); int device_set_drivers_subsystem(sd_device *device); int device_set_driver(sd_device *device, const char *driver); int device_set_usec_initialized(sd_device *device, usec_t when); diff --git a/src/libsystemd/sd-device/device-private.c b/src/libsystemd/sd-device/device-private.c index 5f3644aac4..de12ad7e00 100644 --- a/src/libsystemd/sd-device/device-private.c +++ b/src/libsystemd/sd-device/device-private.c @@ -255,28 +255,6 @@ static int device_set_seqnum(sd_device *device, const char *str) { return 0; } -static int device_set_diskseq(sd_device *device, const char *str) { - uint64_t diskseq; - int r; - - assert(device); - assert(str); - - r = safe_atou64(str, &diskseq); - if (r < 0) - return r; - if (diskseq == 0) - return -EINVAL; - - r = device_add_property_internal(device, "DISKSEQ", str); - if (r < 0) - return r; - - device->diskseq = diskseq; - - return 0; -} - static int device_amend(sd_device *device, const char *key, const char *value) { int r; diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index bf9217b649..22200c0eea 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -570,7 +570,34 @@ int device_set_devnum(sd_device *device, const char *major, const char *minor) { return 0; } -static int handle_uevent_line(sd_device *device, const char *key, const char *value, const char **major, const char **minor) { +int device_set_diskseq(sd_device *device, const char *str) { + uint64_t diskseq; + int r; + + assert(device); + assert(str); + + r = safe_atou64(str, &diskseq); + if (r < 0) + return r; + if (diskseq == 0) + return -EINVAL; + + r = device_add_property_internal(device, "DISKSEQ", str); + if (r < 0) + return r; + + device->diskseq = diskseq; + + return 0; +} + +static int handle_uevent_line( + sd_device *device, + const char *key, + const char *value, + const char **major, + const char **minor) { int r; assert(device); @@ -595,6 +622,10 @@ static int handle_uevent_line(sd_device *device, const char *key, const char *va r = device_set_devmode(device, value); if (r < 0) return r; + } else if (streq(key, "DISKSEQ")) { + r = device_set_diskseq(device, value); + if (r < 0) + return r; } else if (streq(key, "MAJOR")) *major = value; else if (streq(key, "MINOR")) From a0e902598c9f5fbce55653f679e0ce91bc3369b7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 4 Apr 2022 15:25:01 +0200 Subject: [PATCH 3/6] udevadm: show more fields of sd_device objects in "udevadm info" Let's make things easier to debug, and show a more comprehensive set of fields, extending on the existing output syntax that starts with one marker character followed by a colon and a space. --- man/udevadm.xml | 32 +++++++++++++++++++++++++ src/udev/udevadm-info.c | 52 ++++++++++++++++++++++++++++++++++------- 2 files changed, 75 insertions(+), 9 deletions(-) diff --git a/man/udevadm.xml b/man/udevadm.xml index e299a75879..162287fa5f 100644 --- a/man/udevadm.xml +++ b/man/udevadm.xml @@ -227,6 +227,30 @@ P: Device path in /sys/ + + M: + Device name in /sys/ (i.e. the last component of P:) + + + R: + Device number in /sys/ (i.e. the numeric suffix of the last component of P:) + + + U: + Kernel subsystem + + + T: + Kernel device type within subsystem + + + D: + Kernel device node major/minor + + + I: + Network interface index + N: Kernel device node name @@ -239,6 +263,14 @@ S: Device node symlink + + Q: + Block device sequence number (DISKSEQ) + + + V: + Attached driver + E: Device property diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c index a088c1727c..721c5665b3 100644 --- a/src/udev/udevadm-info.c +++ b/src/udev/udevadm-info.c @@ -171,26 +171,60 @@ static int print_device_chain(sd_device *device) { } static int print_record(sd_device *device) { - const char *str, *val; - int i; + const char *str, *val, *subsys; + dev_t devnum; + uint64_t q; + int i, ifi; assert(device); - (void) sd_device_get_devpath(device, &str); + /* We don't show syspath here, because it's identical to devpath (modulo the "/sys" prefix). + * + * We don't show action/seqnum here because that only makes sense for records synthesized from + * uevents, not for those synthesized from database entries. + * + * We don't show sysattrs here, because they can be expensive and potentially issue expensive driver + * IO. */ + + assert_se(sd_device_get_devpath(device, &str) >= 0); printf("P: %s\n", str); + if (sd_device_get_sysname(device, &str) >= 0) + printf("M: %s\n", str); + + if (sd_device_get_sysnum(device, &str) >= 0) + printf("R: %s\n", str); + + if (sd_device_get_subsystem(device, &subsys) >= 0) + printf("U: %s\n", subsys); + + if (sd_device_get_devtype(device, &str) >= 0) + printf("T: %s\n", str); + + if (sd_device_get_devnum(device, &devnum) >= 0) + printf("D: %c %u:%u\n", streq_ptr(subsys, "block") ? 'b' : 'c', major(devnum), minor(devnum)); + + if (sd_device_get_ifindex(device, &ifi) >= 0) + printf("I: %i\n", ifi); + if (sd_device_get_devname(device, &str) >= 0) { assert_se(val = path_startswith(str, "/dev/")); printf("N: %s\n", val); + + if (device_get_devlink_priority(device, &i) >= 0) + printf("L: %i\n", i); + + FOREACH_DEVICE_DEVLINK(device, str) { + assert_se(val = path_startswith(str, "/dev/")); + printf("S: %s\n", val); + } } - if (device_get_devlink_priority(device, &i) >= 0) - printf("L: %i\n", i); + if (sd_device_get_diskseq(device, &q) >= 0) + printf("Q: %" PRIu64 "\n", q); - FOREACH_DEVICE_DEVLINK(device, str) { - assert_se(val = path_startswith(str, "/dev/")); - printf("S: %s\n", val); - } + if (sd_device_get_driver(device, &str) >= 0) + printf("V: %s\n", str); FOREACH_DEVICE_PROPERTY(device, str, val) printf("E: %s=%s\n", str, val); From 13005c8f2c7f0169728fef804f164c3574b8e0f7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 4 Apr 2022 16:00:25 +0200 Subject: [PATCH 4/6] udevadm: add a dash of color to "udevadm info" Let's make it easier to discern the "header" of device records from the "body", i.e. non-property data from property data, by using some conservative coloring. --- src/udev/udevadm-info.c | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c index 721c5665b3..73dbbcaa33 100644 --- a/src/udev/udevadm-info.c +++ b/src/udev/udevadm-info.c @@ -22,9 +22,10 @@ #include "static-destruct.h" #include "string-table.h" #include "string-util.h" +#include "terminal-util.h" #include "udev-util.h" -#include "udevadm-util.h" #include "udevadm.h" +#include "udevadm-util.h" typedef enum ActionType { ACTION_QUERY, @@ -184,47 +185,59 @@ static int print_record(sd_device *device) { * uevents, not for those synthesized from database entries. * * We don't show sysattrs here, because they can be expensive and potentially issue expensive driver - * IO. */ + * IO. + * + * Coloring: let's be conservative with coloring. Let's use it to group related fields. Right now: + * + * • white for fields that give the device a name + * • green for fields that categorize the device into subsystem/devtype and similar + * • cyan for fields about associated device nodes/symlinks/network interfaces and such + * • magenta for block device diskseq + * • yellow for driver info + * • no color for regular properties */ assert_se(sd_device_get_devpath(device, &str) >= 0); - printf("P: %s\n", str); + printf("P: %s%s%s\n", ansi_highlight_white(), str, ansi_normal()); if (sd_device_get_sysname(device, &str) >= 0) - printf("M: %s\n", str); + printf("M: %s%s%s\n", ansi_highlight_white(), str, ansi_normal()); if (sd_device_get_sysnum(device, &str) >= 0) - printf("R: %s\n", str); + printf("R: %s%s%s\n", ansi_highlight_white(), str, ansi_normal()); if (sd_device_get_subsystem(device, &subsys) >= 0) - printf("U: %s\n", subsys); + printf("U: %s%s%s\n", ansi_highlight_green(), subsys, ansi_normal()); if (sd_device_get_devtype(device, &str) >= 0) - printf("T: %s\n", str); + printf("T: %s%s%s\n", ansi_highlight_green(), str, ansi_normal()); if (sd_device_get_devnum(device, &devnum) >= 0) - printf("D: %c %u:%u\n", streq_ptr(subsys, "block") ? 'b' : 'c', major(devnum), minor(devnum)); + printf("D: %s%c %u:%u%s\n", + ansi_highlight_cyan(), + streq_ptr(subsys, "block") ? 'b' : 'c', major(devnum), minor(devnum), + ansi_normal()); if (sd_device_get_ifindex(device, &ifi) >= 0) - printf("I: %i\n", ifi); + printf("I: %s%i%s\n", ansi_highlight_cyan(), ifi, ansi_normal()); if (sd_device_get_devname(device, &str) >= 0) { assert_se(val = path_startswith(str, "/dev/")); - printf("N: %s\n", val); + printf("N: %s%s%s\n", ansi_highlight_cyan(), val, ansi_normal()); if (device_get_devlink_priority(device, &i) >= 0) - printf("L: %i\n", i); + printf("L: %s%i%s\n", ansi_highlight_cyan(), i, ansi_normal()); FOREACH_DEVICE_DEVLINK(device, str) { assert_se(val = path_startswith(str, "/dev/")); - printf("S: %s\n", val); + printf("S: %s%s%s\n", ansi_highlight_cyan(), val, ansi_normal()); } } if (sd_device_get_diskseq(device, &q) >= 0) - printf("Q: %" PRIu64 "\n", q); + printf("Q: %s%" PRIu64 "%s\n", ansi_highlight_magenta(), q, ansi_normal()); if (sd_device_get_driver(device, &str) >= 0) - printf("V: %s\n", str); + printf("V: %s%s%s\n", ansi_highlight_yellow4(), str, ansi_normal()); FOREACH_DEVICE_PROPERTY(device, str, val) printf("E: %s=%s\n", str, val); From 7ba77d8f5510d5b86c8ab94590e8a030c40509b6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 4 Apr 2022 16:01:25 +0200 Subject: [PATCH 5/6] udevadm: if invalid devices are specified on "info" verb, continue If multiple devices are specified on "udevadm info", then show data about them all even if one is missing. Return first encountered error though. --- src/udev/udevadm-info.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c index 73dbbcaa33..12a1769bd8 100644 --- a/src/udev/udevadm-info.c +++ b/src/udev/udevadm-info.c @@ -489,7 +489,7 @@ static int help(void) { int info_main(int argc, char *argv[], void *userdata) { _cleanup_strv_free_ char **devices = NULL; _cleanup_free_ char *name = NULL; - int c, r; + int c, r, ret; enum { ARG_PROPERTY = 0x100, @@ -631,14 +631,21 @@ int info_main(int argc, char *argv[], void *userdata) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "-x/--export or -P/--export-prefix cannot be used with --value"); + ret = 0; STRV_FOREACH(p, devices) { _cleanup_(sd_device_unrefp) sd_device *device = NULL; r = find_device(*p, NULL, &device); - if (r == -EINVAL) - return log_error_errno(r, "Bad argument \"%s\", expected an absolute path in /dev/ or /sys or a unit name: %m", *p); - if (r < 0) - return log_error_errno(r, "Unknown device \"%s\": %m", *p); + if (r < 0) { + if (r == -EINVAL) + log_error_errno(r, "Bad argument \"%s\", expected an absolute path in /dev/ or /sys/ or a unit name: %m", *p); + else + log_error_errno(r, "Unknown device \"%s\": %m", *p); + + if (ret == 0) + ret = r; + continue; + } if (arg_wait_for_initialization_timeout > 0) { sd_device *d; @@ -665,5 +672,5 @@ int info_main(int argc, char *argv[], void *userdata) { return r; } - return 0; + return ret; } From b51f4eaf7b58f064092215cea9c6fc1c5af5646e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 4 Apr 2022 15:35:01 +0200 Subject: [PATCH 6/6] man: document various sd_device_get_xyz() functions --- man/rules/meson.build | 13 +++ man/sd_device_get_syspath.xml | 200 ++++++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+) create mode 100644 man/sd_device_get_syspath.xml diff --git a/man/rules/meson.build b/man/rules/meson.build index f10abdaf0d..add28a724c 100644 --- a/man/rules/meson.build +++ b/man/rules/meson.build @@ -502,6 +502,19 @@ manpages = [ 'sd_bus_track_unrefp'], ''], ['sd_bus_wait', '3', [], ''], + ['sd_device_get_syspath', + '3', + ['sd_device_get_devname', + 'sd_device_get_devnum', + 'sd_device_get_devpath', + 'sd_device_get_devtype', + 'sd_device_get_diskseq', + 'sd_device_get_driver', + 'sd_device_get_ifindex', + 'sd_device_get_subsystem', + 'sd_device_get_sysname', + 'sd_device_get_sysnum'], + ''], ['sd_event_add_child', '3', ['sd_event_add_child_pidfd', diff --git a/man/sd_device_get_syspath.xml b/man/sd_device_get_syspath.xml new file mode 100644 index 0000000000..54cb87a3f4 --- /dev/null +++ b/man/sd_device_get_syspath.xml @@ -0,0 +1,200 @@ + + + + + + + + sd_device_get_syspath + systemd + + + + sd_device_get_syspath + 3 + + + + sd_device_get_syspath + sd_device_get_devpath + sd_device_get_sysname + sd_device_get_sysnum + sd_device_get_subsystem + sd_device_get_devtype + sd_device_get_devname + sd_device_get_devnum + sd_device_get_ifindex + sd_device_get_driver + sd_device_get_diskseq + + Returns various fields of device objects + + + + + #include <systemd/sd-device.h> + + + int sd_device_get_syspath + sd_device *device + const char **ret + + + + int sd_device_get_devpath + sd_device *device + const char **ret + + + + int sd_device_get_sysname + sd_device *device + const char **ret + + + + int sd_device_get_sysnum + sd_device *device + const char **ret + + + + int sd_device_get_subsystem + sd_device *device + const char **ret + + + + int sd_device_get_devtype + sd_device *device + const char **ret + + + + int sd_device_get_devname + sd_device *device + const char **ret + + + + int sd_device_get_devnum + sd_device *device + dev_t *ret + + + + int sd_device_get_ifindex + sd_device *device + int *ret + + + + int sd_device_get_driver + sd_device *device + const char **ret + + + + int sd_device_get_diskseq + sd_device *device + uint64_t *ret + + + + + + + Description + + sd_device_get_syspath() returns the sysfs path of the specified device record, + including the /sys prefix. Example: /sys/devices/virtual/tty/tty7 + + sd_device_get_devpath() returns the sysfs path of the specified device record, + excluding the /sys prefix. Example: /devices/virtual/tty/tty7 + + sd_device_get_sysname() returns the sysfs name of the specified device record, + i.e. the last component of the sysfs path. Example: tty7 for the device + /sys/devices/virtual/tty/tty7 + + sd_device_get_sysnum() returns the sysfs device number of the specified device + record, i.e. the numeric suffix of the last component of the sysfs path. Example: 7 + for the device /sys/devices/virtual/tty/tty7 + + sd_device_get_subsystem() returns the kernel subsystem of the specified device + record. This is a short string fitting into a filename, and thus does not contain a slash and cannot be + empty. Example: tty, block or net. + + sd_device_get_devtype() returns the device type of the specified device + record, if the subsystem manages multiple types of devices. Example: for devices of the + block subsystem this can be disk or partition + + + sd_device_get_devname() returns the device node path of the specified device + record if the device has a device node. Example: for /sys/devices/virtual/tty/tty7 + the string /dev/tty7 is typically returned. + + sd_device_get_devnum() returns the device node major/minor + (i.e. dev_t) of the specified device record if the device has a device node (i.e. the one + returned by sd_device_get_devname()). For devices belonging to the + block subsystem this refers to a block device node, in all other cases to a character + device node. Example: for the /sys/devices/virtual/tty/tty7 device this typically + returns the device number with major/minor 4:7. + + sd_device_get_ifindex() returns the network interface index of the specified + device record, if the device encapsulates a network interface device, i.e. belongs to the + net subsystem. Example: the lo interface typically has interface + index 1. + + sd_device_get_driver() returns the kernel driver name attached to the + device. Note that the driver field is set on the devices consumed by the driver, not on the device + created by it. Example: a PCI device /sys/bus/pci/devices/0000:00:1f.6 might be + attached to a driver e1000e. + + sd_device_get_diskseq() returns the kernel disk sequence number of the block + device. This number monotonically increases whenever a backing medium of a block device changes without + the device name changing, and is relevant for block devices encapsulating devices with changing media + (e.g. floppy or CD-ROM), or loopback block devices. Only defined for block devices, i.e. those of + subsystem block. + + + + Return Value + + On success, these calls return 0 or a positive integer. On failure, they return a negative + errno-style error code. + + + Errors + + Returned errors may indicate the following problems: + + + + -EINVAL + + A specified parameter is invalid. + + + + -ENOENT + + The requested field is not present in the device record. + + + + + + + + + + See Also + + + systemd1 + + + +