]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/terminal-util.c
Merge pull request #8283 from poettering/nspawn-user-fix
[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 r = fd;
500 fd = -1;
501
502 return r;
503 }
504
505 int release_terminal(void) {
506 static const struct sigaction sa_new = {
507 .sa_handler = SIG_IGN,
508 .sa_flags = SA_RESTART,
509 };
510
511 _cleanup_close_ int fd = -1;
512 struct sigaction sa_old;
513 int r;
514
515 fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
516 if (fd < 0)
517 return -errno;
518
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);
522
523 r = ioctl(fd, TIOCNOTTY) < 0 ? -errno : 0;
524
525 assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
526
527 return r;
528 }
529
530 int terminal_vhangup_fd(int fd) {
531 assert(fd >= 0);
532
533 if (ioctl(fd, TIOCVHANGUP) < 0)
534 return -errno;
535
536 return 0;
537 }
538
539 int terminal_vhangup(const char *name) {
540 _cleanup_close_ int fd;
541
542 fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
543 if (fd < 0)
544 return fd;
545
546 return terminal_vhangup_fd(fd);
547 }
548
549 int vt_disallocate(const char *name) {
550 _cleanup_close_ int fd = -1;
551 const char *e, *n;
552 unsigned u;
553 int r;
554
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) */
558
559 e = path_startswith(name, "/dev/");
560 if (!e)
561 return -EINVAL;
562
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 */
566
567 fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
568 if (fd < 0)
569 return fd;
570
571 loop_write(fd,
572 "\033[r" /* clear scrolling region */
573 "\033[H" /* move home */
574 "\033[2J", /* clear screen */
575 10, false);
576 return 0;
577 }
578
579 n = startswith(e, "tty");
580 if (!n)
581 return -EINVAL;
582
583 r = safe_atou(n, &u);
584 if (r < 0)
585 return r;
586
587 if (u <= 0)
588 return -EINVAL;
589
590 /* Try to deallocate */
591 fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
592 if (fd < 0)
593 return fd;
594
595 r = ioctl(fd, VT_DISALLOCATE, u);
596 fd = safe_close(fd);
597
598 if (r >= 0)
599 return 0;
600
601 if (errno != EBUSY)
602 return -errno;
603
604 /* Couldn't deallocate, so let's clear it fully with
605 * scrollback */
606 fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
607 if (fd < 0)
608 return fd;
609
610 loop_write(fd,
611 "\033[r" /* clear scrolling region */
612 "\033[H" /* move home */
613 "\033[3J", /* clear screen including scrollback, requires Linux 2.6.40 */
614 10, false);
615 return 0;
616 }
617
618 int make_console_stdio(void) {
619 int fd, r;
620
621 /* Make /dev/console the controlling terminal and stdin/stdout/stderr */
622
623 fd = acquire_terminal("/dev/console", ACQUIRE_TERMINAL_FORCE|ACQUIRE_TERMINAL_PERMISSIVE, USEC_INFINITY);
624 if (fd < 0)
625 return log_error_errno(fd, "Failed to acquire terminal: %m");
626
627 r = reset_terminal_fd(fd, true);
628 if (r < 0)
629 log_warning_errno(r, "Failed to reset terminal, ignoring: %m");
630
631 r = make_stdio(fd);
632 if (r < 0)
633 return log_error_errno(r, "Failed to duplicate terminal fd: %m");
634
635 reset_terminal_feature_caches();
636
637 return 0;
638 }
639
640 bool tty_is_vc(const char *tty) {
641 assert(tty);
642
643 return vtnr_from_tty(tty) >= 0;
644 }
645
646 bool tty_is_console(const char *tty) {
647 assert(tty);
648
649 return streq(skip_dev_prefix(tty), "console");
650 }
651
652 int vtnr_from_tty(const char *tty) {
653 int i, r;
654
655 assert(tty);
656
657 tty = skip_dev_prefix(tty);
658
659 if (!startswith(tty, "tty") )
660 return -EINVAL;
661
662 if (tty[3] < '0' || tty[3] > '9')
663 return -EINVAL;
664
665 r = safe_atoi(tty+3, &i);
666 if (r < 0)
667 return r;
668
669 if (i < 0 || i > 63)
670 return -EINVAL;
671
672 return i;
673 }
674
675 int resolve_dev_console(char **ret) {
676 _cleanup_free_ char *active = NULL;
677 char *tty;
678 int r;
679
680 assert(ret);
681
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) */
684
685 if (path_is_read_only_fs("/sys") > 0)
686 return -ENOMEDIUM;
687
688 r = read_one_line_file("/sys/class/tty/console/active", &active);
689 if (r < 0)
690 return r;
691
692 /* If multiple log outputs are configured the last one is what /dev/console points to */
693 tty = strrchr(active, ' ');
694 if (tty)
695 tty++;
696 else
697 tty = active;
698
699 if (streq(tty, "tty0")) {
700 active = mfree(active);
701
702 /* Get the active VC (e.g. tty1) */
703 r = read_one_line_file("/sys/class/tty/tty0/active", &active);
704 if (r < 0)
705 return r;
706
707 tty = active;
708 }
709
710 if (tty == active) {
711 *ret = active;
712 active = NULL;
713 } else {
714 char *tmp;
715
716 tmp = strdup(tty);
717 if (!tmp)
718 return -ENOMEM;
719
720 *ret = tmp;
721 }
722
723 return 0;
724 }
725
726 int get_kernel_consoles(char ***ret) {
727 _cleanup_strv_free_ char **l = NULL;
728 _cleanup_free_ char *line = NULL;
729 const char *p;
730 int r;
731
732 assert(ret);
733
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)
737 goto fallback;
738
739 r = read_one_line_file("/sys/class/tty/console/active", &line);
740 if (r < 0)
741 return r;
742
743 p = line;
744 for (;;) {
745 _cleanup_free_ char *tty = NULL;
746 char *path;
747
748 r = extract_first_word(&p, &tty, NULL, 0);
749 if (r < 0)
750 return r;
751 if (r == 0)
752 break;
753
754 if (streq(tty, "tty0")) {
755 tty = mfree(tty);
756 r = read_one_line_file("/sys/class/tty/tty0/active", &tty);
757 if (r < 0)
758 return r;
759 }
760
761 path = strappend("/dev/", tty);
762 if (!path)
763 return -ENOMEM;
764
765 if (access(path, F_OK) < 0) {
766 log_debug_errno(errno, "Console device %s is not accessible, skipping: %m", path);
767 free(path);
768 continue;
769 }
770
771 r = strv_consume(&l, path);
772 if (r < 0)
773 return r;
774 }
775
776 if (strv_isempty(l)) {
777 log_debug("No devices found for system console");
778 goto fallback;
779 }
780
781 *ret = l;
782 l = NULL;
783
784 return 0;
785
786 fallback:
787 r = strv_extend(&l, "/dev/console");
788 if (r < 0)
789 return r;
790
791 *ret = l;
792 l = NULL;
793
794 return 0;
795 }
796
797 bool tty_is_vc_resolve(const char *tty) {
798 _cleanup_free_ char *resolved = NULL;
799
800 assert(tty);
801
802 tty = skip_dev_prefix(tty);
803
804 if (streq(tty, "console")) {
805 if (resolve_dev_console(&resolved) < 0)
806 return false;
807
808 tty = resolved;
809 }
810
811 return tty_is_vc(tty);
812 }
813
814 const char *default_term_for_tty(const char *tty) {
815 return tty && tty_is_vc_resolve(tty) ? "linux" : "vt220";
816 }
817
818 int fd_columns(int fd) {
819 struct winsize ws = {};
820
821 if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
822 return -errno;
823
824 if (ws.ws_col <= 0)
825 return -EIO;
826
827 return ws.ws_col;
828 }
829
830 unsigned columns(void) {
831 const char *e;
832 int c;
833
834 if (cached_columns > 0)
835 return cached_columns;
836
837 c = 0;
838 e = getenv("COLUMNS");
839 if (e)
840 (void) safe_atoi(e, &c);
841
842 if (c <= 0)
843 c = fd_columns(STDOUT_FILENO);
844
845 if (c <= 0)
846 c = 80;
847
848 cached_columns = c;
849 return cached_columns;
850 }
851
852 int fd_lines(int fd) {
853 struct winsize ws = {};
854
855 if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
856 return -errno;
857
858 if (ws.ws_row <= 0)
859 return -EIO;
860
861 return ws.ws_row;
862 }
863
864 unsigned lines(void) {
865 const char *e;
866 int l;
867
868 if (cached_lines > 0)
869 return cached_lines;
870
871 l = 0;
872 e = getenv("LINES");
873 if (e)
874 (void) safe_atoi(e, &l);
875
876 if (l <= 0)
877 l = fd_lines(STDOUT_FILENO);
878
879 if (l <= 0)
880 l = 24;
881
882 cached_lines = l;
883 return cached_lines;
884 }
885
886 /* intended to be used as a SIGWINCH sighandler */
887 void columns_lines_cache_reset(int signum) {
888 cached_columns = 0;
889 cached_lines = 0;
890 }
891
892 void reset_terminal_feature_caches(void) {
893 cached_columns = 0;
894 cached_lines = 0;
895
896 cached_colors_enabled = -1;
897 cached_underline_enabled = -1;
898 cached_on_tty = -1;
899 }
900
901 bool on_tty(void) {
902 if (cached_on_tty < 0)
903 cached_on_tty = isatty(STDOUT_FILENO) > 0;
904
905 return cached_on_tty;
906 }
907
908 int make_stdio(int fd) {
909 int r = 0;
910
911 assert(fd >= 0);
912
913 if (dup2(fd, STDIN_FILENO) < 0)
914 r = -errno;
915 if (dup2(fd, STDOUT_FILENO) < 0 && r >= 0)
916 r = -errno;
917 if (dup2(fd, STDERR_FILENO) < 0 && r >= 0)
918 r = -errno;
919
920 safe_close_above_stdio(fd);
921
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();
924
925 return r;
926 }
927
928 int make_null_stdio(void) {
929 int null_fd, r;
930
931 null_fd = open("/dev/null", O_RDWR|O_NOCTTY|O_CLOEXEC);
932 if (null_fd < 0)
933 return -errno;
934
935 r = make_stdio(null_fd);
936
937 reset_terminal_feature_caches();
938
939 return r;
940 }
941
942 int getttyname_malloc(int fd, char **ret) {
943 size_t l = 100;
944 int r;
945
946 assert(fd >= 0);
947 assert(ret);
948
949 for (;;) {
950 char path[l];
951
952 r = ttyname_r(fd, path, sizeof(path));
953 if (r == 0) {
954 char *c;
955
956 c = strdup(skip_dev_prefix(path));
957 if (!c)
958 return -ENOMEM;
959
960 *ret = c;
961 return 0;
962 }
963
964 if (r != ERANGE)
965 return -r;
966
967 l *= 2;
968 }
969
970 return 0;
971 }
972
973 int getttyname_harder(int fd, char **r) {
974 int k;
975 char *s = NULL;
976
977 k = getttyname_malloc(fd, &s);
978 if (k < 0)
979 return k;
980
981 if (streq(s, "tty")) {
982 free(s);
983 return get_ctty(0, NULL, r);
984 }
985
986 *r = s;
987 return 0;
988 }
989
990 int get_ctty_devnr(pid_t pid, dev_t *d) {
991 int r;
992 _cleanup_free_ char *line = NULL;
993 const char *p;
994 unsigned long ttynr;
995
996 assert(pid >= 0);
997
998 p = procfs_file_alloca(pid, "stat");
999 r = read_one_line_file(p, &line);
1000 if (r < 0)
1001 return r;
1002
1003 p = strrchr(line, ')');
1004 if (!p)
1005 return -EIO;
1006
1007 p++;
1008
1009 if (sscanf(p, " "
1010 "%*c " /* state */
1011 "%*d " /* ppid */
1012 "%*d " /* pgrp */
1013 "%*d " /* session */
1014 "%lu ", /* ttynr */
1015 &ttynr) != 1)
1016 return -EIO;
1017
1018 if (major(ttynr) == 0 && minor(ttynr) == 0)
1019 return -ENXIO;
1020
1021 if (d)
1022 *d = (dev_t) ttynr;
1023
1024 return 0;
1025 }
1026
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;
1030 const char *p;
1031 dev_t devnr;
1032 int k;
1033
1034 assert(r);
1035
1036 k = get_ctty_devnr(pid, &devnr);
1037 if (k < 0)
1038 return k;
1039
1040 sprintf(fn, "/dev/char/%u:%u", major(devnr), minor(devnr));
1041
1042 k = readlink_malloc(fn, &s);
1043 if (k < 0) {
1044
1045 if (k != -ENOENT)
1046 return k;
1047
1048 /* This is an ugly hack */
1049 if (major(devnr) == 136) {
1050 if (asprintf(&b, "pts/%u", minor(devnr)) < 0)
1051 return -ENOMEM;
1052 } else {
1053 /* Probably something like the ptys which have no
1054 * symlink in /dev/char. Let's return something
1055 * vaguely useful. */
1056
1057 b = strdup(fn + 5);
1058 if (!b)
1059 return -ENOMEM;
1060 }
1061 } else {
1062 if (startswith(s, "/dev/"))
1063 p = s + 5;
1064 else if (startswith(s, "../"))
1065 p = s + 3;
1066 else
1067 p = s;
1068
1069 b = strdup(p);
1070 if (!b)
1071 return -ENOMEM;
1072 }
1073
1074 *r = b;
1075 if (_devnr)
1076 *_devnr = devnr;
1077
1078 return 0;
1079 }
1080
1081 int ptsname_malloc(int fd, char **ret) {
1082 size_t l = 100;
1083
1084 assert(fd >= 0);
1085 assert(ret);
1086
1087 for (;;) {
1088 char *c;
1089
1090 c = new(char, l);
1091 if (!c)
1092 return -ENOMEM;
1093
1094 if (ptsname_r(fd, c, l) == 0) {
1095 *ret = c;
1096 return 0;
1097 }
1098 if (errno != ERANGE) {
1099 free(c);
1100 return -errno;
1101 }
1102
1103 free(c);
1104 l *= 2;
1105 }
1106 }
1107
1108 int ptsname_namespace(int pty, char **ret) {
1109 int no = -1, r;
1110
1111 /* Like ptsname(), but doesn't assume that the path is
1112 * accessible in the local namespace. */
1113
1114 r = ioctl(pty, TIOCGPTN, &no);
1115 if (r < 0)
1116 return -errno;
1117
1118 if (no < 0)
1119 return -EIO;
1120
1121 if (asprintf(ret, "/dev/pts/%i", no) < 0)
1122 return -ENOMEM;
1123
1124 return 0;
1125 }
1126
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 };
1130 pid_t child;
1131 int r;
1132
1133 assert(pid > 0);
1134
1135 r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
1136 if (r < 0)
1137 return r;
1138
1139 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
1140 return -errno;
1141
1142 r = safe_fork("(sd-openpt)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
1143 if (r < 0)
1144 return r;
1145 if (r == 0) {
1146 int master;
1147
1148 pair[0] = safe_close(pair[0]);
1149
1150 r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
1151 if (r < 0)
1152 _exit(EXIT_FAILURE);
1153
1154 master = posix_openpt(flags|O_NOCTTY|O_CLOEXEC);
1155 if (master < 0)
1156 _exit(EXIT_FAILURE);
1157
1158 if (unlockpt(master) < 0)
1159 _exit(EXIT_FAILURE);
1160
1161 if (send_one_fd(pair[1], master, 0) < 0)
1162 _exit(EXIT_FAILURE);
1163
1164 _exit(EXIT_SUCCESS);
1165 }
1166
1167 pair[1] = safe_close(pair[1]);
1168
1169 r = wait_for_terminate_and_check("(sd-openpt)", child, 0);
1170 if (r < 0)
1171 return r;
1172 if (r != EXIT_SUCCESS)
1173 return -EIO;
1174
1175 return receive_one_fd(pair[0], 0);
1176 }
1177
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 };
1181 pid_t child;
1182 int r;
1183
1184 r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
1185 if (r < 0)
1186 return r;
1187
1188 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
1189 return -errno;
1190
1191 r = safe_fork("(sd-terminal)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
1192 if (r < 0)
1193 return r;
1194 if (r == 0) {
1195 int master;
1196
1197 pair[0] = safe_close(pair[0]);
1198
1199 r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
1200 if (r < 0)
1201 _exit(EXIT_FAILURE);
1202
1203 master = open_terminal(name, mode|O_NOCTTY|O_CLOEXEC);
1204 if (master < 0)
1205 _exit(EXIT_FAILURE);
1206
1207 if (send_one_fd(pair[1], master, 0) < 0)
1208 _exit(EXIT_FAILURE);
1209
1210 _exit(EXIT_SUCCESS);
1211 }
1212
1213 pair[1] = safe_close(pair[1]);
1214
1215 r = wait_for_terminate_and_check("(sd-terminal)", child, 0);
1216 if (r < 0)
1217 return r;
1218 if (r != EXIT_SUCCESS)
1219 return -EIO;
1220
1221 return receive_one_fd(pair[0], 0);
1222 }
1223
1224 static bool getenv_terminal_is_dumb(void) {
1225 const char *e;
1226
1227 e = getenv("TERM");
1228 if (!e)
1229 return true;
1230
1231 return streq(e, "dumb");
1232 }
1233
1234 bool terminal_is_dumb(void) {
1235 if (!on_tty())
1236 return true;
1237
1238 return getenv_terminal_is_dumb();
1239 }
1240
1241 bool colors_enabled(void) {
1242
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. */
1248
1249 if (cached_colors_enabled < 0) {
1250 int val;
1251
1252 val = getenv_bool("SYSTEMD_COLORS");
1253 if (val >= 0)
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();
1258 else
1259 cached_colors_enabled = !terminal_is_dumb();
1260 }
1261
1262 return cached_colors_enabled;
1263 }
1264
1265 bool dev_console_colors_enabled(void) {
1266 _cleanup_free_ char *s = NULL;
1267 int b;
1268
1269 /* Returns true if we assume that color is supported on /dev/console.
1270 *
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. */
1275
1276 b = getenv_bool("SYSTEMD_COLORS");
1277 if (b >= 0)
1278 return b;
1279
1280 if (getenv_for_pid(1, "TERM", &s) <= 0)
1281 (void) proc_cmdline_get_key("TERM", 0, &s);
1282
1283 return !streq_ptr(s, "dumb");
1284 }
1285
1286 bool underline_enabled(void) {
1287
1288 if (cached_underline_enabled < 0) {
1289
1290 /* The Linux console doesn't support underlining, turn it off, but only there. */
1291
1292 if (colors_enabled())
1293 cached_underline_enabled = !streq_ptr(getenv("TERM"), "linux");
1294 else
1295 cached_underline_enabled = false;
1296 }
1297
1298 return cached_underline_enabled;
1299 }
1300
1301 int vt_default_utf8(void) {
1302 _cleanup_free_ char *b = NULL;
1303 int r;
1304
1305 /* Read the default VT UTF8 setting from the kernel */
1306
1307 r = read_one_line_file("/sys/module/vt/parameters/default_utf8", &b);
1308 if (r < 0)
1309 return r;
1310
1311 return parse_boolean(b);
1312 }
1313
1314 int vt_reset_keyboard(int fd) {
1315 int kb;
1316
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;
1319
1320 if (ioctl(fd, KDSKBMODE, kb) < 0)
1321 return -errno;
1322
1323 return 0;
1324 }