static char **arg_controllers = NULL;
static char *arg_uuid = NULL;
static bool arg_private_network = false;
+static bool arg_read_only = false;
static bool arg_boot = false;
static int help(void) {
" -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"
" --uuid=UUID Set a specific machine UUID for the container\n"
- " --private-network Disable network in container\n",
+ " --private-network Disable network in container\n"
+ " --read-only Mount the root directory read-only\n",
program_invocation_short_name);
return 0;
enum {
ARG_PRIVATE_NETWORK = 0x100,
- ARG_UUID
+ ARG_UUID,
+ ARG_READ_ONLY
};
static const struct option options[] = {
{ "private-network", no_argument, NULL, ARG_PRIVATE_NETWORK },
{ "boot", no_argument, NULL, 'b' },
{ "uuid", required_argument, NULL, ARG_UUID },
+ { "read-only", no_argument, NULL, ARG_READ_ONLY },
{ NULL, 0, NULL, 0 }
};
arg_uuid = optarg;
break;
+ case ARG_READ_ONLY:
+ arg_read_only = true;
+ break;
+
case '?':
return -EINVAL;
return 0;
}
+static int setup_resolv_conf(const char *dest) {
+ char *where;
+
+ assert(dest);
+
+ if (arg_private_network)
+ return 0;
+
+ /* Fix resolv.conf, if possible */
+ if (asprintf(&where, "%s/etc/resolv.conf", dest) < 0) {
+ log_error("Out of memory");
+ return -ENOMEM;
+ }
+
+ if (mount("/etc/resolv.conf", where, "bind", MS_BIND, NULL) >= 0)
+ mount("/etc/resolv.conf", where, "bind", MS_BIND|MS_REMOUNT|MS_RDONLY, NULL);
+
+ free(where);
+
+ return 0;
+}
+
static int copy_devnodes(const char *dest) {
static const char devnodes[] =
if (mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0)
goto child_fail;
+ /* Turn directory into bind mount */
+ if (mount(arg_directory, arg_directory, "bind", MS_BIND, NULL) < 0) {
+ log_error("Failed to make bind mount.");
+ goto child_fail;
+ }
+
+ if (arg_read_only)
+ if (mount(arg_directory, arg_directory, "bind", MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
+ log_error("Failed to make read-only.");
+ goto child_fail;
+ }
+
if (mount_all(arg_directory) < 0)
goto child_fail;
if (setup_timezone(arg_directory) < 0)
goto child_fail;
+ if (setup_resolv_conf(arg_directory) < 0)
+ goto child_fail;
+
if (chdir(arg_directory) < 0) {
log_error("chdir(%s) failed: %m", arg_directory);
goto child_fail;
dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO)
goto child_fail;
- if (mount(arg_directory, "/", "bind", MS_BIND, NULL) < 0) {
- log_error("mount(MS_MOVE) failed: %m");
+ if (mount(arg_directory, "/", "bind", MS_MOVE, NULL) < 0) {
+ log_error("mount(MS_BIND) failed: %m");
goto child_fail;
}