1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include <linux/tiocl.h>
10 #include <sys/inotify.h>
11 #include <sys/ioctl.h>
12 #include <sys/sysmacros.h>
17 #include "alloc-util.h"
18 #include "ansi-color.h"
20 #include "devnum-util.h"
21 #include "errno-util.h"
22 #include "extract-word.h"
26 #include "hexdecoct.h"
27 #include "inotify-util.h"
30 #include "missing_magic.h"
31 #include "namespace-util.h"
32 #include "parse-util.h"
33 #include "path-util.h"
34 #include "proc-cmdline.h"
35 #include "process-util.h"
36 #include "signal-util.h"
37 #include "socket-util.h"
38 #include "stat-util.h"
39 #include "stdio-util.h"
40 #include "string-util.h"
42 #include "terminal-util.h"
43 #include "time-util.h"
46 #define ANSI_RESET_CURSOR \
47 "\033?25h" /* turn on cursor */ \
48 "\033?12l" /* reset cursor blinking */ \
49 "\033 1q" /* reset cursor style */
51 /* How much to wait for a reply to a terminal sequence */
52 #define CONSOLE_REPLY_WAIT_USEC (333 * USEC_PER_MSEC)
54 static volatile unsigned cached_columns
= 0;
55 static volatile unsigned cached_lines
= 0;
57 static volatile int cached_on_tty
= -1;
58 static volatile int cached_on_dev_null
= -1;
60 bool isatty_safe(int fd
) {
66 /* Linux/glibc returns EIO for hung up TTY on isatty(). Which is wrong, the thing doesn't stop being
67 * a TTY after all, just because it is temporarily hung up. Let's work around this here, until this
68 * is fixed in glibc. See: https://sourceware.org/bugzilla/show_bug.cgi?id=32103 */
72 /* Be resilient if we're working on stdio, since they're set up by parent process. */
73 assert(errno
!= EBADF
|| IN_SET(fd
, STDIN_FILENO
, STDOUT_FILENO
, STDERR_FILENO
));
79 _cleanup_close_
int fd
= -EBADF
;
81 /* Switch to the specified vt number. If the VT is specified <= 0 switch to the VT the kernel log messages go,
82 * if that's configured. */
84 fd
= open_terminal("/dev/tty0", O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NONBLOCK
);
90 TIOCL_GETKMSGREDIRECT
,
94 if (ioctl(fd
, TIOCLINUX
, tiocl
) < 0)
97 vt
= tiocl
[0] <= 0 ? 1 : tiocl
[0];
100 return RET_NERRNO(ioctl(fd
, VT_ACTIVATE
, vt
));
103 int read_one_char(FILE *f
, char *ret
, usec_t t
, bool echo
, bool *need_nl
) {
104 _cleanup_free_
char *line
= NULL
;
105 struct termios old_termios
;
113 /* If this is a terminal, then switch canonical mode off, so that we can read a single
114 * character. (Note that fmemopen() streams do not have an fd associated with them, let's handle that
115 * nicely.) If 'echo' is false we'll also disable ECHO mode so that the pressed key is not made
116 * visible to the user. */
118 if (fd
>= 0 && tcgetattr(fd
, &old_termios
) >= 0) {
119 struct termios new_termios
= old_termios
;
121 new_termios
.c_lflag
&= ~(ICANON
|(echo
? 0 : ECHO
));
122 new_termios
.c_cc
[VMIN
] = 1;
123 new_termios
.c_cc
[VTIME
] = 0;
125 if (tcsetattr(fd
, TCSANOW
, &new_termios
) >= 0) {
128 if (t
!= USEC_INFINITY
) {
129 if (fd_wait_for_event(fd
, POLLIN
, t
) <= 0) {
130 (void) tcsetattr(fd
, TCSANOW
, &old_termios
);
135 r
= safe_fgetc(f
, &c
);
136 (void) tcsetattr(fd
, TCSANOW
, &old_termios
);
143 *need_nl
= c
!= '\n';
150 if (t
!= USEC_INFINITY
&& fd
>= 0) {
151 /* Let's wait the specified amount of time for input. When we have no fd we skip this, under
152 * the assumption that this is an fmemopen() stream or so where waiting doesn't make sense
153 * anyway, as the data is either already in the stream or cannot possible be placed there
154 * while we access the stream */
156 if (fd_wait_for_event(fd
, POLLIN
, t
) <= 0)
160 /* If this is not a terminal, then read a full line instead */
162 r
= read_line(f
, 16, &line
); /* longer than necessary, to eat up UTF-8 chars/vt100 key sequences */
168 if (strlen(line
) != 1)
178 #define DEFAULT_ASK_REFRESH_USEC (2*USEC_PER_SEC)
180 int ask_char(char *ret
, const char *replies
, const char *fmt
, ...) {
192 fputs(ansi_highlight(), stdout
);
200 fputs(ansi_normal(), stdout
);
204 r
= read_one_char(stdin
, &c
, DEFAULT_ASK_REFRESH_USEC
, /* echo= */ true, &need_nl
);
211 puts("Bad input, please try again.");
222 if (strchr(replies
, c
)) {
227 puts("Read unexpected character, please try again.");
231 typedef enum CompletionResult
{
232 COMPLETION_ALREADY
, /* the input string is already complete */
233 COMPLETION_FULL
, /* completed the input string to be complete now */
234 COMPLETION_PARTIAL
, /* completed the input string so that is still incomplete */
235 COMPLETION_NONE
, /* found no matching completion */
236 _COMPLETION_RESULT_MAX
,
237 _COMPLETION_RESULT_INVALID
= -EINVAL
,
238 _COMPLETION_RESULT_ERRNO_MAX
= -ERRNO_MAX
,
241 static CompletionResult
pick_completion(const char *string
, char *const*completions
, char **ret
) {
242 _cleanup_free_
char *found
= NULL
;
243 bool partial
= false;
245 string
= strempty(string
);
247 STRV_FOREACH(c
, completions
) {
249 /* Ignore entries that are not actually completions */
250 if (!startswith(*c
, string
))
253 /* Store first completion that matches */
262 /* If there's another completion that works truncate the one we already found by common
264 size_t n
= str_common_prefix(found
, *c
);
272 *ret
= TAKE_PTR(found
);
275 return COMPLETION_NONE
;
277 return COMPLETION_PARTIAL
;
279 return streq(string
, *ret
) ? COMPLETION_ALREADY
: COMPLETION_FULL
;
282 static void clear_by_backspace(size_t n
) {
283 /* Erase the specified number of character cells backwards on the terminal */
284 for (size_t i
= 0; i
< n
; i
++)
285 fputs("\b \b", stdout
);
290 GetCompletionsCallback get_completions
,
292 const char *text
, ...) {
300 /* Output the prompt */
301 fputs(ansi_highlight(), stdout
);
305 fputs(ansi_normal(), stdout
);
308 _cleanup_free_
char *string
= NULL
;
311 /* Do interactive logic only if stdin + stdout are connected to the same place. And yes, we could use
312 * STDIN_FILENO and STDOUT_FILENO here, but let's be overly correct for once, after all libc allows
313 * swapping out stdin/stdout. */
314 int fd_input
= fileno(stdin
);
315 int fd_output
= fileno(stdout
);
316 if (fd_input
< 0 || fd_output
< 0 || same_fd(fd_input
, fd_output
) <= 0)
319 /* Try to disable echo, which also tells us if this even is a terminal */
320 struct termios old_termios
;
321 if (tcgetattr(fd_input
, &old_termios
) < 0)
324 struct termios new_termios
= old_termios
;
325 termios_disable_echo(&new_termios
);
326 if (tcsetattr(fd_input
, TCSANOW
, &new_termios
) < 0)
330 int c
= fgetc(stdin
);
332 /* On EOF or NUL, end the request, don't output anything anymore */
333 if (IN_SET(c
, EOF
, 0))
336 /* On Return also end the request, but make this visible */
337 if (IN_SET(c
, '\n', '\r')) {
345 _cleanup_strv_free_
char **completions
= NULL
;
346 if (get_completions
) {
347 r
= get_completions(string
, &completions
, userdata
);
352 _cleanup_free_
char *new_string
= NULL
;
353 CompletionResult cr
= pick_completion(string
, completions
, &new_string
);
358 if (IN_SET(cr
, COMPLETION_PARTIAL
, COMPLETION_FULL
)) {
359 /* Output the new suffix we learned */
360 fputs(ASSERT_PTR(startswith(new_string
, strempty(string
))), stdout
);
362 /* And update the whole string */
363 free_and_replace(string
, new_string
);
366 if (cr
== COMPLETION_NONE
)
367 fputc('\a', stdout
); /* BEL */
369 if (IN_SET(cr
, COMPLETION_PARTIAL
, COMPLETION_ALREADY
)) {
370 /* If this worked only partially, or if the user hit TAB even though we were
371 * complete already, then show the remaining options (in the latter case just
375 _cleanup_strv_free_
char **filtered
= strv_filter_prefix(completions
, string
);
381 r
= show_menu(filtered
,
382 /* n_columns= */ SIZE_MAX
,
383 /* column_width= */ SIZE_MAX
,
384 /* ellipsize_percentage= */ 0,
385 /* grey_prefix=*/ string
,
386 /* with_numbers= */ false);
390 /* Show the prompt again */
391 fputs(ansi_highlight(), stdout
);
395 fputs(ansi_normal(), stdout
);
396 fputs(string
, stdout
);
399 } else if (IN_SET(c
, '\b', 127)) {
403 fputc('\a', stdout
); /* BEL */
405 size_t m
= utf8_last_length(string
, n
);
407 char *e
= string
+ n
- m
;
408 clear_by_backspace(utf8_console_width(e
));
414 } else if (c
== 21) {
415 /* Ctrl-u → erase all input */
417 clear_by_backspace(utf8_console_width(string
));
424 /* Ctrl-d → cancel this field input */
429 } else if (char_is_cc(c
) || n
>= LINE_MAX
)
430 /* refuse control characters and too long strings */
431 fputc('\a', stdout
); /* BEL */
435 if (!GREEDY_REALLOC(string
, n
+2)) {
440 string
[n
++] = (char) c
;
449 if (tcsetattr(fd_input
, TCSANOW
, &old_termios
) < 0)
458 *ret
= TAKE_PTR(string
);
462 (void) tcsetattr(fd_input
, TCSANOW
, &old_termios
);
466 /* A simple fallback without TTY magic */
467 r
= read_line(stdin
, LONG_LINE_MAX
, &string
);
473 *ret
= TAKE_PTR(string
);
477 bool any_key_to_proceed(void) {
479 /* Insert a new line here as well as to when the user inputs, as this is also used during the boot up
480 * sequence when status messages may be interleaved with the current program output. This ensures
481 * that the status messages aren't appended on the same line as this message. */
484 fputs(ansi_highlight_magenta(), stdout
);
485 fputs("-- Press any key to proceed --", stdout
);
486 fputs(ansi_normal(), stdout
);
491 (void) read_one_char(stdin
, &key
, USEC_INFINITY
, /* echo= */ false, /* need_nl= */ NULL
);
499 static size_t widest_list_element(char *const*l
) {
502 /* Returns the largest console width of all elements in 'l' */
505 w
= MAX(w
, utf8_console_width(*i
));
510 int show_menu(char **x
,
513 unsigned ellipsize_percentage
,
514 const char *grey_prefix
,
517 assert(n_columns
> 0);
519 if (n_columns
== SIZE_MAX
)
522 if (column_width
== SIZE_MAX
) {
523 size_t widest
= widest_list_element(x
);
525 /* If not specified, derive column width from screen width */
526 size_t column_max
= (columns()-1) / n_columns
;
528 /* Subtract room for numbers */
529 if (with_numbers
&& column_max
> 6)
532 /* If columns would get too tight let's make this a linear list instead. */
533 if (column_max
< 10 && widest
> 10) {
535 column_max
= columns()-1;
537 if (with_numbers
&& column_max
> 6)
541 column_width
= CLAMP(widest
+1, 10U, column_max
);
544 size_t n
= strv_length(x
);
545 size_t per_column
= DIV_ROUND_UP(n
, n_columns
);
547 size_t break_lines
= lines();
551 /* The first page gets two extra lines, since we want to show
553 size_t break_modulo
= break_lines
;
554 if (break_modulo
> 3)
557 for (size_t i
= 0; i
< per_column
; i
++) {
559 for (size_t j
= 0; j
< n_columns
; j
++) {
560 _cleanup_free_
char *e
= NULL
;
562 if (j
* per_column
+ i
>= n
)
565 e
= ellipsize(x
[j
* per_column
+ i
], column_width
, ellipsize_percentage
);
572 j
* per_column
+ i
+ 1,
575 if (grey_prefix
&& startswith(e
, grey_prefix
)) {
576 size_t k
= MIN(strlen(grey_prefix
), column_width
);
582 (int) (column_width
- k
), e
+k
);
584 printf("%-*s", (int) column_width
, e
);
589 /* on the first screen we reserve 2 extra lines for the title */
590 if (i
% break_lines
== break_modulo
)
591 if (!any_key_to_proceed())
598 int open_terminal(const char *name
, int mode
) {
599 _cleanup_close_
int fd
= -EBADF
;
602 * If a TTY is in the process of being closed opening it might cause EIO. This is horribly awful, but
603 * unlikely to be changed in the kernel. Hence we work around this problem by retrying a couple of
606 * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245
609 assert((mode
& (O_CREAT
|O_PATH
|O_DIRECTORY
|O_TMPFILE
)) == 0);
611 for (unsigned c
= 0;; c
++) {
612 fd
= open(name
, mode
, 0);
619 /* Max 1s in total */
623 (void) usleep_safe(50 * USEC_PER_MSEC
);
626 if (!isatty_safe(fd
))
632 int acquire_terminal(
634 AcquireTerminalFlags flags
,
637 _cleanup_close_
int notify
= -EBADF
, fd
= -EBADF
;
638 usec_t ts
= USEC_INFINITY
;
643 AcquireTerminalFlags mode
= flags
& _ACQUIRE_TERMINAL_MODE_MASK
;
644 assert(IN_SET(mode
, ACQUIRE_TERMINAL_TRY
, ACQUIRE_TERMINAL_FORCE
, ACQUIRE_TERMINAL_WAIT
));
645 assert(mode
== ACQUIRE_TERMINAL_WAIT
|| !FLAGS_SET(flags
, ACQUIRE_TERMINAL_WATCH_SIGTERM
));
647 /* We use inotify to be notified when the tty is closed. We create the watch before checking if we can actually
648 * acquire it, so that we don't lose any event.
650 * Note: strictly speaking this actually watches for the device being closed, it does *not* really watch
651 * whether a tty loses its controlling process. However, unless some rogue process uses TIOCNOTTY on /dev/tty
652 * *after* closing its tty otherwise this will not become a problem. As long as the administrator makes sure to
653 * not configure any service on the same tty as an untrusted user this should not be a problem. (Which they
654 * probably should not do anyway.) */
656 if (mode
== ACQUIRE_TERMINAL_WAIT
) {
657 notify
= inotify_init1(IN_CLOEXEC
| IN_NONBLOCK
);
661 wd
= inotify_add_watch(notify
, name
, IN_CLOSE
);
665 if (timeout
!= USEC_INFINITY
)
666 ts
= now(CLOCK_MONOTONIC
);
669 /* If we are called with ACQUIRE_TERMINAL_WATCH_SIGTERM we'll unblock SIGTERM during ppoll() temporarily */
671 assert_se(sigprocmask(SIG_SETMASK
, /* newset= */ NULL
, &poll_ss
) >= 0);
672 if (flags
& ACQUIRE_TERMINAL_WATCH_SIGTERM
) {
673 assert_se(sigismember(&poll_ss
, SIGTERM
) > 0);
674 assert_se(sigdelset(&poll_ss
, SIGTERM
) >= 0);
679 r
= flush_fd(notify
);
684 /* We pass here O_NOCTTY only so that we can check the return value TIOCSCTTY and have a reliable way
685 * to figure out if we successfully became the controlling process of the tty */
686 fd
= open_terminal(name
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
690 /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed if we already own the tty. */
691 struct sigaction sa_old
;
692 assert_se(sigaction(SIGHUP
, &sigaction_ignore
, &sa_old
) >= 0);
694 /* First, try to get the tty */
695 r
= RET_NERRNO(ioctl(fd
, TIOCSCTTY
, mode
== ACQUIRE_TERMINAL_FORCE
));
697 /* Reset signal handler to old value */
698 assert_se(sigaction(SIGHUP
, &sa_old
, NULL
) >= 0);
700 /* Success? Exit the loop now! */
704 /* Any failure besides -EPERM? Fail, regardless of the mode. */
708 if (flags
& ACQUIRE_TERMINAL_PERMISSIVE
) /* If we are in permissive mode, then EPERM is fine, turn this
709 * into a success. Note that EPERM is also returned if we
710 * already are the owner of the TTY. */
713 if (mode
!= ACQUIRE_TERMINAL_WAIT
) /* If we are in TRY or FORCE mode, then propagate EPERM as EPERM */
721 if (timeout
== USEC_INFINITY
)
722 left
= USEC_INFINITY
;
724 assert(ts
!= USEC_INFINITY
);
726 usec_t n
= usec_sub_unsigned(now(CLOCK_MONOTONIC
), ts
);
746 union inotify_event_buffer buffer
;
748 l
= read(notify
, &buffer
, sizeof(buffer
));
750 if (ERRNO_IS_TRANSIENT(errno
))
756 FOREACH_INOTIFY_EVENT(e
, buffer
, l
) {
757 if (e
->mask
& IN_Q_OVERFLOW
) /* If we hit an inotify queue overflow, simply check if the terminal is up for grabs now. */
760 if (e
->wd
!= wd
|| !(e
->mask
& IN_CLOSE
)) /* Safety checks */
767 /* We close the tty fd here since if the old session ended our handle will be dead. It's important that
768 * we do this after sleeping, so that we don't enter an endless loop. */
775 int release_terminal(void) {
776 _cleanup_close_
int fd
= -EBADF
;
779 fd
= open("/dev/tty", O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NONBLOCK
);
783 /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
784 * by our own TIOCNOTTY */
785 struct sigaction sa_old
;
786 assert_se(sigaction(SIGHUP
, &sigaction_ignore
, &sa_old
) >= 0);
788 r
= RET_NERRNO(ioctl(fd
, TIOCNOTTY
));
790 assert_se(sigaction(SIGHUP
, &sa_old
, NULL
) >= 0);
795 int terminal_new_session(void) {
797 /* Make us the new session leader, and set stdin tty to be our controlling terminal.
799 * Why stdin? Well, the ctty logic is relevant for signal delivery mostly, i.e. if people hit C-c
800 * or the line is hung up. Such events are basically just a form of input, via a side channel
801 * (that side channel being signal delivery, i.e. SIGINT, SIGHUP et al). Hence we focus on input,
802 * not output here. */
804 if (!isatty_safe(STDIN_FILENO
))
808 return RET_NERRNO(ioctl(STDIN_FILENO
, TIOCSCTTY
, 0));
811 void terminal_detach_session(void) {
813 (void) release_terminal();
816 int terminal_vhangup_fd(int fd
) {
818 return RET_NERRNO(ioctl(fd
, TIOCVHANGUP
));
821 int terminal_vhangup(const char *tty
) {
822 _cleanup_close_
int fd
= -EBADF
;
826 fd
= open_terminal(tty
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
830 return terminal_vhangup_fd(fd
);
833 int vt_disallocate(const char *tty_path
) {
836 /* Deallocate the VT if possible. If not possible (i.e. because it is the active one), at least clear
837 * it entirely (including the scrollback buffer). */
839 int ttynr
= vtnr_from_tty(tty_path
);
841 _cleanup_close_
int fd
= open_terminal("/dev/tty0", O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NONBLOCK
);
845 /* Try to deallocate */
846 if (ioctl(fd
, VT_DISALLOCATE
, ttynr
) >= 0)
852 /* So this is not a VT (in which case we cannot deallocate it), or we failed to deallocate. Let's at
853 * least clear the screen. */
855 _cleanup_close_
int fd2
= open_terminal(tty_path
, O_WRONLY
|O_NOCTTY
|O_CLOEXEC
|O_NONBLOCK
);
859 return loop_write_full(fd2
,
861 "\033[r" /* clear scrolling region */
862 "\033[H" /* move home */
863 "\033[3J" /* clear screen including scrollback, requires Linux 2.6.40 */
864 "\033c", /* reset to initial state */
866 100 * USEC_PER_MSEC
);
869 static int vt_default_utf8(void) {
870 _cleanup_free_
char *b
= NULL
;
873 /* Read the default VT UTF8 setting from the kernel */
875 r
= read_one_line_file("/sys/module/vt/parameters/default_utf8", &b
);
879 return parse_boolean(b
);
882 static int vt_reset_keyboard(int fd
) {
887 /* If we can't read the default, then default to Unicode. It's 2024 after all. */
888 r
= vt_default_utf8();
890 log_debug_errno(r
, "Failed to determine kernel VT UTF-8 mode, assuming enabled: %m");
892 kb
= vt_default_utf8() != 0 ? K_UNICODE
: K_XLATE
;
893 return RET_NERRNO(ioctl(fd
, KDSKBMODE
, kb
));
896 static int terminal_reset_ioctl(int fd
, bool switch_to_text
) {
897 struct termios termios
;
900 /* Set terminal to some sane defaults */
904 /* We leave locked terminal attributes untouched, so that Plymouth may set whatever it wants to set,
905 * and we don't interfere with that. */
907 /* Disable exclusive mode, just in case */
908 if (ioctl(fd
, TIOCNXCL
) < 0)
909 log_debug_errno(errno
, "TIOCNXCL ioctl failed on TTY, ignoring: %m");
911 /* Switch to text mode */
913 if (ioctl(fd
, KDSETMODE
, KD_TEXT
) < 0)
914 log_debug_errno(errno
, "KDSETMODE ioctl for switching to text mode failed on TTY, ignoring: %m");
916 /* Set default keyboard mode */
917 r
= vt_reset_keyboard(fd
);
919 log_debug_errno(r
, "Failed to reset VT keyboard, ignoring: %m");
921 if (tcgetattr(fd
, &termios
) < 0) {
922 r
= log_debug_errno(errno
, "Failed to get terminal parameters: %m");
926 /* We only reset the stuff that matters to the software. How
927 * hardware is set up we don't touch assuming that somebody
928 * else will do that for us */
930 termios
.c_iflag
&= ~(IGNBRK
| BRKINT
| ISTRIP
| INLCR
| IGNCR
| IUCLC
);
931 termios
.c_iflag
|= ICRNL
| IMAXBEL
| IUTF8
;
932 termios
.c_oflag
|= ONLCR
| OPOST
;
933 termios
.c_cflag
|= CREAD
;
934 termios
.c_lflag
= ISIG
| ICANON
| IEXTEN
| ECHO
| ECHOE
| ECHOK
| ECHOCTL
| ECHOKE
;
936 termios
.c_cc
[VINTR
] = 03; /* ^C */
937 termios
.c_cc
[VQUIT
] = 034; /* ^\ */
938 termios
.c_cc
[VERASE
] = 0177;
939 termios
.c_cc
[VKILL
] = 025; /* ^X */
940 termios
.c_cc
[VEOF
] = 04; /* ^D */
941 termios
.c_cc
[VSTART
] = 021; /* ^Q */
942 termios
.c_cc
[VSTOP
] = 023; /* ^S */
943 termios
.c_cc
[VSUSP
] = 032; /* ^Z */
944 termios
.c_cc
[VLNEXT
] = 026; /* ^V */
945 termios
.c_cc
[VWERASE
] = 027; /* ^W */
946 termios
.c_cc
[VREPRINT
] = 022; /* ^R */
947 termios
.c_cc
[VEOL
] = 0;
948 termios
.c_cc
[VEOL2
] = 0;
950 termios
.c_cc
[VTIME
] = 0;
951 termios
.c_cc
[VMIN
] = 1;
953 r
= RET_NERRNO(tcsetattr(fd
, TCSANOW
, &termios
));
955 log_debug_errno(r
, "Failed to set terminal parameters: %m");
958 /* Just in case, flush all crap out */
959 (void) tcflush(fd
, TCIOFLUSH
);
964 static int terminal_reset_ansi_seq(int fd
) {
969 if (getenv_terminal_is_dumb())
972 r
= fd_nonblock(fd
, true);
974 return log_debug_errno(r
, "Failed to set terminal to non-blocking mode: %m");
976 k
= loop_write_full(fd
,
978 "\033[!p" /* soft terminal reset */
979 "\033]104\007" /* reset colors */
980 "\033[?7h" /* enable line-wrapping */
981 "\033[1G" /* place cursor at beginning of current line */
982 "\033[0J", /* erase till end of screen */
984 100 * USEC_PER_MSEC
);
986 log_debug_errno(k
, "Failed to reset terminal through ANSI sequences: %m");
989 r
= fd_nonblock(fd
, false);
991 log_debug_errno(r
, "Failed to set terminal back to blocking mode: %m");
994 return k
< 0 ? k
: r
;
997 void reset_dev_console_fd(int fd
, bool switch_to_text
) {
1002 _cleanup_close_
int lock_fd
= lock_dev_console();
1004 log_debug_errno(lock_fd
, "Failed to lock /dev/console, ignoring: %m");
1006 r
= terminal_reset_ioctl(fd
, switch_to_text
);
1008 log_warning_errno(r
, "Failed to reset /dev/console, ignoring: %m");
1010 unsigned rows
, cols
;
1011 r
= proc_cmdline_tty_size("/dev/console", &rows
, &cols
);
1013 log_warning_errno(r
, "Failed to get /dev/console size, ignoring: %m");
1015 r
= terminal_set_size_fd(fd
, NULL
, rows
, cols
);
1017 log_warning_errno(r
, "Failed to set configured terminal size on /dev/console, ignoring: %m");
1019 (void) terminal_fix_size(fd
, fd
);
1021 r
= terminal_reset_ansi_seq(fd
);
1023 log_warning_errno(r
, "Failed to reset /dev/console using ANSI sequences, ignoring: %m");
1026 int lock_dev_console(void) {
1027 _cleanup_close_
int fd
= -EBADF
;
1030 /* NB: We do not use O_NOFOLLOW here, because some container managers might place a symlink to some
1031 * pty in /dev/console, in which case it should be fine to lock the target TTY. */
1032 fd
= open_terminal("/dev/console", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1036 r
= lock_generic(fd
, LOCK_BSD
, LOCK_EX
);
1043 int make_console_stdio(void) {
1046 /* Make /dev/console the controlling terminal and stdin/stdout/stderr, if we can. If we can't use
1047 * /dev/null instead. This is particularly useful if /dev/console is turned off, e.g. if console=null
1048 * is specified on the kernel command line. */
1050 fd
= acquire_terminal("/dev/console", ACQUIRE_TERMINAL_FORCE
|ACQUIRE_TERMINAL_PERMISSIVE
, USEC_INFINITY
);
1052 log_warning_errno(fd
, "Failed to acquire terminal, using /dev/null stdin/stdout/stderr instead: %m");
1054 r
= make_null_stdio();
1056 return log_error_errno(r
, "Failed to make /dev/null stdin/stdout/stderr: %m");
1059 reset_dev_console_fd(fd
, /* switch_to_text= */ true);
1061 r
= rearrange_stdio(fd
, fd
, fd
); /* This invalidates 'fd' both on success and on failure. */
1063 return log_error_errno(r
, "Failed to make terminal stdin/stdout/stderr: %m");
1066 reset_terminal_feature_caches();
1070 static int vtnr_from_tty_raw(const char *tty
, unsigned *ret
) {
1073 tty
= skip_dev_prefix(tty
);
1075 const char *e
= startswith(tty
, "tty");
1079 return safe_atou(e
, ret
);
1082 int vtnr_from_tty(const char *tty
) {
1088 r
= vtnr_from_tty_raw(tty
, &u
);
1091 if (!vtnr_is_valid(u
))
1097 bool tty_is_vc(const char *tty
) {
1100 /* NB: for >= 0 values no range check is conducted here, on the assumption that the caller will
1101 * either extract vtnr through vtnr_from_tty() later where ERANGE would be reported, or doesn't care
1102 * about whether it's strictly valid, but only asking "does this fall into the vt category?", for which
1103 * "yes" seems to be a better answer. */
1105 return vtnr_from_tty_raw(tty
, /* ret = */ NULL
) >= 0;
1108 bool tty_is_console(const char *tty
) {
1111 return streq(skip_dev_prefix(tty
), "console");
1114 int resolve_dev_console(char **ret
) {
1119 /* Resolve where /dev/console is pointing to. If /dev/console is a symlink (like in container
1120 * managers), we'll just resolve the symlink. If it's a real device node, we'll use if
1121 * /sys/class/tty/tty0/active, but only if /sys/ is actually ours (i.e. not read-only-mounted which
1122 * is a sign for container setups). */
1124 _cleanup_free_
char *chased
= NULL
;
1125 r
= chase("/dev/console", /* root= */ NULL
, /* flags= */ 0, &chased
, /* ret_fd= */ NULL
);
1128 if (!path_equal(chased
, "/dev/console")) {
1129 *ret
= TAKE_PTR(chased
);
1133 r
= path_is_read_only_fs("/sys");
1139 _cleanup_free_
char *active
= NULL
;
1140 r
= read_one_line_file("/sys/class/tty/console/active", &active
);
1144 /* If multiple log outputs are configured the last one is what /dev/console points to */
1145 const char *tty
= strrchr(active
, ' ');
1151 if (streq(tty
, "tty0")) {
1152 active
= mfree(active
);
1154 /* Get the active VC (e.g. tty1) */
1155 r
= read_one_line_file("/sys/class/tty/tty0/active", &active
);
1162 _cleanup_free_
char *path
= NULL
;
1163 path
= path_join("/dev", tty
);
1167 *ret
= TAKE_PTR(path
);
1171 int get_kernel_consoles(char ***ret
) {
1172 _cleanup_strv_free_
char **l
= NULL
;
1173 _cleanup_free_
char *line
= NULL
;
1178 /* If /sys/ is mounted read-only this means we are running in some kind of container environment.
1179 * In that case /sys/ would reflect the host system, not us, hence ignore the data we can read from it. */
1180 if (path_is_read_only_fs("/sys") > 0)
1183 r
= read_one_line_file("/sys/class/tty/console/active", &line
);
1187 for (const char *p
= line
;;) {
1188 _cleanup_free_
char *tty
= NULL
, *path
= NULL
;
1190 r
= extract_first_word(&p
, &tty
, NULL
, 0);
1196 if (streq(tty
, "tty0")) {
1198 r
= read_one_line_file("/sys/class/tty/tty0/active", &tty
);
1203 path
= path_join("/dev", tty
);
1207 if (access(path
, F_OK
) < 0) {
1208 log_debug_errno(errno
, "Console device %s is not accessible, skipping: %m", path
);
1212 r
= strv_consume(&l
, TAKE_PTR(path
));
1217 if (strv_isempty(l
)) {
1218 log_debug("No devices found for system console");
1223 return strv_length(*ret
);
1226 r
= strv_extend(&l
, "/dev/console");
1234 bool tty_is_vc_resolve(const char *tty
) {
1235 _cleanup_free_
char *resolved
= NULL
;
1239 if (streq(skip_dev_prefix(tty
), "console")) {
1240 if (resolve_dev_console(&resolved
) < 0)
1246 return tty_is_vc(tty
);
1249 int fd_columns(int fd
) {
1250 struct winsize ws
= {};
1255 if (ioctl(fd
, TIOCGWINSZ
, &ws
) < 0)
1259 return -ENODATA
; /* some tty types come up with invalid row/column initially, return a recognizable error for that */
1264 int getenv_columns(void) {
1267 const char *e
= getenv("COLUMNS");
1272 r
= safe_atou_bounded(e
, 1, USHRT_MAX
, &c
);
1279 unsigned columns(void) {
1281 if (cached_columns
> 0)
1282 return cached_columns
;
1284 int c
= getenv_columns();
1286 c
= fd_columns(STDOUT_FILENO
);
1294 return cached_columns
;
1297 int fd_lines(int fd
) {
1298 struct winsize ws
= {};
1303 if (ioctl(fd
, TIOCGWINSZ
, &ws
) < 0)
1307 return -ENODATA
; /* some tty types come up with invalid row/column initially, return a recognizable error for that */
1312 unsigned lines(void) {
1316 if (cached_lines
> 0)
1317 return cached_lines
;
1320 e
= getenv("LINES");
1322 (void) safe_atoi(e
, &l
);
1324 if (l
<= 0 || l
> USHRT_MAX
) {
1325 l
= fd_lines(STDOUT_FILENO
);
1331 return cached_lines
;
1334 int terminal_set_size_fd(int fd
, const char *ident
, unsigned rows
, unsigned cols
) {
1342 if (rows
== UINT_MAX
&& cols
== UINT_MAX
)
1345 if (ioctl(fd
, TIOCGWINSZ
, &ws
) < 0)
1346 return log_debug_errno(errno
,
1347 "TIOCGWINSZ ioctl for getting %s size failed, not setting terminal size: %m",
1350 if (rows
== UINT_MAX
)
1352 else if (rows
> USHRT_MAX
)
1355 if (cols
== UINT_MAX
)
1357 else if (cols
> USHRT_MAX
)
1360 if (rows
== ws
.ws_row
&& cols
== ws
.ws_col
)
1366 if (ioctl(fd
, TIOCSWINSZ
, &ws
) < 0)
1367 return log_debug_errno(errno
, "TIOCSWINSZ ioctl for setting %s size failed: %m", ident
);
1372 int proc_cmdline_tty_size(const char *tty
, unsigned *ret_rows
, unsigned *ret_cols
) {
1373 _cleanup_free_
char *rowskey
= NULL
, *rowsvalue
= NULL
, *colskey
= NULL
, *colsvalue
= NULL
;
1374 unsigned rows
= UINT_MAX
, cols
= UINT_MAX
;
1379 if (!ret_rows
&& !ret_cols
)
1382 tty
= skip_dev_prefix(tty
);
1383 if (path_startswith(tty
, "pts/"))
1384 return -EMEDIUMTYPE
;
1385 if (!in_charset(tty
, ALPHANUMERICAL
))
1386 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
),
1387 "TTY name '%s' contains non-alphanumeric characters, not searching kernel cmdline for size.", tty
);
1389 rowskey
= strjoin("systemd.tty.rows.", tty
);
1393 colskey
= strjoin("systemd.tty.columns.", tty
);
1397 r
= proc_cmdline_get_key_many(/* flags = */ 0,
1398 rowskey
, &rowsvalue
,
1399 colskey
, &colsvalue
);
1401 return log_debug_errno(r
, "Failed to read TTY size of %s from kernel cmdline: %m", tty
);
1404 r
= safe_atou(rowsvalue
, &rows
);
1406 return log_debug_errno(r
, "Failed to parse %s=%s: %m", rowskey
, rowsvalue
);
1410 r
= safe_atou(colsvalue
, &cols
);
1412 return log_debug_errno(r
, "Failed to parse %s=%s: %m", colskey
, colsvalue
);
1420 return rows
!= UINT_MAX
|| cols
!= UINT_MAX
;
1423 /* intended to be used as a SIGWINCH sighandler */
1424 void columns_lines_cache_reset(int signum
) {
1429 void reset_terminal_feature_caches(void) {
1434 cached_on_dev_null
= -1;
1436 reset_ansi_feature_caches();
1441 /* We check both stdout and stderr, so that situations where pipes on the shell are used are reliably
1442 * recognized, regardless if only the output or the errors are piped to some place. Since on_tty() is generally
1443 * used to default to a safer, non-interactive, non-color mode of operation it's probably good to be defensive
1444 * here, and check for both. Note that we don't check for STDIN_FILENO, because it should fine to use fancy
1445 * terminal functionality when outputting stuff, even if the input is piped to us. */
1447 if (cached_on_tty
< 0)
1449 isatty_safe(STDOUT_FILENO
) &&
1450 isatty_safe(STDERR_FILENO
);
1452 return cached_on_tty
;
1455 int getttyname_malloc(int fd
, char **ret
) {
1456 char path
[PATH_MAX
]; /* PATH_MAX is counted *with* the trailing NUL byte */
1462 r
= ttyname_r(fd
, path
, sizeof path
); /* positive error */
1465 return -ENAMETOOLONG
;
1469 return strdup_to(ret
, skip_dev_prefix(path
));
1472 int getttyname_harder(int fd
, char **ret
) {
1473 _cleanup_free_
char *s
= NULL
;
1476 r
= getttyname_malloc(fd
, &s
);
1480 if (streq(s
, "tty"))
1481 return get_ctty(0, NULL
, ret
);
1487 int get_ctty_devnr(pid_t pid
, dev_t
*ret
) {
1488 _cleanup_free_
char *line
= NULL
;
1489 unsigned long ttynr
;
1495 p
= procfs_file_alloca(pid
, "stat");
1496 r
= read_one_line_file(p
, &line
);
1500 p
= strrchr(line
, ')');
1510 "%*d " /* session */
1515 if (devnum_is_zero(ttynr
))
1519 *ret
= (dev_t
) ttynr
;
1524 int get_ctty(pid_t pid
, dev_t
*ret_devnr
, char **ret
) {
1525 char pty
[STRLEN("/dev/pts/") + DECIMAL_STR_MAX(dev_t
) + 1];
1526 _cleanup_free_
char *buf
= NULL
;
1527 const char *fn
= NULL
, *w
;
1531 r
= get_ctty_devnr(pid
, &devnr
);
1535 r
= device_path_make_canonical(S_IFCHR
, devnr
, &buf
);
1539 if (r
!= -ENOENT
) /* No symlink for this in /dev/char/? */
1542 /* Maybe this is PTY? PTY devices are not listed in /dev/char/, as they don't follow the
1543 * Linux device model and hence device_path_make_canonical() doesn't work for them. Let's
1544 * assume this is a PTY for a moment, and check if the device node this would then map to in
1545 * /dev/pts/ matches the one we are looking for. This way we don't have to hardcode the major
1546 * number (which is 136 btw), but we still rely on the fact that PTY numbers map directly to
1547 * the minor number of the pty. */
1548 xsprintf(pty
, "/dev/pts/%u", minor(devnr
));
1550 if (stat(pty
, &st
) < 0) {
1551 if (errno
!= ENOENT
)
1554 } else if (S_ISCHR(st
.st_mode
) && devnr
== st
.st_rdev
) /* Bingo! */
1558 /* Doesn't exist, or not a PTY? Probably something similar to the PTYs which have no
1559 * symlink in /dev/char/. Let's return something vaguely useful. */
1560 r
= device_path_make_major_minor(S_IFCHR
, devnr
, &buf
);
1569 w
= path_startswith(fn
, "/dev/");
1574 r
= strdup_to(ret
, w
);
1585 int ptsname_malloc(int fd
, char **ret
) {
1589 for (size_t l
= 50;;) {
1590 _cleanup_free_
char *c
= NULL
;
1596 if (ptsname_r(fd
, c
, l
) >= 0) {
1600 if (errno
!= ERANGE
)
1603 if (!MUL_ASSIGN_SAFE(&l
, 2))
1608 int openpt_allocate(int flags
, char **ret_peer_path
) {
1609 _cleanup_close_
int fd
= -EBADF
;
1612 fd
= posix_openpt(flags
|O_NOCTTY
|O_CLOEXEC
);
1616 _cleanup_free_
char *p
= NULL
;
1617 if (ret_peer_path
) {
1618 r
= ptsname_malloc(fd
, &p
);
1622 if (!path_startswith(p
, "/dev/pts/"))
1626 if (unlockpt(fd
) < 0)
1630 *ret_peer_path
= TAKE_PTR(p
);
1635 static int ptsname_namespace(int pty
, char **ret
) {
1641 /* Like ptsname(), but doesn't assume that the path is
1642 * accessible in the local namespace. */
1644 if (ioctl(pty
, TIOCGPTN
, &no
) < 0)
1650 if (asprintf(ret
, "/dev/pts/%i", no
) < 0)
1656 int openpt_allocate_in_namespace(
1657 const PidRef
*pidref
,
1659 char **ret_peer_path
) {
1661 _cleanup_close_
int pidnsfd
= -EBADF
, mntnsfd
= -EBADF
, usernsfd
= -EBADF
, rootfd
= -EBADF
, fd
= -EBADF
;
1662 _cleanup_close_pair_
int pair
[2] = EBADF_PAIR
;
1665 r
= pidref_namespace_open(pidref
, &pidnsfd
, &mntnsfd
, /* ret_netns_fd = */ NULL
, &usernsfd
, &rootfd
);
1669 if (socketpair(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
, 0, pair
) < 0)
1675 /* except_fds= */ NULL
,
1676 /* n_except_fds= */ 0,
1677 FORK_RESET_SIGNALS
|FORK_DEATHSIG_SIGKILL
|FORK_WAIT
,
1680 /* netns_fd= */ -EBADF
,
1683 /* ret_pid= */ NULL
);
1687 pair
[0] = safe_close(pair
[0]);
1689 fd
= openpt_allocate(flags
, /* ret_peer_path= */ NULL
);
1691 _exit(EXIT_FAILURE
);
1693 if (send_one_fd(pair
[1], fd
, 0) < 0)
1694 _exit(EXIT_FAILURE
);
1696 _exit(EXIT_SUCCESS
);
1699 pair
[1] = safe_close(pair
[1]);
1701 fd
= receive_one_fd(pair
[0], 0);
1705 if (ret_peer_path
) {
1706 r
= ptsname_namespace(fd
, ret_peer_path
);
1714 static bool on_dev_null(void) {
1715 struct stat dst
, ost
, est
;
1717 if (cached_on_dev_null
>= 0)
1718 return cached_on_dev_null
;
1720 if (stat("/dev/null", &dst
) < 0 || fstat(STDOUT_FILENO
, &ost
) < 0 || fstat(STDERR_FILENO
, &est
) < 0)
1721 cached_on_dev_null
= false;
1723 cached_on_dev_null
= stat_inode_same(&dst
, &ost
) && stat_inode_same(&dst
, &est
);
1725 return cached_on_dev_null
;
1728 bool getenv_terminal_is_dumb(void) {
1735 return streq(e
, "dumb");
1738 bool terminal_is_dumb(void) {
1739 if (!on_tty() && !on_dev_null())
1742 return getenv_terminal_is_dumb();
1745 bool dev_console_colors_enabled(void) {
1746 _cleanup_free_
char *s
= NULL
;
1749 /* Returns true if we assume that color is supported on /dev/console.
1751 * For that we first check if we explicitly got told to use colors or not, by checking $SYSTEMD_COLORS. If that
1752 * isn't set we check whether PID 1 has $TERM set, and if not, whether TERM is set on the kernel command
1753 * line. If we find $TERM set we assume color if it's not set to "dumb", similarly to how regular
1754 * colors_enabled() operates. */
1756 m
= parse_systemd_colors();
1760 if (getenv("NO_COLOR"))
1763 if (getenv_for_pid(1, "TERM", &s
) <= 0)
1764 (void) proc_cmdline_get_key("TERM", 0, &s
);
1766 return !streq_ptr(s
, "dumb");
1769 int vt_restore(int fd
) {
1771 static const struct vt_mode mode
= {
1779 if (!isatty_safe(fd
))
1780 return log_debug_errno(SYNTHETIC_ERRNO(ENOTTY
), "Asked to restore the VT for an fd that does not refer to a terminal: %m");
1782 if (ioctl(fd
, KDSETMODE
, KD_TEXT
) < 0)
1783 RET_GATHER(ret
, log_debug_errno(errno
, "Failed to set VT to text mode, ignoring: %m"));
1785 r
= vt_reset_keyboard(fd
);
1787 RET_GATHER(ret
, log_debug_errno(r
, "Failed to reset keyboard mode, ignoring: %m"));
1789 if (ioctl(fd
, VT_SETMODE
, &mode
) < 0)
1790 RET_GATHER(ret
, log_debug_errno(errno
, "Failed to set VT_AUTO mode, ignoring: %m"));
1792 r
= fchmod_and_chown(fd
, TTY_MODE
, 0, GID_INVALID
);
1794 RET_GATHER(ret
, log_debug_errno(r
, "Failed to chmod()/chown() VT, ignoring: %m"));
1799 int vt_release(int fd
, bool restore
) {
1802 /* This function releases the VT by acknowledging the VT-switch signal
1803 * sent by the kernel and optionally reset the VT in text and auto
1804 * VT-switching modes. */
1806 if (!isatty_safe(fd
))
1807 return log_debug_errno(SYNTHETIC_ERRNO(ENOTTY
), "Asked to release the VT for an fd that does not refer to a terminal: %m");
1809 if (ioctl(fd
, VT_RELDISP
, 1) < 0)
1813 return vt_restore(fd
);
1818 void get_log_colors(int priority
, const char **on
, const char **off
, const char **highlight
) {
1819 /* Note that this will initialize output variables only when there's something to output.
1820 * The caller must pre-initialize to "" or NULL as appropriate. */
1822 if (priority
<= LOG_ERR
) {
1824 *on
= ansi_highlight_red();
1826 *off
= ansi_normal();
1828 *highlight
= ansi_highlight();
1830 } else if (priority
<= LOG_WARNING
) {
1832 *on
= ansi_highlight_yellow();
1834 *off
= ansi_normal();
1836 *highlight
= ansi_highlight();
1838 } else if (priority
<= LOG_NOTICE
) {
1840 *on
= ansi_highlight();
1842 *off
= ansi_normal();
1844 *highlight
= ansi_highlight_red();
1846 } else if (priority
>= LOG_DEBUG
) {
1850 *off
= ansi_normal();
1852 *highlight
= ansi_highlight_red();
1856 int terminal_set_cursor_position(int fd
, unsigned row
, unsigned column
) {
1859 char cursor_position
[STRLEN("\x1B[" ";" "H") + DECIMAL_STR_MAX(unsigned) * 2 + 1];
1860 xsprintf(cursor_position
, "\x1B[%u;%uH", row
, column
);
1862 return loop_write(fd
, cursor_position
, SIZE_MAX
);
1865 int terminal_reset_defensive(int fd
, TerminalResetFlags flags
) {
1869 assert(!FLAGS_SET(flags
, TERMINAL_RESET_AVOID_ANSI_SEQ
|TERMINAL_RESET_FORCE_ANSI_SEQ
));
1871 /* Resets the terminal comprehensively, i.e. via both ioctl()s and via ANSI sequences, but do so only
1872 * if $TERM is unset or set to "dumb" */
1874 if (!isatty_safe(fd
))
1877 RET_GATHER(r
, terminal_reset_ioctl(fd
, FLAGS_SET(flags
, TERMINAL_RESET_SWITCH_TO_TEXT
)));
1879 if (!FLAGS_SET(flags
, TERMINAL_RESET_AVOID_ANSI_SEQ
) &&
1880 (FLAGS_SET(flags
, TERMINAL_RESET_FORCE_ANSI_SEQ
) || !getenv_terminal_is_dumb()))
1881 RET_GATHER(r
, terminal_reset_ansi_seq(fd
));
1886 int terminal_reset_defensive_locked(int fd
, TerminalResetFlags flags
) {
1889 _cleanup_close_
int lock_fd
= lock_dev_console();
1891 log_debug_errno(lock_fd
, "Failed to acquire lock for /dev/console, ignoring: %m");
1893 return terminal_reset_defensive(fd
, flags
);
1896 void termios_disable_echo(struct termios
*termios
) {
1899 termios
->c_lflag
&= ~(ICANON
|ECHO
);
1900 termios
->c_cc
[VMIN
] = 1;
1901 termios
->c_cc
[VTIME
] = 0;
1904 static int terminal_verify_same(int input_fd
, int output_fd
) {
1905 assert(input_fd
>= 0);
1906 assert(output_fd
>= 0);
1908 /* Validates that the specified fds reference the same TTY */
1910 if (input_fd
!= output_fd
) {
1912 if (fstat(input_fd
, &sti
) < 0)
1915 if (!S_ISCHR(sti
.st_mode
)) /* TTYs are character devices */
1919 if (fstat(output_fd
, &sto
) < 0)
1922 if (!S_ISCHR(sto
.st_mode
))
1925 if (sti
.st_rdev
!= sto
.st_rdev
)
1929 if (!isatty_safe(input_fd
)) /* The check above was just for char device, but now let's ensure it's actually a tty */
1935 typedef enum BackgroundColorState
{
1939 BACKGROUND_FIRST_ONE
,
1940 BACKGROUND_SECOND_ONE
,
1941 BACKGROUND_SEMICOLON
,
1948 BACKGROUND_STRING_TERMINATOR
,
1949 } BackgroundColorState
;
1951 typedef struct BackgroundColorContext
{
1952 BackgroundColorState state
;
1953 uint32_t red
, green
, blue
;
1954 unsigned red_bits
, green_bits
, blue_bits
;
1955 } BackgroundColorContext
;
1957 static int scan_background_color_response(
1958 BackgroundColorContext
*context
,
1961 size_t *ret_processed
) {
1965 assert(ret_processed
);
1967 for (size_t i
= 0; i
< size
; i
++) {
1970 switch (context
->state
) {
1972 case BACKGROUND_TEXT
:
1973 context
->state
= c
== '\x1B' ? BACKGROUND_ESCAPE
: BACKGROUND_TEXT
;
1976 case BACKGROUND_ESCAPE
:
1977 context
->state
= c
== ']' ? BACKGROUND_BRACKET
: BACKGROUND_TEXT
;
1980 case BACKGROUND_BRACKET
:
1981 context
->state
= c
== '1' ? BACKGROUND_FIRST_ONE
: BACKGROUND_TEXT
;
1984 case BACKGROUND_FIRST_ONE
:
1985 context
->state
= c
== '1' ? BACKGROUND_SECOND_ONE
: BACKGROUND_TEXT
;
1988 case BACKGROUND_SECOND_ONE
:
1989 context
->state
= c
== ';' ? BACKGROUND_SEMICOLON
: BACKGROUND_TEXT
;
1992 case BACKGROUND_SEMICOLON
:
1993 context
->state
= c
== 'r' ? BACKGROUND_R
: BACKGROUND_TEXT
;
1997 context
->state
= c
== 'g' ? BACKGROUND_G
: BACKGROUND_TEXT
;
2001 context
->state
= c
== 'b' ? BACKGROUND_B
: BACKGROUND_TEXT
;
2005 context
->state
= c
== ':' ? BACKGROUND_RED
: BACKGROUND_TEXT
;
2008 case BACKGROUND_RED
:
2010 context
->state
= context
->red_bits
> 0 ? BACKGROUND_GREEN
: BACKGROUND_TEXT
;
2012 int d
= unhexchar(c
);
2013 if (d
< 0 || context
->red_bits
>= sizeof(context
->red
)*8)
2014 context
->state
= BACKGROUND_TEXT
;
2016 context
->red
= (context
->red
<< 4) | d
;
2017 context
->red_bits
+= 4;
2022 case BACKGROUND_GREEN
:
2024 context
->state
= context
->green_bits
> 0 ? BACKGROUND_BLUE
: BACKGROUND_TEXT
;
2026 int d
= unhexchar(c
);
2027 if (d
< 0 || context
->green_bits
>= sizeof(context
->green
)*8)
2028 context
->state
= BACKGROUND_TEXT
;
2030 context
->green
= (context
->green
<< 4) | d
;
2031 context
->green_bits
+= 4;
2036 case BACKGROUND_BLUE
:
2038 if (context
->blue_bits
> 0) {
2039 *ret_processed
= i
+ 1;
2040 return 1; /* success! */
2043 context
->state
= BACKGROUND_TEXT
;
2044 } else if (c
== '\x1b')
2045 context
->state
= context
->blue_bits
> 0 ? BACKGROUND_STRING_TERMINATOR
: BACKGROUND_TEXT
;
2047 int d
= unhexchar(c
);
2048 if (d
< 0 || context
->blue_bits
>= sizeof(context
->blue
)*8)
2049 context
->state
= BACKGROUND_TEXT
;
2051 context
->blue
= (context
->blue
<< 4) | d
;
2052 context
->blue_bits
+= 4;
2057 case BACKGROUND_STRING_TERMINATOR
:
2059 *ret_processed
= i
+ 1;
2060 return 1; /* success! */
2063 context
->state
= c
== ']' ? BACKGROUND_ESCAPE
: BACKGROUND_TEXT
;
2068 /* Reset any colors we might have picked up */
2069 if (IN_SET(context
->state
, BACKGROUND_TEXT
, BACKGROUND_ESCAPE
)) {
2071 context
->red
= context
->green
= context
->blue
= 0;
2072 context
->red_bits
= context
->green_bits
= context
->blue_bits
= 0;
2076 *ret_processed
= size
;
2077 return 0; /* all good, but not enough data yet */
2080 int get_default_background_color(double *ret_red
, double *ret_green
, double *ret_blue
) {
2081 _cleanup_close_
int nonblock_input_fd
= -EBADF
;
2088 if (!colors_enabled())
2091 r
= terminal_verify_same(STDIN_FILENO
, STDOUT_FILENO
);
2095 if (streq_ptr(getenv("TERM"), "linux")) {
2096 /* Linux console is black */
2097 *ret_red
= *ret_green
= *ret_blue
= 0.0;
2101 struct termios old_termios
;
2102 if (tcgetattr(STDIN_FILENO
, &old_termios
) < 0)
2105 struct termios new_termios
= old_termios
;
2106 termios_disable_echo(&new_termios
);
2108 if (tcsetattr(STDIN_FILENO
, TCSANOW
, &new_termios
) < 0)
2111 r
= loop_write(STDOUT_FILENO
, ANSI_OSC
"11;?" ANSI_ST
, SIZE_MAX
);
2115 /* Open a 2nd input fd, in non-blocking mode, so that we won't ever hang in read() should someone
2116 * else process the POLLIN. */
2118 nonblock_input_fd
= r
= fd_reopen(STDIN_FILENO
, O_RDONLY
|O_CLOEXEC
|O_NONBLOCK
|O_NOCTTY
);
2122 usec_t end
= usec_add(now(CLOCK_MONOTONIC
), CONSOLE_REPLY_WAIT_USEC
);
2123 char buf
[STRLEN(ANSI_OSC
"11;rgb:0/0/0" ANSI_ST
)]; /* shortest possible reply */
2124 size_t buf_full
= 0;
2125 BackgroundColorContext context
= {};
2127 for (bool first
= true;; first
= false) {
2128 if (buf_full
== 0) {
2129 usec_t n
= now(CLOCK_MONOTONIC
);
2135 r
= fd_wait_for_event(nonblock_input_fd
, POLLIN
, usec_sub_unsigned(end
, n
));
2143 /* On the first try, read multiple characters, i.e. the shortest valid
2144 * reply. Afterwards read byte-wise, since we don't want to read too much, and
2145 * unnecessarily drop too many characters from the input queue. */
2146 ssize_t l
= read(nonblock_input_fd
, buf
, first
? sizeof(buf
) : 1);
2148 if (errno
== EAGAIN
)
2154 assert((size_t) l
<= sizeof(buf
));
2159 r
= scan_background_color_response(&context
, buf
, buf_full
, &processed
);
2163 assert(processed
<= buf_full
);
2164 buf_full
-= processed
;
2165 memmove(buf
, buf
+ processed
, buf_full
);
2168 assert(context
.red_bits
> 0);
2169 *ret_red
= (double) context
.red
/ ((UINT64_C(1) << context
.red_bits
) - 1);
2170 assert(context
.green_bits
> 0);
2171 *ret_green
= (double) context
.green
/ ((UINT64_C(1) << context
.green_bits
) - 1);
2172 assert(context
.blue_bits
> 0);
2173 *ret_blue
= (double) context
.blue
/ ((UINT64_C(1) << context
.blue_bits
) - 1);
2180 RET_GATHER(r
, RET_NERRNO(tcsetattr(STDIN_FILENO
, TCSANOW
, &old_termios
)));
2184 typedef enum CursorPositionState
{
2189 } CursorPositionState
;
2191 typedef struct CursorPositionContext
{
2192 CursorPositionState state
;
2193 unsigned row
, column
;
2194 } CursorPositionContext
;
2196 static int scan_cursor_position_response(
2197 CursorPositionContext
*context
,
2200 size_t *ret_processed
) {
2204 assert(ret_processed
);
2206 for (size_t i
= 0; i
< size
; i
++) {
2209 switch (context
->state
) {
2212 context
->state
= c
== '\x1B' ? CURSOR_ESCAPE
: CURSOR_TEXT
;
2216 context
->state
= c
== '[' ? CURSOR_ROW
: CURSOR_TEXT
;
2221 context
->state
= context
->row
> 0 ? CURSOR_COLUMN
: CURSOR_TEXT
;
2223 int d
= undecchar(c
);
2225 /* We read a decimal character, let's suffix it to the number we so far read,
2226 * but let's do an overflow check first. */
2227 if (d
< 0 || context
->row
> (UINT_MAX
-d
)/10)
2228 context
->state
= CURSOR_TEXT
;
2230 context
->row
= context
->row
* 10 + d
;
2236 if (context
->column
> 0) {
2237 *ret_processed
= i
+ 1;
2238 return 1; /* success! */
2241 context
->state
= CURSOR_TEXT
;
2243 int d
= undecchar(c
);
2245 /* As above, add the decimal character to our column number */
2246 if (d
< 0 || context
->column
> (UINT_MAX
-d
)/10)
2247 context
->state
= CURSOR_TEXT
;
2249 context
->column
= context
->column
* 10 + d
;
2255 /* Reset any positions we might have picked up */
2256 if (IN_SET(context
->state
, CURSOR_TEXT
, CURSOR_ESCAPE
))
2257 context
->row
= context
->column
= 0;
2260 *ret_processed
= size
;
2261 return 0; /* all good, but not enough data yet */
2264 int terminal_get_size_by_dsr(
2268 unsigned *ret_columns
) {
2270 _cleanup_close_
int nonblock_input_fd
= -EBADF
;
2273 assert(input_fd
>= 0);
2274 assert(output_fd
>= 0);
2276 /* Tries to determine the terminal dimension by means of ANSI sequences rather than TIOCGWINSZ
2277 * ioctl(). Why bother with this? The ioctl() information is often incorrect on serial terminals
2278 * (since there's no handshake or protocol to determine the right dimensions in RS232), but since the
2279 * ANSI sequences are interpreted by the final terminal instead of an intermediary tty driver they
2280 * should be more accurate.
2282 * Unfortunately there's no direct ANSI sequence to query terminal dimensions. But we can hack around
2283 * it: we position the cursor briefly at an absolute location very far down and very far to the
2284 * right, and then read back where we actually ended up. Because cursor locations are capped at the
2285 * terminal width/height we should then see the right values. In order to not risk integer overflows
2286 * in terminal applications we'll use INT16_MAX-1 as location to jump to — hopefully a value that is
2287 * large enough for any real-life terminals, but small enough to not overflow anything or be
2288 * recognized as a "niche" value. (Note that the dimension fields in "struct winsize" are 16bit only,
2291 if (terminal_is_dumb())
2294 r
= terminal_verify_same(input_fd
, output_fd
);
2296 return log_debug_errno(r
, "Called with distinct input/output fds: %m");
2298 struct termios old_termios
;
2299 if (tcgetattr(input_fd
, &old_termios
) < 0)
2300 return log_debug_errno(errno
, "Failed to get terminal settings: %m");
2302 struct termios new_termios
= old_termios
;
2303 termios_disable_echo(&new_termios
);
2305 if (tcsetattr(input_fd
, TCSANOW
, &new_termios
) < 0)
2306 return log_debug_errno(errno
, "Failed to set new terminal settings: %m");
2308 unsigned saved_row
= 0, saved_column
= 0;
2310 r
= loop_write(output_fd
,
2311 "\x1B[6n" /* Request cursor position (DSR/CPR) */
2312 "\x1B[32766;32766H" /* Position cursor really far to the right and to the bottom, but let's stay within the 16bit signed range */
2313 "\x1B[6n", /* Request cursor position again */
2318 /* Open a 2nd input fd, in non-blocking mode, so that we won't ever hang in read() should someone
2319 * else process the POLLIN. */
2321 nonblock_input_fd
= r
= fd_reopen(input_fd
, O_RDONLY
|O_CLOEXEC
|O_NONBLOCK
|O_NOCTTY
);
2325 usec_t end
= usec_add(now(CLOCK_MONOTONIC
), CONSOLE_REPLY_WAIT_USEC
);
2326 char buf
[STRLEN("\x1B[1;1R")]; /* The shortest valid reply possible */
2327 size_t buf_full
= 0;
2328 CursorPositionContext context
= {};
2330 for (bool first
= true;; first
= false) {
2331 if (buf_full
== 0) {
2332 usec_t n
= now(CLOCK_MONOTONIC
);
2338 r
= fd_wait_for_event(nonblock_input_fd
, POLLIN
, usec_sub_unsigned(end
, n
));
2346 /* On the first try, read multiple characters, i.e. the shortest valid
2347 * reply. Afterwards read byte-wise, since we don't want to read too much, and
2348 * unnecessarily drop too many characters from the input queue. */
2349 ssize_t l
= read(nonblock_input_fd
, buf
, first
? sizeof(buf
) : 1);
2351 if (errno
== EAGAIN
)
2358 assert((size_t) l
<= sizeof(buf
));
2363 r
= scan_cursor_position_response(&context
, buf
, buf_full
, &processed
);
2367 assert(processed
<= buf_full
);
2368 buf_full
-= processed
;
2369 memmove(buf
, buf
+ processed
, buf_full
);
2372 if (saved_row
== 0) {
2373 assert(saved_column
== 0);
2375 /* First sequence, this is the cursor position before we set it somewhere
2376 * into the void at the bottom right. Let's save where we are so that we can
2379 /* Superficial validity checks */
2380 if (context
.row
<= 0 || context
.column
<= 0 || context
.row
>= 32766 || context
.column
>= 32766) {
2385 saved_row
= context
.row
;
2386 saved_column
= context
.column
;
2389 context
= (CursorPositionContext
) {};
2391 /* Second sequence, this is the cursor position after we set it somewhere
2392 * into the void at the bottom right. */
2394 /* Superficial validity checks (no particular reason to check for < 4, it's
2395 * just a way to look for unreasonably small values) */
2396 if (context
.row
< 4 || context
.column
< 4 || context
.row
>= 32766 || context
.column
>= 32766) {
2402 *ret_rows
= context
.row
;
2404 *ret_columns
= context
.column
;
2413 /* Restore cursor position */
2414 if (saved_row
> 0 && saved_column
> 0)
2415 RET_GATHER(r
, terminal_set_cursor_position(output_fd
, saved_row
, saved_column
));
2417 RET_GATHER(r
, RET_NERRNO(tcsetattr(input_fd
, TCSANOW
, &old_termios
)));
2421 int terminal_fix_size(int input_fd
, int output_fd
) {
2422 unsigned rows
, columns
;
2425 /* Tries to update the current terminal dimensions to the ones reported via ANSI sequences */
2427 r
= terminal_verify_same(input_fd
, output_fd
);
2431 struct winsize ws
= {};
2432 if (ioctl(output_fd
, TIOCGWINSZ
, &ws
) < 0)
2433 return log_debug_errno(errno
, "Failed to query terminal dimensions, ignoring: %m");
2435 r
= terminal_get_size_by_dsr(input_fd
, output_fd
, &rows
, &columns
);
2437 return log_debug_errno(r
, "Failed to acquire terminal dimensions via ANSI sequences, not adjusting terminal dimensions: %m");
2439 if (ws
.ws_row
== rows
&& ws
.ws_col
== columns
) {
2440 log_debug("Terminal dimensions reported via ANSI sequences match currently set terminal dimensions, not changing.");
2444 ws
.ws_col
= columns
;
2447 if (ioctl(output_fd
, TIOCSWINSZ
, &ws
) < 0)
2448 return log_debug_errno(errno
, "Failed to update terminal dimensions, ignoring: %m");
2450 log_debug("Fixed terminal dimensions to %ux%u based on ANSI sequence information.", columns
, rows
);
2454 #define MAX_TERMINFO_LENGTH 64
2455 /* python -c 'print("".join(hex(ord(i))[2:] for i in "name").upper())' */
2456 #define DCS_TERMINFO_Q ANSI_DCS "+q" "6E616D65" ANSI_ST
2457 /* The answer is either 0+r… (invalid) or 1+r… (OK). */
2458 #define DCS_TERMINFO_R0 ANSI_DCS "0+r" ANSI_ST
2459 #define DCS_TERMINFO_R1 ANSI_DCS "1+r" "6E616D65" "=" /* This is followed by Pt ST. */
2460 assert_cc(STRLEN(DCS_TERMINFO_R0
) <= STRLEN(DCS_TERMINFO_R1 ANSI_ST
));
2462 static int scan_terminfo_response(
2471 /* Check if we have enough space for the shortest possible answer. */
2472 if (size
< STRLEN(DCS_TERMINFO_R0
))
2475 /* Check if the terminating sequence is present */
2476 if (memcmp(buf
+ size
- STRLEN(ANSI_ST
), ANSI_ST
, STRLEN(ANSI_ST
)) != 0)
2479 if (size
<= STRLEN(DCS_TERMINFO_R1 ANSI_ST
))
2480 return -EINVAL
; /* The answer is invalid or empty */
2482 if (memcmp(buf
, DCS_TERMINFO_R1
, STRLEN(DCS_TERMINFO_R1
)) != 0)
2483 return -EINVAL
; /* The answer is not valid */
2485 _cleanup_free_
void *dec
= NULL
;
2487 r
= unhexmem_full(buf
+ STRLEN(DCS_TERMINFO_R1
), size
- STRLEN(DCS_TERMINFO_R1 ANSI_ST
),
2488 /* secure= */ false,
2493 assert(((const char *) dec
)[dec_size
] == '\0'); /* unhexmem appends NUL for our convenience */
2494 if (memchr(dec
, '\0', dec_size
) || string_has_cc(dec
, NULL
) || !filename_is_valid(dec
))
2497 *ret_name
= TAKE_PTR(dec
);
2501 int terminal_get_terminfo_by_dcs(int fd
, char **ret_name
) {
2507 /* Note: fd must be in non-blocking read-write mode! */
2509 struct termios old_termios
;
2510 if (tcgetattr(fd
, &old_termios
) < 0)
2513 struct termios new_termios
= old_termios
;
2514 termios_disable_echo(&new_termios
);
2516 if (tcsetattr(fd
, TCSANOW
, &new_termios
) < 0)
2519 r
= loop_write(fd
, DCS_TERMINFO_Q
, SIZE_MAX
);
2523 usec_t end
= usec_add(now(CLOCK_MONOTONIC
), CONSOLE_REPLY_WAIT_USEC
);
2524 char buf
[STRLEN(DCS_TERMINFO_R1
) + MAX_TERMINFO_LENGTH
+ STRLEN(ANSI_ST
)];
2528 usec_t n
= now(CLOCK_MONOTONIC
);
2534 r
= fd_wait_for_event(fd
, POLLIN
, usec_sub_unsigned(end
, n
));
2542 /* On the first read, read multiple characters, i.e. the shortest valid reply. Afterwards
2543 * read byte by byte, since we don't want to read too much and drop characters from the input
2545 ssize_t l
= read(fd
, buf
+ bytes
, bytes
== 0 ? STRLEN(DCS_TERMINFO_R0
) : 1);
2547 if (errno
== EAGAIN
)
2553 assert((size_t) l
<= sizeof(buf
) - bytes
);
2556 r
= scan_terminfo_response(buf
, bytes
, ret_name
);
2560 if (bytes
== sizeof(buf
)) {
2561 r
= -EOPNOTSUPP
; /* The response has the right prefix, but we didn't find a valid
2562 * answer with a terminator in the allotted space. Something is
2563 * wrong, possibly some unrelated bytes got injected into the
2570 /* We ignore failure here. We already got a reply and if cleanup fails, we can't help that. */
2571 (void) tcsetattr(fd
, TCSANOW
, &old_termios
);
2575 int have_terminfo_file(const char *name
) {
2576 /* This is a heuristic check if we have the file, using the directory layout used on
2577 * current Linux systems. Checks for other layouts can be added later if appropriate. */
2580 assert(filename_is_valid(name
));
2582 _cleanup_free_
char *p
= path_join("/usr/share/terminfo", CHAR_TO_STR(name
[0]), name
);
2584 return log_oom_debug();
2586 r
= RET_NERRNO(access(p
, F_OK
));
2594 int query_term_for_tty(const char *tty
, char **ret_term
) {
2595 _cleanup_free_
char *dcs_term
= NULL
;
2601 if (tty_is_vc_resolve(tty
))
2602 return strdup_to(ret_term
, "linux");
2604 /* Try to query the terminal implementation that we're on. This will not work in all
2605 * cases, which is fine, since this is intended to be used as a fallback. */
2607 _cleanup_close_
int tty_fd
= open_terminal(tty
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NONBLOCK
);
2609 return log_debug_errno(tty_fd
, "Failed to open %s to query terminfo: %m", tty
);
2611 r
= terminal_get_terminfo_by_dcs(tty_fd
, &dcs_term
);
2613 return log_debug_errno(r
, "Failed to query %s for terminfo: %m", tty
);
2615 r
= have_terminfo_file(dcs_term
);
2617 return log_debug_errno(r
, "Failed to look for terminfo %s: %m", dcs_term
);
2619 return log_info_errno(SYNTHETIC_ERRNO(ENODATA
),
2620 "Terminfo %s not found for %s.", dcs_term
, tty
);
2622 *ret_term
= TAKE_PTR(dcs_term
);
2626 int terminal_is_pty_fd(int fd
) {
2631 /* Returns true if we are looking at a pty, i.e. if it's backed by the /dev/pts/ file system */
2633 if (!isatty_safe(fd
))
2636 r
= is_fs_type_at(fd
, NULL
, DEVPTS_SUPER_MAGIC
);
2640 /* The ptmx device is weird, it exists twice, once inside and once outside devpts. To detect the
2641 * latter case, let's fire off an ioctl() that only works on ptmx devices. */
2644 if (ioctl(fd
, TIOCGPKT
, &v
) < 0) {
2645 if (ERRNO_IS_NOT_SUPPORTED(errno
))
2654 int pty_open_peer(int fd
, int mode
) {
2657 /* Opens the peer PTY using the new race-free TIOCGPTPEER ioctl() (kernel 4.13).
2659 * This is safe to be called on TTYs from other namespaces. */
2661 assert((mode
& (O_CREAT
|O_PATH
|O_DIRECTORY
|O_TMPFILE
)) == 0);
2663 /* This replicates the EIO retry logic of open_terminal() in a modified way. */
2664 for (unsigned c
= 0;; c
++) {
2665 int peer_fd
= ioctl(fd
, TIOCGPTPEER
, mode
);
2672 /* Max 1s in total */
2676 (void) usleep_safe(50 * USEC_PER_MSEC
);