summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2016-08-03 20:14:32 -0400
committerGitHub <noreply@github.com>2016-08-03 20:14:32 -0400
commit19c8201744035d92a6480cc58944c0c18fcebdc6 (patch)
treeb718ee042a6d42292255dcbefffd777a2dc9ec54
parentd26d41f36c598aeddcb25cca19ee3526f771c045 (diff)
parentf7b7b3df9e24713464d9089f62958c8c5c3aac49 (diff)
Merge pull request #3820 from poettering/nspawn-resolvconf
nspawn resolv.conf handling improvements, and inherit $TERM all the way through nspawn → console login
-rw-r--r--man/systemd-nspawn.xml27
-rw-r--r--src/basic/terminal-util.c2
-rw-r--r--src/core/execute.c71
-rw-r--r--src/core/main.c2
-rw-r--r--src/core/manager.c1
-rw-r--r--src/nspawn/nspawn.c43
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;