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
+
+
+
+
diff --git a/man/udevadm.xml b/man/udevadm.xml
index 3248cfd256..b0e448e568 100644
--- a/man/udevadm.xml
+++ b/man/udevadm.xml
@@ -230,6 +230,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
@@ -242,6 +266,14 @@
S:
Device node symlink
+
+ Q:
+ Block device sequence number (DISKSEQ)
+
+
+ V:
+ Attached driver
+
E:
Device property
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 4f413880eb..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"))
@@ -1047,14 +1078,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;
}
diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c
index a088c1727c..12a1769bd8 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,
@@ -171,26 +172,72 @@ 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);
- printf("P: %s\n", 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.
+ *
+ * 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%s%s\n", ansi_highlight_white(), str, ansi_normal());
+
+ if (sd_device_get_sysname(device, &str) >= 0)
+ printf("M: %s%s%s\n", ansi_highlight_white(), str, ansi_normal());
+
+ if (sd_device_get_sysnum(device, &str) >= 0)
+ printf("R: %s%s%s\n", ansi_highlight_white(), str, ansi_normal());
+
+ if (sd_device_get_subsystem(device, &subsys) >= 0)
+ printf("U: %s%s%s\n", ansi_highlight_green(), subsys, ansi_normal());
+
+ if (sd_device_get_devtype(device, &str) >= 0)
+ printf("T: %s%s%s\n", ansi_highlight_green(), str, ansi_normal());
+
+ if (sd_device_get_devnum(device, &devnum) >= 0)
+ 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: %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: %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%s%s\n", ansi_highlight_cyan(), val, ansi_normal());
+ }
}
- if (device_get_devlink_priority(device, &i) >= 0)
- printf("L: %i\n", i);
+ if (sd_device_get_diskseq(device, &q) >= 0)
+ printf("Q: %s%" PRIu64 "%s\n", ansi_highlight_magenta(), q, ansi_normal());
- 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%s%s\n", ansi_highlight_yellow4(), str, ansi_normal());
FOREACH_DEVICE_PROPERTY(device, str, val)
printf("E: %s=%s\n", str, val);
@@ -442,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,
@@ -584,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;
@@ -618,5 +672,5 @@ int info_main(int argc, char *argv[], void *userdata) {
return r;
}
- return 0;
+ return ret;
}