diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2022-08-12 01:54:47 +0900 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2022-08-12 21:41:12 +0900 |
commit | 95c250be0d35fccdcea2a04026dece28c047d3a4 (patch) | |
tree | e47add2830c0def75163f85bb34db693a872aabc /src/libsystemd | |
parent | edf6cbc30f60627fedaf88480ba03b6bbed9da99 (diff) | |
download | systemd-95c250be0d35fccdcea2a04026dece28c047d3a4.tar.gz |
sd-device: allow to create sd-device object through a symlink outside of /sys
For example, /proc/device-tree is a symlink to /sys/firmware/devicetree/base,
and the kernel documentation says the symlink should be used by userspace app.
See, https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-firmware-ofw.
Hence, it is useful to make `sd_device_new_from_path()` support such symlink.
Diffstat (limited to 'src/libsystemd')
-rw-r--r-- | src/libsystemd/sd-device/sd-device.c | 26 |
1 files changed, 18 insertions, 8 deletions
diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index 1050234afe..8574337bda 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -145,15 +145,12 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) { assert(device); assert(_syspath); - /* must be a subdirectory of /sys */ - if (!path_startswith(_syspath, "/sys/")) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "sd-device: Syspath '%s' is not a subdirectory of /sys", - _syspath); - if (verify) { _cleanup_close_ int fd = -1; + /* The input path maybe a symlink located outside of /sys. Let's try to chase the symlink at first. + * The primary usecase is that e.g. /proc/device-tree is a symlink to /sys/firmware/devicetree/base. + * By chasing symlinks in the path at first, we can call sd_device_new_from_path() with such path. */ r = chase_symlinks(_syspath, NULL, 0, &syspath, &fd); if (r == -ENOENT) /* the device does not exist (any more?) */ @@ -230,6 +227,12 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) { "sd-device: the syspath \"%s\" is outside of sysfs, refusing.", syspath); } } else { + /* must be a subdirectory of /sys */ + if (!path_startswith(_syspath, "/sys/")) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "sd-device: Syspath '%s' is not a subdirectory of /sys", + _syspath); + syspath = strdup(_syspath); if (!syspath) return log_oom_debug(); @@ -250,13 +253,16 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) { return 0; } -_public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) { +static int device_new_from_syspath(sd_device **ret, const char *syspath, bool strict) { _cleanup_(sd_device_unrefp) sd_device *device = NULL; int r; assert_return(ret, -EINVAL); assert_return(syspath, -EINVAL); + if (strict && !path_startswith(syspath, "/sys/")) + return -EINVAL; + r = device_new_aux(&device); if (r < 0) return r; @@ -269,6 +275,10 @@ _public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) { return 0; } +_public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) { + return device_new_from_syspath(ret, syspath, /* strict = */ true); +} + static int device_new_from_mode_and_devnum(sd_device **ret, mode_t mode, dev_t devnum) { _cleanup_(sd_device_unrefp) sd_device *dev = NULL; _cleanup_free_ char *syspath = NULL; @@ -516,7 +526,7 @@ _public_ int sd_device_new_from_path(sd_device **ret, const char *path) { if (path_startswith(path, "/dev")) return sd_device_new_from_devname(ret, path); - return sd_device_new_from_syspath(ret, path); + return device_new_from_syspath(ret, path, /* strict = */ false); } int device_set_devtype(sd_device *device, const char *devtype) { |