From: Lennart Poettering Date: Mon, 13 Apr 2026 08:45:29 +0000 (+0200) Subject: stat-util: also introduce stat_verify_block() and use it everywhere X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=bda7e913372bef6002529eacf47d66c9a1473348;p=thirdparty%2Fsystemd.git stat-util: also introduce stat_verify_block() and use it everywhere --- diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c index 3811bd019ed..2bdd8af21dc 100644 --- a/src/basic/stat-util.c +++ b/src/basic/stat-util.c @@ -203,6 +203,28 @@ int fd_verify_linked(int fd) { return verify_stat_at(fd, NULL, false, stat_verify_linked, true); } +int stat_verify_block(const struct stat *st) { + assert(st); + + if (S_ISDIR(st->st_mode)) + return -EISDIR; + + if (S_ISLNK(st->st_mode)) + return -ELOOP; + + if (!S_ISBLK(st->st_mode)) + return -ENOTBLK; + + return 0; +} + +int fd_verify_block(int fd) { + if (IN_SET(fd, AT_FDCWD, XAT_FDROOT)) + return -EISDIR; + + return verify_stat_at(fd, /* path= */ NULL, /* follow= */ false, stat_verify_block, /* verify= */ true); +} + int stat_verify_device_node(const struct stat *st) { assert(st); diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h index 6eded0d8481..55bc5b6c7ea 100644 --- a/src/basic/stat-util.h +++ b/src/basic/stat-util.h @@ -28,6 +28,9 @@ int is_socket(const char *path); int stat_verify_linked(const struct stat *st); int fd_verify_linked(int fd); +int stat_verify_block(const struct stat *st); +int fd_verify_block(int fd); + int stat_verify_device_node(const struct stat *st); int is_device_node(const char *path); diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c index 43cc208e598..405e9c34fdd 100644 --- a/src/fsck/fsck.c +++ b/src/fsck/fsck.c @@ -28,6 +28,7 @@ #include "process-util.h" #include "socket-util.h" #include "special.h" +#include "stat-util.h" #include "stdio-util.h" #include "string-table.h" #include "string-util.h" @@ -299,10 +300,9 @@ static int run(int argc, char *argv[]) { if (stat(device, &st) < 0) return log_error_errno(errno, "Failed to stat %s: %m", device); - if (!S_ISBLK(st.st_mode)) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "%s is not a block device.", - device); + r = stat_verify_block(&st); + if (r < 0) + return log_error_errno(r, "'%s' is not a block device.", device); r = sd_device_new_from_stat_rdev(&dev, &st); if (r < 0) diff --git a/src/hibernate-resume/hibernate-resume.c b/src/hibernate-resume/hibernate-resume.c index f3cf399e1d8..2c6eed3248a 100644 --- a/src/hibernate-resume/hibernate-resume.c +++ b/src/hibernate-resume/hibernate-resume.c @@ -13,6 +13,7 @@ #include "main-func.h" #include "parse-util.h" #include "pretty-print.h" +#include "stat-util.h" #include "static-destruct.h" static HibernateInfo arg_info = {}; @@ -165,9 +166,9 @@ static int run(int argc, char *argv[]) { if (stat(arg_info.device, &st) < 0) return log_error_errno(errno, "Failed to stat resume device '%s': %m", arg_info.device); - if (!S_ISBLK(st.st_mode)) - return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK), - "Resume device '%s' is not a block device.", arg_info.device); + r = stat_verify_block(&st); + if (r < 0) + return log_error_errno(r, "Resume device '%s' is not a block device.", arg_info.device); /* The write shall not return if a resume takes place. */ r = write_resume_config(st.st_rdev, arg_info.offset, arg_info.device); diff --git a/src/home/homed-home.c b/src/home/homed-home.c index 12e0eed2dae..f467ef7015d 100644 --- a/src/home/homed-home.c +++ b/src/home/homed-home.c @@ -3214,8 +3214,9 @@ static int home_get_image_path_seat(Home *h, char **ret) { if (stat(ip, &st) < 0) return -errno; - if (!S_ISBLK(st.st_mode)) - return -ENOTBLK; + r = stat_verify_block(&st); + if (r < 0) + return r; r = sd_device_new_from_stat_rdev(&d, &st); if (r < 0) diff --git a/src/home/homework-luks.c b/src/home/homework-luks.c index 5342bea21e6..f105acfa3bf 100644 --- a/src/home/homework-luks.c +++ b/src/home/homework-luks.c @@ -202,16 +202,14 @@ static int probe_file_system_by_path(const char *path, char **ret_fstype, sd_id1 } static int block_get_size_by_fd(int fd, uint64_t *ret) { - struct stat st; + int r; assert(fd >= 0); assert(ret); - if (fstat(fd, &st) < 0) - return -errno; - - if (!S_ISBLK(st.st_mode)) - return -ENOTBLK; + r = fd_verify_block(fd); + if (r < 0) + return r; return blockdev_get_device_size(fd, ret); } @@ -2275,8 +2273,9 @@ int home_create_luks( if (setup->image_fd < 0) return setup->image_fd; - if (!S_ISBLK(st.st_mode)) - return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK), "Device is not a block device, refusing."); + r = stat_verify_block(&st); + if (r < 0) + return log_error_errno(r, "Device is not a block device, refusing."); if (asprintf(&sysfs, "/sys/dev/block/" DEVNUM_FORMAT_STR "/partition", DEVNUM_FORMAT_VAL(st.st_rdev)) < 0) return log_oom(); diff --git a/src/mount/mount-tool.c b/src/mount/mount-tool.c index 768ff349e27..f1c4c90d768 100644 --- a/src/mount/mount-tool.c +++ b/src/mount/mount-tool.c @@ -1413,9 +1413,9 @@ static int discover_device(void) { if (S_ISREG(st.st_mode)) return discover_loop_backing_file(); - if (!S_ISBLK(st.st_mode)) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Unsupported mount source type for --discover: %s", arg_mount_what); + r = stat_verify_block(&st); + if (r < 0) + return log_error_errno(r, "Unsupported mount source type for --discover: %s", arg_mount_what); r = sd_device_new_from_stat_rdev(&d, &st); if (r < 0) diff --git a/src/shared/btrfs-util.c b/src/shared/btrfs-util.c index 9bd0a74c5fe..8e41f569ba2 100644 --- a/src/shared/btrfs-util.c +++ b/src/shared/btrfs-util.c @@ -149,8 +149,9 @@ int btrfs_get_block_device_at(int dir_fd, const char *path, dev_t *ret) { if (stat((char*) di.path, &st) < 0) return -errno; - if (!S_ISBLK(st.st_mode)) - return -ENOTBLK; + r = stat_verify_block(&st); + if (r < 0) + return r; if (major(st.st_rdev) == 0) return -ENODEV; diff --git a/src/shared/discover-image.c b/src/shared/discover-image.c index 6b995491349..1595bb21840 100644 --- a/src/shared/discover-image.c +++ b/src/shared/discover-image.c @@ -1895,17 +1895,15 @@ int image_read_only(Image *i, bool b, RuntimeScope scope) { case IMAGE_BLOCK: { _cleanup_close_ int fd = -EBADF; - struct stat st; int state = b; fd = open(i->path, O_CLOEXEC|O_RDONLY|O_NONBLOCK|O_NOCTTY); if (fd < 0) return -errno; - if (fstat(fd, &st) < 0) - return -errno; - if (!S_ISBLK(st.st_mode)) - return -ENOTTY; + r = fd_verify_block(fd); + if (r < 0) + return r; if (ioctl(fd, BLKROSET, &state) < 0) return -errno; diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 9817ed87ec1..c5911beb710 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -2141,14 +2141,16 @@ DissectedImage* dissected_image_unref(DissectedImage *m) { static int is_loop_device(const char *path) { char s[SYS_BLOCK_PATH_MAX("/../loop/")]; struct stat st; + int r; assert(path); if (stat(path, &st) < 0) return -errno; - if (!S_ISBLK(st.st_mode)) - return -ENOTBLK; + r = stat_verify_block(&st); + if (r < 0) + return r; xsprintf_sys_block_path(s, "/loop/", st.st_dev); if (access(s, F_OK) < 0) { diff --git a/src/shared/hibernate-util.c b/src/shared/hibernate-util.c index 001eaa920cc..c141cdc8c67 100644 --- a/src/shared/hibernate-util.c +++ b/src/shared/hibernate-util.c @@ -209,8 +209,9 @@ static int swap_entry_get_resume_config(SwapEntry *swap) { return -errno; if (!swap->swapfile) { - if (!S_ISBLK(st.st_mode)) - return -ENOTBLK; + r = stat_verify_block(&st); + if (r < 0) + return r; swap->devno = st.st_rdev; swap->offset = 0; diff --git a/src/shared/loop-util.c b/src/shared/loop-util.c index 1c843661cc4..e6fe4dbb49d 100644 --- a/src/shared/loop-util.c +++ b/src/shared/loop-util.c @@ -378,9 +378,9 @@ static int loop_configure( } static int fd_get_max_discard(int fd, uint64_t *ret) { - struct stat st; char sysfs_path[STRLEN("/sys/dev/block/" ":" "/queue/discard_max_bytes") + DECIMAL_STR_MAX(dev_t) * 2 + 1]; _cleanup_free_ char *buffer = NULL; + struct stat st; int r; assert(ret); @@ -388,8 +388,9 @@ static int fd_get_max_discard(int fd, uint64_t *ret) { if (fstat(ASSERT_FD(fd), &st) < 0) return -errno; - if (!S_ISBLK(st.st_mode)) - return -ENOTBLK; + r = stat_verify_block(&st); + if (r < 0) + return r; xsprintf(sysfs_path, "/sys/dev/block/" DEVNUM_FORMAT_STR "/queue/discard_max_bytes", DEVNUM_FORMAT_VAL(st.st_rdev)); @@ -401,14 +402,16 @@ static int fd_get_max_discard(int fd, uint64_t *ret) { } static int fd_set_max_discard(int fd, uint64_t max_discard) { - struct stat st; char sysfs_path[STRLEN("/sys/dev/block/" ":" "/queue/discard_max_bytes") + DECIMAL_STR_MAX(dev_t) * 2 + 1]; + struct stat st; + int r; if (fstat(ASSERT_FD(fd), &st) < 0) return -errno; - if (!S_ISBLK(st.st_mode)) - return -ENOTBLK; + r = stat_verify_block(&st); + if (r < 0) + return r; xsprintf(sysfs_path, "/sys/dev/block/" DEVNUM_FORMAT_STR "/queue/discard_max_bytes", DEVNUM_FORMAT_VAL(st.st_rdev));