From: Yu Watanabe Date: Tue, 7 Jan 2025 18:23:29 +0000 (+0900) Subject: sd-device: make sd_device_new_from_path() accept relative path to device node X-Git-Tag: v258-rc1~1658 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=cdd53cb74b0882ed2a249117c895b94013fa6ea9;p=thirdparty%2Fsystemd.git sd-device: make sd_device_new_from_path() accept relative path to device node Even though udevadm accepts relative syspath, previously, udevadm could not use relative path to device node: === $ cd /dev $ udevadm info sda Bad argument "sda", expected an absolute path in /dev/ or /sys/ or a unit name: Invalid argument $ udevadm info /usr/../dev/sda Unknown device "/usr/../dev/sda": No such device === With this change, both the above cases work fine. Note, still sd_device_new_from_devname() requires absolute path starts with /dev/, for safety. --- diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index 9e281597796..a608ae326f4 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -541,10 +541,8 @@ _public_ int sd_device_new_from_stat_rdev(sd_device **ret, const struct stat *st return device_new_from_mode_and_devnum(ret, st->st_mode, st->st_rdev); } -_public_ int sd_device_new_from_devname(sd_device **ret, const char *devname) { - struct stat st; - dev_t devnum; - mode_t mode; +static int device_new_from_devname(sd_device **ret, const char *devname, bool strict) { + int r; assert_return(ret, -EINVAL); assert_return(devname, -EINVAL); @@ -552,28 +550,41 @@ _public_ int sd_device_new_from_devname(sd_device **ret, const char *devname) { /* This function actually accepts both devlinks and devnames, i.e. both symlinks and device * nodes below /dev/. */ - /* Also ignore when the specified path is "/dev". */ - if (isempty(path_startswith(devname, "/dev"))) + if (strict && isempty(path_startswith(devname, "/dev/"))) return -EINVAL; + dev_t devnum; + mode_t mode; if (device_path_parse_major_minor(devname, &mode, &devnum) >= 0) /* Let's shortcut when "/dev/block/maj:min" or "/dev/char/maj:min" is specified. * In that case, we can directly convert the path to syspath, hence it is not necessary * that the specified path exists. So, this works fine without udevd being running. */ return device_new_from_mode_and_devnum(ret, mode, devnum); - if (stat(devname, &st) < 0) - return ERRNO_IS_DEVICE_ABSENT(errno) ? -ENODEV : -errno; + _cleanup_free_ char *resolved = NULL; + struct stat st; + r = chase_and_stat(devname, /* root = */ NULL, /* flags = */ 0, &resolved, &st); + if (ERRNO_IS_NEG_DEVICE_ABSENT(r)) + return -ENODEV; + if (r < 0) + return r; + + if (isempty(path_startswith(resolved, "/dev/"))) + return -EINVAL; return sd_device_new_from_stat_rdev(ret, &st); } +_public_ int sd_device_new_from_devname(sd_device **ret, const char *devname) { + return device_new_from_devname(ret, devname, /* strict = */ true); +} + _public_ int sd_device_new_from_path(sd_device **ret, const char *path) { assert_return(ret, -EINVAL); assert_return(path, -EINVAL); - if (path_startswith(path, "/dev")) - return sd_device_new_from_devname(ret, path); + if (device_new_from_devname(ret, path, /* strict = */ false) >= 0) + return 0; return device_new_from_syspath(ret, path, /* strict = */ false); } diff --git a/test/units/TEST-17-UDEV.10.sh b/test/units/TEST-17-UDEV.10.sh index afa05909c40..e38291bdde8 100755 --- a/test/units/TEST-17-UDEV.10.sh +++ b/test/units/TEST-17-UDEV.10.sh @@ -103,6 +103,11 @@ udevadm info -e --initialized-nomatch >/dev/null # udevadm info -c udevadm info -w /sys/class/net/$netdev udevadm info --wait-for-initialization=5 /sys/class/net/$netdev +pushd /dev +udevadm info null >/dev/null +udevadm info ./null >/dev/null +popd +udevadm info /usr/../dev/null >/dev/null udevadm info -h assert_rc 124 timeout 1 udevadm monitor