diff --git a/src/basic/devnum-util.c b/src/basic/devnum-util.c new file mode 100644 index 0000000000..d13a87d6d1 --- /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 0000000000..9632e992bb --- /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 92a4df2017..501fcf147f 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 222b2304cd..35fbb5ec6a 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 8273124626..f2222dcffb 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 b25cabc6b4..c7293db698 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 37513a43e7..4483ceb7de 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 6119f21c1b..7cf74e97d0 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 c8bc205d1b..d9c901d73b 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 a393370f8d..eac071bcc6 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 46996d28f4..3af9e78a1e 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 2e2dfcb2aa..d3b617dc1a 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 4731687b7f..8b35b2364d 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 c2b9eb64f9..a0253c34c1 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 5416d12fcf..9cfb0e7ae6 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 7001870dfb..574d1556af 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 d31526fc22..22f16b9edc 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 ff4cd0a631..7d46759822 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 eef48c2527..4995e5885a 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 44564ba619..86c014d25e 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 0d1da2773f..31dcf0ffdf 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 34aa88198b..051242e836 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 a0c60be26e..c3b90bb227 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 7016f3840e..91cb605fb1 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 fca24329d4..75e639dd99 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 39a9a766c0..530688fc97 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 fbf8ee5064..7aacad1204 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 a61bdcbae6..fc395221ae 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 8ec3d09a58..a56f2ff618 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 ccc0bd2687..20fbb916e9 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 3df34cf7fb..edc524cc75 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 6e7fe1a3bb..c47dd71d19 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 0000000000..9cb9a8ea76 --- /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 daa547c793..388d0fe3f7 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 9975a1848d..c5afde02d0 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 4d9907e424..0842d67d85 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 deacbc31c5..c9f58e8c29 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 951711f120..32935e8aa4 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 90065b410b..aa16582d9e 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"