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.
This commit is contained in:
Lennart Poettering 2022-04-13 15:38:21 +02:00
parent c87c307806
commit 7176f06c9e
39 changed files with 329 additions and 288 deletions

133
src/basic/devnum-util.c Normal file
View file

@ -0,0 +1,133 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <string.h>
#include <sys/stat.h>
#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;
}

37
src/basic/devnum-util.h Normal file
View file

@ -0,0 +1,37 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <inttypes.h>
#include <stdbool.h>
#include <sys/types.h>
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;
}

View file

@ -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',

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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;
}

View file

@ -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"

View file

@ -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);

View file

@ -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)

View file

@ -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"

View file

@ -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"

View file

@ -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"

View file

@ -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);

View file

@ -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"

View file

@ -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);

View file

@ -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;

View file

@ -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"

View file

@ -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;

View file

@ -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"

View file

@ -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"

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -1,11 +1,13 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <linux/magic.h>
#include <sys/vfs.h>
#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"

View file

@ -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;

View file

@ -1,20 +1,21 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <sys/quota.h>
#include <sys/stat.h>
#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);
}

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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"

View file

@ -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'),

109
src/test/test-devnum-util.c Normal file
View file

@ -0,0 +1,109 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <sys/stat.h>
#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);

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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"

View file

@ -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"

View file

@ -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"