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");
631 r
= rearrange_stdio(fd
, fd
, fd
); /* This invalidates 'fd' both on success and on failure. */
633 return log_error_errno(r
, "Failed to make terminal stdin/stdout/stderr: %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
);
711 *ret
= TAKE_PTR(active
);
725 int get_kernel_consoles(char ***ret
) {
726 _cleanup_strv_free_
char **l
= NULL
;
727 _cleanup_free_
char *line
= NULL
;
733 /* If /sys is mounted read-only this means we are running in some kind of container environment. In that
734 * case /sys would reflect the host system, not us, hence ignore the data we can read from it. */
735 if (path_is_read_only_fs("/sys") > 0)
738 r
= read_one_line_file("/sys/class/tty/console/active", &line
);
744 _cleanup_free_
char *tty
= NULL
;
747 r
= extract_first_word(&p
, &tty
, NULL
, 0);
753 if (streq(tty
, "tty0")) {
755 r
= read_one_line_file("/sys/class/tty/tty0/active", &tty
);
760 path
= strappend("/dev/", tty
);
764 if (access(path
, F_OK
) < 0) {
765 log_debug_errno(errno
, "Console device %s is not accessible, skipping: %m", path
);
770 r
= strv_consume(&l
, path
);
775 if (strv_isempty(l
)) {
776 log_debug("No devices found for system console");
785 r
= strv_extend(&l
, "/dev/console");
794 bool tty_is_vc_resolve(const char *tty
) {
795 _cleanup_free_
char *resolved
= NULL
;
799 tty
= skip_dev_prefix(tty
);
801 if (streq(tty
, "console")) {
802 if (resolve_dev_console(&resolved
) < 0)
808 return tty_is_vc(tty
);
811 const char *default_term_for_tty(const char *tty
) {
812 return tty
&& tty_is_vc_resolve(tty
) ? "linux" : "vt220";
815 int fd_columns(int fd
) {
816 struct winsize ws
= {};
818 if (ioctl(fd
, TIOCGWINSZ
, &ws
) < 0)
827 unsigned columns(void) {
831 if (cached_columns
> 0)
832 return cached_columns
;
835 e
= getenv("COLUMNS");
837 (void) safe_atoi(e
, &c
);
840 c
= fd_columns(STDOUT_FILENO
);
846 return cached_columns
;
849 int fd_lines(int fd
) {
850 struct winsize ws
= {};
852 if (ioctl(fd
, TIOCGWINSZ
, &ws
) < 0)
861 unsigned lines(void) {
865 if (cached_lines
> 0)
871 (void) safe_atoi(e
, &l
);
874 l
= fd_lines(STDOUT_FILENO
);
883 /* intended to be used as a SIGWINCH sighandler */
884 void columns_lines_cache_reset(int signum
) {
889 void reset_terminal_feature_caches(void) {
893 cached_colors_enabled
= -1;
894 cached_underline_enabled
= -1;
899 if (cached_on_tty
< 0)
900 cached_on_tty
= isatty(STDOUT_FILENO
) > 0;
902 return cached_on_tty
;
905 int getttyname_malloc(int fd
, char **ret
) {
915 r
= ttyname_r(fd
, path
, sizeof(path
));
919 c
= strdup(skip_dev_prefix(path
));
936 int getttyname_harder(int fd
, char **r
) {
940 k
= getttyname_malloc(fd
, &s
);
944 if (streq(s
, "tty")) {
946 return get_ctty(0, NULL
, r
);
953 int get_ctty_devnr(pid_t pid
, dev_t
*d
) {
955 _cleanup_free_
char *line
= NULL
;
961 p
= procfs_file_alloca(pid
, "stat");
962 r
= read_one_line_file(p
, &line
);
966 p
= strrchr(line
, ')');
981 if (major(ttynr
) == 0 && minor(ttynr
) == 0)
990 int get_ctty(pid_t pid
, dev_t
*_devnr
, char **r
) {
991 char fn
[STRLEN("/dev/char/") + 2*DECIMAL_STR_MAX(unsigned) + 1 + 1], *b
= NULL
;
992 _cleanup_free_
char *s
= NULL
;
999 k
= get_ctty_devnr(pid
, &devnr
);
1003 sprintf(fn
, "/dev/char/%u:%u", major(devnr
), minor(devnr
));
1005 k
= readlink_malloc(fn
, &s
);
1011 /* This is an ugly hack */
1012 if (major(devnr
) == 136) {
1013 if (asprintf(&b
, "pts/%u", minor(devnr
)) < 0)
1016 /* Probably something like the ptys which have no
1017 * symlink in /dev/char. Let's return something
1018 * vaguely useful. */
1025 if (startswith(s
, "/dev/"))
1027 else if (startswith(s
, "../"))
1044 int ptsname_malloc(int fd
, char **ret
) {
1057 if (ptsname_r(fd
, c
, l
) == 0) {
1061 if (errno
!= ERANGE
) {
1071 int ptsname_namespace(int pty
, char **ret
) {
1074 /* Like ptsname(), but doesn't assume that the path is
1075 * accessible in the local namespace. */
1077 r
= ioctl(pty
, TIOCGPTN
, &no
);
1084 if (asprintf(ret
, "/dev/pts/%i", no
) < 0)
1090 int openpt_in_namespace(pid_t pid
, int flags
) {
1091 _cleanup_close_
int pidnsfd
= -1, mntnsfd
= -1, usernsfd
= -1, rootfd
= -1;
1092 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
1098 r
= namespace_open(pid
, &pidnsfd
, &mntnsfd
, NULL
, &usernsfd
, &rootfd
);
1102 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, pair
) < 0)
1105 r
= safe_fork("(sd-openpt)", FORK_RESET_SIGNALS
|FORK_DEATHSIG
, &child
);
1111 pair
[0] = safe_close(pair
[0]);
1113 r
= namespace_enter(pidnsfd
, mntnsfd
, -1, usernsfd
, rootfd
);
1115 _exit(EXIT_FAILURE
);
1117 master
= posix_openpt(flags
|O_NOCTTY
|O_CLOEXEC
);
1119 _exit(EXIT_FAILURE
);
1121 if (unlockpt(master
) < 0)
1122 _exit(EXIT_FAILURE
);
1124 if (send_one_fd(pair
[1], master
, 0) < 0)
1125 _exit(EXIT_FAILURE
);
1127 _exit(EXIT_SUCCESS
);
1130 pair
[1] = safe_close(pair
[1]);
1132 r
= wait_for_terminate_and_check("(sd-openpt)", child
, 0);
1135 if (r
!= EXIT_SUCCESS
)
1138 return receive_one_fd(pair
[0], 0);
1141 int open_terminal_in_namespace(pid_t pid
, const char *name
, int mode
) {
1142 _cleanup_close_
int pidnsfd
= -1, mntnsfd
= -1, usernsfd
= -1, rootfd
= -1;
1143 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
1147 r
= namespace_open(pid
, &pidnsfd
, &mntnsfd
, NULL
, &usernsfd
, &rootfd
);
1151 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, pair
) < 0)
1154 r
= safe_fork("(sd-terminal)", FORK_RESET_SIGNALS
|FORK_DEATHSIG
, &child
);
1160 pair
[0] = safe_close(pair
[0]);
1162 r
= namespace_enter(pidnsfd
, mntnsfd
, -1, usernsfd
, rootfd
);
1164 _exit(EXIT_FAILURE
);
1166 master
= open_terminal(name
, mode
|O_NOCTTY
|O_CLOEXEC
);
1168 _exit(EXIT_FAILURE
);
1170 if (send_one_fd(pair
[1], master
, 0) < 0)
1171 _exit(EXIT_FAILURE
);
1173 _exit(EXIT_SUCCESS
);
1176 pair
[1] = safe_close(pair
[1]);
1178 r
= wait_for_terminate_and_check("(sd-terminal)", child
, 0);
1181 if (r
!= EXIT_SUCCESS
)
1184 return receive_one_fd(pair
[0], 0);
1187 static bool getenv_terminal_is_dumb(void) {
1194 return streq(e
, "dumb");
1197 bool terminal_is_dumb(void) {
1201 return getenv_terminal_is_dumb();
1204 bool colors_enabled(void) {
1206 /* Returns true if colors are considered supported on our stdout. For that we check $SYSTEMD_COLORS first
1207 * (which is the explicit way to turn colors on/off). If that didn't work we turn colors off unless we are on a
1208 * 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
1209 * we are PID 1 then we do not check whether we are connected to a TTY, because we don't keep /dev/console open
1210 * continously due to fear of SAK, and hence things are a bit weird. */
1212 if (cached_colors_enabled
< 0) {
1215 val
= getenv_bool("SYSTEMD_COLORS");
1217 cached_colors_enabled
= val
;
1218 else if (getpid_cached() == 1)
1219 /* PID1 outputs to the console without holding it open all the time */
1220 cached_colors_enabled
= !getenv_terminal_is_dumb();
1222 cached_colors_enabled
= !terminal_is_dumb();
1225 return cached_colors_enabled
;
1228 bool dev_console_colors_enabled(void) {
1229 _cleanup_free_
char *s
= NULL
;
1232 /* Returns true if we assume that color is supported on /dev/console.
1234 * For that we first check if we explicitly got told to use colors or not, by checking $SYSTEMD_COLORS. If that
1235 * isn't set we check whether PID 1 has $TERM set, and if not, whether TERM is set on the kernel command
1236 * line. If we find $TERM set we assume color if it's not set to "dumb", similarly to how regular
1237 * colors_enabled() operates. */
1239 b
= getenv_bool("SYSTEMD_COLORS");
1243 if (getenv_for_pid(1, "TERM", &s
) <= 0)
1244 (void) proc_cmdline_get_key("TERM", 0, &s
);
1246 return !streq_ptr(s
, "dumb");
1249 bool underline_enabled(void) {
1251 if (cached_underline_enabled
< 0) {
1253 /* The Linux console doesn't support underlining, turn it off, but only there. */
1255 if (colors_enabled())
1256 cached_underline_enabled
= !streq_ptr(getenv("TERM"), "linux");
1258 cached_underline_enabled
= false;
1261 return cached_underline_enabled
;
1264 int vt_default_utf8(void) {
1265 _cleanup_free_
char *b
= NULL
;
1268 /* Read the default VT UTF8 setting from the kernel */
1270 r
= read_one_line_file("/sys/module/vt/parameters/default_utf8", &b
);
1274 return parse_boolean(b
);
1277 int vt_reset_keyboard(int fd
) {
1280 /* If we can't read the default, then default to unicode. It's 2017 after all. */
1281 kb
= vt_default_utf8() != 0 ? K_UNICODE
: K_XLATE
;
1283 if (ioctl(fd
, KDSKBMODE
, kb
) < 0)