]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/basic/blockdev-util.c
Merge pull request #16678 from poettering/loop-configure
[thirdparty/systemd.git] / src / basic / blockdev-util.c
index 7d94c55a6dcafb69dd3b4e0b864a131958d90e7f..21ff3ba1b13c018ac283476216d308b12585b19b 100644 (file)
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <sys/file.h>
 #include <unistd.h>
 
 #include "alloc-util.h"
@@ -29,6 +30,8 @@ int block_get_whole_disk(dev_t d, dev_t *ret) {
                 *ret = d;
                 return 0;
         }
+        if (errno != ENOENT)
+                return -errno;
 
         /* If it is a partition find the originating device */
         xsprintf_sys_block_path(p, "/partition", d);
@@ -185,3 +188,66 @@ int get_block_device_harder(const char *path, dev_t *ret) {
 
         return 1;
 }
+
+int lock_whole_block_device(dev_t devt, int operation) {
+        _cleanup_free_ char *whole_node = NULL;
+        _cleanup_close_ int lock_fd = -1;
+        dev_t whole_devt;
+        int r;
+
+        /* Let's get a BSD file lock on the whole block device, as per: https://systemd.io/BLOCK_DEVICE_LOCKING */
+
+        r = block_get_whole_disk(devt, &whole_devt);
+        if (r < 0)
+                return r;
+
+        r = device_path_make_major_minor(S_IFBLK, whole_devt, &whole_node);
+        if (r < 0)
+                return r;
+
+        lock_fd = open(whole_node, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
+        if (lock_fd < 0)
+                return -errno;
+
+        if (flock(lock_fd, operation) < 0)
+                return -errno;
+
+        return TAKE_FD(lock_fd);
+}
+
+int blockdev_partscan_enabled(int fd) {
+        _cleanup_free_ char *p = NULL, *buf = NULL;
+        unsigned long long ull;
+        struct stat st;
+        int r;
+
+        /* Checks if partition scanning is correctly enabled on the block device */
+
+        if (fstat(fd, &st) < 0)
+                return -errno;
+
+        if (!S_ISBLK(st.st_mode))
+                return -ENOTBLK;
+
+        if (asprintf(&p, "/sys/dev/block/%u:%u/capability", major(st.st_rdev), minor(st.st_rdev)) < 0)
+                return -ENOMEM;
+
+        r = read_one_line_file(p, &buf);
+        if (r == -ENOENT) /* If the capability file doesn't exist then we are most likely looking at a
+                           * partition block device, not the whole block device. And that means we have no
+                           * partition scanning on for it (we do for its parent, but not for the partition
+                           * itself). */
+                return false;
+        if (r < 0)
+                return r;
+
+        r = safe_atollu_full(buf, 16, &ull);
+        if (r < 0)
+                return r;
+
+#ifndef GENHD_FL_NO_PART_SCAN
+#define GENHD_FL_NO_PART_SCAN (0x0200)
+#endif
+
+        return !FLAGS_SET(ull, GENHD_FL_NO_PART_SCAN);
+}