summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Yakubovich <eugene.yakubovich@coreos.com>2015-07-21 15:48:38 -0700
committerEugene Yakubovich <eugene.yakubovich@coreos.com>2015-08-28 18:06:05 -0700
commit5e5bfa6e1c915e795dd99ab65275c4bf9af667ed (patch)
treed97072b83b0a6be50e246fa99d1d99536fb75460
parent0d04f1ffec81842ed7135746ccefe58186c93707 (diff)
nspawn: add (no)rbind option to --bind and --bind-ro
--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".
-rw-r--r--man/systemd-nspawn.xml7
-rw-r--r--src/nspawn/nspawn.c56
2 files changed, 55 insertions, 8 deletions
diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml
index 4966749259..6165fe1357 100644
--- a/man/systemd-nspawn.xml
+++ b/man/systemd-nspawn.xml
@@ -576,12 +576,15 @@
<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
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 837947ee28..edf5b9fc57 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -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) {