summaryrefslogtreecommitdiffstats
path: root/src/shared/loop-util.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2020-01-07 16:56:05 +0100
committerLennart Poettering <lennart@poettering.net>2020-01-09 11:18:06 +0100
commitb0a94268f8761cfa0dfa532fb8b18620b381f440 (patch)
tree868a81058ceaa69109a9d98eee7d469eb7402671 /src/shared/loop-util.c
parentnamespace: tweak checks whether we can mount image read-only (diff)
downloadsystemd-b0a94268f8761cfa0dfa532fb8b18620b381f440.tar.xz
systemd-b0a94268f8761cfa0dfa532fb8b18620b381f440.zip
core: when we cannot open an image file for write, try read-only
Closes: #14442
Diffstat (limited to 'src/shared/loop-util.c')
-rw-r--r--src/shared/loop-util.c25
1 files changed, 21 insertions, 4 deletions
diff --git a/src/shared/loop-util.c b/src/shared/loop-util.c
index d92ef96162..7aee239e33 100644
--- a/src/shared/loop-util.c
+++ b/src/shared/loop-util.c
@@ -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);
}