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;