summaryrefslogtreecommitdiff
path: root/src
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 /src
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".
Diffstat (limited to 'src')
-rw-r--r--src/nspawn/nspawn.c56
1 files changed, 50 insertions, 6 deletions
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) {