1
0
mirror of https://github.com/systemd/systemd.git synced 2024-11-01 09:21:26 +03:00

Merge pull request #3820 from poettering/nspawn-resolvconf

nspawn resolv.conf handling improvements, and inherit $TERM all the way through nspawn → console login
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2016-08-03 20:14:32 -04:00 committed by GitHub
commit 19c8201744
6 changed files with 90 additions and 56 deletions

View File

@ -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>
@ -846,23 +844,6 @@
parameter may be used more than once.</para></listitem>
</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>
@ -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>

View File

@ -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) {

View File

@ -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) {

View File

@ -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;
}

View File

@ -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;

View File

@ -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;