return 0;
}
-static int setup_dev_console(const char *dest, const char *console) {
- _cleanup_umask_ mode_t u;
- const char *to;
+static int setup_stdio_as_dev_console(void) {
+ int terminal;
int r;
- assert(dest);
-
- u = umask(0000);
+ terminal = open_terminal("/dev/console", O_RDWR);
+ if (terminal < 0)
+ return log_error_errno(terminal, "Failed to open console: %m");
- if (!console)
- return 0;
+ /* Make sure we can continue logging to the original stderr, even if
+ * stderr points elsewhere now */
+ r = log_dup_console();
+ if (r < 0)
+ return log_error_errno(r, "Failed to duplicate stderr: %m");
- r = chmod_and_chown(console, 0600, arg_uid_shift, arg_uid_shift);
+ /* invalidates 'terminal' on success and failure */
+ r = rearrange_stdio(terminal, terminal, terminal);
if (r < 0)
- return log_error_errno(r, "Failed to correct access mode for TTY: %m");
+ return log_error_errno(r, "Failed to move console to stdin/stdout/stderr: %m");
+
+ return 0;
+}
- /* We need to bind mount the right tty to /dev/console since
- * ptys can only exist on pts file systems. To have something
- * to bind mount things on we create a empty regular file. */
+static int setup_dev_console(const char *console) {
+ _cleanup_free_ char *p = NULL;
+ int r;
- to = prefix_roota(dest, "/dev/console");
- r = touch(to);
+ /* Create /dev/console symlink */
+ r = path_make_relative("/dev", console, &p);
if (r < 0)
- return log_error_errno(r, "touch() for /dev/console failed: %m");
+ return log_error_errno(r, "Failed to create relative path: %m");
- return mount_verbose(LOG_ERR, console, to, NULL, MS_BIND, NULL);
+ if (symlink(p, "/dev/console") < 0)
+ return log_error_errno(errno, "Failed to create /dev/console symlink: %m");
+
+ return 0;
}
static int setup_keyring(void) {
bool secondary,
int kmsg_socket,
int rtnl_socket,
+ int master_pty_socket,
FDSet *fds) {
+ _cleanup_close_ int master = -1;
_cleanup_free_ char *home = NULL;
char as_uuid[37];
size_t n_env = 1;
rtnl_socket = safe_close(rtnl_socket);
}
+ if (arg_console_mode != CONSOLE_PIPE) {
+ _cleanup_free_ char *console = NULL;
+
+ /* Allocate a pty and make it available as /dev/console. */
+ master = openpt_allocate(O_RDWR|O_NONBLOCK, &console);
+ if (master < 0)
+ return log_error_errno(master, "Failed to allocate a pty: %m");
+
+ r = setup_dev_console(console);
+ if (r < 0)
+ return log_error_errno(r, "Failed to setup /dev/console: %m");
+
+ r = send_one_fd(master_pty_socket, master, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to send master fd: %m");
+ master_pty_socket = safe_close(master_pty_socket);
+
+ r = setup_stdio_as_dev_console();
+ if (r < 0)
+ return r;
+ }
+
r = patch_sysctl();
if (r < 0)
return r;
static int outer_child(
Barrier *barrier,
const char *directory,
- const char *console,
DissectedImage *dissected_image,
bool secondary,
int pid_socket,
int kmsg_socket,
int rtnl_socket,
int uid_shift_socket,
+ int master_pty_socket,
int unified_cgroup_hierarchy_socket,
FDSet *fds,
int netns_fd) {
assert(pid_socket >= 0);
assert(uuid_socket >= 0);
assert(notify_socket >= 0);
+ assert(master_pty_socket >= 0);
assert(kmsg_socket >= 0);
log_debug("Outer child is initializing.");
if (prctl(PR_SET_PDEATHSIG, SIGKILL) < 0)
return log_error_errno(errno, "PR_SET_PDEATHSIG failed: %m");
- if (arg_console_mode != CONSOLE_PIPE) {
- int terminal;
-
- assert(console);
-
- terminal = open_terminal(console, O_RDWR);
- if (terminal < 0)
- return log_error_errno(terminal, "Failed to open console: %m");
-
- /* Make sure we can continue logging to the original stderr, even if stderr points elsewhere now */
- r = log_dup_console();
- if (r < 0)
- return log_error_errno(r, "Failed to duplicate stderr: %m");
-
- r = rearrange_stdio(terminal, terminal, terminal); /* invalidates 'terminal' on success and failure */
- if (r < 0)
- return log_error_errno(r, "Failed to move console to stdin/stdout/stderr: %m");
- }
-
r = reset_audit_loginuid();
if (r < 0)
return r;
if (r < 0)
return r;
- r = setup_dev_console(directory, console);
- if (r < 0)
- return r;
-
r = setup_keyring();
if (r < 0)
return r;
return log_error_errno(r, "Failed to join network namespace: %m");
}
- r = inner_child(barrier, directory, secondary, kmsg_socket, rtnl_socket, fds);
+ r = inner_child(barrier, directory, secondary, kmsg_socket, rtnl_socket, master_pty_socket, fds);
if (r < 0)
_exit(EXIT_FAILURE);
l = send_one_fd(notify_socket, fd, 0);
if (l < 0)
- return log_error_errno(errno, "Failed to send notify fd: %m");
+ return log_error_errno(l, "Failed to send notify fd: %m");
pid_socket = safe_close(pid_socket);
uuid_socket = safe_close(uuid_socket);
notify_socket = safe_close(notify_socket);
+ master_pty_socket = safe_close(master_pty_socket);
kmsg_socket = safe_close(kmsg_socket);
rtnl_socket = safe_close(rtnl_socket);
netns_fd = safe_close(netns_fd);
return merge_settings(settings, arg_oci_bundle);
}
-static int run_container(int master,
- const char* console,
+static int run_container(
DissectedImage *dissected_image,
bool secondary,
FDSet *fds,
char veth_name[IFNAMSIZ], bool *veth_created,
union in_addr_union *exposed,
- pid_t *pid, int *ret) {
+ int *master, pid_t *pid, int *ret) {
static const struct sigaction sa = {
.sa_handler = nop_signal_handler,
uuid_socket_pair[2] = { -1, -1 },
notify_socket_pair[2] = { -1, -1 },
uid_shift_socket_pair[2] = { -1, -1 },
+ master_pty_socket_pair[2] = { -1, -1 },
unified_cgroup_hierarchy_socket_pair[2] = { -1, -1};
- _cleanup_close_ int notify_socket= -1;
+ _cleanup_close_ int notify_socket = -1;
_cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL;
_cleanup_(sd_event_source_unrefp) sd_event_source *notify_event_source = NULL;
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, notify_socket_pair) < 0)
return log_error_errno(errno, "Failed to create notify socket pair: %m");
+ if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, master_pty_socket_pair) < 0)
+ return log_error_errno(errno, "Failed to create console socket pair: %m");
+
if (arg_userns_mode != USER_NAMESPACE_NO)
if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, uid_shift_socket_pair) < 0)
return log_error_errno(errno, "Failed to create uid shift socket pair: %m");
/* The outer child only has a file system namespace. */
barrier_set_role(&barrier, BARRIER_CHILD);
- master = safe_close(master);
-
kmsg_socket_pair[0] = safe_close(kmsg_socket_pair[0]);
rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]);
pid_socket_pair[0] = safe_close(pid_socket_pair[0]);
uuid_socket_pair[0] = safe_close(uuid_socket_pair[0]);
notify_socket_pair[0] = safe_close(notify_socket_pair[0]);
+ master_pty_socket_pair[0] = safe_close(master_pty_socket_pair[0]);
uid_shift_socket_pair[0] = safe_close(uid_shift_socket_pair[0]);
unified_cgroup_hierarchy_socket_pair[0] = safe_close(unified_cgroup_hierarchy_socket_pair[0]);
r = outer_child(&barrier,
arg_directory,
- console,
dissected_image,
secondary,
pid_socket_pair[1],
kmsg_socket_pair[1],
rtnl_socket_pair[1],
uid_shift_socket_pair[1],
+ master_pty_socket_pair[1],
unified_cgroup_hierarchy_socket_pair[1],
fds,
netns_fd);
pid_socket_pair[1] = safe_close(pid_socket_pair[1]);
uuid_socket_pair[1] = safe_close(uuid_socket_pair[1]);
notify_socket_pair[1] = safe_close(notify_socket_pair[1]);
+ master_pty_socket_pair[1] = safe_close(master_pty_socket_pair[1]);
uid_shift_socket_pair[1] = safe_close(uid_shift_socket_pair[1]);
unified_cgroup_hierarchy_socket_pair[1] = safe_close(unified_cgroup_hierarchy_socket_pair[1]);
rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]);
- if (IN_SET(arg_console_mode, CONSOLE_INTERACTIVE, CONSOLE_READ_ONLY)) {
- assert(master >= 0);
+ if (arg_console_mode != CONSOLE_PIPE) {
+ _cleanup_close_ int fd = -1;
+ PTYForwardFlags flags = 0;
- r = pty_forward_new(event, master,
- PTY_FORWARD_IGNORE_VHANGUP | (arg_console_mode == CONSOLE_READ_ONLY ? PTY_FORWARD_READ_ONLY : 0),
- &forward);
- if (r < 0)
- return log_error_errno(r, "Failed to create PTY forwarder: %m");
+ /* Retrieve the master pty allocated by inner child */
+ fd = receive_one_fd(master_pty_socket_pair[0], 0);
+ if (fd < 0)
+ return log_error_errno(fd, "Failed to receive master pty from the inner child: %m");
+
+ switch (arg_console_mode) {
+
+ case CONSOLE_READ_ONLY:
+ flags |= PTY_FORWARD_READ_ONLY;
- if (arg_console_width != (unsigned) -1 || arg_console_height != (unsigned) -1)
- (void) pty_forward_set_width_height(forward, arg_console_width, arg_console_height);
+ _fallthrough_;
+
+ case CONSOLE_INTERACTIVE:
+ flags |= PTY_FORWARD_IGNORE_VHANGUP;
+
+ r = pty_forward_new(event, fd, flags, &forward);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create PTY forwarder: %m");
+
+ if (arg_console_width != (unsigned) -1 || arg_console_height != (unsigned) -1)
+ (void) pty_forward_set_width_height(forward,
+ arg_console_width,
+ arg_console_height);
+ break;
+
+ default:
+ assert(arg_console_mode == CONSOLE_PASSIVE);
+ }
+
+ *master = TAKE_FD(fd);
}
r = sd_event_loop(event);
}
static int run(int argc, char *argv[]) {
- _cleanup_free_ char *console = NULL;
_cleanup_close_ int master = -1;
_cleanup_fdset_free_ FDSet *fds = NULL;
int r, n_fd_passed, ret = EXIT_SUCCESS;
if (arg_console_mode == CONSOLE_PIPE) /* if we pass STDERR on to the container, don't add our own logs into it too */
arg_quiet = true;
- if (arg_console_mode != CONSOLE_PIPE) {
- master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
- if (master < 0) {
- r = log_error_errno(errno, "Failed to acquire pseudo tty: %m");
- goto finish;
- }
-
- r = ptsname_malloc(master, &console);
- if (r < 0) {
- r = log_error_errno(r, "Failed to determine tty name: %m");
- goto finish;
- }
-
- if (arg_selinux_apifs_context) {
- r = mac_selinux_apply(console, arg_selinux_apifs_context);
- if (r < 0)
- goto finish;
- }
-
- if (unlockpt(master) < 0) {
- r = log_error_errno(errno, "Failed to unlock tty: %m");
- goto finish;
- }
- }
-
if (!arg_quiet)
log_info("Spawning container %s on %s.\nPress ^] three times within 1s to kill container.",
arg_machine, arg_image ?: arg_directory);
}
for (;;) {
- r = run_container(master,
- console,
- dissected_image,
+ r = run_container(dissected_image,
secondary,
fds,
veth_name, &veth_created,
- &exposed,
+ &exposed, &master,
&pid, &ret);
if (r <= 0)
break;