diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index fef5c2c..fddd76e 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -194,6 +194,32 @@ + + + Remount/rebind specified + directories to the container. Takes + a ~\-separated list of mounts. The source + and destination directories are ^\-separated. + + For example: + /hostdir1^/containerdir1~/hostdir2^/containerdir2 + + + + + + + Remount/rebind (read-only) + specified directories to the container. Takes + a ~\-separated list of mounts. The source + and destination directories are ^\-separated. + + For example: + /hostdir1^/containerdir1~/hostdir2^/containerdir2 + + + + Turn off networking in diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 59171ab..ec89b74 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -70,6 +70,8 @@ static char *arg_uuid = NULL; static bool arg_private_network = false; static bool arg_read_only = false; static bool arg_boot = false; +static char **arg_mount = NULL; +static char **arg_mountro = NULL; static LinkJournal arg_link_journal = LINK_AUTO; static uint64_t arg_retain = (1ULL << CAP_CHOWN) | @@ -105,6 +107,8 @@ static int help(void) { " -b --boot Boot up full system (i.e. invoke init)\n" " -u --user=USER Run the command under specified user or uid\n" " -C --controllers=LIST Put the container in specified comma-separated cgroup hierarchies\n" + " -m --mount=LIST Remount (rebind) the specified directories\n" + " -M --mountro=LIST Remount (rebind) the specified directories (read-only)\n" " --uuid=UUID Set a specific machine UUID for the container\n" " --private-network Disable network in container\n" " --read-only Mount the root directory read-only\n" @@ -137,6 +141,8 @@ static int parse_argv(int argc, char *argv[]) { { "read-only", no_argument, NULL, ARG_READ_ONLY }, { "capability", required_argument, NULL, ARG_CAPABILITY }, { "link-journal", required_argument, NULL, ARG_LINK_JOURNAL }, + { "mount", required_argument, NULL, 'm' }, + { "mountro", required_argument, NULL, 'M' }, { NULL, 0, NULL, 0 } }; @@ -145,7 +151,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "+hD:u:C:bj", options, NULL)) >= 0) { + while ((c = getopt_long(argc, argv, "+hD:u:C:bjm:M:", options, NULL)) >= 0) { switch (c) { @@ -163,6 +169,26 @@ static int parse_argv(int argc, char *argv[]) { break; + case 'm': + strv_free(arg_mount); + arg_mount = strv_split(optarg, "~"); + if (!arg_mount) { + log_error("Failed to split mount list."); + return -ENOMEM; + } + strv_uniq(arg_mount); + break; + + case 'M': + strv_free(arg_mountro); + arg_mountro = strv_split(optarg, "~"); + if (!arg_mountro) { + log_error("Failed to split mountro list."); + return -ENOMEM; + } + strv_uniq(arg_mountro); + break; + case 'u': free(arg_user); if (!(arg_user = strdup(optarg))) { @@ -331,6 +357,69 @@ static int mount_all(const char *dest) { return r; } +static int mount_userlist(const char *dest, char **list, int ro) { + + char *where; + char **mnt, **path; + int r = 0; + + STRV_FOREACH(mnt, list) { + int t; + + path = strv_split(*mnt, "^"); + if (path == NULL || path[1] == NULL) { + log_error("mount-userlist(%s) failed", *mnt); + continue; + } + + if (asprintf(&where, "%s/%s", dest, path[1]) < 0) { + log_error("Out of memory"); + + if (r == 0) + r = -ENOMEM; + + break; + } + + t = path_is_mount_point(where, false); + if (t < 0) { + log_error("Failed to detect whether %s is a mount point: %s", where, strerror(-t)); + free(where); + + if (r == 0) + r = t; + + continue; + } + + mkdir_p_label(where, 0755); + + if (mount(path[0], where, "bind", MS_BIND, NULL) < 0) { + + log_error("mount(%s) failed: %m", where); + + if (r == 0) + r = -errno; + } + + if (ro) { + if (mount(path[0], where, "bind", + MS_BIND|MS_RDONLY|MS_REMOUNT, NULL) < 0) { + + log_error("mountro(%s) failed: %m", where); + + if (r == 0) + r = -errno; + } + } + + free(where); + strv_free(path); + } + + return r; +} + static int setup_timezone(const char *dest) { _cleanup_free_ char *where = NULL, *p = NULL, *q = NULL, *check = NULL, *what = NULL; char *z, *y; @@ -1236,6 +1325,12 @@ int main(int argc, char *argv[]) { if (mount_all(arg_directory) < 0) goto child_fail; + if (mount_userlist(arg_directory, arg_mount, 0) < 0) + goto child_fail; + + if (mount_userlist(arg_directory, arg_mountro, 1) < 0) + goto child_fail; + if (copy_devnodes(arg_directory) < 0) goto child_fail;