]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
nspawn: add (no)rbind option to --bind and --bind-ro 649/head
authorEugene Yakubovich <eugene.yakubovich@coreos.com>
Tue, 21 Jul 2015 22:48:38 +0000 (15:48 -0700)
committerEugene Yakubovich <eugene.yakubovich@coreos.com>
Sat, 29 Aug 2015 01:06:05 +0000 (18:06 -0700)
--bind and --bind-ro perform the bind mount
non-recursively. It is sometimes (often?) desirable
to do a recursive mount. This patch adds an optional
set of bind mount options in the form of:
--bind=src-path:dst-path:options
options are comma separated and currently only
"rbind" and "norbind" are allowed.
Default value is "rbind".

man/systemd-nspawn.xml
src/nspawn/nspawn.c

index 496674925973d77bbff73dcd9ff147de88d00f10..6165fe1357484d6f9e6c49911d542030124d5e22 100644 (file)
         <term><option>--bind-ro=</option></term>
 
         <listitem><para>Bind mount a file or directory from the host
-        into the container. Either takes a path argument -- in which
+        into the container. Takes one of: a path argument -- in which
         case the specified path will be mounted from the host to the
         same path in the container --, or a colon-separated pair of
         paths -- in which case the first specified path is the source
         in the host, and the second path is the destination in the
-        container. Backslash escapes are interpreted so
+        container --, or a colon-separated triple of source path,
+        destination path and mount options. Mount options are comma
+        separated and currently only "rbind" and "norbind"
+        are allowed. Defaults to "rbind". Backslash escapes are interpreted so
         <literal>\:</literal> may be used to embed colons in either path.
         This option may be specified multiple times for
         creating multiple independent bind mount points. The
index 837947ee285980e0742060b1a848ec4f5aca3b42..edf5b9fc5763c42bff6ecc15d6ebee952442a9e6 100644 (file)
@@ -257,9 +257,11 @@ static void help(void) {
                "                            try-guest, try-host\n"
                "  -j                        Equivalent to --link-journal=try-guest\n"
                "     --read-only            Mount the root directory read-only\n"
-               "     --bind=PATH[:PATH]     Bind mount a file or directory from the host into\n"
+               "     --bind=PATH[:PATH[:OPTIONS]]\n"
+               "                            Bind mount a file or directory from the host into\n"
                "                            the container\n"
-               "     --bind-ro=PATH[:PATH]  Similar, but creates a read-only bind mount\n"
+               "     --bind-ro=PATH[:PATH[:OPTIONS]\n"
+               "                            Similar, but creates a read-only bind mount\n"
                "     --tmpfs=PATH:[OPTIONS] Mount an empty tmpfs to the specified directory\n"
                "     --overlay=PATH[:PATH...]:PATH\n"
                "                            Create an overlay mount from the host to \n"
@@ -656,14 +658,15 @@ static int parse_argv(int argc, char *argv[]) {
                 case ARG_BIND:
                 case ARG_BIND_RO: {
                         const char *current = optarg;
-                        _cleanup_free_ char *source = NULL, *destination = NULL;
+                        _cleanup_free_ char *source = NULL, *destination = NULL, *opts = NULL;
                         CustomMount *m;
 
-                        r = extract_many_words(&current, ":", EXTRACT_DONT_COALESCE_SEPARATORS, &source, &destination, NULL);
+                        r = extract_many_words(&current, ":", EXTRACT_DONT_COALESCE_SEPARATORS, &source, &destination, &opts, NULL);
                         switch (r) {
                         case 1:
                                 destination = strdup(source);
                         case 2:
+                        case 3:
                                 break;
                         case -ENOMEM:
                                 return log_oom();
@@ -687,8 +690,9 @@ static int parse_argv(int argc, char *argv[]) {
                         m->source = source;
                         m->destination = destination;
                         m->read_only = c == ARG_BIND_RO;
+                        m->options = opts;
 
-                        source = destination = NULL;
+                        source = destination = opts = NULL;
 
                         break;
                 }
@@ -1158,13 +1162,53 @@ static int mount_all(const char *dest, bool userns) {
         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;
+
+        assert(options);
+
+        for (;;) {
+                _cleanup_free_ char *word = NULL;
+                int r = extract_first_word(&p, &word, ",", EXTRACT_QUOTES);
+                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) {
         struct stat source_st, dest_st;
         const char *where;
+        unsigned long mount_flags = MS_BIND | MS_REC;
+        _cleanup_free_ char *mount_opts = NULL;
         int r;
 
         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);
 
@@ -1201,7 +1245,7 @@ static int mount_bind(const char *dest, CustomMount *m) {
         if (r < 0 && r != -EEXIST)
                 return log_error_errno(r, "Failed to create mount point %s: %m", where);
 
-        if (mount(m->source, where, NULL, MS_BIND, NULL) < 0)
+        if (mount(m->source, where, NULL, mount_flags, mount_opts) < 0)
                 return log_error_errno(errno, "mount(%s) failed: %m", where);
 
         if (m->read_only) {