Merge pull request #17082 from poettering/nspawn-ctty-tweaks
nspawn controlling tty tweaks
This commit is contained in:
commit
d2841d563e
|
@ -1370,15 +1370,18 @@
|
||||||
|
|
||||||
<listitem><para>Configures how to set up standard input, output and error output for the container
|
<listitem><para>Configures how to set up standard input, output and error output for the container
|
||||||
payload, as well as the <filename>/dev/console</filename> device for the container. Takes one of
|
payload, as well as the <filename>/dev/console</filename> device for the container. Takes one of
|
||||||
<option>interactive</option>, <option>read-only</option>, <option>passive</option>, or
|
<option>interactive</option>, <option>read-only</option>, <option>passive</option>,
|
||||||
<option>pipe</option>. If <option>interactive</option>, a pseudo-TTY is allocated and made available
|
<option>pipe</option> or <option>autopipe</option>. If <option>interactive</option>, a pseudo-TTY is
|
||||||
as <filename>/dev/console</filename> in the container. It is then bi-directionally connected to the
|
allocated and made available as <filename>/dev/console</filename> in the container. It is then
|
||||||
standard input and output passed to <command>systemd-nspawn</command>. <option>read-only</option> is
|
bi-directionally connected to the standard input and output passed to
|
||||||
similar but only the output of the container is propagated and no input from the caller is read. If
|
<command>systemd-nspawn</command>. <option>read-only</option> is similar but only the output of the
|
||||||
<option>passive</option>, a pseudo TTY is allocated, but it is not connected anywhere. Finally, in
|
container is propagated and no input from the caller is read. If <option>passive</option>, a pseudo
|
||||||
<option>pipe</option> mode no pseudo TTY is allocated, but the standard input, output and error
|
TTY is allocated, but it is not connected anywhere. In <option>pipe</option> mode no pseudo TTY is
|
||||||
output file descriptors passed to <command>systemd-nspawn</command> are passed on — as they are — to
|
allocated, but the standard input, output and error output file descriptors passed to
|
||||||
the container payload, see the following paragraph. Defaults to <option>interactive</option> if
|
<command>systemd-nspawn</command> are passed on — as they are — to the container payload, see the
|
||||||
|
following paragraph. Finally, <option>autopipe</option> mode operates like
|
||||||
|
<option>interactive</option> when <command>systemd-nspawn</command> is invoked on a terminal, and
|
||||||
|
like <option>pipe</option> otherwise. Defaults to <option>interactive</option> if
|
||||||
<command>systemd-nspawn</command> is invoked from a terminal, and <option>read-only</option>
|
<command>systemd-nspawn</command> is invoked from a terminal, and <option>read-only</option>
|
||||||
otherwise.</para>
|
otherwise.</para>
|
||||||
|
|
||||||
|
|
|
@ -53,12 +53,6 @@ int stub_pid1(sd_id128_t uuid) {
|
||||||
assert_se(sigfillset(&fullmask) >= 0);
|
assert_se(sigfillset(&fullmask) >= 0);
|
||||||
assert_se(sigprocmask(SIG_BLOCK, &fullmask, &oldmask) >= 0);
|
assert_se(sigprocmask(SIG_BLOCK, &fullmask, &oldmask) >= 0);
|
||||||
|
|
||||||
/* Surrender the terminal this stub may control so that child processes can have a controlling terminal
|
|
||||||
* without resorting to setsid hacks. */
|
|
||||||
r = ioctl(STDIN_FILENO, TIOCNOTTY);
|
|
||||||
if (r < 0 && errno != ENOTTY)
|
|
||||||
return log_error_errno(errno, "Failed to surrender controlling terminal: %m");
|
|
||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (pid < 0)
|
if (pid < 0)
|
||||||
return log_error_errno(errno, "Failed to fork child pid: %m");
|
return log_error_errno(errno, "Failed to fork child pid: %m");
|
||||||
|
@ -66,7 +60,10 @@ int stub_pid1(sd_id128_t uuid) {
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
/* Return in the child */
|
/* Return in the child */
|
||||||
assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) >= 0);
|
assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) >= 0);
|
||||||
setsid();
|
|
||||||
|
if (setsid() < 0)
|
||||||
|
return log_error_errno(errno, "Failed to become session leader in payload process: %m");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,6 +73,12 @@ int stub_pid1(sd_id128_t uuid) {
|
||||||
(void) close_all_fds(NULL, 0);
|
(void) close_all_fds(NULL, 0);
|
||||||
log_open();
|
log_open();
|
||||||
|
|
||||||
|
if (ioctl(STDIN_FILENO, TIOCNOTTY) < 0) {
|
||||||
|
if (errno != ENOTTY)
|
||||||
|
log_warning_errno(errno, "Unexpected error from TIOCNOTTY ioctl in init stub process, ignoring: %m");
|
||||||
|
} else
|
||||||
|
log_warning("Expected TIOCNOTTY to fail, but it succeeded in init stub process, ignoring.");
|
||||||
|
|
||||||
/* Flush out /proc/self/environ, so that we don't leak the environment from the host into the container. Also,
|
/* Flush out /proc/self/environ, so that we don't leak the environment from the host into the container. Also,
|
||||||
* set $container= and $container_uuid= so that clients in the container that query it from /proc/1/environ
|
* set $container= and $container_uuid= so that clients in the container that query it from /proc/1/environ
|
||||||
* find them set. */
|
* find them set. */
|
||||||
|
|
|
@ -11,10 +11,12 @@
|
||||||
#endif
|
#endif
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
#include <sys/personality.h>
|
#include <sys/personality.h>
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
#include <termios.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "sd-bus.h"
|
#include "sd-bus.h"
|
||||||
|
@ -254,10 +256,11 @@ STATIC_DESTRUCTOR_REGISTER(arg_sysctl, strv_freep);
|
||||||
|
|
||||||
static int handle_arg_console(const char *arg) {
|
static int handle_arg_console(const char *arg) {
|
||||||
if (streq(arg, "help")) {
|
if (streq(arg, "help")) {
|
||||||
puts("interactive\n"
|
puts("autopipe\n"
|
||||||
"read-only\n"
|
"interactive\n"
|
||||||
"passive\n"
|
"passive\n"
|
||||||
"pipe");
|
"pipe\n"
|
||||||
|
"read-only");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,9 +270,20 @@ static int handle_arg_console(const char *arg) {
|
||||||
arg_console_mode = CONSOLE_READ_ONLY;
|
arg_console_mode = CONSOLE_READ_ONLY;
|
||||||
else if (streq(arg, "passive"))
|
else if (streq(arg, "passive"))
|
||||||
arg_console_mode = CONSOLE_PASSIVE;
|
arg_console_mode = CONSOLE_PASSIVE;
|
||||||
else if (streq(arg, "pipe"))
|
else if (streq(arg, "pipe")) {
|
||||||
|
if (isatty(STDIN_FILENO) > 0 && isatty(STDOUT_FILENO) > 0)
|
||||||
|
log_full(arg_quiet ? LOG_DEBUG : LOG_NOTICE,
|
||||||
|
"Console mode 'pipe' selected, but standard input/output are connected to an interactive TTY. "
|
||||||
|
"Most likely you want to use 'interactive' console mode for proper interactivity and shell job control. "
|
||||||
|
"Proceeding anyway.");
|
||||||
|
|
||||||
arg_console_mode = CONSOLE_PIPE;
|
arg_console_mode = CONSOLE_PIPE;
|
||||||
else
|
} else if (streq(arg, "autopipe")) {
|
||||||
|
if (isatty(STDIN_FILENO) > 0 && isatty(STDOUT_FILENO) > 0)
|
||||||
|
arg_console_mode = CONSOLE_INTERACTIVE;
|
||||||
|
else
|
||||||
|
arg_console_mode = CONSOLE_PIPE;
|
||||||
|
} else
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown console mode: %s", optarg);
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown console mode: %s", optarg);
|
||||||
|
|
||||||
arg_settings_mask |= SETTING_CONSOLE_MODE;
|
arg_settings_mask |= SETTING_CONSOLE_MODE;
|
||||||
|
@ -2269,10 +2283,12 @@ static int setup_pts(const char *dest) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int setup_stdio_as_dev_console(void) {
|
static int setup_stdio_as_dev_console(void) {
|
||||||
int terminal;
|
_cleanup_close_ int terminal = -1;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
terminal = open_terminal("/dev/console", O_RDWR);
|
/* We open the TTY in O_NOCTTY mode, so that we do not become controller yet. We'll do that later
|
||||||
|
* explicitly, if we are configured to. */
|
||||||
|
terminal = open_terminal("/dev/console", O_RDWR|O_NOCTTY);
|
||||||
if (terminal < 0)
|
if (terminal < 0)
|
||||||
return log_error_errno(terminal, "Failed to open console: %m");
|
return log_error_errno(terminal, "Failed to open console: %m");
|
||||||
|
|
||||||
|
@ -2284,6 +2300,7 @@ static int setup_stdio_as_dev_console(void) {
|
||||||
|
|
||||||
/* invalidates 'terminal' on success and failure */
|
/* invalidates 'terminal' on success and failure */
|
||||||
r = rearrange_stdio(terminal, terminal, terminal);
|
r = rearrange_stdio(terminal, terminal, terminal);
|
||||||
|
TAKE_FD(terminal);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to move console to stdin/stdout/stderr: %m");
|
return log_error_errno(r, "Failed to move console to stdin/stdout/stderr: %m");
|
||||||
|
|
||||||
|
@ -3366,8 +3383,7 @@ static int inner_child(
|
||||||
* wait until the parent is ready with the
|
* wait until the parent is ready with the
|
||||||
* setup, too... */
|
* setup, too... */
|
||||||
if (!barrier_place_and_sync(barrier)) /* #5 */
|
if (!barrier_place_and_sync(barrier)) /* #5 */
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(ESRCH),
|
return log_error_errno(SYNTHETIC_ERRNO(ESRCH), "Parent died too early");
|
||||||
"Parent died too early");
|
|
||||||
|
|
||||||
if (arg_chdir)
|
if (arg_chdir)
|
||||||
if (chdir(arg_chdir) < 0)
|
if (chdir(arg_chdir) < 0)
|
||||||
|
@ -3379,6 +3395,13 @@ static int inner_child(
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arg_console_mode != CONSOLE_PIPE) {
|
||||||
|
/* So far our pty wasn't controlled by any process. Finally, it's time to change that, if we
|
||||||
|
* are configured for that. Acquire it as controlling tty. */
|
||||||
|
if (ioctl(STDIN_FILENO, TIOCSCTTY) < 0)
|
||||||
|
return log_error_errno(errno, "Failed to acquire controlling TTY: %m");
|
||||||
|
}
|
||||||
|
|
||||||
log_debug("Inner child completed, invoking payload.");
|
log_debug("Inner child completed, invoking payload.");
|
||||||
|
|
||||||
/* Now, explicitly close the log, so that we then can close all remaining fds. Closing the log explicitly first
|
/* Now, explicitly close the log, so that we then can close all remaining fds. Closing the log explicitly first
|
||||||
|
|
Loading…
Reference in New Issue