From 7176f06c9efea4b86f3f55e448fc80e16d43e54b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 13 Apr 2022 15:38:21 +0200 Subject: [PATCH] basic: split out dev_t related calls into new devno-util.[ch] No actual code changes, just splitting out of some dev_t handling related calls from stat-util.[ch], they are quite a number already, and deserve their own module now I think. Also, try to settle on the name "devnum" as the name for the concept, instead of "devno" or "dev" or "devid". "devnum" is the name exported in udev APIs, hence probably best to stick to that. (this just renames a few symbols to "devum", local variables are left untouched, to make the patch not too invasive) No actual code changes. --- src/basic/devnum-util.c | 133 ++++++++++++++++++++ src/basic/devnum-util.h | 37 ++++++ src/basic/meson.build | 2 + src/basic/parse-util.c | 28 ----- src/basic/parse-util.h | 1 - src/basic/stat-util.c | 95 -------------- src/basic/stat-util.h | 29 ----- src/basic/terminal-util.c | 1 + src/boot/bless-boot.c | 4 +- src/boot/bootctl.c | 3 +- src/core/bpf-devices.c | 2 +- src/core/cgroup.c | 2 +- src/gpt-auto-generator/gpt-auto-generator.c | 1 + src/home/homed-manager.c | 2 +- src/home/homework-luks.c | 2 +- src/home/homework-quota.c | 4 +- src/libsystemd/sd-device/sd-device.c | 4 +- src/login/logind-session-dbus.c | 2 +- src/login/logind-session.c | 3 +- src/nspawn/nspawn-oci.c | 2 +- src/partition/growfs.c | 1 + src/partition/repart.c | 4 +- src/shared/blockdev-util.c | 6 +- src/shared/bootspec.c | 4 +- src/shared/find-esp.c | 2 + src/shared/loop-util.c | 3 +- src/shared/quota-util.c | 9 +- src/shared/quota-util.h | 2 +- src/shared/sleep-config.c | 4 +- src/sysext/sysext.c | 4 +- src/sysupdate/sysupdate-resource.c | 2 +- src/test/meson.build | 2 + src/test/test-devnum-util.c | 109 ++++++++++++++++ src/test/test-parse-util.c | 17 --- src/test/test-stat-util.c | 82 ------------ src/tmpfiles/tmpfiles.c | 4 +- src/udev/udev-node.c | 1 + src/udev/udevadm-lock.c | 2 +- src/volatile-root/volatile-root.c | 2 +- 39 files changed, 329 insertions(+), 288 deletions(-) create mode 100644 src/basic/devnum-util.c create mode 100644 src/basic/devnum-util.h create mode 100644 src/test/test-devnum-util.c diff --git a/src/basic/devnum-util.c b/src/basic/devnum-util.c new file mode 100644 index 00000000000..d13a87d6d18 --- /dev/null +++ b/src/basic/devnum-util.c @@ -0,0 +1,133 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include + +#include "chase-symlinks.h" +#include "devnum-util.h" +#include "parse-util.h" +#include "path-util.h" +#include "string-util.h" + +int parse_devnum(const char *s, dev_t *ret) { + const char *major; + unsigned x, y; + size_t n; + int r; + + n = strspn(s, DIGITS); + if (n == 0) + return -EINVAL; + if (s[n] != ':') + return -EINVAL; + + major = strndupa_safe(s, n); + r = safe_atou(major, &x); + if (r < 0) + return r; + + r = safe_atou(s + n + 1, &y); + if (r < 0) + return r; + + if (!DEVICE_MAJOR_VALID(x) || !DEVICE_MINOR_VALID(y)) + return -ERANGE; + + *ret = makedev(x, y); + return 0; +} + +int device_path_make_major_minor(mode_t mode, dev_t devnum, char **ret) { + const char *t; + + /* Generates the /dev/{char|block}/MAJOR:MINOR path for a dev_t */ + + if (S_ISCHR(mode)) + t = "char"; + else if (S_ISBLK(mode)) + t = "block"; + else + return -ENODEV; + + if (asprintf(ret, "/dev/%s/%u:%u", t, major(devnum), minor(devnum)) < 0) + return -ENOMEM; + + return 0; +} + +int device_path_make_canonical(mode_t mode, dev_t devnum, char **ret) { + _cleanup_free_ char *p = NULL; + int r; + + /* Finds the canonical path for a device, i.e. resolves the /dev/{char|block}/MAJOR:MINOR path to the end. */ + + assert(ret); + + if (major(devnum) == 0 && minor(devnum) == 0) { + char *s; + + /* A special hack to make sure our 'inaccessible' device nodes work. They won't have symlinks in + * /dev/block/ and /dev/char/, hence we handle them specially here. */ + + if (S_ISCHR(mode)) + s = strdup("/run/systemd/inaccessible/chr"); + else if (S_ISBLK(mode)) + s = strdup("/run/systemd/inaccessible/blk"); + else + return -ENODEV; + + if (!s) + return -ENOMEM; + + *ret = s; + return 0; + } + + r = device_path_make_major_minor(mode, devnum, &p); + if (r < 0) + return r; + + return chase_symlinks(p, NULL, 0, ret, NULL); +} + +int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devnum) { + mode_t mode; + dev_t devnum; + int r; + + /* Tries to extract the major/minor directly from the device path if we can. Handles /dev/block/ and /dev/char/ + * paths, as well out synthetic inaccessible device nodes. Never goes to disk. Returns -ENODEV if the device + * path cannot be parsed like this. */ + + if (path_equal(path, "/run/systemd/inaccessible/chr")) { + mode = S_IFCHR; + devnum = makedev(0, 0); + } else if (path_equal(path, "/run/systemd/inaccessible/blk")) { + mode = S_IFBLK; + devnum = makedev(0, 0); + } else { + const char *w; + + w = path_startswith(path, "/dev/block/"); + if (w) + mode = S_IFBLK; + else { + w = path_startswith(path, "/dev/char/"); + if (!w) + return -ENODEV; + + mode = S_IFCHR; + } + + r = parse_devnum(w, &devnum); + if (r < 0) + return r; + } + + if (ret_mode) + *ret_mode = mode; + if (ret_devnum) + *ret_devnum = devnum; + + return 0; +} diff --git a/src/basic/devnum-util.h b/src/basic/devnum-util.h new file mode 100644 index 00000000000..9632e992bb8 --- /dev/null +++ b/src/basic/devnum-util.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include +#include +#include + +int parse_devnum(const char *s, dev_t *ret); + +/* glibc and the Linux kernel have different ideas about the major/minor size. These calls will check whether the + * specified major is valid by the Linux kernel's standards, not by glibc's. Linux has 20bits of minor, and 12 bits of + * major space. See MINORBITS in linux/kdev_t.h in the kernel sources. (If you wonder why we define _y here, instead of + * comparing directly >= 0: it's to trick out -Wtype-limits, which would otherwise complain if the type is unsigned, as + * such a test would be pointless in such a case.) */ + +#define DEVICE_MAJOR_VALID(x) \ + ({ \ + typeof(x) _x = (x), _y = 0; \ + _x >= _y && _x < (UINT32_C(1) << 12); \ + \ + }) + +#define DEVICE_MINOR_VALID(x) \ + ({ \ + typeof(x) _x = (x), _y = 0; \ + _x >= _y && _x < (UINT32_C(1) << 20); \ + }) + +int device_path_make_major_minor(mode_t mode, dev_t devnum, char **ret); +int device_path_make_canonical(mode_t mode, dev_t devnum, char **ret); +int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devnum); + +static inline bool devnum_set_and_equal(dev_t a, dev_t b) { + /* Returns true if a and b definitely refer to the same device. If either is zero, this means "don't + * know" and we'll return false */ + return a == b && a != 0; +} diff --git a/src/basic/meson.build b/src/basic/meson.build index 92a4df20177..501fcf147fa 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -32,6 +32,8 @@ basic_sources = files( 'conf-files.c', 'conf-files.h', 'def.h', + 'devnum-util.c', + 'devnum-util.h', 'dirent-util.c', 'dirent-util.h', 'dns-def.h', diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c index 222b2304cd0..35fbb5ec6ad 100644 --- a/src/basic/parse-util.c +++ b/src/basic/parse-util.c @@ -692,34 +692,6 @@ int parse_ip_prefix_length(const char *s, int *ret) { return 0; } -int parse_dev(const char *s, dev_t *ret) { - const char *major; - unsigned x, y; - size_t n; - int r; - - n = strspn(s, DIGITS); - if (n == 0) - return -EINVAL; - if (s[n] != ':') - return -EINVAL; - - major = strndupa_safe(s, n); - r = safe_atou(major, &x); - if (r < 0) - return r; - - r = safe_atou(s + n + 1, &y); - if (r < 0) - return r; - - if (!DEVICE_MAJOR_VALID(x) || !DEVICE_MINOR_VALID(y)) - return -ERANGE; - - *ret = makedev(x, y); - return 0; -} - int parse_oom_score_adjust(const char *s, int *ret) { int r, v; diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h index 8273124626f..f2222dcffb0 100644 --- a/src/basic/parse-util.h +++ b/src/basic/parse-util.h @@ -12,7 +12,6 @@ typedef unsigned long loadavg_t; int parse_boolean(const char *v) _pure_; -int parse_dev(const char *s, dev_t *ret); int parse_pid(const char *s, pid_t* ret_pid); int parse_mode(const char *s, mode_t *ret); int parse_ifindex(const char *s); diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c index b25cabc6b48..c7293db6989 100644 --- a/src/basic/stat-util.c +++ b/src/basic/stat-util.c @@ -314,101 +314,6 @@ int fd_verify_directory(int fd) { return stat_verify_directory(&st); } -int device_path_make_major_minor(mode_t mode, dev_t devno, char **ret) { - const char *t; - - /* Generates the /dev/{char|block}/MAJOR:MINOR path for a dev_t */ - - if (S_ISCHR(mode)) - t = "char"; - else if (S_ISBLK(mode)) - t = "block"; - else - return -ENODEV; - - if (asprintf(ret, "/dev/%s/%u:%u", t, major(devno), minor(devno)) < 0) - return -ENOMEM; - - return 0; -} - -int device_path_make_canonical(mode_t mode, dev_t devno, char **ret) { - _cleanup_free_ char *p = NULL; - int r; - - /* Finds the canonical path for a device, i.e. resolves the /dev/{char|block}/MAJOR:MINOR path to the end. */ - - assert(ret); - - if (major(devno) == 0 && minor(devno) == 0) { - char *s; - - /* A special hack to make sure our 'inaccessible' device nodes work. They won't have symlinks in - * /dev/block/ and /dev/char/, hence we handle them specially here. */ - - if (S_ISCHR(mode)) - s = strdup("/run/systemd/inaccessible/chr"); - else if (S_ISBLK(mode)) - s = strdup("/run/systemd/inaccessible/blk"); - else - return -ENODEV; - - if (!s) - return -ENOMEM; - - *ret = s; - return 0; - } - - r = device_path_make_major_minor(mode, devno, &p); - if (r < 0) - return r; - - return chase_symlinks(p, NULL, 0, ret, NULL); -} - -int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devno) { - mode_t mode; - dev_t devno; - int r; - - /* Tries to extract the major/minor directly from the device path if we can. Handles /dev/block/ and /dev/char/ - * paths, as well out synthetic inaccessible device nodes. Never goes to disk. Returns -ENODEV if the device - * path cannot be parsed like this. */ - - if (path_equal(path, "/run/systemd/inaccessible/chr")) { - mode = S_IFCHR; - devno = makedev(0, 0); - } else if (path_equal(path, "/run/systemd/inaccessible/blk")) { - mode = S_IFBLK; - devno = makedev(0, 0); - } else { - const char *w; - - w = path_startswith(path, "/dev/block/"); - if (w) - mode = S_IFBLK; - else { - w = path_startswith(path, "/dev/char/"); - if (!w) - return -ENODEV; - - mode = S_IFCHR; - } - - r = parse_dev(w, &devno); - if (r < 0) - return r; - } - - if (ret_mode) - *ret_mode = mode; - if (ret_devno) - *ret_devno = devno; - - return 0; -} - int proc_mounted(void) { int r; diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h index 37513a43e77..4483ceb7de7 100644 --- a/src/basic/stat-util.h +++ b/src/basic/stat-util.h @@ -71,29 +71,6 @@ int fd_verify_regular(int fd); int stat_verify_directory(const struct stat *st); int fd_verify_directory(int fd); -/* glibc and the Linux kernel have different ideas about the major/minor size. These calls will check whether the - * specified major is valid by the Linux kernel's standards, not by glibc's. Linux has 20bits of minor, and 12 bits of - * major space. See MINORBITS in linux/kdev_t.h in the kernel sources. (If you wonder why we define _y here, instead of - * comparing directly >= 0: it's to trick out -Wtype-limits, which would otherwise complain if the type is unsigned, as - * such a test would be pointless in such a case.) */ - -#define DEVICE_MAJOR_VALID(x) \ - ({ \ - typeof(x) _x = (x), _y = 0; \ - _x >= _y && _x < (UINT32_C(1) << 12); \ - \ - }) - -#define DEVICE_MINOR_VALID(x) \ - ({ \ - typeof(x) _x = (x), _y = 0; \ - _x >= _y && _x < (UINT32_C(1) << 20); \ - }) - -int device_path_make_major_minor(mode_t mode, dev_t devno, char **ret); -int device_path_make_canonical(mode_t mode, dev_t devno, char **ret); -int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devno); - int proc_mounted(void); bool stat_inode_same(const struct stat *a, const struct stat *b); @@ -119,9 +96,3 @@ int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct s struct new_statx nsx; \ } var #endif - -static inline bool devid_set_and_equal(dev_t a, dev_t b) { - /* Returns true if a and b definitely refer to the same device. If either is zero, this means "don't - * know" and we'll return false */ - return a == b && a != 0; -} diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index 6119f21c1b1..7cf74e97d0a 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -22,6 +22,7 @@ #include "alloc-util.h" #include "def.h" +#include "devnum-util.h" #include "env-util.h" #include "fd-util.h" #include "fileio.h" diff --git a/src/boot/bless-boot.c b/src/boot/bless-boot.c index c8bc205d1b0..d9c901d73bb 100644 --- a/src/boot/bless-boot.c +++ b/src/boot/bless-boot.c @@ -5,6 +5,7 @@ #include "alloc-util.h" #include "bootspec.h" +#include "devnum-util.h" #include "efi-api.h" #include "efi-loader.h" #include "efivars.h" @@ -16,7 +17,6 @@ #include "parse-util.h" #include "path-util.h" #include "pretty-print.h" -#include "stat-util.h" #include "sync-util.h" #include "terminal-util.h" #include "util.h" @@ -121,7 +121,7 @@ static int acquire_path(void) { "Couldn't find $BOOT partition. It is recommended to mount it to /boot.\n" "Alternatively, use --path= to specify path to mount point."); - if (esp_path && xbootldr_path && !devid_set_and_equal(esp_devid, xbootldr_devid)) /* in case the two paths refer to the same inode, suppress one */ + if (esp_path && xbootldr_path && !devnum_set_and_equal(esp_devid, xbootldr_devid)) /* in case the two paths refer to the same inode, suppress one */ a = strv_new(esp_path, xbootldr_path); else if (esp_path) a = strv_new(esp_path); diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index a393370f8d4..eac071bcc63 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -16,6 +16,7 @@ #include "blkid-util.h" #include "bootspec.h" #include "copy.h" +#include "devnum-util.h" #include "dirent-util.h" #include "efi-api.h" #include "efi-loader.h" @@ -595,7 +596,7 @@ static int boot_config_load_and_select( /* If XBOOTLDR and ESP actually refer to the same block device, suppress XBOOTLDR, since it would * find the same entries twice. */ - bool same = esp_path && xbootldr_path && devid_set_and_equal(esp_devid, xbootldr_devid); + bool same = esp_path && xbootldr_path && devnum_set_and_equal(esp_devid, xbootldr_devid); r = boot_config_load(config, esp_path, same ? NULL : xbootldr_path); if (r < 0) diff --git a/src/core/bpf-devices.c b/src/core/bpf-devices.c index 46996d28f4e..3af9e78a1e3 100644 --- a/src/core/bpf-devices.c +++ b/src/core/bpf-devices.c @@ -5,12 +5,12 @@ #include "bpf-devices.h" #include "bpf-program.h" +#include "devnum-util.h" #include "fd-util.h" #include "fileio.h" #include "nulstr-util.h" #include "parse-util.h" #include "path-util.h" -#include "stat-util.h" #include "stdio-util.h" #include "string-util.h" diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 2e2dfcb2aab..d3b617dc1a3 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -16,6 +16,7 @@ #include "cgroup-setup.h" #include "cgroup-util.h" #include "cgroup.h" +#include "devnum-util.h" #include "fd-util.h" #include "fileio.h" #include "in-addr-prefix-util.h" @@ -31,7 +32,6 @@ #include "procfs-util.h" #include "restrict-ifaces.h" #include "special.h" -#include "stat-util.h" #include "stdio-util.h" #include "string-table.h" #include "string-util.h" diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index 4731687b7f8..8b35b2364d3 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -12,6 +12,7 @@ #include "blockdev-util.h" #include "btrfs-util.h" #include "device-util.h" +#include "devnum-util.h" #include "dirent-util.h" #include "dissect-image.h" #include "dropin.h" diff --git a/src/home/homed-manager.c b/src/home/homed-manager.c index c2b9eb64f9b..a0253c34c1d 100644 --- a/src/home/homed-manager.c +++ b/src/home/homed-manager.c @@ -527,7 +527,7 @@ static int search_quota(uid_t uid, const char *exclude_quota_path) { previous_devno = st.st_dev; - r = quotactl_devno(QCMD_FIXED(Q_GETQUOTA, USRQUOTA), st.st_dev, uid, &req); + r = quotactl_devnum(QCMD_FIXED(Q_GETQUOTA, USRQUOTA), st.st_dev, uid, &req); if (r < 0) { if (ERRNO_IS_NOT_SUPPORTED(r)) log_debug_errno(r, "No UID quota support on %s, ignoring.", where); diff --git a/src/home/homework-luks.c b/src/home/homework-luks.c index 5416d12fcf9..9cfb0e7ae61 100644 --- a/src/home/homework-luks.c +++ b/src/home/homework-luks.c @@ -19,6 +19,7 @@ #include "blockdev-util.h" #include "btrfs-util.h" #include "chattr-util.h" +#include "devnum-util.h" #include "dm-util.h" #include "env-util.h" #include "errno-util.h" @@ -46,7 +47,6 @@ #include "process-util.h" #include "random-util.h" #include "resize-fs.h" -#include "stat-util.h" #include "strv.h" #include "sync-util.h" #include "tmpfile-util.h" diff --git a/src/home/homework-quota.c b/src/home/homework-quota.c index 7001870dfb8..574d1556af1 100644 --- a/src/home/homework-quota.c +++ b/src/home/homework-quota.c @@ -54,7 +54,7 @@ int home_update_quota_classic(UserRecord *h, const char *path) { if (devno == 0) return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system %s not backed by a block device.", path); - r = quotactl_devno(QCMD_FIXED(Q_GETQUOTA, USRQUOTA), devno, h->uid, &req); + r = quotactl_devnum(QCMD_FIXED(Q_GETQUOTA, USRQUOTA), devno, h->uid, &req); if (r < 0) { if (ERRNO_IS_NOT_SUPPORTED(r)) return log_error_errno(r, "No UID quota support on %s.", path); @@ -74,7 +74,7 @@ int home_update_quota_classic(UserRecord *h, const char *path) { req.dqb_valid = QIF_BLIMITS; req.dqb_bsoftlimit = req.dqb_bhardlimit = h->disk_size / QIF_DQBLKSIZE; - r = quotactl_devno(QCMD_FIXED(Q_SETQUOTA, USRQUOTA), devno, h->uid, &req); + r = quotactl_devnum(QCMD_FIXED(Q_SETQUOTA, USRQUOTA), devno, h->uid, &req); if (r < 0) { if (r == -ESRCH) return log_error_errno(SYNTHETIC_ERRNO(ENOTTY), "UID quota not available on %s.", path); diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index d31526fc222..22f16b9edc1 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -12,6 +12,7 @@ #include "device-internal.h" #include "device-private.h" #include "device-util.h" +#include "devnum-util.h" #include "dirent-util.h" #include "fd-util.h" #include "fileio.h" @@ -25,7 +26,6 @@ #include "path-util.h" #include "set.h" #include "socket-util.h" -#include "stat-util.h" #include "stdio-util.h" #include "string-util.h" #include "strv.h" @@ -786,7 +786,7 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) { if (isempty(id)) return -EINVAL; - r = parse_dev(id + 1, &devt); + r = parse_devnum(id + 1, &devt); if (r < 0) return r; diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c index ff4cd0a631b..7d46759822b 100644 --- a/src/login/logind-session-dbus.c +++ b/src/login/logind-session-dbus.c @@ -8,6 +8,7 @@ #include "bus-label.h" #include "bus-polkit.h" #include "bus-util.h" +#include "devnum-util.h" #include "fd-util.h" #include "logind-brightness.h" #include "logind-dbus.h" @@ -21,7 +22,6 @@ #include "missing_capability.h" #include "path-util.h" #include "signal-util.h" -#include "stat-util.h" #include "strv.h" #include "user-util.h" #include "util.h" diff --git a/src/login/logind-session.c b/src/login/logind-session.c index eef48c25275..4995e5885aa 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -15,6 +15,7 @@ #include "audit-util.h" #include "bus-error.h" #include "bus-util.h" +#include "devnum-util.h" #include "env-file.h" #include "escape.h" #include "fd-util.h" @@ -377,7 +378,7 @@ static int session_load_devices(Session *s, const char *devices) { break; } - k = parse_dev(word, &dev); + k = parse_devnum(word, &dev); if (k < 0) { r = k; continue; diff --git a/src/nspawn/nspawn-oci.c b/src/nspawn/nspawn-oci.c index 44564ba6195..86c014d25e7 100644 --- a/src/nspawn/nspawn-oci.c +++ b/src/nspawn/nspawn-oci.c @@ -8,6 +8,7 @@ #include "bus-util.h" #include "cap-list.h" #include "cpu-set-util.h" +#include "devnum-util.h" #include "env-util.h" #include "format-util.h" #include "fs-util.h" @@ -20,7 +21,6 @@ #if HAVE_SECCOMP #include "seccomp-util.h" #endif -#include "stat-util.h" #include "stdio-util.h" #include "string-util.h" #include "strv.h" diff --git a/src/partition/growfs.c b/src/partition/growfs.c index 0d1da2773f0..31dcf0ffdf1 100644 --- a/src/partition/growfs.c +++ b/src/partition/growfs.c @@ -14,6 +14,7 @@ #include "btrfs-util.h" #include "cryptsetup-util.h" #include "device-nodes.h" +#include "devnum-util.h" #include "dissect-image.h" #include "escape.h" #include "fd-util.h" diff --git a/src/partition/repart.c b/src/partition/repart.c index 34aa88198b7..051242e836c 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -24,6 +24,7 @@ #include "conf-parser.h" #include "cryptsetup-util.h" #include "def.h" +#include "devnum-util.h" #include "dirent-util.h" #include "efivars.h" #include "errno-util.h" @@ -55,7 +56,6 @@ #include "resize-fs.h" #include "sort-util.h" #include "specifier.h" -#include "stat-util.h" #include "stdio-util.h" #include "string-table.h" #include "string-util.h" @@ -3885,7 +3885,7 @@ static int resolve_copy_blocks_auto( if (r < 0) return log_error_errno(r, "Failed to read %s: %m", q); - r = parse_dev(t, &sl); + r = parse_devnum(t, &sl); if (r < 0) { log_debug_errno(r, "Failed to parse %s, ignoring: %m", q); continue; diff --git a/src/shared/blockdev-util.c b/src/shared/blockdev-util.c index a0c60be26e9..c3b90bb2273 100644 --- a/src/shared/blockdev-util.c +++ b/src/shared/blockdev-util.c @@ -6,12 +6,12 @@ #include "alloc-util.h" #include "blockdev-util.h" #include "btrfs-util.h" +#include "devnum-util.h" #include "dirent-util.h" #include "fd-util.h" #include "fileio.h" #include "missing_magic.h" #include "parse-util.h" -#include "stat-util.h" int block_get_whole_disk(dev_t d, dev_t *ret) { char p[SYS_BLOCK_PATH_MAX("/partition")]; @@ -44,7 +44,7 @@ int block_get_whole_disk(dev_t d, dev_t *ret) { if (r < 0) return r; - r = parse_dev(s, &devt); + r = parse_devnum(s, &devt); if (r < 0) return r; @@ -170,7 +170,7 @@ int block_get_originating(dev_t dt, dev_t *ret) { if (r < 0) return r; - r = parse_dev(t, &devt); + r = parse_devnum(t, &devt); if (r < 0) return -EINVAL; diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c index 7016f3840e1..91cb605fb1c 100644 --- a/src/shared/bootspec.c +++ b/src/shared/bootspec.c @@ -5,6 +5,7 @@ #include "bootspec.h" #include "bootspec-fundamental.h" #include "conf-files.h" +#include "devnum-util.h" #include "dirent-util.h" #include "efi-loader.h" #include "env-file.h" @@ -15,7 +16,6 @@ #include "pe-header.h" #include "recurse-dir.h" #include "sort-util.h" -#include "stat-util.h" #include "strv.h" #include "unaligned.h" @@ -918,7 +918,7 @@ int boot_config_load_auto( return r; /* It's fine if the XBOOTLDR partition doesn't exist, hence we ignore ENOKEY here */ /* If both paths actually refer to the same inode, suppress the xbootldr path */ - if (esp_where && xbootldr_where && devid_set_and_equal(esp_devid, xbootldr_devid)) + if (esp_where && xbootldr_where && devnum_set_and_equal(esp_devid, xbootldr_devid)) xbootldr_where = mfree(xbootldr_where); return boot_config_load(config, esp_where, xbootldr_where); diff --git a/src/shared/find-esp.c b/src/shared/find-esp.c index fca24329d4d..75e639dd99f 100644 --- a/src/shared/find-esp.c +++ b/src/shared/find-esp.c @@ -1,11 +1,13 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include +#include #include "sd-device.h" #include "alloc-util.h" #include "blkid-util.h" +#include "devnum-util.h" #include "env-util.h" #include "errno-util.h" #include "find-esp.h" diff --git a/src/shared/loop-util.c b/src/shared/loop-util.c index 39a9a766c01..530688fc97f 100644 --- a/src/shared/loop-util.c +++ b/src/shared/loop-util.c @@ -18,6 +18,7 @@ #include "alloc-util.h" #include "blockdev-util.h" #include "device-util.h" +#include "devnum-util.h" #include "env-util.h" #include "errno-util.h" #include "fd-util.h" @@ -876,7 +877,7 @@ static int resize_partition(int partition_fd, uint64_t offset, uint64_t size) { r = read_one_line_file(sysfs, &buffer); if (r < 0) return r; - r = parse_dev(buffer, &devno); + r = parse_devnum(buffer, &devno); if (r < 0) return r; diff --git a/src/shared/quota-util.c b/src/shared/quota-util.c index fbf8ee50644..7aacad12048 100644 --- a/src/shared/quota-util.c +++ b/src/shared/quota-util.c @@ -1,20 +1,21 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include +#include #include "alloc-util.h" #include "blockdev-util.h" +#include "devnum-util.h" #include "quota-util.h" -#include "stat-util.h" -int quotactl_devno(int cmd, dev_t devno, int id, void *addr) { +int quotactl_devnum(int cmd, dev_t devnum, int id, void *addr) { _cleanup_free_ char *devnode = NULL; int r; /* Like quotactl() but takes a dev_t instead of a path to a device node, and fixes caddr_t → void*, * like we should, today */ - r = device_path_make_major_minor(S_IFBLK, devno, &devnode); + r = device_path_make_major_minor(S_IFBLK, devnum, &devnode); if (r < 0) return r; @@ -37,5 +38,5 @@ int quotactl_path(int cmd, const char *path, int id, void *addr) { if (devno == 0) /* Doesn't have a block device */ return -ENODEV; - return quotactl_devno(cmd, devno, id, addr); + return quotactl_devnum(cmd, devno, id, addr); } diff --git a/src/shared/quota-util.h b/src/shared/quota-util.h index a61bdcbae60..fc395221ae6 100644 --- a/src/shared/quota-util.h +++ b/src/shared/quota-util.h @@ -15,5 +15,5 @@ static inline int QCMD_FIXED(uint32_t cmd, uint32_t type) { return (int) QCMD(cmd, type); } -int quotactl_devno(int cmd, dev_t devno, int id, void *addr); +int quotactl_devnum(int cmd, dev_t devnum, int id, void *addr); int quotactl_path(int cmd, const char *path, int id, void *addr); diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c index 8ec3d09a583..a56f2ff6182 100644 --- a/src/shared/sleep-config.c +++ b/src/shared/sleep-config.c @@ -20,13 +20,13 @@ #include "btrfs-util.h" #include "conf-parser.h" #include "def.h" +#include "devnum-util.h" #include "env-util.h" #include "errno-util.h" #include "fd-util.h" #include "fileio.h" #include "log.h" #include "macro.h" -#include "parse-util.h" #include "path-util.h" #include "sleep-config.h" #include "stat-util.h" @@ -274,7 +274,7 @@ static int read_resume_files(dev_t *ret_resume, uint64_t *ret_resume_offset) { if (r < 0) return log_debug_errno(r, "Error reading /sys/power/resume: %m"); - r = parse_dev(resume_str, &resume); + r = parse_devnum(resume_str, &resume); if (r < 0) return log_debug_errno(r, "Error parsing /sys/power/resume device: %s: %m", resume_str); diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c index ccc0bd2687e..20fbb916e9b 100644 --- a/src/sysext/sysext.c +++ b/src/sysext/sysext.c @@ -8,6 +8,7 @@ #include "capability-util.h" #include "chase-symlinks.h" +#include "devnum-util.h" #include "discover-image.h" #include "dissect-image.h" #include "env-util.h" @@ -31,7 +32,6 @@ #include "pretty-print.h" #include "process-util.h" #include "sort-util.h" -#include "stat-util.h" #include "terminal-util.h" #include "user-util.h" #include "verbs.h" @@ -84,7 +84,7 @@ static int is_our_mount_point(const char *p) { if (r < 0) return log_error_errno(r, "Failed to determine whether hierarchy '%s' contains '.systemd-sysext/dev': %m", p); - r = parse_dev(buf, &dev); + r = parse_devnum(buf, &dev); if (r < 0) return log_error_errno(r, "Failed to parse device major/minor stored in '.systemd-sysext/dev' file on '%s': %m", p); diff --git a/src/sysupdate/sysupdate-resource.c b/src/sysupdate/sysupdate-resource.c index 3df34cf7fb2..edc524cc759 100644 --- a/src/sysupdate/sysupdate-resource.c +++ b/src/sysupdate/sysupdate-resource.c @@ -7,6 +7,7 @@ #include "alloc-util.h" #include "blockdev-util.h" #include "chase-symlinks.h" +#include "devnum-util.h" #include "dirent-util.h" #include "env-util.h" #include "fd-util.h" @@ -18,7 +19,6 @@ #include "macro.h" #include "process-util.h" #include "sort-util.h" -#include "stat-util.h" #include "string-table.h" #include "sysupdate-cache.h" #include "sysupdate-instance.h" diff --git a/src/test/meson.build b/src/test/meson.build index 6e7fe1a3bb0..c47dd71d197 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -244,6 +244,8 @@ tests += [ [files('test-stat-util.c')], + [files('test-devnum-util.c')], + [files('test-os-util.c')], [files('test-libcrypt-util.c'), diff --git a/src/test/test-devnum-util.c b/src/test/test-devnum-util.c new file mode 100644 index 00000000000..9cb9a8ea769 --- /dev/null +++ b/src/test/test-devnum-util.c @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include + +#include "devnum-util.h" +#include "path-util.h" +#include "stat-util.h" +#include "tests.h" + +TEST(parse_devnum) { + dev_t dev; + + assert_se(parse_devnum("", &dev) == -EINVAL); + assert_se(parse_devnum("junk", &dev) == -EINVAL); + assert_se(parse_devnum("0", &dev) == -EINVAL); + assert_se(parse_devnum("5", &dev) == -EINVAL); + assert_se(parse_devnum("5:", &dev) == -EINVAL); + assert_se(parse_devnum(":5", &dev) == -EINVAL); + assert_se(parse_devnum("-1:-1", &dev) == -EINVAL); +#if SIZEOF_DEV_T < 8 + assert_se(parse_devnum("4294967295:4294967295", &dev) == -EINVAL); +#endif + assert_se(parse_devnum("8:11", &dev) >= 0 && major(dev) == 8 && minor(dev) == 11); + assert_se(parse_devnum("0:0", &dev) >= 0 && major(dev) == 0 && minor(dev) == 0); +} + +TEST(device_major_minor_valid) { + /* on glibc dev_t is 64bit, even though in the kernel it is only 32bit */ + assert_cc(sizeof(dev_t) == sizeof(uint64_t)); + + assert_se(DEVICE_MAJOR_VALID(0U)); + assert_se(DEVICE_MINOR_VALID(0U)); + + assert_se(DEVICE_MAJOR_VALID(1U)); + assert_se(DEVICE_MINOR_VALID(1U)); + + assert_se(!DEVICE_MAJOR_VALID(-1U)); + assert_se(!DEVICE_MINOR_VALID(-1U)); + + assert_se(DEVICE_MAJOR_VALID(1U << 10)); + assert_se(DEVICE_MINOR_VALID(1U << 10)); + + assert_se(DEVICE_MAJOR_VALID((1U << 12) - 1)); + assert_se(DEVICE_MINOR_VALID((1U << 20) - 1)); + + assert_se(!DEVICE_MAJOR_VALID((1U << 12))); + assert_se(!DEVICE_MINOR_VALID((1U << 20))); + + assert_se(!DEVICE_MAJOR_VALID(1U << 25)); + assert_se(!DEVICE_MINOR_VALID(1U << 25)); + + assert_se(!DEVICE_MAJOR_VALID(UINT32_MAX)); + assert_se(!DEVICE_MINOR_VALID(UINT32_MAX)); + + assert_se(!DEVICE_MAJOR_VALID(UINT64_MAX)); + assert_se(!DEVICE_MINOR_VALID(UINT64_MAX)); + + assert_se(DEVICE_MAJOR_VALID(major(0))); + assert_se(DEVICE_MINOR_VALID(minor(0))); +} + +static void test_device_path_make_canonical_one(const char *path) { + _cleanup_free_ char *resolved = NULL, *raw = NULL; + struct stat st; + dev_t devno; + mode_t mode; + int r; + + log_debug("> %s", path); + + if (stat(path, &st) < 0) { + assert_se(errno == ENOENT); + log_notice("Path %s not found, skipping test", path); + return; + } + + r = device_path_make_canonical(st.st_mode, st.st_rdev, &resolved); + if (r == -ENOENT) { + /* maybe /dev/char/x:y and /dev/block/x:y are missing in this test environment, because we + * run in a container or so? */ + log_notice("Device %s cannot be resolved, skipping test", path); + return; + } + + assert_se(r >= 0); + assert_se(path_equal(path, resolved)); + + assert_se(device_path_make_major_minor(st.st_mode, st.st_rdev, &raw) >= 0); + assert_se(device_path_parse_major_minor(raw, &mode, &devno) >= 0); + + assert_se(st.st_rdev == devno); + assert_se((st.st_mode & S_IFMT) == (mode & S_IFMT)); +} + +TEST(device_path_make_canonical) { + test_device_path_make_canonical_one("/dev/null"); + test_device_path_make_canonical_one("/dev/zero"); + test_device_path_make_canonical_one("/dev/full"); + test_device_path_make_canonical_one("/dev/random"); + test_device_path_make_canonical_one("/dev/urandom"); + test_device_path_make_canonical_one("/dev/tty"); + + if (is_device_node("/run/systemd/inaccessible/blk") > 0) { + test_device_path_make_canonical_one("/run/systemd/inaccessible/chr"); + test_device_path_make_canonical_one("/run/systemd/inaccessible/blk"); + } +} + +DEFINE_TEST_MAIN(LOG_INFO); diff --git a/src/test/test-parse-util.c b/src/test/test-parse-util.c index daa547c793b..388d0fe3f7e 100644 --- a/src/test/test-parse-util.c +++ b/src/test/test-parse-util.c @@ -812,23 +812,6 @@ TEST(parse_nice) { assert_se(parse_nice("+20", &n) == -ERANGE); } -TEST(parse_dev) { - dev_t dev; - - assert_se(parse_dev("", &dev) == -EINVAL); - assert_se(parse_dev("junk", &dev) == -EINVAL); - assert_se(parse_dev("0", &dev) == -EINVAL); - assert_se(parse_dev("5", &dev) == -EINVAL); - assert_se(parse_dev("5:", &dev) == -EINVAL); - assert_se(parse_dev(":5", &dev) == -EINVAL); - assert_se(parse_dev("-1:-1", &dev) == -EINVAL); -#if SIZEOF_DEV_T < 8 - assert_se(parse_dev("4294967295:4294967295", &dev) == -EINVAL); -#endif - assert_se(parse_dev("8:11", &dev) >= 0 && major(dev) == 8 && minor(dev) == 11); - assert_se(parse_dev("0:0", &dev) >= 0 && major(dev) == 0 && minor(dev) == 0); -} - TEST(parse_errno) { assert_se(parse_errno("EILSEQ") == EILSEQ); assert_se(parse_errno("EINVAL") == EINVAL); diff --git a/src/test/test-stat-util.c b/src/test/test-stat-util.c index 9975a1848d2..c5afde02d0c 100644 --- a/src/test/test-stat-util.c +++ b/src/test/test-stat-util.c @@ -149,88 +149,6 @@ TEST(fd_is_ns) { assert_se(IN_SET(fd_is_ns(fd, CLONE_NEWNET), 1, -EUCLEAN)); } -TEST(device_major_minor_valid) { - /* on glibc dev_t is 64bit, even though in the kernel it is only 32bit */ - assert_cc(sizeof(dev_t) == sizeof(uint64_t)); - - assert_se(DEVICE_MAJOR_VALID(0U)); - assert_se(DEVICE_MINOR_VALID(0U)); - - assert_se(DEVICE_MAJOR_VALID(1U)); - assert_se(DEVICE_MINOR_VALID(1U)); - - assert_se(!DEVICE_MAJOR_VALID(-1U)); - assert_se(!DEVICE_MINOR_VALID(-1U)); - - assert_se(DEVICE_MAJOR_VALID(1U << 10)); - assert_se(DEVICE_MINOR_VALID(1U << 10)); - - assert_se(DEVICE_MAJOR_VALID((1U << 12) - 1)); - assert_se(DEVICE_MINOR_VALID((1U << 20) - 1)); - - assert_se(!DEVICE_MAJOR_VALID((1U << 12))); - assert_se(!DEVICE_MINOR_VALID((1U << 20))); - - assert_se(!DEVICE_MAJOR_VALID(1U << 25)); - assert_se(!DEVICE_MINOR_VALID(1U << 25)); - - assert_se(!DEVICE_MAJOR_VALID(UINT32_MAX)); - assert_se(!DEVICE_MINOR_VALID(UINT32_MAX)); - - assert_se(!DEVICE_MAJOR_VALID(UINT64_MAX)); - assert_se(!DEVICE_MINOR_VALID(UINT64_MAX)); - - assert_se(DEVICE_MAJOR_VALID(major(0))); - assert_se(DEVICE_MINOR_VALID(minor(0))); -} - -static void test_device_path_make_canonical_one(const char *path) { - _cleanup_free_ char *resolved = NULL, *raw = NULL; - struct stat st; - dev_t devno; - mode_t mode; - int r; - - log_debug("> %s", path); - - if (stat(path, &st) < 0) { - assert_se(errno == ENOENT); - log_notice("Path %s not found, skipping test", path); - return; - } - - r = device_path_make_canonical(st.st_mode, st.st_rdev, &resolved); - if (r == -ENOENT) { - /* maybe /dev/char/x:y and /dev/block/x:y are missing in this test environment, because we - * run in a container or so? */ - log_notice("Device %s cannot be resolved, skipping test", path); - return; - } - - assert_se(r >= 0); - assert_se(path_equal(path, resolved)); - - assert_se(device_path_make_major_minor(st.st_mode, st.st_rdev, &raw) >= 0); - assert_se(device_path_parse_major_minor(raw, &mode, &devno) >= 0); - - assert_se(st.st_rdev == devno); - assert_se((st.st_mode & S_IFMT) == (mode & S_IFMT)); -} - -TEST(device_path_make_canonical) { - test_device_path_make_canonical_one("/dev/null"); - test_device_path_make_canonical_one("/dev/zero"); - test_device_path_make_canonical_one("/dev/full"); - test_device_path_make_canonical_one("/dev/random"); - test_device_path_make_canonical_one("/dev/urandom"); - test_device_path_make_canonical_one("/dev/tty"); - - if (is_device_node("/run/systemd/inaccessible/blk") > 0) { - test_device_path_make_canonical_one("/run/systemd/inaccessible/chr"); - test_device_path_make_canonical_one("/run/systemd/inaccessible/blk"); - } -} - TEST(dir_is_empty) { _cleanup_(rm_rf_physical_and_freep) char *empty_dir = NULL; _cleanup_free_ char *j = NULL, *jj = NULL; diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 4d9907e4245..0842d67d855 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -26,6 +26,7 @@ #include "conf-files.h" #include "copy.h" #include "def.h" +#include "devnum-util.h" #include "dirent-util.h" #include "dissect-image.h" #include "env-util.h" @@ -58,7 +59,6 @@ #include "set.h" #include "sort-util.h" #include "specifier.h" -#include "stat-util.h" #include "stdio-util.h" #include "string-table.h" #include "string-util.h" @@ -3084,7 +3084,7 @@ static int parse_line( return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG), "Device file requires argument."); } - r = parse_dev(i.argument, &i.major_minor); + r = parse_devnum(i.argument, &i.major_minor); if (r < 0) { *invalid_config = true; return log_syntax(NULL, LOG_ERR, fname, line, r, "Can't parse device file major/minor '%s'.", i.argument); diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index deacbc31c56..c9f58e8c29b 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -12,6 +12,7 @@ #include "alloc-util.h" #include "device-private.h" #include "device-util.h" +#include "devnum-util.h" #include "dirent-util.h" #include "escape.h" #include "fd-util.h" diff --git a/src/udev/udevadm-lock.c b/src/udev/udevadm-lock.c index 951711f1203..32935e8aa41 100644 --- a/src/udev/udevadm-lock.c +++ b/src/udev/udevadm-lock.c @@ -7,6 +7,7 @@ #include "blockdev-util.h" #include "btrfs-util.h" +#include "devnum-util.h" #include "fd-util.h" #include "fdset.h" #include "main-func.h" @@ -16,7 +17,6 @@ #include "process-util.h" #include "signal-util.h" #include "sort-util.h" -#include "stat-util.h" #include "strv.h" #include "time-util.h" #include "udevadm.h" diff --git a/src/volatile-root/volatile-root.c b/src/volatile-root/volatile-root.c index 90065b410b0..aa16582d9e4 100644 --- a/src/volatile-root/volatile-root.c +++ b/src/volatile-root/volatile-root.c @@ -5,13 +5,13 @@ #include "alloc-util.h" #include "blockdev-util.h" #include "chase-symlinks.h" +#include "devnum-util.h" #include "escape.h" #include "main-func.h" #include "mkdir.h" #include "mount-util.h" #include "mountpoint-util.h" #include "path-util.h" -#include "stat-util.h" #include "string-util.h" #include "volatile-util.h"