]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: when we cannot open an image file for write, try read-only 14508/head
authorLennart Poettering <lennart@poettering.net>
Tue, 7 Jan 2020 15:56:05 +0000 (16:56 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 9 Jan 2020 10:18:06 +0000 (11:18 +0100)
Closes: #14442
src/core/namespace.c
src/shared/loop-util.c

index fd38174ac02ae3d437bbafc9c95721fb66825ce9..a6f803671eb2baf9e4027784f88d7ae22f5d791e 100644 (file)
@@ -1289,7 +1289,7 @@ int setup_namespace(
                         dissect_image_flags |= DISSECT_IMAGE_READ_ONLY;
 
                 r = loop_device_make_by_path(root_image,
-                                             dissect_image_flags & DISSECT_IMAGE_READ_ONLY ? O_RDONLY : O_RDWR,
+                                             FLAGS_SET(dissect_image_flags, DISSECT_IMAGE_READ_ONLY) ? O_RDONLY : -1 /* < 0 means writable if possible, read-only as fallback */,
                                              LO_FLAGS_PARTSCAN,
                                              &loop_device);
                 if (r < 0)
index d92ef961624cf8e41dbf4cbd584f7c3aefc3012c..7aee239e33a81c82b2e314407dc62758aa50be45 100644 (file)
@@ -14,6 +14,7 @@
 #include <unistd.h>
 
 #include "alloc-util.h"
+#include "errno-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "loop-util.h"
@@ -157,14 +158,30 @@ int loop_device_make(
 
 int loop_device_make_by_path(const char *path, int open_flags, uint32_t loop_flags, LoopDevice **ret) {
         _cleanup_close_ int fd = -1;
+        int r;
 
         assert(path);
         assert(ret);
-        assert(IN_SET(open_flags, O_RDWR, O_RDONLY));
+        assert(open_flags < 0 || IN_SET(open_flags, O_RDWR, O_RDONLY));
 
-        fd = open(path, O_CLOEXEC|O_NONBLOCK|O_NOCTTY|open_flags);
-        if (fd < 0)
-                return -errno;
+        /* Passing < 0 as open_flags here means we'll try to open the device writable if we can, retrying
+         * read-only if we cannot. */
+
+        fd = open(path, O_CLOEXEC|O_NONBLOCK|O_NOCTTY|(open_flags >= 0 ? open_flags : O_RDWR));
+        if (fd < 0) {
+                r = -errno;
+
+                /* Retry read-only? */
+                if (open_flags >= 0 || !(ERRNO_IS_PRIVILEGE(r) || r == -EROFS))
+                        return r;
+
+                fd = open(path, O_CLOEXEC|O_NONBLOCK|O_NOCTTY|O_RDONLY);
+                if (fd < 0)
+                        return r; /* Propagate original error */
+
+                open_flags = O_RDONLY;
+        } else if (open_flags < 0)
+                open_flags = O_RDWR;
 
         return loop_device_make(fd, open_flags, 0, 0, loop_flags, ret);
 }