summaryrefslogtreecommitdiff
path: root/src/nspawn/nspawn.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2016-02-03 20:32:06 +0100
committerLennart Poettering <lennart@poettering.net>2016-02-03 23:58:24 +0100
commit7732f92bad5f24a4bd03bb357af46da56b0ac94d (patch)
tree10e33a8ec564376365e05a0f12681a73aab40986 /src/nspawn/nspawn.c
parent021dd87bc055a5bfb2dcef83fc868fe24648b959 (diff)
nspawn: optionally run a stub init process as PID 1
This adds a new switch --as-pid2, which allows running commands as PID 2, while a stub init process is run as PID 1. This is useful in order to run arbitrary commands in a container, as PID1's semantics are different from all other processes regarding reaping of unknown children or signal handling.
Diffstat (limited to 'src/nspawn/nspawn.c')
-rw-r--r--src/nspawn/nspawn.c52
1 files changed, 40 insertions, 12 deletions
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 0dae9984c9..e7314ac29c 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -79,6 +79,7 @@
#include "nspawn-register.h"
#include "nspawn-settings.h"
#include "nspawn-setuid.h"
+#include "nspawn-stub-pid1.h"
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
@@ -123,7 +124,7 @@ static const char *arg_selinux_apifs_context = NULL;
static const char *arg_slice = NULL;
static bool arg_private_network = false;
static bool arg_read_only = false;
-static bool arg_boot = false;
+static StartMode arg_start_mode = START_PID1;
static bool arg_ephemeral = false;
static LinkJournal arg_link_journal = LINK_AUTO;
static bool arg_link_journal_try = false;
@@ -193,6 +194,7 @@ static void help(void) {
" -x --ephemeral Run container with snapshot of root directory, and\n"
" remove it after exit\n"
" -i --image=PATH File system device or disk image for the container\n"
+ " -a --as-pid2 Maintain a stub init as PID1, invoke binary as PID2\n"
" -b --boot Boot up full system (i.e. invoke init)\n"
" --chdir=PATH Set working directory in the container\n"
" -u --user=USER Run the command under specified user or uid\n"
@@ -358,6 +360,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "ephemeral", no_argument, NULL, 'x' },
{ "user", required_argument, NULL, 'u' },
{ "private-network", no_argument, NULL, ARG_PRIVATE_NETWORK },
+ { "as-pid2", no_argument, NULL, 'a' },
{ "boot", no_argument, NULL, 'b' },
{ "uuid", required_argument, NULL, ARG_UUID },
{ "read-only", no_argument, NULL, ARG_READ_ONLY },
@@ -404,7 +407,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "+hD:u:bL:M:jS:Z:qi:xp:n", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "+hD:u:abL:M:jS:Z:qi:xp:n", options, NULL)) >= 0)
switch (c) {
@@ -495,8 +498,23 @@ static int parse_argv(int argc, char *argv[]) {
break;
case 'b':
- arg_boot = true;
- arg_settings_mask |= SETTING_BOOT;
+ if (arg_start_mode == START_PID2) {
+ log_error("--boot and --as-pid2 may not be combined.");
+ return -EINVAL;
+ }
+
+ arg_start_mode = START_BOOT;
+ arg_settings_mask |= SETTING_START_MODE;
+ break;
+
+ case 'a':
+ if (arg_start_mode == START_BOOT) {
+ log_error("--boot and --as-pid2 may not be combined.");
+ return -EINVAL;
+ }
+
+ arg_start_mode = START_PID2;
+ arg_settings_mask |= SETTING_START_MODE;
break;
case ARG_UUID:
@@ -876,7 +894,7 @@ static int parse_argv(int argc, char *argv[]) {
if (arg_share_system)
arg_register = false;
- if (arg_boot && arg_share_system) {
+ if (arg_start_mode != START_PID1 && arg_share_system) {
log_error("--boot and --share-system may not be combined.");
return -EINVAL;
}
@@ -924,7 +942,7 @@ static int parse_argv(int argc, char *argv[]) {
if (!arg_parameters)
return log_oom();
- arg_settings_mask |= SETTING_BOOT;
+ arg_settings_mask |= SETTING_START_MODE;
}
/* Load all settings from .nspawn files */
@@ -960,7 +978,7 @@ static int verify_arguments(void) {
return -EINVAL;
}
- if (arg_boot && arg_kill_signal <= 0)
+ if (arg_start_mode == START_BOOT && arg_kill_signal <= 0)
arg_kill_signal = SIGRTMIN+3;
return 0;
@@ -2584,6 +2602,12 @@ static int inner_child(
if (chdir(arg_chdir) < 0)
return log_error_errno(errno, "Failed to change to specified working directory %s: %m", arg_chdir);
+ if (arg_start_mode == START_PID2) {
+ r = stub_pid1();
+ if (r < 0)
+ return r;
+ }
+
/* Now, explicitly close the log, so that we
* then can close all remaining fds. Closing
* the log explicitly first has the benefit
@@ -2595,7 +2619,7 @@ static int inner_child(
log_close();
(void) fdset_close_others(fds);
- if (arg_boot) {
+ if (arg_start_mode == START_BOOT) {
char **a;
size_t m;
@@ -2917,9 +2941,9 @@ static int load_settings(void) {
/* Copy over bits from the settings, unless they have been
* explicitly masked by command line switches. */
- if ((arg_settings_mask & SETTING_BOOT) == 0 &&
- settings->boot >= 0) {
- arg_boot = settings->boot;
+ if ((arg_settings_mask & SETTING_START_MODE) == 0 &&
+ settings->start_mode >= 0) {
+ arg_start_mode = settings->start_mode;
strv_free(arg_parameters);
arg_parameters = settings->parameters;
@@ -3074,6 +3098,10 @@ int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
+ /* Make sure rename_process() in the stub init process can work */
+ saved_argv = argv;
+ saved_argc = argc;
+
r = parse_argv(argc, argv);
if (r <= 0)
goto finish;
@@ -3180,7 +3208,7 @@ int main(int argc, char *argv[]) {
}
}
- if (arg_boot) {
+ if (arg_start_mode == START_BOOT) {
if (path_is_os_tree(arg_directory) <= 0) {
log_error("Directory %s doesn't look like an OS root directory (os-release file is missing). Refusing.", arg_directory);
r = -EINVAL;