]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
terminal-util: introduce terminal_{new,detach}_session helpers 35811/head
authorMike Yuan <me@yhndnzj.com>
Thu, 2 Jan 2025 15:25:40 +0000 (16:25 +0100)
committerMike Yuan <me@yhndnzj.com>
Thu, 2 Jan 2025 20:14:38 +0000 (21:14 +0100)
Prompted by #35761

src/basic/terminal-util.c
src/basic/terminal-util.h
src/core/main.c
src/test/test-terminal-util.c
src/tty-ask-password-agent/tty-ask-password-agent.c
src/udev/udevd.c

index c81001ab6775fce0c355e16891ca4c401d183085..3831543a6abc5cc425685914b5d78285021151b2 100644 (file)
@@ -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));
index 6433c0690748029dc9c046a871b3415bdcbfdc42..82df771cec8ac1721efdeefc370ff33800256561 100644 (file)
@@ -7,6 +7,7 @@
 #include <syslog.h>
 #include <sys/types.h>
 #include <termios.h>
+#include <unistd.h>
 
 #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);
 
index 693293ac9c30bac705363cd38086e5e6c0f6d553..aee645ddff871ff4757c104404de6e32737819f8 100644 (file)
@@ -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)
index 38c9f7e34ac3e6d23cb27d85db3d4c3dfe9e2d66..ac7eacb01a05869dadfa129473ac0cc9d60bb470 100644 (file)
@@ -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);
index 094810dcb39032763c7240a0afe2fd7719bdaaec..c6097c412028a7635e129c302c1b3a01f319ffcb 100644 (file)
@@ -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));
 }
index 8f0e5cc0d6830cef64897a071f068a35a247d346..1dfbc1f47811238463f68c02b8199378dcf8a031 100644 (file)
@@ -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);