summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/shared/mount-util.c85
-rw-r--r--src/shared/mount-util.h2
2 files changed, 87 insertions, 0 deletions
diff --git a/src/shared/mount-util.c b/src/shared/mount-util.c
index 8acbadcaf9..8ba054471f 100644
--- a/src/shared/mount-util.c
+++ b/src/shared/mount-util.c
@@ -1574,3 +1574,88 @@ int mount_credentials_fs(const char *path, size_t size, bool ro) {
credentials_fs_mount_flags(ro),
opts);
}
+
+int make_fsmount(
+ int error_log_level,
+ const char *what,
+ const char *type,
+ unsigned long flags,
+ const char *options,
+ int userns_fd) {
+
+ _cleanup_close_ int fs_fd = -EBADF, mnt_fd = -EBADF;
+ _cleanup_free_ char *o = NULL;
+ unsigned long f;
+ int r;
+
+ assert(type);
+ assert(what);
+
+ r = mount_option_mangle(options, flags, &f, &o);
+ if (r < 0)
+ return log_full_errno(
+ error_log_level, r, "Failed to mangle mount options %s: %m",
+ strempty(options));
+
+ if (DEBUG_LOGGING) {
+ _cleanup_free_ char *fl = NULL;
+ (void) mount_flags_to_string(f, &fl);
+
+ log_debug("Creating mount fd for %s (%s) (%s \"%s\")...",
+ strna(what), strna(type), strnull(fl), strempty(o));
+ }
+
+ fs_fd = fsopen(type, FSOPEN_CLOEXEC);
+ if (fs_fd < 0)
+ return log_full_errno(error_log_level, errno, "Failed to open superblock for \"%s\": %m", type);
+
+ if (fsconfig(fs_fd, FSCONFIG_SET_STRING, "source", what, 0) < 0)
+ return log_full_errno(error_log_level, errno, "Failed to set mount source for \"%s\" to \"%s\": %m", type, what);
+
+ if (FLAGS_SET(f, MS_RDONLY))
+ if (fsconfig(fs_fd, FSCONFIG_SET_FLAG, "ro", NULL, 0) < 0)
+ return log_full_errno(error_log_level, errno, "Failed to set read only mount flag for \"%s\": %m", type);
+
+ for (const char *p = o;;) {
+ _cleanup_free_ char *word = NULL;
+ char *eq;
+
+ r = extract_first_word(&p, &word, ",", EXTRACT_KEEP_QUOTE);
+ if (r < 0)
+ return log_full_errno(error_log_level, r, "Failed to parse mount option string \"%s\": %m", o);
+ if (r == 0)
+ break;
+
+ eq = strchr(word, '=');
+ if (eq) {
+ *eq = 0;
+ eq++;
+
+ if (fsconfig(fs_fd, FSCONFIG_SET_STRING, word, eq, 0) < 0)
+ return log_full_errno(error_log_level, errno, "Failed to set mount option \"%s=%s\" for \"%s\": %m", word, eq, type);
+ } else {
+ if (fsconfig(fs_fd, FSCONFIG_SET_FLAG, word, NULL, 0) < 0)
+ return log_full_errno(error_log_level, errno, "Failed to set mount flag \"%s\" for \"%s\": %m", word, type);
+ }
+ }
+
+ if (fsconfig(fs_fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0) < 0)
+ return log_full_errno(error_log_level, errno, "Failed to realize fs fd for \"%s\" (\"%s\"): %m", what, type);
+
+ mnt_fd = fsmount(fs_fd, FSMOUNT_CLOEXEC, 0);
+ if (mnt_fd < 0)
+ return log_full_errno(error_log_level, errno, "Failed to create mount fd for \"%s\" (\"%s\"): %m", what, type);
+
+ if (mount_setattr(mnt_fd, "", AT_EMPTY_PATH|AT_RECURSIVE,
+ &(struct mount_attr) {
+ .attr_set = ms_flags_to_mount_attr(f) | (userns_fd >= 0 ? MOUNT_ATTR_IDMAP : 0),
+ .userns_fd = userns_fd,
+ }, MOUNT_ATTR_SIZE_VER0) < 0)
+ return log_full_errno(error_log_level,
+ errno,
+ "Failed to set mount flags for \"%s\" (\"%s\"): %m",
+ what,
+ type);
+
+ return TAKE_FD(mnt_fd);
+}
diff --git a/src/shared/mount-util.h b/src/shared/mount-util.h
index fb496e156b..a56530c42e 100644
--- a/src/shared/mount-util.h
+++ b/src/shared/mount-util.h
@@ -136,3 +136,5 @@ int trigger_automount_at(int dir_fd, const char *path);
unsigned long credentials_fs_mount_flags(bool ro);
int mount_credentials_fs(const char *path, size_t size, bool ro);
+
+int make_fsmount(int error_log_level, const char *what, const char *type, unsigned long flags, const char *options, int userns_fd);