From 66cb2fde7b0ab6603775ad13c30c004f5fd88f0c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 7 Oct 2015 22:45:48 +0200 Subject: basic: move two more terminal-related calls into terminal-util.[ch] --- src/basic/terminal-util.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) (limited to 'src/basic/terminal-util.c') diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index 22ee6ad83f..50a86a331c 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -1054,6 +1054,33 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) { return 0; } +int ptsname_malloc(int fd, char **ret) { + size_t l = 100; + + assert(fd >= 0); + assert(ret); + + for (;;) { + char *c; + + c = new(char, l); + if (!c) + return -ENOMEM; + + if (ptsname_r(fd, c, l) == 0) { + *ret = c; + return 0; + } + if (errno != ERANGE) { + free(c); + return -errno; + } + + free(c); + l *= 2; + } +} + int ptsname_namespace(int pty, char **ret) { int no = -1, r; @@ -1072,3 +1099,56 @@ int ptsname_namespace(int pty, char **ret) { return 0; } + +int openpt_in_namespace(pid_t pid, int flags) { + _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1; + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + siginfo_t si; + pid_t child; + int r; + + assert(pid > 0); + + r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd); + if (r < 0) + return r; + + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0) + return -errno; + + child = fork(); + if (child < 0) + return -errno; + + if (child == 0) { + int master; + + pair[0] = safe_close(pair[0]); + + r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd); + if (r < 0) + _exit(EXIT_FAILURE); + + master = posix_openpt(flags|O_NOCTTY|O_CLOEXEC); + if (master < 0) + _exit(EXIT_FAILURE); + + if (unlockpt(master) < 0) + _exit(EXIT_FAILURE); + + if (send_one_fd(pair[1], master, 0) < 0) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + pair[1] = safe_close(pair[1]); + + r = wait_for_terminate(child, &si); + if (r < 0) + return r; + if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS) + return -EIO; + + return receive_one_fd(pair[0], 0); +} -- cgit v1.2.3-54-g00ecf From 40e1f4ea7458a0a80eaf1ef356e52bfe0835412e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 7 Oct 2015 23:38:20 +0200 Subject: machined: when opening a shell via machined, pass tty fds in With this change we'll open the shell's tty right from machined and then pass it to the transient unit we create. This way we make sure the pty is opened exactly as long as the transient service is around, and no longer, and vice versa. This way pty forwarders do not have to deal with EIO problems due to vhangup, as the pty is open all the time from the point we set things up to the point where the service goes away. --- src/basic/terminal-util.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++ src/basic/terminal-util.h | 1 + src/machine/machine-dbus.c | 21 +++++++++++--------- src/machine/machine.c | 19 ++++++++++++++++++ src/machine/machine.h | 1 + src/machine/machinectl.c | 2 +- 6 files changed, 82 insertions(+), 10 deletions(-) (limited to 'src/basic/terminal-util.c') diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index 50a86a331c..e9097d8ae5 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -1152,3 +1152,51 @@ int openpt_in_namespace(pid_t pid, int flags) { return receive_one_fd(pair[0], 0); } + +int open_terminal_in_namespace(pid_t pid, const char *name, int mode) { + _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1; + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + siginfo_t si; + pid_t child; + int r; + + r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd); + if (r < 0) + return r; + + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0) + return -errno; + + child = fork(); + if (child < 0) + return -errno; + + if (child == 0) { + int master; + + pair[0] = safe_close(pair[0]); + + r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd); + if (r < 0) + _exit(EXIT_FAILURE); + + master = open_terminal(name, mode|O_NOCTTY|O_CLOEXEC); + if (master < 0) + _exit(EXIT_FAILURE); + + if (send_one_fd(pair[1], master, 0) < 0) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + pair[1] = safe_close(pair[1]); + + r = wait_for_terminate(child, &si); + if (r < 0) + return r; + if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS) + return -EIO; + + return receive_one_fd(pair[0], 0); +} diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h index 050d0524a5..ee0b68b433 100644 --- a/src/basic/terminal-util.h +++ b/src/basic/terminal-util.h @@ -124,3 +124,4 @@ int ptsname_malloc(int fd, char **ret); int ptsname_namespace(int pty, char **ret); int openpt_in_namespace(pid_t pid, int flags); +int open_terminal_in_namespace(pid_t pid, const char *name, int mode); diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index 21026829a9..6e41e92962 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -639,7 +639,7 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu _cleanup_free_ char *pty_name = NULL; _cleanup_bus_flush_close_unref_ sd_bus *allocated_bus = NULL; sd_bus *container_bus = NULL; - _cleanup_close_ int master = -1; + _cleanup_close_ int master = -1, slave = -1; _cleanup_strv_free_ char **env = NULL, **args = NULL; Machine *m = userdata; const char *p, *unit, *user, *path, *description, *utmp_id; @@ -700,8 +700,11 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu return r; p = path_startswith(pty_name, "/dev/pts/"); - if (!p) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "PTS name %s is invalid", pty_name); + assert(p); + + slave = machine_open_terminal(m, pty_name, O_RDWR|O_NOCTTY|O_CLOEXEC); + if (slave < 0) + return slave; utmp_id = path_startswith(pty_name, "/dev/"); assert(utmp_id); @@ -735,16 +738,14 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu description = strjoina("Shell for User ", isempty(user) ? "root" : user); r = sd_bus_message_append(tm, - "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)", + "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)", "Description", "s", description, - "StandardInput", "s", "tty", - "StandardOutput", "s", "tty", - "StandardError", "s", "tty", - "TTYPath", "s", pty_name, + "StandardInputFileDescriptor", "h", slave, + "StandardOutputFileDescriptor", "h", slave, + "StandardErrorFileDescriptor", "h", slave, "SendSIGHUP", "b", true, "IgnoreSIGPIPE", "b", false, "KillMode", "s", "mixed", - "TTYVHangup", "b", true, "TTYReset", "b", true, "UtmpIdentifier", "s", utmp_id, "UtmpMode", "s", "user", @@ -845,6 +846,8 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu if (r < 0) return r; + slave = safe_close(slave); + r = sd_bus_message_new_method_return(message, &reply); if (r < 0) return r; diff --git a/src/machine/machine.c b/src/machine/machine.c index 0f1942d1f4..7ab84607fb 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -572,6 +572,25 @@ int machine_openpt(Machine *m, int flags) { } } +int machine_open_terminal(Machine *m, const char *path, int mode) { + assert(m); + + switch (m->class) { + + case MACHINE_HOST: + return open_terminal(path, mode); + + case MACHINE_CONTAINER: + if (m->leader <= 0) + return -EINVAL; + + return open_terminal_in_namespace(m->leader, path, mode); + + default: + return -EOPNOTSUPP; + } +} + MachineOperation *machine_operation_unref(MachineOperation *o) { if (!o) return NULL; diff --git a/src/machine/machine.h b/src/machine/machine.h index 5f978289f2..ad7f2a162f 100644 --- a/src/machine/machine.h +++ b/src/machine/machine.h @@ -123,3 +123,4 @@ const char *kill_who_to_string(KillWho k) _const_; KillWho kill_who_from_string(const char *s) _pure_; int machine_openpt(Machine *m, int flags); +int machine_open_terminal(Machine *m, const char *path, int mode); diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index e75b183328..0a21ab4415 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -1390,7 +1390,7 @@ static int shell_machine(int argc, char *argv[], void *userdata) { if (r < 0) return bus_log_parse_error(r); - return process_forward(event, &forward, master, PTY_FORWARD_IGNORE_INITIAL_VHANGUP, machine); + return process_forward(event, &forward, master, 0, machine); } static int remove_image(int argc, char *argv[], void *userdata) { -- cgit v1.2.3-54-g00ecf From 3d18b167558bde95a076b16d40f9454f169e70ba Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 8 Oct 2015 14:33:53 +0200 Subject: util: do not reset terminal in acquire_terminal() Before, we'd always reset acquired terminals, which is not really desired, as we expose a setting TTYReset= which is supposed to control whether the TTY is reset or not. Previously that setting would only enable a second resetting of the TTY, which is of course pointless... Hence, move the implicit resetting out of acquire_terminal() and make the callers do it if they need it. --- src/basic/terminal-util.c | 8 ++-- src/core/execute.c | 54 +++++++++------------- .../tty-ask-password-agent.c | 4 ++ 3 files changed, 30 insertions(+), 36 deletions(-) (limited to 'src/basic/terminal-util.c') diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index e9097d8ae5..1bda9564fb 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -480,10 +480,6 @@ int acquire_terminal( safe_close(notify); - r = reset_terminal_fd(fd, true); - if (r < 0) - log_warning_errno(r, "Failed to reset terminal: %m"); - return fd; fail: @@ -616,6 +612,10 @@ int make_console_stdio(void) { if (fd < 0) return log_error_errno(fd, "Failed to acquire terminal: %m"); + r = reset_terminal_fd(fd, true); + if (r < 0) + log_warning_errno(r, "Failed to reset terminal, ignoring: %m"); + r = make_stdio(fd); if (r < 0) return log_error_errno(r, "Failed to duplicate terminal fd: %m"); diff --git a/src/core/execute.c b/src/core/execute.c index 80ad87d4e4..d6217840c0 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -543,9 +543,9 @@ static int chown_terminal(int fd, uid_t uid) { return 0; } -static int setup_confirm_stdio(int *_saved_stdin, - int *_saved_stdout) { - int fd = -1, saved_stdin, saved_stdout = -1, r; +static int setup_confirm_stdio(int *_saved_stdin, int *_saved_stdout) { + _cleanup_close_ int fd = -1, saved_stdin = -1, saved_stdout = -1; + int r; assert(_saved_stdin); assert(_saved_stdout); @@ -555,10 +555,8 @@ static int setup_confirm_stdio(int *_saved_stdin, return -errno; saved_stdout = fcntl(STDOUT_FILENO, F_DUPFD, 3); - if (saved_stdout < 0) { - r = errno; - goto fail; - } + if (saved_stdout < 0) + return -errno; fd = acquire_terminal( "/dev/console", @@ -566,39 +564,33 @@ static int setup_confirm_stdio(int *_saved_stdin, false, false, DEFAULT_CONFIRM_USEC); - if (fd < 0) { - r = fd; - goto fail; - } + if (fd < 0) + return fd; r = chown_terminal(fd, getuid()); if (r < 0) - goto fail; + return r; - if (dup2(fd, STDIN_FILENO) < 0) { - r = -errno; - goto fail; - } + r = reset_terminal_fd(fd, true); + if (r < 0) + return r; - if (dup2(fd, STDOUT_FILENO) < 0) { - r = -errno; - goto fail; - } + if (dup2(fd, STDIN_FILENO) < 0) + return -errno; + + if (dup2(fd, STDOUT_FILENO) < 0) + return -errno; if (fd >= 2) safe_close(fd); + fd = -1; *_saved_stdin = saved_stdin; *_saved_stdout = saved_stdout; - return 0; - -fail: - safe_close(saved_stdout); - safe_close(saved_stdin); - safe_close(fd); + saved_stdin = saved_stdout = -1; - return r; + return 0; } _printf_(1, 2) static int write_confirm_message(const char *format, ...) { @@ -618,9 +610,7 @@ _printf_(1, 2) static int write_confirm_message(const char *format, ...) { return 0; } -static int restore_confirm_stdio(int *saved_stdin, - int *saved_stdout) { - +static int restore_confirm_stdio(int *saved_stdin, int *saved_stdout) { int r = 0; assert(saved_stdin); @@ -636,8 +626,8 @@ static int restore_confirm_stdio(int *saved_stdin, if (dup2(*saved_stdout, STDOUT_FILENO) < 0) r = -errno; - safe_close(*saved_stdin); - safe_close(*saved_stdout); + *saved_stdin = safe_close(*saved_stdin); + *saved_stdout = safe_close(*saved_stdout); return r; } diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c index 5dbc0a9bcc..93cce186f0 100644 --- a/src/tty-ask-password-agent/tty-ask-password-agent.c +++ b/src/tty-ask-password-agent/tty-ask-password-agent.c @@ -315,6 +315,10 @@ static int parse_password(const char *filename, char **wall) { tty_fd = acquire_terminal("/dev/console", false, false, false, USEC_INFINITY); if (tty_fd < 0) return log_error_errno(tty_fd, "Failed to acquire /dev/console: %m"); + + r = reset_terminal_fd(tty_fd, true); + if (r < 0) + log_warning_errno(r, "Failed to reset terminal, ignoring: %m"); } r = ask_password_tty(message, NULL, not_after, echo ? ASK_PASSWORD_ECHO : 0, filename, &password); -- cgit v1.2.3-54-g00ecf From 1ba239315ff449779189bde77361f323851dc39f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 8 Oct 2015 14:36:47 +0200 Subject: util: minor modernization of vt_disallocate() --- src/basic/terminal-util.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'src/basic/terminal-util.c') diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index 1bda9564fb..ca7554a9fa 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -535,8 +535,9 @@ int terminal_vhangup(const char *name) { } int vt_disallocate(const char *name) { - int fd, r; + _cleanup_close_ int fd = -1; unsigned u; + int r; /* Deallocate the VT if possible. If not possible * (i.e. because it is the active one), at least clear it @@ -558,8 +559,6 @@ int vt_disallocate(const char *name) { "\033[H" /* move home */ "\033[2J", /* clear screen */ 10, false); - safe_close(fd); - return 0; } @@ -579,7 +578,7 @@ int vt_disallocate(const char *name) { return fd; r = ioctl(fd, VT_DISALLOCATE, u); - safe_close(fd); + fd = safe_close(fd); if (r >= 0) return 0; @@ -598,8 +597,6 @@ int vt_disallocate(const char *name) { "\033[H" /* move home */ "\033[3J", /* clear screen including scrollback, requires Linux 2.6.40 */ 10, false); - safe_close(fd); - return 0; } -- cgit v1.2.3-54-g00ecf