]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/terminal-util.c
macro: introduce new TAKE_FD() macro
[thirdparty/systemd.git] / src / basic / terminal-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6
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.
11
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.
16
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/>.
19 ***/
20
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <limits.h>
24 #include <stdarg.h>
25 #include <stddef.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/inotify.h>
29 #include <sys/socket.h>
30 #include <sys/sysmacros.h>
31 #include <sys/time.h>
32 #include <linux/kd.h>
33 #include <linux/tiocl.h>
34 #include <linux/vt.h>
35 #include <poll.h>
36 #include <signal.h>
37 #include <sys/ioctl.h>
38 #include <sys/types.h>
39 #include <termios.h>
40 #include <unistd.h>
41
42 #include "alloc-util.h"
43 #include "env-util.h"
44 #include "fd-util.h"
45 #include "fileio.h"
46 #include "fs-util.h"
47 #include "io-util.h"
48 #include "log.h"
49 #include "macro.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"
57 #include "strv.h"
58 #include "terminal-util.h"
59 #include "time-util.h"
60 #include "util.h"
61
62 static volatile unsigned cached_columns = 0;
63 static volatile unsigned cached_lines = 0;
64
65 static volatile int cached_on_tty = -1;
66 static volatile int cached_colors_enabled = -1;
67 static volatile int cached_underline_enabled = -1;
68
69 int chvt(int vt) {
70 _cleanup_close_ int fd;
71
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. */
74
75 fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
76 if (fd < 0)
77 return -errno;
78
79 if (vt <= 0) {
80 int tiocl[2] = {
81 TIOCL_GETKMSGREDIRECT,
82 0
83 };
84
85 if (ioctl(fd, TIOCLINUX, tiocl) < 0)
86 return -errno;
87
88 vt = tiocl[0] <= 0 ? 1 : tiocl[0];
89 }
90
91 if (ioctl(fd, VT_ACTIVATE, vt) < 0)
92 return -errno;
93
94 return 0;
95 }
96
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];
100
101 assert(f);
102 assert(ret);
103
104 if (tcgetattr(fileno(f), &old_termios) >= 0) {
105 new_termios = old_termios;
106
107 new_termios.c_lflag &= ~ICANON;
108 new_termios.c_cc[VMIN] = 1;
109 new_termios.c_cc[VTIME] = 0;
110
111 if (tcsetattr(fileno(f), TCSADRAIN, &new_termios) >= 0) {
112 size_t k;
113
114 if (t != USEC_INFINITY) {
115 if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0) {
116 tcsetattr(fileno(f), TCSADRAIN, &old_termios);
117 return -ETIMEDOUT;
118 }
119 }
120
121 k = fread(&c, 1, 1, f);
122
123 tcsetattr(fileno(f), TCSADRAIN, &old_termios);
124
125 if (k <= 0)
126 return -EIO;
127
128 if (need_nl)
129 *need_nl = c != '\n';
130
131 *ret = c;
132 return 0;
133 }
134 }
135
136 if (t != USEC_INFINITY) {
137 if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0)
138 return -ETIMEDOUT;
139 }
140
141 errno = 0;
142 if (!fgets(line, sizeof(line), f))
143 return errno > 0 ? -errno : -EIO;
144
145 truncate_nl(line);
146
147 if (strlen(line) != 1)
148 return -EBADMSG;
149
150 if (need_nl)
151 *need_nl = false;
152
153 *ret = line[0];
154 return 0;
155 }
156
157 #define DEFAULT_ASK_REFRESH_USEC (2*USEC_PER_SEC)
158
159 int ask_char(char *ret, const char *replies, const char *fmt, ...) {
160 int r;
161
162 assert(ret);
163 assert(replies);
164 assert(fmt);
165
166 for (;;) {
167 va_list ap;
168 char c;
169 bool need_nl = true;
170
171 if (colors_enabled())
172 fputs(ANSI_HIGHLIGHT, stdout);
173
174 putchar('\r');
175
176 va_start(ap, fmt);
177 vprintf(fmt, ap);
178 va_end(ap);
179
180 if (colors_enabled())
181 fputs(ANSI_NORMAL, stdout);
182
183 fflush(stdout);
184
185 r = read_one_char(stdin, &c, DEFAULT_ASK_REFRESH_USEC, &need_nl);
186 if (r < 0) {
187
188 if (r == -ETIMEDOUT)
189 continue;
190
191 if (r == -EBADMSG) {
192 puts("Bad input, please try again.");
193 continue;
194 }
195
196 putchar('\n');
197 return r;
198 }
199
200 if (need_nl)
201 putchar('\n');
202
203 if (strchr(replies, c)) {
204 *ret = c;
205 return 0;
206 }
207
208 puts("Read unexpected character, please try again.");
209 }
210 }
211
212 int ask_string(char **ret, const char *text, ...) {
213 assert(ret);
214 assert(text);
215
216 for (;;) {
217 char line[LINE_MAX];
218 va_list ap;
219
220 if (colors_enabled())
221 fputs(ANSI_HIGHLIGHT, stdout);
222
223 va_start(ap, text);
224 vprintf(text, ap);
225 va_end(ap);
226
227 if (colors_enabled())
228 fputs(ANSI_NORMAL, stdout);
229
230 fflush(stdout);
231
232 errno = 0;
233 if (!fgets(line, sizeof(line), stdin))
234 return errno > 0 ? -errno : -EIO;
235
236 if (!endswith(line, "\n"))
237 putchar('\n');
238 else {
239 char *s;
240
241 if (isempty(line))
242 continue;
243
244 truncate_nl(line);
245 s = strdup(line);
246 if (!s)
247 return -ENOMEM;
248
249 *ret = s;
250 return 0;
251 }
252 }
253 }
254
255 int reset_terminal_fd(int fd, bool switch_to_text) {
256 struct termios termios;
257 int r = 0;
258
259 /* Set terminal to some sane defaults */
260
261 assert(fd >= 0);
262
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. */
266
267 /* Disable exclusive mode, just in case */
268 (void) ioctl(fd, TIOCNXCL);
269
270 /* Switch to text mode */
271 if (switch_to_text)
272 (void) ioctl(fd, KDSETMODE, KD_TEXT);
273
274 /* Set default keyboard mode */
275 (void) vt_reset_keyboard(fd);
276
277 if (tcgetattr(fd, &termios) < 0) {
278 r = -errno;
279 goto finish;
280 }
281
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 */
285
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;
291
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;
305
306 termios.c_cc[VTIME] = 0;
307 termios.c_cc[VMIN] = 1;
308
309 if (tcsetattr(fd, TCSANOW, &termios) < 0)
310 r = -errno;
311
312 finish:
313 /* Just in case, flush all crap out */
314 (void) tcflush(fd, TCIOFLUSH);
315
316 return r;
317 }
318
319 int reset_terminal(const char *name) {
320 _cleanup_close_ int fd = -1;
321
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
324 * configured. */
325
326 fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
327 if (fd < 0)
328 return fd;
329
330 return reset_terminal_fd(fd, true);
331 }
332
333 int open_terminal(const char *name, int mode) {
334 unsigned c = 0;
335 int fd;
336
337 /*
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.
342 *
343 * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245
344 */
345
346 if (mode & O_CREAT)
347 return -EINVAL;
348
349 for (;;) {
350 fd = open(name, mode, 0);
351 if (fd >= 0)
352 break;
353
354 if (errno != EIO)
355 return -errno;
356
357 /* Max 1s in total */
358 if (c >= 20)
359 return -errno;
360
361 usleep(50 * USEC_PER_MSEC);
362 c++;
363 }
364
365 if (isatty(fd) <= 0) {
366 safe_close(fd);
367 return -ENOTTY;
368 }
369
370 return fd;
371 }
372
373 int acquire_terminal(
374 const char *name,
375 AcquireTerminalFlags flags,
376 usec_t timeout) {
377
378 _cleanup_close_ int notify = -1, fd = -1;
379 usec_t ts = USEC_INFINITY;
380 int r, wd = -1;
381
382 assert(name);
383 assert(IN_SET(flags & ~ACQUIRE_TERMINAL_PERMISSIVE, ACQUIRE_TERMINAL_TRY, ACQUIRE_TERMINAL_FORCE, ACQUIRE_TERMINAL_WAIT));
384
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.
387 *
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.) */
393
394 if ((flags & ~ACQUIRE_TERMINAL_PERMISSIVE) == ACQUIRE_TERMINAL_WAIT) {
395 notify = inotify_init1(IN_CLOEXEC | (timeout != USEC_INFINITY ? IN_NONBLOCK : 0));
396 if (notify < 0)
397 return -errno;
398
399 wd = inotify_add_watch(notify, name, IN_CLOSE);
400 if (wd < 0)
401 return -errno;
402
403 if (timeout != USEC_INFINITY)
404 ts = now(CLOCK_MONOTONIC);
405 }
406
407 for (;;) {
408 struct sigaction sa_old, sa_new = {
409 .sa_handler = SIG_IGN,
410 .sa_flags = SA_RESTART,
411 };
412
413 if (notify >= 0) {
414 r = flush_fd(notify);
415 if (r < 0)
416 return r;
417 }
418
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);
422 if (fd < 0)
423 return fd;
424
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);
427
428 /* First, try to get the tty */
429 r = ioctl(fd, TIOCSCTTY,
430 (flags & ~ACQUIRE_TERMINAL_PERMISSIVE) == ACQUIRE_TERMINAL_FORCE) < 0 ? -errno : 0;
431
432 /* Reset signal handler to old value */
433 assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
434
435 /* Success? Exit the loop now! */
436 if (r >= 0)
437 break;
438
439 /* Any failure besides -EPERM? Fail, regardless of the mode. */
440 if (r != -EPERM)
441 return r;
442
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. */
446 break;
447
448 if (flags != ACQUIRE_TERMINAL_WAIT) /* If we are in TRY or FORCE mode, then propagate EPERM as EPERM */
449 return r;
450
451 assert(notify >= 0);
452 assert(wd >= 0);
453
454 for (;;) {
455 union inotify_event_buffer buffer;
456 struct inotify_event *e;
457 ssize_t l;
458
459 if (timeout != USEC_INFINITY) {
460 usec_t n;
461
462 assert(ts != USEC_INFINITY);
463
464 n = now(CLOCK_MONOTONIC);
465 if (ts + timeout < n)
466 return -ETIMEDOUT;
467
468 r = fd_wait_for_event(notify, POLLIN, ts + timeout - n);
469 if (r < 0)
470 return r;
471 if (r == 0)
472 return -ETIMEDOUT;
473 }
474
475 l = read(notify, &buffer, sizeof(buffer));
476 if (l < 0) {
477 if (IN_SET(errno, EINTR, EAGAIN))
478 continue;
479
480 return -errno;
481 }
482
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. */
485 break;
486
487 if (e->wd != wd || !(e->mask & IN_CLOSE)) /* Safety checks */
488 return -EIO;
489 }
490
491 break;
492 }
493
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. */
496 fd = safe_close(fd);
497 }
498
499 return TAKE_FD(fd);
500 }
501
502 int release_terminal(void) {
503 static const struct sigaction sa_new = {
504 .sa_handler = SIG_IGN,
505 .sa_flags = SA_RESTART,
506 };
507
508 _cleanup_close_ int fd = -1;
509 struct sigaction sa_old;
510 int r;
511
512 fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
513 if (fd < 0)
514 return -errno;
515
516 /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
517 * by our own TIOCNOTTY */
518 assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
519
520 r = ioctl(fd, TIOCNOTTY) < 0 ? -errno : 0;
521
522 assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
523
524 return r;
525 }
526
527 int terminal_vhangup_fd(int fd) {
528 assert(fd >= 0);
529
530 if (ioctl(fd, TIOCVHANGUP) < 0)
531 return -errno;
532
533 return 0;
534 }
535
536 int terminal_vhangup(const char *name) {
537 _cleanup_close_ int fd;
538
539 fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
540 if (fd < 0)
541 return fd;
542
543 return terminal_vhangup_fd(fd);
544 }
545
546 int vt_disallocate(const char *name) {
547 _cleanup_close_ int fd = -1;
548 const char *e, *n;
549 unsigned u;
550 int r;
551
552 /* Deallocate the VT if possible. If not possible
553 * (i.e. because it is the active one), at least clear it
554 * entirely (including the scrollback buffer) */
555
556 e = path_startswith(name, "/dev/");
557 if (!e)
558 return -EINVAL;
559
560 if (!tty_is_vc(name)) {
561 /* So this is not a VT. I guess we cannot deallocate
562 * it then. But let's at least clear the screen */
563
564 fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
565 if (fd < 0)
566 return fd;
567
568 loop_write(fd,
569 "\033[r" /* clear scrolling region */
570 "\033[H" /* move home */
571 "\033[2J", /* clear screen */
572 10, false);
573 return 0;
574 }
575
576 n = startswith(e, "tty");
577 if (!n)
578 return -EINVAL;
579
580 r = safe_atou(n, &u);
581 if (r < 0)
582 return r;
583
584 if (u <= 0)
585 return -EINVAL;
586
587 /* Try to deallocate */
588 fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
589 if (fd < 0)
590 return fd;
591
592 r = ioctl(fd, VT_DISALLOCATE, u);
593 fd = safe_close(fd);
594
595 if (r >= 0)
596 return 0;
597
598 if (errno != EBUSY)
599 return -errno;
600
601 /* Couldn't deallocate, so let's clear it fully with
602 * scrollback */
603 fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
604 if (fd < 0)
605 return fd;
606
607 loop_write(fd,
608 "\033[r" /* clear scrolling region */
609 "\033[H" /* move home */
610 "\033[3J", /* clear screen including scrollback, requires Linux 2.6.40 */
611 10, false);
612 return 0;
613 }
614
615 int make_console_stdio(void) {
616 int fd, r;
617
618 /* Make /dev/console the controlling terminal and stdin/stdout/stderr */
619
620 fd = acquire_terminal("/dev/console", ACQUIRE_TERMINAL_FORCE|ACQUIRE_TERMINAL_PERMISSIVE, USEC_INFINITY);
621 if (fd < 0)
622 return log_error_errno(fd, "Failed to acquire terminal: %m");
623
624 r = reset_terminal_fd(fd, true);
625 if (r < 0)
626 log_warning_errno(r, "Failed to reset terminal, ignoring: %m");
627
628 r = rearrange_stdio(fd, fd, fd); /* This invalidates 'fd' both on success and on failure. */
629 if (r < 0)
630 return log_error_errno(r, "Failed to make terminal stdin/stdout/stderr: %m");
631
632 reset_terminal_feature_caches();
633
634 return 0;
635 }
636
637 bool tty_is_vc(const char *tty) {
638 assert(tty);
639
640 return vtnr_from_tty(tty) >= 0;
641 }
642
643 bool tty_is_console(const char *tty) {
644 assert(tty);
645
646 return streq(skip_dev_prefix(tty), "console");
647 }
648
649 int vtnr_from_tty(const char *tty) {
650 int i, r;
651
652 assert(tty);
653
654 tty = skip_dev_prefix(tty);
655
656 if (!startswith(tty, "tty") )
657 return -EINVAL;
658
659 if (tty[3] < '0' || tty[3] > '9')
660 return -EINVAL;
661
662 r = safe_atoi(tty+3, &i);
663 if (r < 0)
664 return r;
665
666 if (i < 0 || i > 63)
667 return -EINVAL;
668
669 return i;
670 }
671
672 int resolve_dev_console(char **ret) {
673 _cleanup_free_ char *active = NULL;
674 char *tty;
675 int r;
676
677 assert(ret);
678
679 /* Resolve where /dev/console is pointing to, if /sys is actually ours (i.e. not read-only-mounted which is a
680 * sign for container setups) */
681
682 if (path_is_read_only_fs("/sys") > 0)
683 return -ENOMEDIUM;
684
685 r = read_one_line_file("/sys/class/tty/console/active", &active);
686 if (r < 0)
687 return r;
688
689 /* If multiple log outputs are configured the last one is what /dev/console points to */
690 tty = strrchr(active, ' ');
691 if (tty)
692 tty++;
693 else
694 tty = active;
695
696 if (streq(tty, "tty0")) {
697 active = mfree(active);
698
699 /* Get the active VC (e.g. tty1) */
700 r = read_one_line_file("/sys/class/tty/tty0/active", &active);
701 if (r < 0)
702 return r;
703
704 tty = active;
705 }
706
707 if (tty == active)
708 *ret = TAKE_PTR(active);
709 else {
710 char *tmp;
711
712 tmp = strdup(tty);
713 if (!tmp)
714 return -ENOMEM;
715
716 *ret = tmp;
717 }
718
719 return 0;
720 }
721
722 int get_kernel_consoles(char ***ret) {
723 _cleanup_strv_free_ char **l = NULL;
724 _cleanup_free_ char *line = NULL;
725 const char *p;
726 int r;
727
728 assert(ret);
729
730 /* If /sys is mounted read-only this means we are running in some kind of container environment. In that
731 * case /sys would reflect the host system, not us, hence ignore the data we can read from it. */
732 if (path_is_read_only_fs("/sys") > 0)
733 goto fallback;
734
735 r = read_one_line_file("/sys/class/tty/console/active", &line);
736 if (r < 0)
737 return r;
738
739 p = line;
740 for (;;) {
741 _cleanup_free_ char *tty = NULL;
742 char *path;
743
744 r = extract_first_word(&p, &tty, NULL, 0);
745 if (r < 0)
746 return r;
747 if (r == 0)
748 break;
749
750 if (streq(tty, "tty0")) {
751 tty = mfree(tty);
752 r = read_one_line_file("/sys/class/tty/tty0/active", &tty);
753 if (r < 0)
754 return r;
755 }
756
757 path = strappend("/dev/", tty);
758 if (!path)
759 return -ENOMEM;
760
761 if (access(path, F_OK) < 0) {
762 log_debug_errno(errno, "Console device %s is not accessible, skipping: %m", path);
763 free(path);
764 continue;
765 }
766
767 r = strv_consume(&l, path);
768 if (r < 0)
769 return r;
770 }
771
772 if (strv_isempty(l)) {
773 log_debug("No devices found for system console");
774 goto fallback;
775 }
776
777 *ret = TAKE_PTR(l);
778
779 return 0;
780
781 fallback:
782 r = strv_extend(&l, "/dev/console");
783 if (r < 0)
784 return r;
785
786 *ret = TAKE_PTR(l);
787
788 return 0;
789 }
790
791 bool tty_is_vc_resolve(const char *tty) {
792 _cleanup_free_ char *resolved = NULL;
793
794 assert(tty);
795
796 tty = skip_dev_prefix(tty);
797
798 if (streq(tty, "console")) {
799 if (resolve_dev_console(&resolved) < 0)
800 return false;
801
802 tty = resolved;
803 }
804
805 return tty_is_vc(tty);
806 }
807
808 const char *default_term_for_tty(const char *tty) {
809 return tty && tty_is_vc_resolve(tty) ? "linux" : "vt220";
810 }
811
812 int fd_columns(int fd) {
813 struct winsize ws = {};
814
815 if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
816 return -errno;
817
818 if (ws.ws_col <= 0)
819 return -EIO;
820
821 return ws.ws_col;
822 }
823
824 unsigned columns(void) {
825 const char *e;
826 int c;
827
828 if (cached_columns > 0)
829 return cached_columns;
830
831 c = 0;
832 e = getenv("COLUMNS");
833 if (e)
834 (void) safe_atoi(e, &c);
835
836 if (c <= 0)
837 c = fd_columns(STDOUT_FILENO);
838
839 if (c <= 0)
840 c = 80;
841
842 cached_columns = c;
843 return cached_columns;
844 }
845
846 int fd_lines(int fd) {
847 struct winsize ws = {};
848
849 if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
850 return -errno;
851
852 if (ws.ws_row <= 0)
853 return -EIO;
854
855 return ws.ws_row;
856 }
857
858 unsigned lines(void) {
859 const char *e;
860 int l;
861
862 if (cached_lines > 0)
863 return cached_lines;
864
865 l = 0;
866 e = getenv("LINES");
867 if (e)
868 (void) safe_atoi(e, &l);
869
870 if (l <= 0)
871 l = fd_lines(STDOUT_FILENO);
872
873 if (l <= 0)
874 l = 24;
875
876 cached_lines = l;
877 return cached_lines;
878 }
879
880 /* intended to be used as a SIGWINCH sighandler */
881 void columns_lines_cache_reset(int signum) {
882 cached_columns = 0;
883 cached_lines = 0;
884 }
885
886 void reset_terminal_feature_caches(void) {
887 cached_columns = 0;
888 cached_lines = 0;
889
890 cached_colors_enabled = -1;
891 cached_underline_enabled = -1;
892 cached_on_tty = -1;
893 }
894
895 bool on_tty(void) {
896 if (cached_on_tty < 0)
897 cached_on_tty = isatty(STDOUT_FILENO) > 0;
898
899 return cached_on_tty;
900 }
901
902 int getttyname_malloc(int fd, char **ret) {
903 size_t l = 100;
904 int r;
905
906 assert(fd >= 0);
907 assert(ret);
908
909 for (;;) {
910 char path[l];
911
912 r = ttyname_r(fd, path, sizeof(path));
913 if (r == 0) {
914 char *c;
915
916 c = strdup(skip_dev_prefix(path));
917 if (!c)
918 return -ENOMEM;
919
920 *ret = c;
921 return 0;
922 }
923
924 if (r != ERANGE)
925 return -r;
926
927 l *= 2;
928 }
929
930 return 0;
931 }
932
933 int getttyname_harder(int fd, char **r) {
934 int k;
935 char *s = NULL;
936
937 k = getttyname_malloc(fd, &s);
938 if (k < 0)
939 return k;
940
941 if (streq(s, "tty")) {
942 free(s);
943 return get_ctty(0, NULL, r);
944 }
945
946 *r = s;
947 return 0;
948 }
949
950 int get_ctty_devnr(pid_t pid, dev_t *d) {
951 int r;
952 _cleanup_free_ char *line = NULL;
953 const char *p;
954 unsigned long ttynr;
955
956 assert(pid >= 0);
957
958 p = procfs_file_alloca(pid, "stat");
959 r = read_one_line_file(p, &line);
960 if (r < 0)
961 return r;
962
963 p = strrchr(line, ')');
964 if (!p)
965 return -EIO;
966
967 p++;
968
969 if (sscanf(p, " "
970 "%*c " /* state */
971 "%*d " /* ppid */
972 "%*d " /* pgrp */
973 "%*d " /* session */
974 "%lu ", /* ttynr */
975 &ttynr) != 1)
976 return -EIO;
977
978 if (major(ttynr) == 0 && minor(ttynr) == 0)
979 return -ENXIO;
980
981 if (d)
982 *d = (dev_t) ttynr;
983
984 return 0;
985 }
986
987 int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
988 char fn[STRLEN("/dev/char/") + 2*DECIMAL_STR_MAX(unsigned) + 1 + 1], *b = NULL;
989 _cleanup_free_ char *s = NULL;
990 const char *p;
991 dev_t devnr;
992 int k;
993
994 assert(r);
995
996 k = get_ctty_devnr(pid, &devnr);
997 if (k < 0)
998 return k;
999
1000 sprintf(fn, "/dev/char/%u:%u", major(devnr), minor(devnr));
1001
1002 k = readlink_malloc(fn, &s);
1003 if (k < 0) {
1004
1005 if (k != -ENOENT)
1006 return k;
1007
1008 /* This is an ugly hack */
1009 if (major(devnr) == 136) {
1010 if (asprintf(&b, "pts/%u", minor(devnr)) < 0)
1011 return -ENOMEM;
1012 } else {
1013 /* Probably something like the ptys which have no
1014 * symlink in /dev/char. Let's return something
1015 * vaguely useful. */
1016
1017 b = strdup(fn + 5);
1018 if (!b)
1019 return -ENOMEM;
1020 }
1021 } else {
1022 if (startswith(s, "/dev/"))
1023 p = s + 5;
1024 else if (startswith(s, "../"))
1025 p = s + 3;
1026 else
1027 p = s;
1028
1029 b = strdup(p);
1030 if (!b)
1031 return -ENOMEM;
1032 }
1033
1034 *r = b;
1035 if (_devnr)
1036 *_devnr = devnr;
1037
1038 return 0;
1039 }
1040
1041 int ptsname_malloc(int fd, char **ret) {
1042 size_t l = 100;
1043
1044 assert(fd >= 0);
1045 assert(ret);
1046
1047 for (;;) {
1048 char *c;
1049
1050 c = new(char, l);
1051 if (!c)
1052 return -ENOMEM;
1053
1054 if (ptsname_r(fd, c, l) == 0) {
1055 *ret = c;
1056 return 0;
1057 }
1058 if (errno != ERANGE) {
1059 free(c);
1060 return -errno;
1061 }
1062
1063 free(c);
1064 l *= 2;
1065 }
1066 }
1067
1068 int ptsname_namespace(int pty, char **ret) {
1069 int no = -1, r;
1070
1071 /* Like ptsname(), but doesn't assume that the path is
1072 * accessible in the local namespace. */
1073
1074 r = ioctl(pty, TIOCGPTN, &no);
1075 if (r < 0)
1076 return -errno;
1077
1078 if (no < 0)
1079 return -EIO;
1080
1081 if (asprintf(ret, "/dev/pts/%i", no) < 0)
1082 return -ENOMEM;
1083
1084 return 0;
1085 }
1086
1087 int openpt_in_namespace(pid_t pid, int flags) {
1088 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
1089 _cleanup_close_pair_ int pair[2] = { -1, -1 };
1090 pid_t child;
1091 int r;
1092
1093 assert(pid > 0);
1094
1095 r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
1096 if (r < 0)
1097 return r;
1098
1099 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
1100 return -errno;
1101
1102 r = safe_fork("(sd-openpt)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
1103 if (r < 0)
1104 return r;
1105 if (r == 0) {
1106 int master;
1107
1108 pair[0] = safe_close(pair[0]);
1109
1110 r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
1111 if (r < 0)
1112 _exit(EXIT_FAILURE);
1113
1114 master = posix_openpt(flags|O_NOCTTY|O_CLOEXEC);
1115 if (master < 0)
1116 _exit(EXIT_FAILURE);
1117
1118 if (unlockpt(master) < 0)
1119 _exit(EXIT_FAILURE);
1120
1121 if (send_one_fd(pair[1], master, 0) < 0)
1122 _exit(EXIT_FAILURE);
1123
1124 _exit(EXIT_SUCCESS);
1125 }
1126
1127 pair[1] = safe_close(pair[1]);
1128
1129 r = wait_for_terminate_and_check("(sd-openpt)", child, 0);
1130 if (r < 0)
1131 return r;
1132 if (r != EXIT_SUCCESS)
1133 return -EIO;
1134
1135 return receive_one_fd(pair[0], 0);
1136 }
1137
1138 int open_terminal_in_namespace(pid_t pid, const char *name, int mode) {
1139 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
1140 _cleanup_close_pair_ int pair[2] = { -1, -1 };
1141 pid_t child;
1142 int r;
1143
1144 r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
1145 if (r < 0)
1146 return r;
1147
1148 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
1149 return -errno;
1150
1151 r = safe_fork("(sd-terminal)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
1152 if (r < 0)
1153 return r;
1154 if (r == 0) {
1155 int master;
1156
1157 pair[0] = safe_close(pair[0]);
1158
1159 r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
1160 if (r < 0)
1161 _exit(EXIT_FAILURE);
1162
1163 master = open_terminal(name, mode|O_NOCTTY|O_CLOEXEC);
1164 if (master < 0)
1165 _exit(EXIT_FAILURE);
1166
1167 if (send_one_fd(pair[1], master, 0) < 0)
1168 _exit(EXIT_FAILURE);
1169
1170 _exit(EXIT_SUCCESS);
1171 }
1172
1173 pair[1] = safe_close(pair[1]);
1174
1175 r = wait_for_terminate_and_check("(sd-terminal)", child, 0);
1176 if (r < 0)
1177 return r;
1178 if (r != EXIT_SUCCESS)
1179 return -EIO;
1180
1181 return receive_one_fd(pair[0], 0);
1182 }
1183
1184 static bool getenv_terminal_is_dumb(void) {
1185 const char *e;
1186
1187 e = getenv("TERM");
1188 if (!e)
1189 return true;
1190
1191 return streq(e, "dumb");
1192 }
1193
1194 bool terminal_is_dumb(void) {
1195 if (!on_tty())
1196 return true;
1197
1198 return getenv_terminal_is_dumb();
1199 }
1200
1201 bool colors_enabled(void) {
1202
1203 /* Returns true if colors are considered supported on our stdout. For that we check $SYSTEMD_COLORS first
1204 * (which is the explicit way to turn colors on/off). If that didn't work we turn colors off unless we are on a
1205 * 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
1206 * we are PID 1 then we do not check whether we are connected to a TTY, because we don't keep /dev/console open
1207 * continously due to fear of SAK, and hence things are a bit weird. */
1208
1209 if (cached_colors_enabled < 0) {
1210 int val;
1211
1212 val = getenv_bool("SYSTEMD_COLORS");
1213 if (val >= 0)
1214 cached_colors_enabled = val;
1215 else if (getpid_cached() == 1)
1216 /* PID1 outputs to the console without holding it open all the time */
1217 cached_colors_enabled = !getenv_terminal_is_dumb();
1218 else
1219 cached_colors_enabled = !terminal_is_dumb();
1220 }
1221
1222 return cached_colors_enabled;
1223 }
1224
1225 bool dev_console_colors_enabled(void) {
1226 _cleanup_free_ char *s = NULL;
1227 int b;
1228
1229 /* Returns true if we assume that color is supported on /dev/console.
1230 *
1231 * For that we first check if we explicitly got told to use colors or not, by checking $SYSTEMD_COLORS. If that
1232 * isn't set we check whether PID 1 has $TERM set, and if not, whether TERM is set on the kernel command
1233 * line. If we find $TERM set we assume color if it's not set to "dumb", similarly to how regular
1234 * colors_enabled() operates. */
1235
1236 b = getenv_bool("SYSTEMD_COLORS");
1237 if (b >= 0)
1238 return b;
1239
1240 if (getenv_for_pid(1, "TERM", &s) <= 0)
1241 (void) proc_cmdline_get_key("TERM", 0, &s);
1242
1243 return !streq_ptr(s, "dumb");
1244 }
1245
1246 bool underline_enabled(void) {
1247
1248 if (cached_underline_enabled < 0) {
1249
1250 /* The Linux console doesn't support underlining, turn it off, but only there. */
1251
1252 if (colors_enabled())
1253 cached_underline_enabled = !streq_ptr(getenv("TERM"), "linux");
1254 else
1255 cached_underline_enabled = false;
1256 }
1257
1258 return cached_underline_enabled;
1259 }
1260
1261 int vt_default_utf8(void) {
1262 _cleanup_free_ char *b = NULL;
1263 int r;
1264
1265 /* Read the default VT UTF8 setting from the kernel */
1266
1267 r = read_one_line_file("/sys/module/vt/parameters/default_utf8", &b);
1268 if (r < 0)
1269 return r;
1270
1271 return parse_boolean(b);
1272 }
1273
1274 int vt_reset_keyboard(int fd) {
1275 int kb;
1276
1277 /* If we can't read the default, then default to unicode. It's 2017 after all. */
1278 kb = vt_default_utf8() != 0 ? K_UNICODE : K_XLATE;
1279
1280 if (ioctl(fd, KDSKBMODE, kb) < 0)
1281 return -errno;
1282
1283 return 0;
1284 }