]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/shared/loop-util.c
tree-wide: use -EBADF for fd initialization
[thirdparty/systemd.git] / src / shared / loop-util.c
index 84f4e79c07adb30e1e4739c28521c41624bb00ea..eb1a5bb59fdb394a870c335311e68c5ce67c240d 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "alloc-util.h"
 #include "blockdev-util.h"
+#include "data-fd-util.h"
 #include "device-util.h"
 #include "devnum-util.h"
 #include "env-util.h"
@@ -72,12 +73,12 @@ static int get_current_uevent_seqnum(uint64_t *ret) {
 }
 
 static int open_lock_fd(int primary_fd, int operation) {
-        _cleanup_close_ int lock_fd = -1;
+        _cleanup_close_ int lock_fd = -EBADF;
 
         assert(primary_fd >= 0);
         assert(IN_SET(operation & ~LOCK_NB, LOCK_SH, LOCK_EX));
 
-        lock_fd = fd_reopen(primary_fd, O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
+        lock_fd = fd_reopen(primary_fd, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
         if (lock_fd < 0)
                 return lock_fd;
 
@@ -123,6 +124,17 @@ static int loop_configure_verify(int fd, const struct loop_config *c) {
         assert(fd >= 0);
         assert(c);
 
+        if (c->block_size != 0) {
+                int z;
+
+                if (ioctl(fd, BLKSSZGET, &z) < 0)
+                        return -errno;
+
+                assert(z >= 0);
+                if ((uint32_t) z != c->block_size)
+                        log_debug("LOOP_CONFIGURE didn't honour requested block size %u, got %i instead. Ignoring.", c->block_size, z);
+        }
+
         if (c->info.lo_sizelimit != 0) {
                 /* Kernel 5.8 vanilla doesn't properly propagate the size limit into the
                  * block device. If it's used, let's immediately check if it had the desired
@@ -133,7 +145,7 @@ static int loop_configure_verify(int fd, const struct loop_config *c) {
                         return -errno;
 
                 if (z != c->info.lo_sizelimit) {
-                        log_debug("LOOP_CONFIGURE is broken, doesn't honour .lo_sizelimit. Falling back to LOOP_SET_STATUS64.");
+                        log_debug("LOOP_CONFIGURE is broken, doesn't honour .info.lo_sizelimit. Falling back to LOOP_SET_STATUS64.");
                         broken = true;
                 }
         }
@@ -171,7 +183,7 @@ static int loop_configure_fallback(int fd, const struct loop_config *c) {
         info_copy.lo_flags &= LOOP_SET_STATUS_SETTABLE_FLAGS;
 
         /* Since kernel commit 5db470e229e22b7eda6e23b5566e532c96fb5bc3 (kernel v5.0) the LOOP_SET_STATUS64
-         * ioctl can return EAGAIN in case we change the lo_offset field, if someone else is accessing the
+         * ioctl can return EAGAIN in case we change the info.lo_offset field, if someone else is accessing the
          * block device while we try to reconfigure it. This is a pretty common case, since udev might
          * instantly start probing the device as soon as we attach an fd to it. Hence handle it in two ways:
          * first, let's take the BSD lock to ensure that udev will not step in between the point in
@@ -226,8 +238,8 @@ static int loop_configure(
         static bool loop_configure_broken = false;
 
         _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
-        _cleanup_(cleanup_clear_loop_close) int loop_with_fd = -1; /* This must be declared before lock_fd. */
-        _cleanup_close_ int fd = -1, lock_fd = -1;
+        _cleanup_(cleanup_clear_loop_close) int loop_with_fd = -EBADF; /* This must be declared before lock_fd. */
+        _cleanup_close_ int fd = -EBADF, lock_fd = -EBADF;
         _cleanup_free_ char *node = NULL;
         uint64_t diskseq = 0, seqnum = UINT64_MAX;
         usec_t timestamp = USEC_INFINITY;
@@ -391,12 +403,13 @@ static int loop_device_make_internal(
                 int open_flags,
                 uint64_t offset,
                 uint64_t size,
+                uint32_t block_size,
                 uint32_t loop_flags,
                 int lock_op,
                 LoopDevice **ret) {
 
         _cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
-        _cleanup_close_ int direct_io_fd = -1, control = -1;
+        _cleanup_close_ int direct_io_fd = -EBADF, control = -EBADF;
         _cleanup_free_ char *backing_file = NULL;
         struct loop_config config;
         int r, f_flags;
@@ -463,6 +476,7 @@ static int loop_device_make_internal(
 
         config = (struct loop_config) {
                 .fd = fd,
+                .block_size = block_size,
                 .info = {
                         /* Use the specified flags, but configure the read-only flag from the open flags, and force autoclear */
                         .lo_flags = (loop_flags & ~LO_FLAGS_READ_ONLY) | ((open_flags & O_ACCMODE) == O_RDONLY ? LO_FLAGS_READ_ONLY : 0) | LO_FLAGS_AUTOCLEAR,
@@ -546,6 +560,7 @@ int loop_device_make(
                 int open_flags,
                 uint64_t offset,
                 uint64_t size,
+                uint32_t block_size,
                 uint32_t loop_flags,
                 int lock_op,
                 LoopDevice **ret) {
@@ -559,6 +574,7 @@ int loop_device_make(
                         open_flags,
                         offset,
                         size,
+                        block_size,
                         loop_flags_mangle(loop_flags),
                         lock_op,
                         ret);
@@ -572,7 +588,7 @@ int loop_device_make_by_path(
                 LoopDevice **ret) {
 
         int r, basic_flags, direct_flags, rdwr_flags;
-        _cleanup_close_ int fd = -1;
+        _cleanup_close_ int fd = -EBADF;
         bool direct = false;
 
         assert(path);
@@ -622,7 +638,48 @@ int loop_device_make_by_path(
                   direct ? "enabled" : "disabled",
                   direct != (direct_flags != 0) ? " (O_DIRECT was requested but not supported)" : "");
 
-        return loop_device_make_internal(path, fd, open_flags, 0, 0, loop_flags, lock_op, ret);
+        return loop_device_make_internal(path, fd, open_flags, 0, 0, 0, loop_flags, lock_op, ret);
+}
+
+int loop_device_make_by_path_memory(
+                const char *path,
+                int open_flags,
+                uint32_t loop_flags,
+                int lock_op,
+                LoopDevice **ret) {
+
+        _cleanup_close_ int fd = -EBADF, mfd = -EBADF;
+        _cleanup_free_ char *fn = NULL;
+        struct stat st;
+        int r;
+
+        assert(path);
+        assert(IN_SET(open_flags, O_RDWR, O_RDONLY));
+        assert(ret);
+
+        loop_flags &= ~LO_FLAGS_DIRECT_IO; /* memfds don't support O_DIRECT, hence LO_FLAGS_DIRECT_IO can't be used either */
+
+        fd = open(path, O_CLOEXEC|O_NONBLOCK|O_NOCTTY|O_RDONLY);
+        if (fd < 0)
+                return -errno;
+
+        if (fstat(fd, &st) < 0)
+                return -errno;
+
+        if (!S_ISREG(st.st_mode) && !S_ISBLK(st.st_mode))
+                return -EBADF;
+
+        r = path_extract_filename(path, &fn);
+        if (r < 0)
+                return r;
+
+        mfd = memfd_clone_fd(fd, fn, open_flags|O_CLOEXEC);
+        if (mfd < 0)
+                return mfd;
+
+        fd = safe_close(fd); /* Let's close the original early */
+
+        return loop_device_make_internal(NULL, mfd, open_flags, 0, 0, 0, loop_flags, lock_op, ret);
 }
 
 static LoopDevice* loop_device_free(LoopDevice *d) {
@@ -719,7 +776,7 @@ int loop_device_open(
                 int lock_op,
                 LoopDevice **ret) {
 
-        _cleanup_close_ int fd = -1, lock_fd = -1;
+        _cleanup_close_ int fd = -EBADF, lock_fd = -EBADF;
         _cleanup_free_ char *node = NULL, *backing_file = NULL;
         struct loop_info64 info;
         uint64_t diskseq = 0;
@@ -839,7 +896,7 @@ static int resize_partition(int partition_fd, uint64_t offset, uint64_t size) {
         char sysfs[STRLEN("/sys/dev/block/:/partition") + 2*DECIMAL_STR_MAX(dev_t) + 1];
         _cleanup_free_ char *buffer = NULL;
         uint64_t current_offset, current_size, partno;
-        _cleanup_close_ int whole_fd = -1;
+        _cleanup_close_ int whole_fd = -EBADF;
         struct stat st;
         dev_t devno;
         int r;