mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-12 09:17:44 +03:00
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:
parent
0d04f1ffec
commit
5e5bfa6e1c
@ -576,12 +576,15 @@
|
|||||||
<term><option>--bind-ro=</option></term>
|
<term><option>--bind-ro=</option></term>
|
||||||
|
|
||||||
<listitem><para>Bind mount a file or directory from the host
|
<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
|
case the specified path will be mounted from the host to the
|
||||||
same path in the container --, or a colon-separated pair of
|
same path in the container --, or a colon-separated pair of
|
||||||
paths -- in which case the first specified path is the source
|
paths -- in which case the first specified path is the source
|
||||||
in the host, and the second path is the destination in the
|
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.
|
<literal>\:</literal> may be used to embed colons in either path.
|
||||||
This option may be specified multiple times for
|
This option may be specified multiple times for
|
||||||
creating multiple independent bind mount points. The
|
creating multiple independent bind mount points. The
|
||||||
|
@ -257,9 +257,11 @@ static void help(void) {
|
|||||||
" try-guest, try-host\n"
|
" try-guest, try-host\n"
|
||||||
" -j Equivalent to --link-journal=try-guest\n"
|
" -j Equivalent to --link-journal=try-guest\n"
|
||||||
" --read-only Mount the root directory read-only\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"
|
" 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"
|
" --tmpfs=PATH:[OPTIONS] Mount an empty tmpfs to the specified directory\n"
|
||||||
" --overlay=PATH[:PATH...]:PATH\n"
|
" --overlay=PATH[:PATH...]:PATH\n"
|
||||||
" Create an overlay mount from the host to \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:
|
||||||
case ARG_BIND_RO: {
|
case ARG_BIND_RO: {
|
||||||
const char *current = optarg;
|
const char *current = optarg;
|
||||||
_cleanup_free_ char *source = NULL, *destination = NULL;
|
_cleanup_free_ char *source = NULL, *destination = NULL, *opts = NULL;
|
||||||
CustomMount *m;
|
CustomMount *m;
|
||||||
|
|
||||||
r = extract_many_words(¤t, ":", EXTRACT_DONT_COALESCE_SEPARATORS, &source, &destination, NULL);
|
r = extract_many_words(¤t, ":", EXTRACT_DONT_COALESCE_SEPARATORS, &source, &destination, &opts, NULL);
|
||||||
switch (r) {
|
switch (r) {
|
||||||
case 1:
|
case 1:
|
||||||
destination = strdup(source);
|
destination = strdup(source);
|
||||||
case 2:
|
case 2:
|
||||||
|
case 3:
|
||||||
break;
|
break;
|
||||||
case -ENOMEM:
|
case -ENOMEM:
|
||||||
return log_oom();
|
return log_oom();
|
||||||
@ -687,8 +690,9 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
m->source = source;
|
m->source = source;
|
||||||
m->destination = destination;
|
m->destination = destination;
|
||||||
m->read_only = c == ARG_BIND_RO;
|
m->read_only = c == ARG_BIND_RO;
|
||||||
|
m->options = opts;
|
||||||
|
|
||||||
source = destination = NULL;
|
source = destination = opts = NULL;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1158,13 +1162,53 @@ static int mount_all(const char *dest, bool userns) {
|
|||||||
return 0;
|
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) {
|
static int mount_bind(const char *dest, CustomMount *m) {
|
||||||
struct stat source_st, dest_st;
|
struct stat source_st, dest_st;
|
||||||
const char *where;
|
const char *where;
|
||||||
|
unsigned long mount_flags = MS_BIND | MS_REC;
|
||||||
|
_cleanup_free_ char *mount_opts = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(m);
|
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)
|
if (stat(m->source, &source_st) < 0)
|
||||||
return log_error_errno(errno, "Failed to stat %s: %m", m->source);
|
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)
|
if (r < 0 && r != -EEXIST)
|
||||||
return log_error_errno(r, "Failed to create mount point %s: %m", where);
|
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);
|
return log_error_errno(errno, "mount(%s) failed: %m", where);
|
||||||
|
|
||||||
if (m->read_only) {
|
if (m->read_only) {
|
||||||
|
Loading…
Reference in New Issue
Block a user