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.
This commit is contained in:
+40
-12
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user