]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-device: introduce sd_device_open()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 30 Mar 2022 18:29:23 +0000 (03:29 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 1 Apr 2022 06:13:18 +0000 (15:13 +0900)
We usually open() device node obtained by sd_device_get_devname().
However, the device node corresponds to the sd-device object may be
already removed, and another device node with the same path may be
created, hence an unexpected device may be opened.

The sd_device_open() opens device node, and checks the devnum and
diskseq of opened devnum, to avoid the above possibility.

Prompted by https://github.com/systemd/systemd/issues/22906#issuecomment-1082736443.

src/libsystemd/libsystemd.sym
src/libsystemd/sd-device/sd-device.c
src/systemd/sd-device.h

index 0066894d547cff8dbae51b689eff386f159bbcff..bdf76b467b7f80ce64a8a11518e33a8fa87b6d8c 100644 (file)
@@ -775,4 +775,5 @@ global:
         sd_id128_to_uuid_string;
         sd_device_new_from_devname;
         sd_device_new_from_path;
+        sd_device_open;
 } LIBSYSTEMD_250;
index c7389c8a3b5bd9daaf78c6ec43fc25623968d72b..4f413880eb10bcab65fec392ecc0acc9237f7f9e 100644 (file)
@@ -2237,3 +2237,68 @@ _public_ int sd_device_trigger_with_uuid(
         *ret_uuid = u;
         return 0;
 }
+
+_public_ int sd_device_open(sd_device *device, int flags) {
+        _cleanup_close_ int fd = -1, fd2 = -1;
+        const char *devname, *subsystem = NULL;
+        uint64_t q, diskseq = 0;
+        struct stat st;
+        dev_t devnum;
+        int r;
+
+        assert_return(device, -EINVAL);
+        assert_return(FLAGS_SET(flags, O_PATH) || !FLAGS_SET(flags, O_NOFOLLOW), -EINVAL);
+
+        r = sd_device_get_devname(device, &devname);
+        if (r == -ENOENT)
+                return -ENOEXEC;
+        if (r < 0)
+                return r;
+
+        r = sd_device_get_devnum(device, &devnum);
+        if (r == -ENOENT)
+                return -ENOEXEC;
+        if (r < 0)
+                return r;
+
+        r = sd_device_get_subsystem(device, &subsystem);
+        if (r < 0 && r != -ENOENT)
+                return r;
+
+        r = sd_device_get_diskseq(device, &diskseq);
+        if (r < 0 && r != -ENOENT)
+                return r;
+
+        fd = open(devname, FLAGS_SET(flags, O_PATH) ? flags : O_CLOEXEC|O_NOFOLLOW|O_PATH);
+        if (fd < 0)
+                return -errno;
+
+        if (fstat(fd, &st) < 0)
+                return -errno;
+
+        if (st.st_rdev != devnum)
+                return -ENXIO;
+
+        if (streq_ptr(subsystem, "block") ? !S_ISBLK(st.st_mode) : !S_ISCHR(st.st_mode))
+                return -ENXIO;
+
+        /* If flags has O_PATH, then we cannot check diskseq. Let's return earlier. */
+        if (FLAGS_SET(flags, O_PATH))
+                return TAKE_FD(fd);
+
+        fd2 = open(FORMAT_PROC_FD_PATH(fd), flags);
+        if (fd2 < 0)
+                return -errno;
+
+        if (diskseq == 0)
+                return TAKE_FD(fd2);
+
+        r = fd_get_diskseq(fd2, &q);
+        if (r < 0)
+                return r;
+
+        if (q != diskseq)
+                return -ENXIO;
+
+        return TAKE_FD(fd2);
+}
index 2ac670b08cd78723821c553e25f837ef717fe968..f0c3c115e4337b3c872288a782cae7830ea38e51 100644 (file)
@@ -109,6 +109,7 @@ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, const ch
 int sd_device_set_sysattr_valuef(sd_device *device, const char *sysattr, const char *format, ...) _sd_printf_(3, 4);
 int sd_device_trigger(sd_device *device, sd_device_action_t action);
 int sd_device_trigger_with_uuid(sd_device *device, sd_device_action_t action, sd_id128_t *ret_uuid);
+int sd_device_open(sd_device *device, int flags);
 
 /* device enumerator */