diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2017-10-28 17:02:03 -0400 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2017-10-28 17:02:03 -0400 |
commit | f54f8e2b14d85ee250509b51562d990a5d7d40a6 (patch) | |
tree | a850e77c8c64c9f2829f51be884295f3c42571b2 | |
parent | 1127e1c6e5d4fad15022bcd4a3eaf9a7618d5f92 (diff) |
a
-rw-r--r-- | src/nspawn/nspawn-mount.c | 422 | ||||
-rw-r--r-- | src/nspawn/nspawn-mount.h | 27 |
2 files changed, 0 insertions, 449 deletions
diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c index a47eb31922..051eacb3ba 100644 --- a/src/nspawn/nspawn-mount.c +++ b/src/nspawn/nspawn-mount.c @@ -39,199 +39,6 @@ #include "user-util.h" #include "util.h" -CustomMount* custom_mount_add(CustomMount **l, unsigned *n, CustomMountType t) { - CustomMount *c, *ret; - - assert(l); - assert(n); - assert(t >= 0); - assert(t < _CUSTOM_MOUNT_TYPE_MAX); - - c = realloc_multiply(*l, (*n + 1), sizeof(CustomMount)); - if (!c) - return NULL; - - *l = c; - ret = *l + *n; - (*n)++; - - *ret = (CustomMount) { .type = t }; - - return ret; -} - -void custom_mount_free_all(CustomMount *l, unsigned n) { - unsigned i; - - for (i = 0; i < n; i++) { - CustomMount *m = l + i; - - free(m->source); - free(m->destination); - free(m->options); - - if (m->work_dir) { - (void) rm_rf(m->work_dir, REMOVE_ROOT|REMOVE_PHYSICAL); - free(m->work_dir); - } - - if (m->rm_rf_tmpdir) { - (void) rm_rf(m->rm_rf_tmpdir, REMOVE_ROOT|REMOVE_PHYSICAL); - free(m->rm_rf_tmpdir); - } - - strv_free(m->lower); - } - - free(l); -} - -static int custom_mount_compare(const void *a, const void *b) { - const CustomMount *x = a, *y = b; - int r; - - r = path_compare(x->destination, y->destination); - if (r != 0) - return r; - - if (x->type < y->type) - return -1; - if (x->type > y->type) - return 1; - - return 0; -} - -static char *resolve_source_path(const char *dest, const char *source) { - - if (!source) - return NULL; - - if (source[0] == '+') - return prefix_root(dest, source + 1); - - return strdup(source); -} - -int custom_mount_prepare_all(const char *dest, CustomMount *l, unsigned n) { - unsigned i; - int r; - - /* Prepare all custom mounts. This will make source we know all temporary directories. This is called in the - * parent process, so that we know the temporary directories to remove on exit before we fork off the - * children. */ - - assert(l || n == 0); - - /* Order the custom mounts, and make sure we have a working directory */ - qsort_safe(l, n, sizeof(CustomMount), custom_mount_compare); - - for (i = 0; i < n; i++) { - CustomMount *m = l + i; - - if (m->source) { - char *s; - - s = resolve_source_path(dest, m->source); - if (!s) - return log_oom(); - - free(m->source); - m->source = s; - } else { - /* No source specified? In that case, use a throw-away temporary directory in /var/tmp */ - - m->rm_rf_tmpdir = strdup("/var/tmp/nspawn-temp-XXXXXX"); - if (!m->rm_rf_tmpdir) - return log_oom(); - - if (!mkdtemp(m->rm_rf_tmpdir)) { - m->rm_rf_tmpdir = mfree(m->rm_rf_tmpdir); - return log_error_errno(errno, "Failed to acquire temporary directory: %m"); - } - - m->source = strjoin(m->rm_rf_tmpdir, "/src"); - if (!m->source) - return log_oom(); - - if (mkdir(m->source, 0755) < 0) - return log_error_errno(errno, "Failed to create %s: %m", m->source); - } - - if (m->type == CUSTOM_MOUNT_OVERLAY) { - char **j; - - STRV_FOREACH(j, m->lower) { - char *s; - - s = resolve_source_path(dest, *j); - if (!s) - return log_oom(); - - free(*j); - *j = s; - } - - if (m->work_dir) { - char *s; - - s = resolve_source_path(dest, m->work_dir); - if (!s) - return log_oom(); - - free(m->work_dir); - m->work_dir = s; - } else { - assert(m->source); - - r = tempfn_random(m->source, NULL, &m->work_dir); - if (r < 0) - return log_error_errno(r, "Failed to acquire working directory: %m"); - } - - (void) mkdir_label(m->work_dir, 0700); - } - } - - return 0; -} - -int tmpfs_mount_parse(CustomMount **l, unsigned *n, const char *s) { - _cleanup_free_ char *path = NULL, *opts = NULL; - const char *p = s; - CustomMount *m; - int r; - - assert(l); - assert(n); - assert(s); - - r = extract_first_word(&p, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS); - if (r < 0) - return r; - if (r == 0) - return -EINVAL; - - if (isempty(p)) - opts = strdup("mode=0755"); - else - opts = strdup(p); - if (!opts) - return -ENOMEM; - - if (!path_is_absolute(path)) - return -EINVAL; - - m = custom_mount_add(l, n, CUSTOM_MOUNT_TMPFS); - if (!m) - return -ENOMEM; - - m->destination = path; - m->options = opts; - - path = opts = NULL; - return 0; -} static int tmpfs_patch_options( const char *options, @@ -505,235 +312,6 @@ int mount_all(const char *dest, return 0; } -static int parse_mount_bind_options(const char *options, unsigned long *mount_flags, char **mount_opts) { - const char *p = options; - unsigned long flags = *mount_flags; - char *opts = NULL; - int r; - - assert(options); - - for (;;) { - _cleanup_free_ char *word = NULL; - - r = extract_first_word(&p, &word, ",", 0); - if (r < 0) - return log_error_errno(r, "Failed to extract mount option: %m"); - if (r == 0) - break; - - if (streq(word, "rbind")) - flags |= MS_REC; - else if (streq(word, "norbind")) - flags &= ~MS_REC; - else { - log_error("Invalid bind mount option: %s", word); - return -EINVAL; - } - } - - *mount_flags = flags; - /* in the future mount_opts will hold string options for mount(2) */ - *mount_opts = opts; - - return 0; -} - -static int mount_bind(const char *dest, CustomMount *m) { - - _cleanup_free_ char *mount_opts = NULL, *where = NULL; - unsigned long mount_flags = MS_BIND | MS_REC; - struct stat source_st, dest_st; - int r; - - assert(dest); - assert(m); - - if (m->options) { - r = parse_mount_bind_options(m->options, &mount_flags, &mount_opts); - if (r < 0) - return r; - } - - if (stat(m->source, &source_st) < 0) - return log_error_errno(errno, "Failed to stat %s: %m", m->source); - - r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where); - if (r < 0) - return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, m->destination); - if (r > 0) { /* Path exists already? */ - - if (stat(where, &dest_st) < 0) - return log_error_errno(errno, "Failed to stat %s: %m", where); - - if (S_ISDIR(source_st.st_mode) && !S_ISDIR(dest_st.st_mode)) { - log_error("Cannot bind mount directory %s on file %s.", m->source, where); - return -EINVAL; - } - - if (!S_ISDIR(source_st.st_mode) && S_ISDIR(dest_st.st_mode)) { - log_error("Cannot bind mount file %s on directory %s.", m->source, where); - return -EINVAL; - } - - } else { /* Path doesn't exist yet? */ - r = mkdir_parents_label(where, 0755); - if (r < 0) - return log_error_errno(r, "Failed to make parents of %s: %m", where); - - /* Create the mount point. Any non-directory file can be - * mounted on any non-directory file (regular, fifo, socket, - * char, block). - */ - if (S_ISDIR(source_st.st_mode)) - r = mkdir_label(where, 0755); - else - r = touch(where); - if (r < 0) - return log_error_errno(r, "Failed to create mount point %s: %m", where); - - } - - r = mount_verbose(LOG_ERR, m->source, where, NULL, mount_flags, mount_opts); - if (r < 0) - return r; - - if (m->read_only) { - r = bind_remount_recursive(where, true, NULL); - if (r < 0) - return log_error_errno(r, "Read-only bind mount failed: %m"); - } - - return 0; -} - -static int mount_tmpfs( - const char *dest, - CustomMount *m, - bool userns, uid_t uid_shift, uid_t uid_range, - const char *selinux_apifs_context) { - - const char *options; - _cleanup_free_ char *buf = NULL, *where = NULL; - int r; - - assert(dest); - assert(m); - - r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where); - if (r < 0) - return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, m->destination); - if (r == 0) { /* Doesn't exist yet? */ - r = mkdir_p_label(where, 0755); - if (r < 0) - return log_error_errno(r, "Creating mount point for tmpfs %s failed: %m", where); - } - - r = tmpfs_patch_options(m->options, userns, uid_shift, uid_range, false, selinux_apifs_context, &buf); - if (r < 0) - return log_oom(); - options = r > 0 ? buf : m->options; - - return mount_verbose(LOG_ERR, "tmpfs", where, "tmpfs", MS_NODEV|MS_STRICTATIME, options); -} - -static char *joined_and_escaped_lower_dirs(char **lower) { - _cleanup_strv_free_ char **sv = NULL; - - sv = strv_copy(lower); - if (!sv) - return NULL; - - strv_reverse(sv); - - if (!strv_shell_escape(sv, ",:")) - return NULL; - - return strv_join(sv, ":"); -} - -static int mount_overlay(const char *dest, CustomMount *m) { - - _cleanup_free_ char *lower = NULL, *where = NULL, *escaped_source = NULL; - const char *options; - int r; - - assert(dest); - assert(m); - - r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where); - if (r < 0) - return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, m->destination); - if (r == 0) { /* Doesn't exist yet? */ - r = mkdir_label(where, 0755); - if (r < 0) - return log_error_errno(r, "Creating mount point for overlay %s failed: %m", where); - } - - (void) mkdir_p_label(m->source, 0755); - - lower = joined_and_escaped_lower_dirs(m->lower); - if (!lower) - return log_oom(); - - escaped_source = shell_escape(m->source, ",:"); - if (!escaped_source) - return log_oom(); - - if (m->read_only) - options = strjoina("lowerdir=", escaped_source, ":", lower); - else { - _cleanup_free_ char *escaped_work_dir = NULL; - - escaped_work_dir = shell_escape(m->work_dir, ",:"); - if (!escaped_work_dir) - return log_oom(); - - options = strjoina("lowerdir=", lower, ",upperdir=", escaped_source, ",workdir=", escaped_work_dir); - } - - return mount_verbose(LOG_ERR, "overlay", where, "overlay", m->read_only ? MS_RDONLY : 0, options); -} - -int mount_custom( - const char *dest, - CustomMount *mounts, unsigned n, - bool userns, uid_t uid_shift, uid_t uid_range, - const char *selinux_apifs_context) { - - unsigned i; - int r; - - assert(dest); - - for (i = 0; i < n; i++) { - CustomMount *m = mounts + i; - - switch (m->type) { - - case CUSTOM_MOUNT_BIND: - r = mount_bind(dest, m); - break; - - case CUSTOM_MOUNT_TMPFS: - r = mount_tmpfs(dest, m, userns, uid_shift, uid_range, selinux_apifs_context); - break; - - case CUSTOM_MOUNT_OVERLAY: - r = mount_overlay(dest, m); - break; - - default: - assert_not_reached("Unknown custom mount type"); - } - - if (r < 0) - return r; - } - - return 0; -} - int setup_volatile_state( const char *directory, VolatileMode mode, diff --git a/src/nspawn/nspawn-mount.h b/src/nspawn/nspawn-mount.h index 6549a32dd5..7712e867d2 100644 --- a/src/nspawn/nspawn-mount.h +++ b/src/nspawn/nspawn-mount.h @@ -32,36 +32,9 @@ typedef enum MountSettingsMask { Works only if MOUNT_APPLY_APIVFS_RO is also set. */ } MountSettingsMask; -typedef enum CustomMountType { - CUSTOM_MOUNT_BIND, - CUSTOM_MOUNT_TMPFS, - CUSTOM_MOUNT_OVERLAY, - _CUSTOM_MOUNT_TYPE_MAX, - _CUSTOM_MOUNT_TYPE_INVALID = -1 -} CustomMountType; - -typedef struct CustomMount { - CustomMountType type; - bool read_only; - char *source; /* for overlayfs this is the upper directory */ - char *destination; - char *options; - char *work_dir; - char **lower; - char *rm_rf_tmpdir; -} CustomMount; - -CustomMount* custom_mount_add(CustomMount **l, unsigned *n, CustomMountType t); -void custom_mount_free_all(CustomMount *l, unsigned n); -int custom_mount_prepare_all(const char *dest, CustomMount *l, unsigned n); - -int tmpfs_mount_parse(CustomMount **l, unsigned *n, const char *s); - int mount_all(const char *dest, MountSettingsMask mount_settings, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context); int mount_sysfs(const char *dest, MountSettingsMask mount_settings); -int mount_custom(const char *dest, CustomMount *mounts, unsigned n, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context); - int setup_volatile(const char *directory, VolatileMode mode, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context); int setup_volatile_state(const char *directory, VolatileMode mode, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context); |