diff options
-rw-r--r-- | man/systemd-nspawn.xml | 27 | ||||
-rw-r--r-- | src/basic/terminal-util.c | 2 | ||||
-rw-r--r-- | src/core/execute.c | 71 | ||||
-rw-r--r-- | src/core/main.c | 2 | ||||
-rw-r--r-- | src/core/manager.c | 1 | ||||
-rw-r--r-- | src/nspawn/nspawn.c | 43 |
6 files changed, 90 insertions, 56 deletions
diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index 9b623c8353..97b348b565 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -274,8 +274,7 @@ signals. It is recommended to use this mode to invoke arbitrary commands in containers, unless they have been modified to run correctly as PID 1. Or in other words: this switch should be used for pretty much all commands, except when the command refers to an init or shell implementation, as these are generally capable of running - correctly as PID 1. This option may not be combined with <option>--boot</option> or - <option>--share-system</option>.</para> + correctly as PID 1. This option may not be combined with <option>--boot</option>.</para> </listitem> </varlistentry> @@ -285,8 +284,7 @@ <listitem><para>Automatically search for an init binary and invoke it as PID 1, instead of a shell or a user supplied program. If this option is used, arguments specified on the command line are used as arguments for the - init binary. This option may not be combined with <option>--as-pid2</option> or - <option>--share-system</option>.</para> + init binary. This option may not be combined with <option>--as-pid2</option>.</para> <para>The following table explains the different modes of invocation and relationship to <option>--as-pid2</option> (see above):</para> @@ -847,23 +845,6 @@ </varlistentry> <varlistentry> - <term><option>--share-system</option></term> - - <listitem><para>Allows the container to share certain system - facilities with the host. More specifically, this turns off - PID namespacing, UTS namespacing and IPC namespacing, and thus - allows the guest to see and interact more easily with - processes outside of the container. Note that using this - option makes it impossible to start up a full Operating System - in the container, as an init system cannot operate in this - mode. It is only useful to run specific programs or - applications this way, without involving an init system in the - container. This option implies <option>--register=no</option>. - This option may not be combined with - <option>--boot</option>.</para></listitem> - </varlistentry> - - <varlistentry> <term><option>--register=</option></term> <listitem><para>Controls whether the container is registered @@ -877,9 +858,7 @@ and shown by tools such as <citerefentry project='man-pages'><refentrytitle>ps</refentrytitle><manvolnum>1</manvolnum></citerefentry>. If the container does not run an init system, it is - recommended to set this option to <literal>no</literal>. Note - that <option>--share-system</option> implies - <option>--register=no</option>. </para></listitem> + recommended to set this option to <literal>no</literal>.</para></listitem> </varlistentry> <varlistentry> diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index df56d85317..f0a46c48cf 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -785,7 +785,7 @@ bool tty_is_vc_resolve(const char *tty) { } const char *default_term_for_tty(const char *tty) { - return tty && tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt220"; + return tty && tty_is_vc_resolve(tty) ? "linux" : "vt220"; } int fd_columns(int fd) { diff --git a/src/core/execute.c b/src/core/execute.c index 26e9cd5339..77a75245cb 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -219,12 +219,36 @@ static void exec_context_tty_reset(const ExecContext *context, const ExecParamet (void) vt_disallocate(path); } +static bool is_terminal_input(ExecInput i) { + return IN_SET(i, + EXEC_INPUT_TTY, + EXEC_INPUT_TTY_FORCE, + EXEC_INPUT_TTY_FAIL); +} + static bool is_terminal_output(ExecOutput o) { - return - o == EXEC_OUTPUT_TTY || - o == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || - o == EXEC_OUTPUT_KMSG_AND_CONSOLE || - o == EXEC_OUTPUT_JOURNAL_AND_CONSOLE; + return IN_SET(o, + EXEC_OUTPUT_TTY, + EXEC_OUTPUT_SYSLOG_AND_CONSOLE, + EXEC_OUTPUT_KMSG_AND_CONSOLE, + EXEC_OUTPUT_JOURNAL_AND_CONSOLE); +} + +static bool exec_context_needs_term(const ExecContext *c) { + assert(c); + + /* Return true if the execution context suggests we should set $TERM to something useful. */ + + if (is_terminal_input(c->std_input)) + return true; + + if (is_terminal_output(c->std_output)) + return true; + + if (is_terminal_output(c->std_error)) + return true; + + return !!c->tty_path; } static int open_null_as(int flags, int nfd) { @@ -363,13 +387,6 @@ static int open_terminal_as(const char *path, mode_t mode, int nfd) { return r; } -static bool is_terminal_input(ExecInput i) { - return - i == EXEC_INPUT_TTY || - i == EXEC_INPUT_TTY_FORCE || - i == EXEC_INPUT_TTY_FAIL; -} - static int fixup_input(ExecInput std_input, int socket_fd, bool apply_tty_stdin) { if (is_terminal_input(std_input) && !apply_tty_stdin) @@ -1444,12 +1461,21 @@ static int build_environment( our_env[n_env++] = x; } - if (is_terminal_input(c->std_input) || - c->std_output == EXEC_OUTPUT_TTY || - c->std_error == EXEC_OUTPUT_TTY || - c->tty_path) { + if (exec_context_needs_term(c)) { + const char *tty_path, *term = NULL; - x = strdup(default_term_for_tty(exec_context_tty_path(c))); + tty_path = exec_context_tty_path(c); + + /* If we are forked off PID 1 and we are supposed to operate on /dev/console, then let's try to inherit + * the $TERM set for PID 1. This is useful for containers so that the $TERM the container manager + * passes to PID 1 ends up all the way in the console login shown. */ + + if (path_equal(tty_path, "/dev/console") && getppid() == 1) + term = getenv("TERM"); + if (!term) + term = default_term_for_tty(tty_path); + + x = strappend("TERM=", term); if (!x) return -ENOMEM; our_env[n_env++] = x; @@ -1698,6 +1724,17 @@ static int exec_child( *exit_status = EXIT_USER; return r; } + + /* Don't set $HOME or $SHELL if they are are not particularly enlightening anyway. */ + if (isempty(home) || path_equal(home, "/")) + home = NULL; + + if (isempty(shell) || PATH_IN_SET(shell, + "/bin/nologin", + "/sbin/nologin", + "/usr/bin/nologin", + "/usr/sbin/nologin")) + shell = NULL; } if (context->group) { diff --git a/src/core/main.c b/src/core/main.c index c46d886653..094bbef964 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1318,7 +1318,7 @@ static int fixup_environment(void) { return r; if (r == 0) { - term = strdup(default_term_for_tty("/dev/console") + 5); + term = strdup(default_term_for_tty("/dev/console")); if (!term) return -ENOMEM; } diff --git a/src/core/manager.c b/src/core/manager.c index e41b65da50..c20e185d78 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -553,7 +553,6 @@ static int manager_default_environment(Manager *m) { return 0; } - int manager_new(UnitFileScope scope, bool test_run, Manager **_m) { Manager *m; int r; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 6cc1b9177d..5c6605a08e 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -269,7 +269,6 @@ static void help(void) { " --overlay-ro=PATH[:PATH...]:PATH\n" " Similar, but creates a read-only overlay mount\n" " -E --setenv=NAME=VALUE Pass an environment variable to PID 1\n" - " --share-system Share system namespaces with host\n" " --register=BOOLEAN Register container as machine\n" " --keep-unit Do not register a scope for the machine, reuse\n" " the service unit nspawn is running in\n" @@ -405,7 +404,7 @@ static int parse_argv(int argc, char *argv[]) { { "selinux-context", required_argument, NULL, 'Z' }, { "selinux-apifs-context", required_argument, NULL, 'L' }, { "quiet", no_argument, NULL, 'q' }, - { "share-system", no_argument, NULL, ARG_SHARE_SYSTEM }, + { "share-system", no_argument, NULL, ARG_SHARE_SYSTEM }, /* not documented */ { "register", required_argument, NULL, ARG_REGISTER }, { "keep-unit", no_argument, NULL, ARG_KEEP_UNIT }, { "network-interface", required_argument, NULL, ARG_NETWORK_INTERFACE }, @@ -814,6 +813,8 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_SHARE_SYSTEM: + /* We don't officially support this anymore, except for compat reasons. People should use the + * $SYSTEMD_NSPAWN_SHARE_SYSTEM environment variable instead. */ arg_share_system = true; break; @@ -1018,6 +1019,9 @@ static int parse_argv(int argc, char *argv[]) { assert_not_reached("Unhandled option"); } + if (getenv_bool("SYSTEMD_NSPAWN_SHARE_SYSTEM") > 0) + arg_share_system = true; + if (arg_share_system) arg_register = false; @@ -1025,7 +1029,7 @@ static int parse_argv(int argc, char *argv[]) { arg_userns_chown = true; if (arg_start_mode != START_PID1 && arg_share_system) { - log_error("--boot and --share-system may not be combined."); + log_error("--boot and SYSTEMD_NSPAWN_SHARE_SYSTEM=1 may not be combined."); return -EINVAL; } @@ -1254,24 +1258,39 @@ static int setup_resolv_conf(const char *dest) { /* Fix resolv.conf, if possible */ where = prefix_roota(dest, "/etc/resolv.conf"); + if (access("/usr/lib/systemd/resolv.conf", F_OK) >= 0) { + /* resolved is enabled on the host. In this, case bind mount its static resolv.conf file into the + * container, so that the container can use the host's resolver. Given that network namespacing is + * disabled it's only natural of the container also uses the host's resolver. It also has the big + * advantage that the container will be able to follow the host's DNS server configuration changes + * transparently. */ + + if (mount("/usr/lib/systemd/resolv.conf", where, NULL, MS_BIND, NULL) < 0) + log_warning_errno(errno, "Failed to mount /etc/resolv.conf in the container, ignoring: %m"); + else { + if (mount(NULL, where, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY|MS_NOSUID|MS_NODEV, NULL) < 0) + return log_error_errno(errno, "Failed to remount /etc/resolv.conf read-only: %m"); + + return 0; + } + } + + /* If that didn't work, let's copy the file */ r = copy_file("/etc/resolv.conf", where, O_TRUNC|O_NOFOLLOW, 0644, 0); if (r < 0) { - /* If the file already exists as symlink, let's - * suppress the warning, under the assumption that - * resolved or something similar runs inside and the - * symlink points there. + /* If the file already exists as symlink, let's suppress the warning, under the assumption that + * resolved or something similar runs inside and the symlink points there. * - * If the disk image is read-only, there's also no - * point in complaining. + * If the disk image is read-only, there's also no point in complaining. */ log_full_errno(IN_SET(r, -ELOOP, -EROFS) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to copy /etc/resolv.conf to %s: %m", where); + "Failed to copy /etc/resolv.conf to %s, ignoring: %m", where); return 0; } r = userns_lchown(where, 0, 0); if (r < 0) - log_warning_errno(r, "Failed to chown /etc/resolv.conf: %m"); + log_warning_errno(r, "Failed to chown /etc/resolv.conf, ignoring: %m"); return 0; } @@ -1301,7 +1320,7 @@ static int setup_boot_id(const char *dest) { if (mount(from, to, NULL, MS_BIND, NULL) < 0) r = log_error_errno(errno, "Failed to bind mount boot id: %m"); else if (mount(NULL, to, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY|MS_NOSUID|MS_NODEV, NULL) < 0) - log_warning_errno(errno, "Failed to make boot id read-only, ignoring: %m"); + r = log_error_errno(errno, "Failed to make boot id read-only: %m"); (void) unlink(from); return r; |