1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include <sys/inotify.h>
29 #include <sys/socket.h>
30 #include <sys/sysmacros.h>
33 #include <linux/tiocl.h>
37 #include <sys/ioctl.h>
38 #include <sys/types.h>
42 #include "alloc-util.h"
50 #include "parse-util.h"
51 #include "path-util.h"
52 #include "proc-cmdline.h"
53 #include "process-util.h"
54 #include "socket-util.h"
55 #include "stat-util.h"
56 #include "string-util.h"
58 #include "terminal-util.h"
59 #include "time-util.h"
62 static volatile unsigned cached_columns
= 0;
63 static volatile unsigned cached_lines
= 0;
65 static volatile int cached_on_tty
= -1;
66 static volatile int cached_colors_enabled
= -1;
67 static volatile int cached_underline_enabled
= -1;
70 _cleanup_close_
int fd
;
72 /* Switch to the specified vt number. If the VT is specified <= 0 switch to the VT the kernel log messages go,
73 * if that's configured. */
75 fd
= open_terminal("/dev/tty0", O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NONBLOCK
);
81 TIOCL_GETKMSGREDIRECT
,
85 if (ioctl(fd
, TIOCLINUX
, tiocl
) < 0)
88 vt
= tiocl
[0] <= 0 ? 1 : tiocl
[0];
91 if (ioctl(fd
, VT_ACTIVATE
, vt
) < 0)
97 int read_one_char(FILE *f
, char *ret
, usec_t t
, bool *need_nl
) {
98 struct termios old_termios
, new_termios
;
99 char c
, line
[LINE_MAX
];
104 if (tcgetattr(fileno(f
), &old_termios
) >= 0) {
105 new_termios
= old_termios
;
107 new_termios
.c_lflag
&= ~ICANON
;
108 new_termios
.c_cc
[VMIN
] = 1;
109 new_termios
.c_cc
[VTIME
] = 0;
111 if (tcsetattr(fileno(f
), TCSADRAIN
, &new_termios
) >= 0) {
114 if (t
!= USEC_INFINITY
) {
115 if (fd_wait_for_event(fileno(f
), POLLIN
, t
) <= 0) {
116 tcsetattr(fileno(f
), TCSADRAIN
, &old_termios
);
121 k
= fread(&c
, 1, 1, f
);
123 tcsetattr(fileno(f
), TCSADRAIN
, &old_termios
);
129 *need_nl
= c
!= '\n';
136 if (t
!= USEC_INFINITY
) {
137 if (fd_wait_for_event(fileno(f
), POLLIN
, t
) <= 0)
142 if (!fgets(line
, sizeof(line
), f
))
143 return errno
> 0 ? -errno
: -EIO
;
147 if (strlen(line
) != 1)
157 #define DEFAULT_ASK_REFRESH_USEC (2*USEC_PER_SEC)
159 int ask_char(char *ret
, const char *replies
, const char *fmt
, ...) {
171 if (colors_enabled())
172 fputs(ANSI_HIGHLIGHT
, stdout
);
180 if (colors_enabled())
181 fputs(ANSI_NORMAL
, stdout
);
185 r
= read_one_char(stdin
, &c
, DEFAULT_ASK_REFRESH_USEC
, &need_nl
);
192 puts("Bad input, please try again.");
203 if (strchr(replies
, c
)) {
208 puts("Read unexpected character, please try again.");
212 int ask_string(char **ret
, const char *text
, ...) {
220 if (colors_enabled())
221 fputs(ANSI_HIGHLIGHT
, stdout
);
227 if (colors_enabled())
228 fputs(ANSI_NORMAL
, stdout
);
233 if (!fgets(line
, sizeof(line
), stdin
))
234 return errno
> 0 ? -errno
: -EIO
;
236 if (!endswith(line
, "\n"))
255 int reset_terminal_fd(int fd
, bool switch_to_text
) {
256 struct termios termios
;
259 /* Set terminal to some sane defaults */
263 /* We leave locked terminal attributes untouched, so that
264 * Plymouth may set whatever it wants to set, and we don't
265 * interfere with that. */
267 /* Disable exclusive mode, just in case */
268 (void) ioctl(fd
, TIOCNXCL
);
270 /* Switch to text mode */
272 (void) ioctl(fd
, KDSETMODE
, KD_TEXT
);
274 /* Set default keyboard mode */
275 (void) vt_reset_keyboard(fd
);
277 if (tcgetattr(fd
, &termios
) < 0) {
282 /* We only reset the stuff that matters to the software. How
283 * hardware is set up we don't touch assuming that somebody
284 * else will do that for us */
286 termios
.c_iflag
&= ~(IGNBRK
| BRKINT
| ISTRIP
| INLCR
| IGNCR
| IUCLC
);
287 termios
.c_iflag
|= ICRNL
| IMAXBEL
| IUTF8
;
288 termios
.c_oflag
|= ONLCR
;
289 termios
.c_cflag
|= CREAD
;
290 termios
.c_lflag
= ISIG
| ICANON
| IEXTEN
| ECHO
| ECHOE
| ECHOK
| ECHOCTL
| ECHOPRT
| ECHOKE
;
292 termios
.c_cc
[VINTR
] = 03; /* ^C */
293 termios
.c_cc
[VQUIT
] = 034; /* ^\ */
294 termios
.c_cc
[VERASE
] = 0177;
295 termios
.c_cc
[VKILL
] = 025; /* ^X */
296 termios
.c_cc
[VEOF
] = 04; /* ^D */
297 termios
.c_cc
[VSTART
] = 021; /* ^Q */
298 termios
.c_cc
[VSTOP
] = 023; /* ^S */
299 termios
.c_cc
[VSUSP
] = 032; /* ^Z */
300 termios
.c_cc
[VLNEXT
] = 026; /* ^V */
301 termios
.c_cc
[VWERASE
] = 027; /* ^W */
302 termios
.c_cc
[VREPRINT
] = 022; /* ^R */
303 termios
.c_cc
[VEOL
] = 0;
304 termios
.c_cc
[VEOL2
] = 0;
306 termios
.c_cc
[VTIME
] = 0;
307 termios
.c_cc
[VMIN
] = 1;
309 if (tcsetattr(fd
, TCSANOW
, &termios
) < 0)
313 /* Just in case, flush all crap out */
314 (void) tcflush(fd
, TCIOFLUSH
);
319 int reset_terminal(const char *name
) {
320 _cleanup_close_
int fd
= -1;
322 /* We open the terminal with O_NONBLOCK here, to ensure we
323 * don't block on carrier if this is a terminal with carrier
326 fd
= open_terminal(name
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NONBLOCK
);
330 return reset_terminal_fd(fd
, true);
333 int open_terminal(const char *name
, int mode
) {
338 * If a TTY is in the process of being closed opening it might
339 * cause EIO. This is horribly awful, but unlikely to be
340 * changed in the kernel. Hence we work around this problem by
341 * retrying a couple of times.
343 * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245
350 fd
= open(name
, mode
, 0);
357 /* Max 1s in total */
361 usleep(50 * USEC_PER_MSEC
);
365 if (isatty(fd
) <= 0) {
373 int acquire_terminal(
375 AcquireTerminalFlags flags
,
378 _cleanup_close_
int notify
= -1, fd
= -1;
379 usec_t ts
= USEC_INFINITY
;
383 assert(IN_SET(flags
& ~ACQUIRE_TERMINAL_PERMISSIVE
, ACQUIRE_TERMINAL_TRY
, ACQUIRE_TERMINAL_FORCE
, ACQUIRE_TERMINAL_WAIT
));
385 /* We use inotify to be notified when the tty is closed. We create the watch before checking if we can actually
386 * acquire it, so that we don't lose any event.
388 * Note: strictly speaking this actually watches for the device being closed, it does *not* really watch
389 * whether a tty loses its controlling process. However, unless some rogue process uses TIOCNOTTY on /dev/tty
390 * *after* closing its tty otherwise this will not become a problem. As long as the administrator makes sure to
391 * not configure any service on the same tty as an untrusted user this should not be a problem. (Which they
392 * probably should not do anyway.) */
394 if ((flags
& ~ACQUIRE_TERMINAL_PERMISSIVE
) == ACQUIRE_TERMINAL_WAIT
) {
395 notify
= inotify_init1(IN_CLOEXEC
| (timeout
!= USEC_INFINITY
? IN_NONBLOCK
: 0));
399 wd
= inotify_add_watch(notify
, name
, IN_CLOSE
);
403 if (timeout
!= USEC_INFINITY
)
404 ts
= now(CLOCK_MONOTONIC
);
408 struct sigaction sa_old
, sa_new
= {
409 .sa_handler
= SIG_IGN
,
410 .sa_flags
= SA_RESTART
,
414 r
= flush_fd(notify
);
419 /* We pass here O_NOCTTY only so that we can check the return value TIOCSCTTY and have a reliable way
420 * to figure out if we successfully became the controlling process of the tty */
421 fd
= open_terminal(name
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
425 /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed if we already own the tty. */
426 assert_se(sigaction(SIGHUP
, &sa_new
, &sa_old
) == 0);
428 /* First, try to get the tty */
429 r
= ioctl(fd
, TIOCSCTTY
,
430 (flags
& ~ACQUIRE_TERMINAL_PERMISSIVE
) == ACQUIRE_TERMINAL_FORCE
) < 0 ? -errno
: 0;
432 /* Reset signal handler to old value */
433 assert_se(sigaction(SIGHUP
, &sa_old
, NULL
) == 0);
435 /* Success? Exit the loop now! */
439 /* Any failure besides -EPERM? Fail, regardless of the mode. */
443 if (flags
& ACQUIRE_TERMINAL_PERMISSIVE
) /* If we are in permissive mode, then EPERM is fine, turn this
444 * into a success. Note that EPERM is also returned if we
445 * already are the owner of the TTY. */
448 if (flags
!= ACQUIRE_TERMINAL_WAIT
) /* If we are in TRY or FORCE mode, then propagate EPERM as EPERM */
455 union inotify_event_buffer buffer
;
456 struct inotify_event
*e
;
459 if (timeout
!= USEC_INFINITY
) {
462 assert(ts
!= USEC_INFINITY
);
464 n
= now(CLOCK_MONOTONIC
);
465 if (ts
+ timeout
< n
)
468 r
= fd_wait_for_event(notify
, POLLIN
, ts
+ timeout
- n
);
475 l
= read(notify
, &buffer
, sizeof(buffer
));
477 if (IN_SET(errno
, EINTR
, EAGAIN
))
483 FOREACH_INOTIFY_EVENT(e
, buffer
, l
) {
484 if (e
->mask
& IN_Q_OVERFLOW
) /* If we hit an inotify queue overflow, simply check if the terminal is up for grabs now. */
487 if (e
->wd
!= wd
|| !(e
->mask
& IN_CLOSE
)) /* Safety checks */
494 /* We close the tty fd here since if the old session ended our handle will be dead. It's important that
495 * we do this after sleeping, so that we don't enter an endless loop. */
505 int release_terminal(void) {
506 static const struct sigaction sa_new
= {
507 .sa_handler
= SIG_IGN
,
508 .sa_flags
= SA_RESTART
,
511 _cleanup_close_
int fd
= -1;
512 struct sigaction sa_old
;
515 fd
= open("/dev/tty", O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NONBLOCK
);
519 /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
520 * by our own TIOCNOTTY */
521 assert_se(sigaction(SIGHUP
, &sa_new
, &sa_old
) == 0);
523 r
= ioctl(fd
, TIOCNOTTY
) < 0 ? -errno
: 0;
525 assert_se(sigaction(SIGHUP
, &sa_old
, NULL
) == 0);
530 int terminal_vhangup_fd(int fd
) {
533 if (ioctl(fd
, TIOCVHANGUP
) < 0)
539 int terminal_vhangup(const char *name
) {
540 _cleanup_close_
int fd
;
542 fd
= open_terminal(name
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NONBLOCK
);
546 return terminal_vhangup_fd(fd
);
549 int vt_disallocate(const char *name
) {
550 _cleanup_close_
int fd
= -1;
555 /* Deallocate the VT if possible. If not possible
556 * (i.e. because it is the active one), at least clear it
557 * entirely (including the scrollback buffer) */
559 e
= path_startswith(name
, "/dev/");
563 if (!tty_is_vc(name
)) {
564 /* So this is not a VT. I guess we cannot deallocate
565 * it then. But let's at least clear the screen */
567 fd
= open_terminal(name
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
572 "\033[r" /* clear scrolling region */
573 "\033[H" /* move home */
574 "\033[2J", /* clear screen */
579 n
= startswith(e
, "tty");
583 r
= safe_atou(n
, &u
);
590 /* Try to deallocate */
591 fd
= open_terminal("/dev/tty0", O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NONBLOCK
);
595 r
= ioctl(fd
, VT_DISALLOCATE
, u
);
604 /* Couldn't deallocate, so let's clear it fully with
606 fd
= open_terminal(name
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
611 "\033[r" /* clear scrolling region */
612 "\033[H" /* move home */
613 "\033[3J", /* clear screen including scrollback, requires Linux 2.6.40 */
618 int make_console_stdio(void) {
621 /* Make /dev/console the controlling terminal and stdin/stdout/stderr */
623 fd
= acquire_terminal("/dev/console", ACQUIRE_TERMINAL_FORCE
|ACQUIRE_TERMINAL_PERMISSIVE
, USEC_INFINITY
);
625 return log_error_errno(fd
, "Failed to acquire terminal: %m");
627 r
= reset_terminal_fd(fd
, true);
629 log_warning_errno(r
, "Failed to reset terminal, ignoring: %m");
633 return log_error_errno(r
, "Failed to duplicate terminal fd: %m");
635 reset_terminal_feature_caches();
640 bool tty_is_vc(const char *tty
) {
643 return vtnr_from_tty(tty
) >= 0;
646 bool tty_is_console(const char *tty
) {
649 return streq(skip_dev_prefix(tty
), "console");
652 int vtnr_from_tty(const char *tty
) {
657 tty
= skip_dev_prefix(tty
);
659 if (!startswith(tty
, "tty") )
662 if (tty
[3] < '0' || tty
[3] > '9')
665 r
= safe_atoi(tty
+3, &i
);
675 int resolve_dev_console(char **ret
) {
676 _cleanup_free_
char *active
= NULL
;
682 /* Resolve where /dev/console is pointing to, if /sys is actually ours (i.e. not read-only-mounted which is a
683 * sign for container setups) */
685 if (path_is_read_only_fs("/sys") > 0)
688 r
= read_one_line_file("/sys/class/tty/console/active", &active
);
692 /* If multiple log outputs are configured the last one is what /dev/console points to */
693 tty
= strrchr(active
, ' ');
699 if (streq(tty
, "tty0")) {
700 active
= mfree(active
);
702 /* Get the active VC (e.g. tty1) */
703 r
= read_one_line_file("/sys/class/tty/tty0/active", &active
);
726 int get_kernel_consoles(char ***ret
) {
727 _cleanup_strv_free_
char **l
= NULL
;
728 _cleanup_free_
char *line
= NULL
;
734 /* If /sys is mounted read-only this means we are running in some kind of container environment. In that
735 * case /sys would reflect the host system, not us, hence ignore the data we can read from it. */
736 if (path_is_read_only_fs("/sys") > 0)
739 r
= read_one_line_file("/sys/class/tty/console/active", &line
);
745 _cleanup_free_
char *tty
= NULL
;
748 r
= extract_first_word(&p
, &tty
, NULL
, 0);
754 if (streq(tty
, "tty0")) {
756 r
= read_one_line_file("/sys/class/tty/tty0/active", &tty
);
761 path
= strappend("/dev/", tty
);
765 if (access(path
, F_OK
) < 0) {
766 log_debug_errno(errno
, "Console device %s is not accessible, skipping: %m", path
);
771 r
= strv_consume(&l
, path
);
776 if (strv_isempty(l
)) {
777 log_debug("No devices found for system console");
787 r
= strv_extend(&l
, "/dev/console");
797 bool tty_is_vc_resolve(const char *tty
) {
798 _cleanup_free_
char *resolved
= NULL
;
802 tty
= skip_dev_prefix(tty
);
804 if (streq(tty
, "console")) {
805 if (resolve_dev_console(&resolved
) < 0)
811 return tty_is_vc(tty
);
814 const char *default_term_for_tty(const char *tty
) {
815 return tty
&& tty_is_vc_resolve(tty
) ? "linux" : "vt220";
818 int fd_columns(int fd
) {
819 struct winsize ws
= {};
821 if (ioctl(fd
, TIOCGWINSZ
, &ws
) < 0)
830 unsigned columns(void) {
834 if (cached_columns
> 0)
835 return cached_columns
;
838 e
= getenv("COLUMNS");
840 (void) safe_atoi(e
, &c
);
843 c
= fd_columns(STDOUT_FILENO
);
849 return cached_columns
;
852 int fd_lines(int fd
) {
853 struct winsize ws
= {};
855 if (ioctl(fd
, TIOCGWINSZ
, &ws
) < 0)
864 unsigned lines(void) {
868 if (cached_lines
> 0)
874 (void) safe_atoi(e
, &l
);
877 l
= fd_lines(STDOUT_FILENO
);
886 /* intended to be used as a SIGWINCH sighandler */
887 void columns_lines_cache_reset(int signum
) {
892 void reset_terminal_feature_caches(void) {
896 cached_colors_enabled
= -1;
897 cached_underline_enabled
= -1;
902 if (cached_on_tty
< 0)
903 cached_on_tty
= isatty(STDOUT_FILENO
) > 0;
905 return cached_on_tty
;
908 int make_stdio(int fd
) {
913 if (dup2(fd
, STDIN_FILENO
) < 0)
915 if (dup2(fd
, STDOUT_FILENO
) < 0 && r
>= 0)
917 if (dup2(fd
, STDERR_FILENO
) < 0 && r
>= 0)
920 safe_close_above_stdio(fd
);
922 /* Explicitly unset O_CLOEXEC, since if fd was < 3, then dup2() was a NOP and the bit hence possibly set. */
923 stdio_unset_cloexec();
928 int make_null_stdio(void) {
931 null_fd
= open("/dev/null", O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
935 r
= make_stdio(null_fd
);
937 reset_terminal_feature_caches();
942 int getttyname_malloc(int fd
, char **ret
) {
952 r
= ttyname_r(fd
, path
, sizeof(path
));
956 c
= strdup(skip_dev_prefix(path
));
973 int getttyname_harder(int fd
, char **r
) {
977 k
= getttyname_malloc(fd
, &s
);
981 if (streq(s
, "tty")) {
983 return get_ctty(0, NULL
, r
);
990 int get_ctty_devnr(pid_t pid
, dev_t
*d
) {
992 _cleanup_free_
char *line
= NULL
;
998 p
= procfs_file_alloca(pid
, "stat");
999 r
= read_one_line_file(p
, &line
);
1003 p
= strrchr(line
, ')');
1013 "%*d " /* session */
1018 if (major(ttynr
) == 0 && minor(ttynr
) == 0)
1027 int get_ctty(pid_t pid
, dev_t
*_devnr
, char **r
) {
1028 char fn
[STRLEN("/dev/char/") + 2*DECIMAL_STR_MAX(unsigned) + 1 + 1], *b
= NULL
;
1029 _cleanup_free_
char *s
= NULL
;
1036 k
= get_ctty_devnr(pid
, &devnr
);
1040 sprintf(fn
, "/dev/char/%u:%u", major(devnr
), minor(devnr
));
1042 k
= readlink_malloc(fn
, &s
);
1048 /* This is an ugly hack */
1049 if (major(devnr
) == 136) {
1050 if (asprintf(&b
, "pts/%u", minor(devnr
)) < 0)
1053 /* Probably something like the ptys which have no
1054 * symlink in /dev/char. Let's return something
1055 * vaguely useful. */
1062 if (startswith(s
, "/dev/"))
1064 else if (startswith(s
, "../"))
1081 int ptsname_malloc(int fd
, char **ret
) {
1094 if (ptsname_r(fd
, c
, l
) == 0) {
1098 if (errno
!= ERANGE
) {
1108 int ptsname_namespace(int pty
, char **ret
) {
1111 /* Like ptsname(), but doesn't assume that the path is
1112 * accessible in the local namespace. */
1114 r
= ioctl(pty
, TIOCGPTN
, &no
);
1121 if (asprintf(ret
, "/dev/pts/%i", no
) < 0)
1127 int openpt_in_namespace(pid_t pid
, int flags
) {
1128 _cleanup_close_
int pidnsfd
= -1, mntnsfd
= -1, usernsfd
= -1, rootfd
= -1;
1129 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
1135 r
= namespace_open(pid
, &pidnsfd
, &mntnsfd
, NULL
, &usernsfd
, &rootfd
);
1139 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, pair
) < 0)
1142 r
= safe_fork("(sd-openpt)", FORK_RESET_SIGNALS
|FORK_DEATHSIG
, &child
);
1148 pair
[0] = safe_close(pair
[0]);
1150 r
= namespace_enter(pidnsfd
, mntnsfd
, -1, usernsfd
, rootfd
);
1152 _exit(EXIT_FAILURE
);
1154 master
= posix_openpt(flags
|O_NOCTTY
|O_CLOEXEC
);
1156 _exit(EXIT_FAILURE
);
1158 if (unlockpt(master
) < 0)
1159 _exit(EXIT_FAILURE
);
1161 if (send_one_fd(pair
[1], master
, 0) < 0)
1162 _exit(EXIT_FAILURE
);
1164 _exit(EXIT_SUCCESS
);
1167 pair
[1] = safe_close(pair
[1]);
1169 r
= wait_for_terminate_and_check("(sd-openpt)", child
, 0);
1172 if (r
!= EXIT_SUCCESS
)
1175 return receive_one_fd(pair
[0], 0);
1178 int open_terminal_in_namespace(pid_t pid
, const char *name
, int mode
) {
1179 _cleanup_close_
int pidnsfd
= -1, mntnsfd
= -1, usernsfd
= -1, rootfd
= -1;
1180 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
1184 r
= namespace_open(pid
, &pidnsfd
, &mntnsfd
, NULL
, &usernsfd
, &rootfd
);
1188 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, pair
) < 0)
1191 r
= safe_fork("(sd-terminal)", FORK_RESET_SIGNALS
|FORK_DEATHSIG
, &child
);
1197 pair
[0] = safe_close(pair
[0]);
1199 r
= namespace_enter(pidnsfd
, mntnsfd
, -1, usernsfd
, rootfd
);
1201 _exit(EXIT_FAILURE
);
1203 master
= open_terminal(name
, mode
|O_NOCTTY
|O_CLOEXEC
);
1205 _exit(EXIT_FAILURE
);
1207 if (send_one_fd(pair
[1], master
, 0) < 0)
1208 _exit(EXIT_FAILURE
);
1210 _exit(EXIT_SUCCESS
);
1213 pair
[1] = safe_close(pair
[1]);
1215 r
= wait_for_terminate_and_check("(sd-terminal)", child
, 0);
1218 if (r
!= EXIT_SUCCESS
)
1221 return receive_one_fd(pair
[0], 0);
1224 static bool getenv_terminal_is_dumb(void) {
1231 return streq(e
, "dumb");
1234 bool terminal_is_dumb(void) {
1238 return getenv_terminal_is_dumb();
1241 bool colors_enabled(void) {
1243 /* Returns true if colors are considered supported on our stdout. For that we check $SYSTEMD_COLORS first
1244 * (which is the explicit way to turn colors on/off). If that didn't work we turn colors off unless we are on a
1245 * TTY. And if we are on a TTY we turn it off if $TERM is set to "dumb". There's one special tweak though: if
1246 * we are PID 1 then we do not check whether we are connected to a TTY, because we don't keep /dev/console open
1247 * continously due to fear of SAK, and hence things are a bit weird. */
1249 if (cached_colors_enabled
< 0) {
1252 val
= getenv_bool("SYSTEMD_COLORS");
1254 cached_colors_enabled
= val
;
1255 else if (getpid_cached() == 1)
1256 /* PID1 outputs to the console without holding it open all the time */
1257 cached_colors_enabled
= !getenv_terminal_is_dumb();
1259 cached_colors_enabled
= !terminal_is_dumb();
1262 return cached_colors_enabled
;
1265 bool dev_console_colors_enabled(void) {
1266 _cleanup_free_
char *s
= NULL
;
1269 /* Returns true if we assume that color is supported on /dev/console.
1271 * For that we first check if we explicitly got told to use colors or not, by checking $SYSTEMD_COLORS. If that
1272 * isn't set we check whether PID 1 has $TERM set, and if not, whether TERM is set on the kernel command
1273 * line. If we find $TERM set we assume color if it's not set to "dumb", similarly to how regular
1274 * colors_enabled() operates. */
1276 b
= getenv_bool("SYSTEMD_COLORS");
1280 if (getenv_for_pid(1, "TERM", &s
) <= 0)
1281 (void) proc_cmdline_get_key("TERM", 0, &s
);
1283 return !streq_ptr(s
, "dumb");
1286 bool underline_enabled(void) {
1288 if (cached_underline_enabled
< 0) {
1290 /* The Linux console doesn't support underlining, turn it off, but only there. */
1292 if (colors_enabled())
1293 cached_underline_enabled
= !streq_ptr(getenv("TERM"), "linux");
1295 cached_underline_enabled
= false;
1298 return cached_underline_enabled
;
1301 int vt_default_utf8(void) {
1302 _cleanup_free_
char *b
= NULL
;
1305 /* Read the default VT UTF8 setting from the kernel */
1307 r
= read_one_line_file("/sys/module/vt/parameters/default_utf8", &b
);
1311 return parse_boolean(b
);
1314 int vt_reset_keyboard(int fd
) {
1317 /* If we can't read the default, then default to unicode. It's 2017 after all. */
1318 kb
= vt_default_utf8() != 0 ? K_UNICODE
: K_XLATE
;
1320 if (ioctl(fd
, KDSKBMODE
, kb
) < 0)