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));
#include <syslog.h>
#include <sys/types.h>
#include <termios.h>
+#include <unistd.h>
#include "macro.h"
#include "time-util.h"
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);
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)
#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"
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);
*/
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));
}
#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"
return 0;
/* child */
- (void) setsid();
+ terminal_detach_session();
}
return manager_main(manager);