summaryrefslogtreecommitdiff
path: root/src/nspawn/nspawn.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nspawn/nspawn.c')
-rw-r--r--src/nspawn/nspawn.c131
1 files changed, 79 insertions, 52 deletions
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index b90ccc53ef..c257682451 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -75,6 +75,7 @@ static char *arg_directory = NULL;
static char *arg_user = NULL;
static char **arg_controllers = NULL;
static char *arg_uuid = NULL;
+static char *arg_machine = NULL;
static bool arg_private_network = false;
static bool arg_read_only = false;
static bool arg_boot = false;
@@ -113,13 +114,14 @@ static int help(void) {
printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n"
"Spawn a minimal namespace container for debugging, testing and building.\n\n"
" -h --help Show this help\n"
- " --version Print version string\n"
+ " --version Print version string\n"
" -D --directory=NAME Root directory for the container\n"
" -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\n"
" cgroup hierarchies\n"
" --uuid=UUID Set a specific machine UUID for the container\n"
+ " -M --machine=NAME Set the machine name for the container\n"
" --private-network Disable network in container\n"
" --read-only Mount the root directory read-only\n"
" --capability=CAP In addition to the default, retain specified\n"
@@ -161,6 +163,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "link-journal", required_argument, NULL, ARG_LINK_JOURNAL },
{ "bind", required_argument, NULL, ARG_BIND },
{ "bind-ro", required_argument, NULL, ARG_BIND_RO },
+ { "machine", required_argument, NULL, 'M' },
{ NULL, 0, NULL, 0 }
};
@@ -194,22 +197,19 @@ static int parse_argv(int argc, char *argv[]) {
case 'u':
free(arg_user);
- if (!(arg_user = strdup(optarg))) {
- log_error("Failed to duplicate user name.");
- return -ENOMEM;
- }
+ arg_user = strdup(optarg);
+ if (!arg_user)
+ return log_oom();
break;
case 'C':
strv_free(arg_controllers);
arg_controllers = strv_split(optarg, ",");
- if (!arg_controllers) {
- log_error("Failed to split controllers list.");
- return -ENOMEM;
- }
- strv_uniq(arg_controllers);
+ if (!arg_controllers)
+ return log_oom();
+ cg_shorten_controllers(arg_controllers);
break;
case ARG_PRIVATE_NETWORK:
@@ -224,6 +224,19 @@ static int parse_argv(int argc, char *argv[]) {
arg_uuid = optarg;
break;
+ case 'M':
+ if (!hostname_is_valid(optarg)) {
+ log_error("Invalid machine name: %s", optarg);
+ return -EINVAL;
+ }
+
+ free(arg_machine);
+ arg_machine = strdup(optarg);
+ if (!arg_machine)
+ return log_oom();
+
+ break;
+
case ARG_READ_ONLY:
arg_read_only = true;
break;
@@ -743,25 +756,11 @@ static int setup_kmsg(const char *dest, int kmsg_socket) {
}
static int setup_hostname(void) {
- char *hn;
- int r = 0;
-
- hn = path_get_file_name(arg_directory);
- if (hn) {
- hn = strdup(hn);
- if (!hn)
- return -ENOMEM;
-
- hostname_cleanup(hn);
- if (!isempty(hn))
- if (sethostname(hn, strlen(hn)) < 0)
- r = -errno;
-
- free(hn);
- }
+ if (sethostname(arg_machine, strlen(arg_machine)) < 0)
+ return -errno;
- return r;
+ return 0;
}
static int setup_journal(const char *directory) {
@@ -896,6 +895,25 @@ static int setup_journal(const char *directory) {
return 0;
}
+static int setup_cgroup(const char *path) {
+ char **c;
+ int r;
+
+ r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, path, 1);
+ if (r < 0) {
+ log_error("Failed to create cgroup: %s", strerror(-r));
+ return r;
+ }
+
+ STRV_FOREACH(c, arg_controllers) {
+ r = cg_create_and_attach(*c, path, 1);
+ if (r < 0)
+ log_warning("Failed to create cgroup in controller %s: %s", *c, strerror(-r));
+ }
+
+ return 0;
+}
+
static int drop_capabilities(void) {
return capability_bounding_set_drop(~arg_retain, false);
}
@@ -1159,9 +1177,9 @@ finish:
int main(int argc, char *argv[]) {
pid_t pid = 0;
int r = EXIT_FAILURE, k;
- char *oldcg = NULL, *newcg = NULL;
- char **controller = NULL;
- int master = -1, n_fd_passed;
+ _cleanup_free_ char *machine_root = NULL, *newcg = NULL;
+ _cleanup_close_ int master = -1;
+ int n_fd_passed;
const char *console = NULL;
struct termios saved_attr, raw_attr;
sigset_t mask;
@@ -1193,6 +1211,20 @@ int main(int argc, char *argv[]) {
path_kill_slashes(arg_directory);
+ if (!arg_machine) {
+ arg_machine = strdup(path_get_file_name(arg_directory));
+ if (!arg_machine) {
+ log_oom();
+ goto finish;
+ }
+
+ hostname_cleanup(arg_machine);
+ if (isempty(arg_machine)) {
+ log_error("Failed to determine machine name automatically, please use -M.");
+ goto finish;
+ }
+ }
+
if (geteuid() != 0) {
log_error("Need to be root.");
goto finish;
@@ -1225,27 +1257,26 @@ int main(int argc, char *argv[]) {
fdset_close_others(fds);
log_open();
- k = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, &oldcg);
+ k = cg_get_machine_path(&machine_root);
if (k < 0) {
- log_error("Failed to determine current cgroup: %s", strerror(-k));
+ log_error("Failed to determine machine cgroup path: %s", strerror(-k));
goto finish;
}
- if (asprintf(&newcg, "%s/nspawn-%lu", oldcg, (unsigned long) getpid()) < 0) {
+ newcg = strjoin(machine_root, "/", arg_machine, NULL);
+ if (!newcg) {
log_error("Failed to allocate cgroup path.");
goto finish;
}
- k = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, newcg, 0);
- if (k < 0) {
- log_error("Failed to create cgroup: %s", strerror(-k));
- goto finish;
- }
+ r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, newcg, false);
+ if (r <= 0 && r != -ENOENT) {
+ log_error("Container already running.");
- STRV_FOREACH(controller, arg_controllers) {
- k = cg_create_and_attach(*controller, newcg, 0);
- if (k < 0)
- log_warning("Failed to create cgroup in controller %s: %s", *controller, strerror(-k));
+ free(newcg);
+ newcg = NULL;
+
+ goto finish;
}
master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NDELAY);
@@ -1279,7 +1310,7 @@ int main(int argc, char *argv[]) {
}
if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, kmsg_socket_pair) < 0) {
- log_error("Failed to create kmsg socket pair");
+ log_error("Failed to create kmsg socket pair.");
goto finish;
}
@@ -1382,6 +1413,9 @@ int main(int argc, char *argv[]) {
goto child_fail;
}
+ if (setup_cgroup(newcg) < 0)
+ goto child_fail;
+
/* Mark everything as slave, so that we still
* receive mounts from the real root, but don't
* propagate mounts to the real root. */
@@ -1547,7 +1581,7 @@ int main(int argc, char *argv[]) {
}
if ((asprintf((char **)(envp + n_env++), "LISTEN_FDS=%u", n_fd_passed) < 0) ||
- (asprintf((char **)(envp + n_env++), "LISTEN_PID=%lu", (unsigned long) getpid()) < 0)) {
+ (asprintf((char **)(envp + n_env++), "LISTEN_PID=%lu", (unsigned long) 1) < 0)) {
log_oom();
goto child_fail;
}
@@ -1640,21 +1674,14 @@ finish:
if (saved_attr_valid)
tcsetattr(STDIN_FILENO, TCSANOW, &saved_attr);
- if (master >= 0)
- close_nointr_nofail(master);
-
close_pipe(kmsg_socket_pair);
- if (oldcg)
- cg_attach(SYSTEMD_CGROUP_CONTROLLER, oldcg, 0);
-
if (newcg)
cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, newcg, true);
free(arg_directory);
+ free(arg_machine);
strv_free(arg_controllers);
- free(oldcg);
- free(newcg);
fdset_free(fds);