]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
stat-util: also introduce stat_verify_block() and use it everywhere
authorLennart Poettering <lennart@amutable.com>
Mon, 13 Apr 2026 08:45:29 +0000 (10:45 +0200)
committerLennart Poettering <lennart@amutable.com>
Mon, 13 Apr 2026 11:20:43 +0000 (13:20 +0200)
12 files changed:
src/basic/stat-util.c
src/basic/stat-util.h
src/fsck/fsck.c
src/hibernate-resume/hibernate-resume.c
src/home/homed-home.c
src/home/homework-luks.c
src/mount/mount-tool.c
src/shared/btrfs-util.c
src/shared/discover-image.c
src/shared/dissect-image.c
src/shared/hibernate-util.c
src/shared/loop-util.c

index 3811bd019edb65125ba44024a785fdc31e9115fe..2bdd8af21dc9e7ccfb4b874d7c530f8fdce264f8 100644 (file)
@@ -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);
 
index 6eded0d8481741fabc47d31ce885c6dca0e3f442..55bc5b6c7eac0d2a2ddf791c726e5d540ec54a5f 100644 (file)
@@ -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);
 
index 43cc208e598a236b4c9f08bc0b98c9cc0c02473d..405e9c34fddc4fc19cbdda6573f4e0270a5f9b04 100644 (file)
@@ -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)
index f3cf399e1d84b79f951cd9e66fc6e4a911128347..2c6eed3248af669ef64065133629daa2b556e807 100644 (file)
@@ -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);
index 12e0eed2dae3295c4dc34d639a5775ec563c8ce7..f467ef7015d3b2207bb078c1dbea42a356418cfe 100644 (file)
@@ -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)
index 5342bea21e6956cd717e6565dc1c820f1d7df9a7..f105acfa3bf6c589244bd220be88b68f430c46f8 100644 (file)
@@ -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();
index 768ff349e27135596f5abf234b3e50cabe33d321..f1c4c90d768835d892cb0675a9b36caf3c1c1d38 100644 (file)
@@ -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)
index 9bd0a74c5fe83469f2d0c50f0e7ac1e7e77d8603..8e41f569ba2352e330c2b9b4e01a8e23dd5560c9 100644 (file)
@@ -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;
index 6b9954913498c3d4482c291a7e5fe2555575275a..1595bb218404ac9b437951a9ea914d431a75488a 100644 (file)
@@ -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;
index 9817ed87ec1290aef7843b3a61d2af0ad9496079..c5911beb71075e7cc51cfefb99dfe1df5f171ecb 100644 (file)
@@ -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) {
index 001eaa920cc992ab7cae8e656d502b9c4b041ec4..c141cdc8c6701a9015bbee3bf083cb9e23d1d6ba 100644 (file)
@@ -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;
index 1c843661cc44e985355ff800c4610bced220ee7e..e6fe4dbb49d7a4da9e50969fe85fff1fc63aba85 100644 (file)
@@ -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));