]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
blockdev-util: reopen file descriptor only when O_PATH is set
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 19 Sep 2022 23:43:45 +0000 (08:43 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 28 Sep 2022 08:41:09 +0000 (17:41 +0900)
Prompted by 13879c54d4f8b912e1f8c57e0ff7b516dd2a6f52.

src/shared/blockdev-util.c

index b90a5223ccf3661c3a2797c268ce939e5fa71f7b..d99216817027a61a97c4753bf8bff1ae29ba0a7f 100644 (file)
@@ -40,16 +40,26 @@ static int fd_get_devnum(int fd, bool backing, dev_t *ret) {
         else if (major(st.st_dev) != 0)
                 devnum = st.st_dev;
         else {
-                _cleanup_close_ int regfd = -1;
-
                 /* If major(st.st_dev) is zero, this might mean we are backed by btrfs, which needs special
                  * handing, to get the backing device node. */
 
-                regfd = fd_reopen(fd, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
-                if (regfd < 0)
-                        return regfd;
+                r = fcntl(fd, F_GETFL);
+                if (r < 0)
+                        return -errno;
+
+                if (FLAGS_SET(r, O_PATH)) {
+                        _cleanup_close_ int regfd = -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. */
+
+                        regfd = fd_reopen(fd, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
+                        if (regfd < 0)
+                                return regfd;
 
-                r = btrfs_get_block_device_fd(regfd, &devnum);
+                        r = btrfs_get_block_device_fd(regfd, &devnum);
+                } else
+                        r = btrfs_get_block_device_fd(fd, &devnum);
                 if (r == -ENOTTY) /* not btrfs */
                         return -ENOTBLK;
                 if (r < 0)