summaryrefslogtreecommitdiff
path: root/src/libsystemd
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2022-08-12 01:54:47 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2022-08-12 21:41:12 +0900
commit95c250be0d35fccdcea2a04026dece28c047d3a4 (patch)
treee47add2830c0def75163f85bb34db693a872aabc /src/libsystemd
parentedf6cbc30f60627fedaf88480ba03b6bbed9da99 (diff)
downloadsystemd-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.c26
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) {