terminal-util: introduce terminal_{new,detach}_session helpers (#35811)

This commit is contained in:
Daan De Meyer
2025-01-03 09:21:19 +01:00
committed by GitHub
6 changed files with 79 additions and 29 deletions

View 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));

View 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,18 +65,11 @@ typedef enum AcquireTerminalFlags {
int acquire_terminal(const char *name, AcquireTerminalFlags flags, usec_t timeout);
int release_terminal(void);
/* Limits the use of ANSI colors to a subset. */
typedef enum ColorMode {
COLOR_OFF, /* No colors, monochrome output. */
COLOR_16, /* Only the base 16 colors. */
COLOR_256, /* Only 256 colors. */
COLOR_24BIT, /* For truecolor or 24bit color support, no restriction. */
_COLOR_MODE_MAX,
_COLOR_MODE_INVALID = -EINVAL,
} ColorMode;
const char* color_mode_to_string(ColorMode m) _const_;
ColorMode color_mode_from_string(const char *s) _pure_;
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);
@@ -117,15 +111,29 @@ void reset_terminal_feature_caches(void);
bool on_tty(void);
bool getenv_terminal_is_dumb(void);
bool terminal_is_dumb(void);
ColorMode get_color_mode(void);
bool underline_enabled(void);
bool dev_console_colors_enabled(void);
/* Limits the use of ANSI colors to a subset. */
typedef enum ColorMode {
COLOR_OFF, /* No colors, monochrome output. */
COLOR_16, /* Only the base 16 colors. */
COLOR_256, /* Only 256 colors. */
COLOR_24BIT, /* For truecolor or 24bit color support, no restriction. */
_COLOR_MODE_MAX,
_COLOR_MODE_INVALID = -EINVAL,
} ColorMode;
const char* color_mode_to_string(ColorMode m) _const_;
ColorMode color_mode_from_string(const char *s) _pure_;
ColorMode get_color_mode(void);
static inline bool colors_enabled(void) {
/* Returns true if colors are considered supported on our stdout. */
return get_color_mode() != COLOR_OFF;
}
bool underline_enabled(void);
bool dev_console_colors_enabled(void);
int get_ctty_devnr(pid_t pid, dev_t *ret);
int get_ctty(pid_t, dev_t *ret_devnr, char **ret);

View 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)

View 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);

View 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));
}

View 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);