Merge pull request #34123 from yuwata/sd-device

sd-device: expose sd_device_get_device_id() and sd_device_get_driver_subsystem()
This commit is contained in:
Yu Watanabe
2024-08-28 11:33:09 +09:00
committed by GitHub
13 changed files with 203 additions and 64 deletions

View File

@@ -524,12 +524,14 @@ manpages = [
['sd_bus_wait', '3', [], ''],
['sd_device_get_syspath',
'3',
['sd_device_get_devname',
['sd_device_get_device_id',
'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_driver_subsystem',
'sd_device_get_ifindex',
'sd_device_get_subsystem',
'sd_device_get_sysname',

View File

@@ -22,12 +22,14 @@
<refname>sd_device_get_sysname</refname>
<refname>sd_device_get_sysnum</refname>
<refname>sd_device_get_subsystem</refname>
<refname>sd_device_get_driver_subsystem</refname>
<refname>sd_device_get_devtype</refname>
<refname>sd_device_get_devname</refname>
<refname>sd_device_get_devnum</refname>
<refname>sd_device_get_ifindex</refname>
<refname>sd_device_get_driver</refname>
<refname>sd_device_get_diskseq</refname>
<refname>sd_device_get_device_id</refname>
<refpurpose>Returns various fields of device objects</refpurpose>
</refnamediv>
@@ -66,6 +68,12 @@
<paramdef>const char **<parameter>ret</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_device_get_driver_subsystem</function></funcdef>
<paramdef>sd_device *<parameter>device</parameter></paramdef>
<paramdef>const char **<parameter>ret</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_device_get_devtype</function></funcdef>
<paramdef>sd_device *<parameter>device</parameter></paramdef>
@@ -102,6 +110,12 @@
<paramdef>uint64_t *<parameter>ret</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_device_get_device_id</function></funcdef>
<paramdef>sd_device *<parameter>device</parameter></paramdef>
<paramdef>uint64_t *<parameter>ret</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
@@ -126,6 +140,13 @@
record. This is a short string fitting into a filename, and thus does not contain a slash and cannot be
empty. Example: <literal>tty</literal>, <literal>block</literal> or <literal>net</literal>.</para>
<para><function>sd_device_get_driver_subsystem()</function> returns the connected bus type of the devices
loaded by the specified driver device record. For example, when <literal>iwlwifi</literal> driver device
is specified, which is used by the wireless network interfaces connected to PCI bus, this function returns
<literal>pci</literal>. This function only succeeds when <function>sd_device_get_subsystem()</function>
returns <literal>drivers</literal>. Example: <literal>pci</literal>, <literal>i2c</literal>, or
<literal>hid</literal>.</para>
<para><function>sd_device_get_devtype()</function> returns the device type of the specified device
record, if the subsystem manages multiple types of devices. Example: for devices of the
<literal>block</literal> subsystem this can be <literal>disk</literal> or <literal>partition</literal>
@@ -157,6 +178,22 @@
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 <literal>block</literal>.</para>
<para><function>sd_device_get_device_id()</function> returns the short string that identifies the device
record. When the device ID obtained by the function for a specified device record is passed to
<function>sd_device_new_from_device_id()</function>, a new instance of the same device record will be
gained. When a block or character device is specified, which has corresponding device node, this returns
<literal>b</literal> or <literal>c</literal>, respectively, followed by the device node major and minor
numbers separated with a colon. Example: <literal>b259:1</literal> or <literal>c10:121</literal>. Whan a
network interface device is specified, this returns <literal>n</literal> followed by the interface index,
which can be obtained by <function>sd_device_get_ifindex()</function>. Example: <literal>n1</literal>.
When a device in the <literal>driver</literal> subsystem is specified, this returns
<literal>+drivers:</literal> followed by its driver subsystem and sysfs name separated with a colon.
Example: <literal>+drivers:pci:iwlwifi</literal> for a driver device record whose driver subsystem is
<literal>pci</literal> and sysfs name is <literal>iwlwifi</literal>,
When an other type of device is specified, this function returns <literal>+</literal> followed by its
subsystem and sysfs name separated with a colon. Example: <literal>+acpi:ACPI0003:00</literal>,
<literal>+input:input16</literal>, or <literal>+pci:0000:00:1f.6</literal>.</para>
</refsect1>
<refsect1>
@@ -206,6 +243,8 @@
<function>sd_device_get_ifindex()</function>,
<function>sd_device_get_driver()</function>, and
<function>sd_device_get_diskseq()</function> were added in version 251.</para>
<para><function>sd_device_get_driver_subsystem()</function> and
<function>sd_device_get_device_id()</function> were added in version 257.</para>
</refsect1>
<refsect1>

View File

@@ -336,10 +336,18 @@
<entry><literal>R:</literal></entry>
<entry>Device number in <filename>/sys/</filename> (i.e. the numeric suffix of the last component of <literal>P:</literal>)</entry>
</row>
<row>
<entry><literal>J:</literal></entry>
<entry>Device ID</entry>
</row>
<row>
<entry><literal>U:</literal></entry>
<entry>Kernel subsystem</entry>
</row>
<row>
<entry><literal>B:</literal></entry>
<entry>Driver subsystem</entry>
</row>
<row>
<entry><literal>T:</literal></entry>
<entry>Kernel device type within subsystem</entry>

View File

@@ -1046,6 +1046,8 @@ global:
sd_varlink_take_fd;
sd_varlink_unref;
sd_varlink_wait;
sd_device_get_device_id;
sd_device_get_driver_subsystem;
sd_device_monitor_is_running;
sd_device_monitor_get_fd;
sd_device_monitor_get_events;

View File

@@ -711,7 +711,7 @@ static int device_tag(sd_device *device, const char *tag, bool add) {
assert(device);
assert(tag);
r = device_get_device_id(device, &id);
r = sd_device_get_device_id(device, &id);
if (r < 0)
return r;
@@ -797,7 +797,7 @@ static int device_get_db_path(sd_device *device, char **ret) {
assert(device);
assert(ret);
r = device_get_device_id(device, &id);
r = sd_device_get_device_id(device, &id);
if (r < 0)
return r;

View File

@@ -26,7 +26,6 @@ static inline int device_get_sysattr_unsigned(sd_device *device, const char *sys
}
int device_get_sysattr_u32(sd_device *device, const char *sysattr, uint32_t *ret_value);
int device_get_sysattr_bool(sd_device *device, const char *sysattr);
int device_get_device_id(sd_device *device, const char **ret);
int device_get_devlink_priority(sd_device *device, int *ret);
int device_get_devnode_mode(sd_device *device, mode_t *ret);
int device_get_devnode_uid(sd_device *device, uid_t *ret);

View File

@@ -345,9 +345,11 @@ _public_ int sd_device_new_from_ifname(sd_device **ret, const char *ifname) {
assert_return(ret, -EINVAL);
assert_return(ifname, -EINVAL);
r = device_new_from_main_ifname(ret, ifname);
if (r >= 0)
return r;
if (ifname_valid(ifname)) {
r = device_new_from_main_ifname(ret, ifname);
if (r >= 0)
return r;
}
r = rtnl_resolve_ifname_full(NULL, RESOLVE_IFNAME_ALTERNATIVE | RESOLVE_IFNAME_NUMERIC, ifname, &main_name, NULL);
if (r < 0)
@@ -384,25 +386,80 @@ _public_ int sd_device_new_from_ifindex(sd_device **ret, int ifindex) {
return 0;
}
static int device_strjoin_new(
static int device_new_from_path_join(
sd_device **device,
const char *subsystem,
const char *driver_subsystem,
const char *sysname,
const char *a,
const char *b,
const char *c,
const char *d,
sd_device **ret) {
const char *d) {
const char *p;
_cleanup_(sd_device_unrefp) sd_device *new_device = NULL;
_cleanup_free_ char *p = NULL;
int r;
p = strjoina(a, b, c, d);
if (access(p, F_OK) < 0)
return IN_SET(errno, ENOENT, ENAMETOOLONG) ? 0 : -errno; /* If this sysfs is too long then it doesn't exist either */
assert(device);
assert(subsystem);
assert(sysname);
r = sd_device_new_from_syspath(ret, p);
p = path_join(a, b, c, d);
if (!p)
return -ENOMEM;
r = sd_device_new_from_syspath(&new_device, p);
if (r == -ENODEV)
return 0;
if (r < 0)
return r;
return 1;
/* Check if the found device really has the expected subsystem and sysname, for safety. */
if (!device_in_subsystem(new_device, subsystem))
return 0;
const char *new_driver_subsystem = NULL;
(void) sd_device_get_driver_subsystem(new_device, &new_driver_subsystem);
if (!streq_ptr(driver_subsystem, new_driver_subsystem))
return 0;
const char *new_sysname;
r = sd_device_get_sysname(new_device, &new_sysname);
if (r < 0)
return r;
if (!streq(sysname, new_sysname))
return 0;
/* If this is the first device we found, then take it. */
if (!*device) {
*device = TAKE_PTR(new_device);
return 1;
}
/* Unfortunately, (subsystem, sysname) pair is not unique. For examples,
* - /sys/bus/gpio and /sys/class/gpio, both have gpiochip%N. However, these point to different devpaths.
* - /sys/bus/mdio_bus and /sys/class/mdio_bus,
* - /sys/bus/mei and /sys/class/mei,
* - /sys/bus/typec and /sys/class/typec, and so on.
* Hence, if we already know a device, then we need to check if it is equivalent to the newly found one. */
const char *devpath, *new_devpath;
r = sd_device_get_devpath(*device, &devpath);
if (r < 0)
return r;
r = sd_device_get_devpath(new_device, &new_devpath);
if (r < 0)
return r;
if (!streq(devpath, new_devpath))
return log_debug_errno(SYNTHETIC_ERRNO(ETOOMANYREFS),
"sd-device: found multiple devices for subsystem=%s and sysname=%s, refusing: %s, %s",
subsystem, sysname, devpath, new_devpath);
return 1; /* Fortunately, they are consistent. */
}
_public_ int sd_device_new_from_subsystem_sysname(
@@ -410,6 +467,7 @@ _public_ int sd_device_new_from_subsystem_sysname(
const char *subsystem,
const char *sysname) {
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
char *name;
int r;
@@ -428,19 +486,15 @@ _public_ int sd_device_new_from_subsystem_sysname(
if (streq(subsystem, "subsystem")) {
FOREACH_STRING(s, "/sys/bus/", "/sys/class/") {
r = device_strjoin_new(s, name, NULL, NULL, ret);
r = device_new_from_path_join(&device, subsystem, NULL, sysname, s, name, NULL, NULL);
if (r < 0)
return r;
if (r > 0)
return 0;
}
} else if (streq(subsystem, "module")) {
r = device_strjoin_new("/sys/module/", name, NULL, NULL, ret);
r = device_new_from_path_join(&device, subsystem, NULL, sysname, "/sys/module/", name, NULL, NULL);
if (r < 0)
return r;
if (r > 0)
return 0;
} else if (streq(subsystem, "drivers")) {
const char *sep;
@@ -452,35 +506,31 @@ _public_ int sd_device_new_from_subsystem_sysname(
sep++;
if (streq(sep, "drivers")) /* If the sysname is "drivers", then it's the drivers directory itself that is meant. */
r = device_strjoin_new("/sys/bus/", subsys, "/drivers", NULL, ret);
r = device_new_from_path_join(&device, subsystem, subsys, "drivers", "/sys/bus/", subsys, "/drivers", NULL);
else
r = device_strjoin_new("/sys/bus/", subsys, "/drivers/", sep, ret);
r = device_new_from_path_join(&device, subsystem, subsys, sep, "/sys/bus/", subsys, "/drivers/", sep);
if (r < 0)
return r;
if (r > 0)
return 0;
}
}
r = device_strjoin_new("/sys/bus/", subsystem, "/devices/", name, ret);
r = device_new_from_path_join(&device, subsystem, NULL, sysname, "/sys/bus/", subsystem, "/devices/", name);
if (r < 0)
return r;
if (r > 0)
return 0;
r = device_strjoin_new("/sys/class/", subsystem, "/", name, ret);
r = device_new_from_path_join(&device, subsystem, NULL, sysname, "/sys/class/", subsystem, name, NULL);
if (r < 0)
return r;
if (r > 0)
return 0;
r = device_strjoin_new("/sys/firmware/", subsystem, "/", name, ret);
r = device_new_from_path_join(&device, subsystem, NULL, sysname, "/sys/firmware/", subsystem, name, NULL);
if (r < 0)
return r;
if (r > 0)
return 0;
return -ENODEV;
if (!device)
return -ENODEV;
*ret = TAKE_PTR(device);
return 0;
}
_public_ int sd_device_new_from_stat_rdev(sd_device **ret, const struct stat *st) {
@@ -1196,6 +1246,20 @@ _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) {
return 0;
}
_public_ int sd_device_get_driver_subsystem(sd_device *device, const char **ret) {
assert_return(device, -EINVAL);
if (!device_in_subsystem(device, "drivers"))
return -ENOENT;
assert(device->driver_subsystem);
if (ret)
*ret = device->driver_subsystem;
return 0;
}
_public_ int sd_device_get_devtype(sd_device *device, const char **devtype) {
int r;
@@ -1211,7 +1275,7 @@ _public_ int sd_device_get_devtype(sd_device *device, const char **devtype) {
if (devtype)
*devtype = device->devtype;
return !!device->devtype;
return 0;
}
_public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *device, const char *subsystem, const char *devtype, sd_device **ret) {
@@ -1621,9 +1685,8 @@ static int handle_db_line(sd_device *device, char key, const char *value) {
}
}
int device_get_device_id(sd_device *device, const char **ret) {
assert(device);
assert(ret);
_public_ int sd_device_get_device_id(sd_device *device, const char **ret) {
assert_return(device, -EINVAL);
if (!device->device_id) {
_cleanup_free_ char *id = NULL;
@@ -1673,7 +1736,8 @@ int device_get_device_id(sd_device *device, const char **ret) {
device->device_id = TAKE_PTR(id);
}
*ret = device->device_id;
if (ret)
*ret = device->device_id;
return 0;
}

View File

@@ -74,33 +74,37 @@ static void test_sd_device_one(sd_device *d) {
r = sd_device_get_subsystem(d, &subsystem);
if (r < 0)
assert_se(r == -ENOENT);
else if (!streq(subsystem, "gpio")) { /* Unfortunately, there exist /sys/class/gpio and /sys/bus/gpio.
* Hence, sd_device_new_from_subsystem_sysname() and
* sd_device_new_from_device_id() may not work as expected. */
else {
const char *name, *id;
if (streq(subsystem, "drivers"))
name = strjoina(d->driver_subsystem, ":", sysname);
else
if (streq(subsystem, "drivers")) {
const char *driver_subsystem;
ASSERT_OK(sd_device_get_driver_subsystem(d, &driver_subsystem));
name = strjoina(driver_subsystem, ":", sysname);
} else
name = sysname;
assert_se(sd_device_new_from_subsystem_sysname(&dev, subsystem, name) >= 0);
assert_se(sd_device_get_syspath(dev, &val) >= 0);
assert_se(streq(syspath, val));
dev = sd_device_unref(dev);
r = sd_device_new_from_subsystem_sysname(&dev, subsystem, name);
if (r >= 0) {
assert_se(sd_device_get_syspath(dev, &val) >= 0);
assert_se(streq(syspath, val));
dev = sd_device_unref(dev);
} else
ASSERT_ERROR(r, ETOOMANYREFS);
/* The device ID depends on subsystem. */
assert_se(device_get_device_id(d, &id) >= 0);
assert_se(sd_device_get_device_id(d, &id) >= 0);
r = sd_device_new_from_device_id(&dev, id);
if (r == -ENODEV && ifindex > 0)
log_device_warning_errno(d, r,
"Failed to create sd-device object from device ID \"%s\". "
"Maybe running on a non-host network namespace.", id);
else {
assert_se(r >= 0);
else if (r >= 0) {
assert_se(sd_device_get_syspath(dev, &val) >= 0);
assert_se(streq(syspath, val));
dev = sd_device_unref(dev);
}
} else
ASSERT_ERROR(r, ETOOMANYREFS);
/* These require udev database, and reading database requires device ID. */
r = sd_device_get_is_initialized(d);

View File

@@ -74,6 +74,7 @@ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *su
int sd_device_get_syspath(sd_device *device, const char **ret);
int sd_device_get_subsystem(sd_device *device, const char **ret);
int sd_device_get_driver_subsystem(sd_device *device, const char **ret);
int sd_device_get_devtype(sd_device *device, const char **ret);
int sd_device_get_devnum(sd_device *device, dev_t *devnum);
int sd_device_get_ifindex(sd_device *device, int *ifindex);
@@ -85,6 +86,7 @@ int sd_device_get_sysnum(sd_device *device, const char **ret);
int sd_device_get_action(sd_device *device, sd_device_action_t *ret);
int sd_device_get_seqnum(sd_device *device, uint64_t *ret);
int sd_device_get_diskseq(sd_device *device, uint64_t *ret);
int sd_device_get_device_id(sd_device *device, const char **ret);
int sd_device_get_is_initialized(sd_device *device);
int sd_device_get_usec_initialized(sd_device *device, uint64_t *ret);

View File

@@ -729,7 +729,7 @@ static int event_queue_insert(Manager *manager, sd_device *dev) {
if (r < 0 && r != -ENOENT)
return r;
r = device_get_device_id(dev, &id);
r = sd_device_get_device_id(dev, &id);
if (r < 0 && r != -ENOENT)
return r;

View File

@@ -220,7 +220,7 @@ static int stack_directory_find_prioritized_devnode(sd_device *dev, int dirfd, b
if (!dir)
return -errno;
r = device_get_device_id(dev, &id);
r = sd_device_get_device_id(dev, &id);
if (r < 0)
return r;
@@ -246,7 +246,7 @@ static int stack_directory_update(sd_device *dev, int fd, bool add) {
assert(dev);
assert(fd >= 0);
r = device_get_device_id(dev, &id);
r = sd_device_get_device_id(dev, &id);
if (r < 0)
return r;
@@ -405,7 +405,7 @@ static int node_get_current(const char *slink, int dirfd, char **ret_id, int *re
if (r < 0)
return r;
r = device_get_device_id(dev, &id);
r = sd_device_get_device_id(dev, &id);
if (r < 0)
return r;
@@ -446,7 +446,7 @@ static int link_update(sd_device *dev, const char *slink, bool add) {
if (current_id) {
const char *id;
r = device_get_device_id(dev, &id);
r = sd_device_get_device_id(dev, &id);
if (r < 0)
return log_device_debug_errno(dev, r, "Failed to get device id: %m");

View File

@@ -111,7 +111,7 @@ static int udev_watch_clear(sd_device *dev, int dirfd, int *ret_wd) {
assert(dev);
assert(dirfd >= 0);
r = device_get_device_id(dev, &id);
r = sd_device_get_device_id(dev, &id);
if (r < 0)
return log_device_debug_errno(dev, r, "Failed to get device ID: %m");
@@ -188,7 +188,7 @@ int udev_watch_begin(int inotify_fd, sd_device *dev) {
if (r < 0)
return log_device_debug_errno(dev, r, "Failed to get device node: %m");
r = device_get_device_id(dev, &id);
r = sd_device_get_device_id(dev, &id);
if (r < 0)
return log_device_debug_errno(dev, r, "Failed to get device ID: %m");

View File

@@ -323,9 +323,15 @@ static int print_record(sd_device *device, const char *prefix) {
if (sd_device_get_sysnum(device, &str) >= 0)
printf("%sR: %s%s%s\n", prefix, ansi_highlight_white(), str, ansi_normal());
if (sd_device_get_device_id(device, &str) >= 0)
printf("%sJ: %s%s%s\n", prefix, ansi_highlight_white(), str, ansi_normal());
if (sd_device_get_subsystem(device, &subsys) >= 0)
printf("%sU: %s%s%s\n", prefix, ansi_highlight_green(), subsys, ansi_normal());
if (sd_device_get_driver_subsystem(device, &str) >= 0)
printf("%sB: %s%s%s\n", prefix, ansi_highlight_green(), str, ansi_normal());
if (sd_device_get_devtype(device, &str) >= 0)
printf("%sT: %s%s%s\n", prefix, ansi_highlight_green(), str, ansi_normal());
@@ -376,8 +382,9 @@ static int record_to_json(sd_device *device, sd_json_variant **ret) {
assert(device);
assert(ret);
/* We don't show any shorthand fields here as done in print_record() except for SYSNAME and SYSNUM as
* all the other ones have a matching property which will already be included. */
/* We don't show any shorthand fields here as done in print_record() except for SYSNAME, SYSNUM,
* DRIVER_SUBSYSTEM, and DEVICE_ID, as all the other ones have a matching property which will already
* be included. */
if (sd_device_get_sysname(device, &str) >= 0) {
r = sd_json_variant_set_field_string(&v, "SYSNAME", str);
@@ -391,6 +398,18 @@ static int record_to_json(sd_device *device, sd_json_variant **ret) {
return r;
}
if (sd_device_get_driver_subsystem(device, &str) >= 0) {
r = sd_json_variant_set_field_string(&v, "DRIVER_SUBSYSTEM", str);
if (r < 0)
return r;
}
if (sd_device_get_device_id(device, &str) >= 0) {
r = sd_json_variant_set_field_string(&v, "DEVICE_ID", str);
if (r < 0)
return r;
}
FOREACH_DEVICE_PROPERTY(device, key, val) {
r = sd_json_variant_set_field_string(&v, key, val);
if (r < 0)