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:
commit
19c8201744
@ -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>
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user