]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
blockdev-util: make sure get_block_device_fd() works reliably for O_PATH, too
authorLennart Poettering <lennart@poettering.net>
Mon, 19 Sep 2022 12:23:02 +0000 (14:23 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 20 Sep 2022 11:52:01 +0000 (13:52 +0200)
src/shared/blockdev-util.c

index 12d4b54952693f73971d02e8c71bef9905a76043..4402b7a97c05551a4454bf20c9d1279190ad6588 100644 (file)
@@ -131,7 +131,21 @@ int get_block_device_fd(int fd, dev_t *ret) {
                 return 1;
         }
 
-        r = btrfs_get_block_device_fd(fd, ret);
+        r = fcntl(fd, F_GETFL);
+        if (r < 0)
+                return -errno;
+        if (FLAGS_SET(r, O_PATH) && (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))) {
+                _cleanup_close_ int real_fd = -1;
+
+                /* The fstat() above we can execute on an O_PATH fd. But the btrfs ioctl we cannot. Hence
+                 * acquire a "real" fd first, without the O_PATH flag. */
+
+                real_fd = fd_reopen(fd, O_RDONLY|O_CLOEXEC);
+                if (real_fd < 0)
+                        return real_fd;
+                r = btrfs_get_block_device_fd(real_fd, ret);
+        } else
+                r = btrfs_get_block_device_fd(fd, ret);
         if (r > 0)
                 return 1;
         if (r != -ENOTTY) /* not btrfs */