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.
This commit is contained in:
Yu Watanabe
2022-08-12 21:41:12 +09:00
parent edf6cbc30f
commit 95c250be0d
+18 -8
View File
@@ -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) {