mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-24 21:34:08 +03:00
sd-device: introduce sd_device_open()
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.
This commit is contained in:
parent
7e93a65868
commit
f9a726abef
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user