From: Mike Yuan Date: Thu, 2 Jan 2025 15:25:40 +0000 (+0100) Subject: terminal-util: introduce terminal_{new,detach}_session helpers X-Git-Tag: v258-rc1~1748^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1de12823202e2c35292b0e54f2991d1eae72692b;p=thirdparty%2Fsystemd.git terminal-util: introduce terminal_{new,detach}_session helpers Prompted by #35761 --- diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index c81001ab677..3831543a6ab 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -498,6 +498,22 @@ int release_terminal(void) { return r; } +int terminal_new_session(void) { + + /* Make us the new session leader, and set stdin tty to be our controlling terminal. + * + * Why stdin? Well, the ctty logic is relevant for signal delivery mostly, i.e. if people hit C-c + * or the line is hung up. Such events are basically just a form of input, via a side channel + * (that side channel being signal delivery, i.e. SIGINT, SIGHUP et al). Hence we focus on input, + * not output here. */ + + if (!isatty_safe(STDIN_FILENO)) + return -ENXIO; + + (void) setsid(); + return RET_NERRNO(ioctl(STDIN_FILENO, TIOCSCTTY, 0)); +} + int terminal_vhangup_fd(int fd) { assert(fd >= 0); return RET_NERRNO(ioctl(fd, TIOCVHANGUP)); diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h index 6433c069074..82df771cec8 100644 --- a/src/basic/terminal-util.h +++ b/src/basic/terminal-util.h @@ -7,6 +7,7 @@ #include #include #include +#include #include "macro.h" #include "time-util.h" @@ -64,6 +65,12 @@ typedef enum AcquireTerminalFlags { int acquire_terminal(const char *name, AcquireTerminalFlags flags, usec_t timeout); int release_terminal(void); +int terminal_new_session(void); +static inline void terminal_detach_session(void) { + (void) setsid(); + (void) release_terminal(); +} + int terminal_vhangup_fd(int fd); int terminal_vhangup(const char *tty); diff --git a/src/core/main.c b/src/core/main.c index 693293ac9c3..aee645ddff8 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -2971,12 +2971,9 @@ static void setup_console_terminal(bool skip_setup) { if (arg_runtime_scope != RUNTIME_SCOPE_SYSTEM) return; - /* Become a session leader if we aren't one yet. */ - (void) setsid(); - /* If we are init, we connect stdin/stdout/stderr to /dev/null and make sure we don't have a * controlling tty. */ - (void) release_terminal(); + terminal_detach_session(); /* Reset the console, but only if this is really init and we are freshly booted */ if (!skip_setup) diff --git a/src/test/test-terminal-util.c b/src/test/test-terminal-util.c index 38c9f7e34ac..ac7eacb01a0 100644 --- a/src/test/test-terminal-util.c +++ b/src/test/test-terminal-util.c @@ -14,6 +14,7 @@ #include "fs-util.h" #include "macro.h" #include "path-util.h" +#include "process-util.h" #include "strv.h" #include "terminal-util.h" #include "tests.h" @@ -314,4 +315,36 @@ TEST(pty_open_peer) { assert(buf[1] == x[1]); } +TEST(terminal_new_session) { + _cleanup_close_ int pty_fd = -EBADF, peer_fd = -EBADF; + int r; + + ASSERT_OK(pty_fd = openpt_allocate(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK, NULL)); + ASSERT_OK(peer_fd = pty_open_peer(pty_fd, O_RDWR|O_NOCTTY|O_CLOEXEC)); + + r = safe_fork_full("test-term-session", + (int[]) { peer_fd, peer_fd, peer_fd }, + NULL, 0, + FORK_DEATHSIG_SIGKILL|FORK_LOG|FORK_WAIT|FORK_REARRANGE_STDIO, + NULL); + ASSERT_OK(r); + if (r == 0) { + ASSERT_OK(terminal_new_session()); + ASSERT_OK(get_ctty_devnr(0, NULL)); + + terminal_detach_session(); + ASSERT_ERROR(get_ctty_devnr(0, NULL), ENXIO); + + ASSERT_OK(terminal_new_session()); + ASSERT_OK(get_ctty_devnr(0, NULL)); + + terminal_detach_session(); + ASSERT_OK(rearrange_stdio(-EBADF, STDOUT_FILENO, STDERR_FILENO)); + ASSERT_ERROR(get_ctty_devnr(0, NULL), ENXIO); + ASSERT_ERROR(terminal_new_session(), ENXIO); + + _exit(EXIT_SUCCESS); + } +} + DEFINE_TEST_MAIN(LOG_INFO); 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 094810dcb39..c6097c41202 100644 --- a/src/tty-ask-password-agent/tty-ask-password-agent.c +++ b/src/tty-ask-password-agent/tty-ask-password-agent.c @@ -725,15 +725,10 @@ static int run(int argc, char *argv[]) { */ return ask_on_consoles(argv); - if (arg_device) { - /* - * Later on, a controlling terminal will be acquired, - * therefore the current process has to become a session - * leader and should not have a controlling terminal already. - */ - (void) setsid(); - (void) release_terminal(); - } + if (arg_device) + /* Later on, a controlling terminal will be acquired, therefore the current process has to + * become a session leader and should not have a controlling terminal already. */ + terminal_detach_session(); return process_and_watch_password_files(!IN_SET(arg_action, ACTION_QUERY, ACTION_LIST)); } diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 8f0e5cc0d68..1dfbc1f4781 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -13,6 +13,7 @@ #include "process-util.h" #include "rlimit-util.h" #include "selinux-util.h" +#include "terminal-util.h" #include "udev-config.h" #include "udev-manager.h" #include "udevd.h" @@ -74,7 +75,7 @@ int run_udevd(int argc, char *argv[]) { return 0; /* child */ - (void) setsid(); + terminal_detach_session(); } return manager_main(manager);