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".
This commit is contained in:
Eugene Yakubovich 2015-07-21 15:48:38 -07:00
parent 0d04f1ffec
commit 5e5bfa6e1c
2 changed files with 55 additions and 8 deletions

View file

@ -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

View 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) {