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