]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/terminal-util.c
Merge pull request #1496 from poettering/stdin-fd
[thirdparty/systemd.git] / src / basic / terminal-util.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2010 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <sys/ioctl.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <termios.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <signal.h>
27 #include <time.h>
28 #include <assert.h>
29 #include <poll.h>
30 #include <linux/vt.h>
31 #include <linux/tiocl.h>
32 #include <linux/kd.h>
33
34 #include "terminal-util.h"
35 #include "time-util.h"
36 #include "process-util.h"
37 #include "util.h"
38 #include "fileio.h"
39 #include "path-util.h"
40
41 static volatile unsigned cached_columns = 0;
42 static volatile unsigned cached_lines = 0;
43
44 int chvt(int vt) {
45 _cleanup_close_ int fd;
46
47 fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
48 if (fd < 0)
49 return -errno;
50
51 if (vt <= 0) {
52 int tiocl[2] = {
53 TIOCL_GETKMSGREDIRECT,
54 0
55 };
56
57 if (ioctl(fd, TIOCLINUX, tiocl) < 0)
58 return -errno;
59
60 vt = tiocl[0] <= 0 ? 1 : tiocl[0];
61 }
62
63 if (ioctl(fd, VT_ACTIVATE, vt) < 0)
64 return -errno;
65
66 return 0;
67 }
68
69 int read_one_char(FILE *f, char *ret, usec_t t, bool *need_nl) {
70 struct termios old_termios, new_termios;
71 char c, line[LINE_MAX];
72
73 assert(f);
74 assert(ret);
75
76 if (tcgetattr(fileno(f), &old_termios) >= 0) {
77 new_termios = old_termios;
78
79 new_termios.c_lflag &= ~ICANON;
80 new_termios.c_cc[VMIN] = 1;
81 new_termios.c_cc[VTIME] = 0;
82
83 if (tcsetattr(fileno(f), TCSADRAIN, &new_termios) >= 0) {
84 size_t k;
85
86 if (t != USEC_INFINITY) {
87 if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0) {
88 tcsetattr(fileno(f), TCSADRAIN, &old_termios);
89 return -ETIMEDOUT;
90 }
91 }
92
93 k = fread(&c, 1, 1, f);
94
95 tcsetattr(fileno(f), TCSADRAIN, &old_termios);
96
97 if (k <= 0)
98 return -EIO;
99
100 if (need_nl)
101 *need_nl = c != '\n';
102
103 *ret = c;
104 return 0;
105 }
106 }
107
108 if (t != USEC_INFINITY) {
109 if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0)
110 return -ETIMEDOUT;
111 }
112
113 errno = 0;
114 if (!fgets(line, sizeof(line), f))
115 return errno ? -errno : -EIO;
116
117 truncate_nl(line);
118
119 if (strlen(line) != 1)
120 return -EBADMSG;
121
122 if (need_nl)
123 *need_nl = false;
124
125 *ret = line[0];
126 return 0;
127 }
128
129 int ask_char(char *ret, const char *replies, const char *text, ...) {
130 int r;
131
132 assert(ret);
133 assert(replies);
134 assert(text);
135
136 for (;;) {
137 va_list ap;
138 char c;
139 bool need_nl = true;
140
141 if (on_tty())
142 fputs(ANSI_HIGHLIGHT, stdout);
143
144 va_start(ap, text);
145 vprintf(text, ap);
146 va_end(ap);
147
148 if (on_tty())
149 fputs(ANSI_NORMAL, stdout);
150
151 fflush(stdout);
152
153 r = read_one_char(stdin, &c, USEC_INFINITY, &need_nl);
154 if (r < 0) {
155
156 if (r == -EBADMSG) {
157 puts("Bad input, please try again.");
158 continue;
159 }
160
161 putchar('\n');
162 return r;
163 }
164
165 if (need_nl)
166 putchar('\n');
167
168 if (strchr(replies, c)) {
169 *ret = c;
170 return 0;
171 }
172
173 puts("Read unexpected character, please try again.");
174 }
175 }
176
177 int ask_string(char **ret, const char *text, ...) {
178 assert(ret);
179 assert(text);
180
181 for (;;) {
182 char line[LINE_MAX];
183 va_list ap;
184
185 if (on_tty())
186 fputs(ANSI_HIGHLIGHT, stdout);
187
188 va_start(ap, text);
189 vprintf(text, ap);
190 va_end(ap);
191
192 if (on_tty())
193 fputs(ANSI_NORMAL, stdout);
194
195 fflush(stdout);
196
197 errno = 0;
198 if (!fgets(line, sizeof(line), stdin))
199 return errno ? -errno : -EIO;
200
201 if (!endswith(line, "\n"))
202 putchar('\n');
203 else {
204 char *s;
205
206 if (isempty(line))
207 continue;
208
209 truncate_nl(line);
210 s = strdup(line);
211 if (!s)
212 return -ENOMEM;
213
214 *ret = s;
215 return 0;
216 }
217 }
218 }
219
220 int reset_terminal_fd(int fd, bool switch_to_text) {
221 struct termios termios;
222 int r = 0;
223
224 /* Set terminal to some sane defaults */
225
226 assert(fd >= 0);
227
228 /* We leave locked terminal attributes untouched, so that
229 * Plymouth may set whatever it wants to set, and we don't
230 * interfere with that. */
231
232 /* Disable exclusive mode, just in case */
233 (void) ioctl(fd, TIOCNXCL);
234
235 /* Switch to text mode */
236 if (switch_to_text)
237 (void) ioctl(fd, KDSETMODE, KD_TEXT);
238
239 /* Enable console unicode mode */
240 (void) ioctl(fd, KDSKBMODE, K_UNICODE);
241
242 if (tcgetattr(fd, &termios) < 0) {
243 r = -errno;
244 goto finish;
245 }
246
247 /* We only reset the stuff that matters to the software. How
248 * hardware is set up we don't touch assuming that somebody
249 * else will do that for us */
250
251 termios.c_iflag &= ~(IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | IUCLC);
252 termios.c_iflag |= ICRNL | IMAXBEL | IUTF8;
253 termios.c_oflag |= ONLCR;
254 termios.c_cflag |= CREAD;
255 termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOPRT | ECHOKE;
256
257 termios.c_cc[VINTR] = 03; /* ^C */
258 termios.c_cc[VQUIT] = 034; /* ^\ */
259 termios.c_cc[VERASE] = 0177;
260 termios.c_cc[VKILL] = 025; /* ^X */
261 termios.c_cc[VEOF] = 04; /* ^D */
262 termios.c_cc[VSTART] = 021; /* ^Q */
263 termios.c_cc[VSTOP] = 023; /* ^S */
264 termios.c_cc[VSUSP] = 032; /* ^Z */
265 termios.c_cc[VLNEXT] = 026; /* ^V */
266 termios.c_cc[VWERASE] = 027; /* ^W */
267 termios.c_cc[VREPRINT] = 022; /* ^R */
268 termios.c_cc[VEOL] = 0;
269 termios.c_cc[VEOL2] = 0;
270
271 termios.c_cc[VTIME] = 0;
272 termios.c_cc[VMIN] = 1;
273
274 if (tcsetattr(fd, TCSANOW, &termios) < 0)
275 r = -errno;
276
277 finish:
278 /* Just in case, flush all crap out */
279 (void) tcflush(fd, TCIOFLUSH);
280
281 return r;
282 }
283
284 int reset_terminal(const char *name) {
285 _cleanup_close_ int fd = -1;
286
287 /* We open the terminal with O_NONBLOCK here, to ensure we
288 * don't block on carrier if this is a terminal with carrier
289 * configured. */
290
291 fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
292 if (fd < 0)
293 return fd;
294
295 return reset_terminal_fd(fd, true);
296 }
297
298 int open_terminal(const char *name, int mode) {
299 int fd, r;
300 unsigned c = 0;
301
302 /*
303 * If a TTY is in the process of being closed opening it might
304 * cause EIO. This is horribly awful, but unlikely to be
305 * changed in the kernel. Hence we work around this problem by
306 * retrying a couple of times.
307 *
308 * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245
309 */
310
311 if (mode & O_CREAT)
312 return -EINVAL;
313
314 for (;;) {
315 fd = open(name, mode, 0);
316 if (fd >= 0)
317 break;
318
319 if (errno != EIO)
320 return -errno;
321
322 /* Max 1s in total */
323 if (c >= 20)
324 return -errno;
325
326 usleep(50 * USEC_PER_MSEC);
327 c++;
328 }
329
330 r = isatty(fd);
331 if (r < 0) {
332 safe_close(fd);
333 return -errno;
334 }
335
336 if (!r) {
337 safe_close(fd);
338 return -ENOTTY;
339 }
340
341 return fd;
342 }
343
344 int acquire_terminal(
345 const char *name,
346 bool fail,
347 bool force,
348 bool ignore_tiocstty_eperm,
349 usec_t timeout) {
350
351 int fd = -1, notify = -1, r = 0, wd = -1;
352 usec_t ts = 0;
353
354 assert(name);
355
356 /* We use inotify to be notified when the tty is closed. We
357 * create the watch before checking if we can actually acquire
358 * it, so that we don't lose any event.
359 *
360 * Note: strictly speaking this actually watches for the
361 * device being closed, it does *not* really watch whether a
362 * tty loses its controlling process. However, unless some
363 * rogue process uses TIOCNOTTY on /dev/tty *after* closing
364 * its tty otherwise this will not become a problem. As long
365 * as the administrator makes sure not configure any service
366 * on the same tty as an untrusted user this should not be a
367 * problem. (Which he probably should not do anyway.) */
368
369 if (timeout != USEC_INFINITY)
370 ts = now(CLOCK_MONOTONIC);
371
372 if (!fail && !force) {
373 notify = inotify_init1(IN_CLOEXEC | (timeout != USEC_INFINITY ? IN_NONBLOCK : 0));
374 if (notify < 0) {
375 r = -errno;
376 goto fail;
377 }
378
379 wd = inotify_add_watch(notify, name, IN_CLOSE);
380 if (wd < 0) {
381 r = -errno;
382 goto fail;
383 }
384 }
385
386 for (;;) {
387 struct sigaction sa_old, sa_new = {
388 .sa_handler = SIG_IGN,
389 .sa_flags = SA_RESTART,
390 };
391
392 if (notify >= 0) {
393 r = flush_fd(notify);
394 if (r < 0)
395 goto fail;
396 }
397
398 /* We pass here O_NOCTTY only so that we can check the return
399 * value TIOCSCTTY and have a reliable way to figure out if we
400 * successfully became the controlling process of the tty */
401 fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
402 if (fd < 0)
403 return fd;
404
405 /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
406 * if we already own the tty. */
407 assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
408
409 /* First, try to get the tty */
410 if (ioctl(fd, TIOCSCTTY, force) < 0)
411 r = -errno;
412
413 assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
414
415 /* Sometimes it makes sense to ignore TIOCSCTTY
416 * returning EPERM, i.e. when very likely we already
417 * are have this controlling terminal. */
418 if (r < 0 && r == -EPERM && ignore_tiocstty_eperm)
419 r = 0;
420
421 if (r < 0 && (force || fail || r != -EPERM))
422 goto fail;
423
424 if (r >= 0)
425 break;
426
427 assert(!fail);
428 assert(!force);
429 assert(notify >= 0);
430
431 for (;;) {
432 union inotify_event_buffer buffer;
433 struct inotify_event *e;
434 ssize_t l;
435
436 if (timeout != USEC_INFINITY) {
437 usec_t n;
438
439 n = now(CLOCK_MONOTONIC);
440 if (ts + timeout < n) {
441 r = -ETIMEDOUT;
442 goto fail;
443 }
444
445 r = fd_wait_for_event(fd, POLLIN, ts + timeout - n);
446 if (r < 0)
447 goto fail;
448
449 if (r == 0) {
450 r = -ETIMEDOUT;
451 goto fail;
452 }
453 }
454
455 l = read(notify, &buffer, sizeof(buffer));
456 if (l < 0) {
457 if (errno == EINTR || errno == EAGAIN)
458 continue;
459
460 r = -errno;
461 goto fail;
462 }
463
464 FOREACH_INOTIFY_EVENT(e, buffer, l) {
465 if (e->wd != wd || !(e->mask & IN_CLOSE)) {
466 r = -EIO;
467 goto fail;
468 }
469 }
470
471 break;
472 }
473
474 /* We close the tty fd here since if the old session
475 * ended our handle will be dead. It's important that
476 * we do this after sleeping, so that we don't enter
477 * an endless loop. */
478 fd = safe_close(fd);
479 }
480
481 safe_close(notify);
482
483 return fd;
484
485 fail:
486 safe_close(fd);
487 safe_close(notify);
488
489 return r;
490 }
491
492 int release_terminal(void) {
493 static const struct sigaction sa_new = {
494 .sa_handler = SIG_IGN,
495 .sa_flags = SA_RESTART,
496 };
497
498 _cleanup_close_ int fd = -1;
499 struct sigaction sa_old;
500 int r = 0;
501
502 fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
503 if (fd < 0)
504 return -errno;
505
506 /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
507 * by our own TIOCNOTTY */
508 assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
509
510 if (ioctl(fd, TIOCNOTTY) < 0)
511 r = -errno;
512
513 assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
514
515 return r;
516 }
517
518 int terminal_vhangup_fd(int fd) {
519 assert(fd >= 0);
520
521 if (ioctl(fd, TIOCVHANGUP) < 0)
522 return -errno;
523
524 return 0;
525 }
526
527 int terminal_vhangup(const char *name) {
528 _cleanup_close_ int fd;
529
530 fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
531 if (fd < 0)
532 return fd;
533
534 return terminal_vhangup_fd(fd);
535 }
536
537 int vt_disallocate(const char *name) {
538 _cleanup_close_ int fd = -1;
539 unsigned u;
540 int r;
541
542 /* Deallocate the VT if possible. If not possible
543 * (i.e. because it is the active one), at least clear it
544 * entirely (including the scrollback buffer) */
545
546 if (!startswith(name, "/dev/"))
547 return -EINVAL;
548
549 if (!tty_is_vc(name)) {
550 /* So this is not a VT. I guess we cannot deallocate
551 * it then. But let's at least clear the screen */
552
553 fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
554 if (fd < 0)
555 return fd;
556
557 loop_write(fd,
558 "\033[r" /* clear scrolling region */
559 "\033[H" /* move home */
560 "\033[2J", /* clear screen */
561 10, false);
562 return 0;
563 }
564
565 if (!startswith(name, "/dev/tty"))
566 return -EINVAL;
567
568 r = safe_atou(name+8, &u);
569 if (r < 0)
570 return r;
571
572 if (u <= 0)
573 return -EINVAL;
574
575 /* Try to deallocate */
576 fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
577 if (fd < 0)
578 return fd;
579
580 r = ioctl(fd, VT_DISALLOCATE, u);
581 fd = safe_close(fd);
582
583 if (r >= 0)
584 return 0;
585
586 if (errno != EBUSY)
587 return -errno;
588
589 /* Couldn't deallocate, so let's clear it fully with
590 * scrollback */
591 fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
592 if (fd < 0)
593 return fd;
594
595 loop_write(fd,
596 "\033[r" /* clear scrolling region */
597 "\033[H" /* move home */
598 "\033[3J", /* clear screen including scrollback, requires Linux 2.6.40 */
599 10, false);
600 return 0;
601 }
602
603 int make_console_stdio(void) {
604 int fd, r;
605
606 /* Make /dev/console the controlling terminal and stdin/stdout/stderr */
607
608 fd = acquire_terminal("/dev/console", false, true, true, USEC_INFINITY);
609 if (fd < 0)
610 return log_error_errno(fd, "Failed to acquire terminal: %m");
611
612 r = reset_terminal_fd(fd, true);
613 if (r < 0)
614 log_warning_errno(r, "Failed to reset terminal, ignoring: %m");
615
616 r = make_stdio(fd);
617 if (r < 0)
618 return log_error_errno(r, "Failed to duplicate terminal fd: %m");
619
620 return 0;
621 }
622
623 int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) {
624 static const char status_indent[] = " "; /* "[" STATUS "] " */
625 _cleanup_free_ char *s = NULL;
626 _cleanup_close_ int fd = -1;
627 struct iovec iovec[6] = {};
628 int n = 0;
629 static bool prev_ephemeral;
630
631 assert(format);
632
633 /* This is independent of logging, as status messages are
634 * optional and go exclusively to the console. */
635
636 if (vasprintf(&s, format, ap) < 0)
637 return log_oom();
638
639 fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
640 if (fd < 0)
641 return fd;
642
643 if (ellipse) {
644 char *e;
645 size_t emax, sl;
646 int c;
647
648 c = fd_columns(fd);
649 if (c <= 0)
650 c = 80;
651
652 sl = status ? sizeof(status_indent)-1 : 0;
653
654 emax = c - sl - 1;
655 if (emax < 3)
656 emax = 3;
657
658 e = ellipsize(s, emax, 50);
659 if (e) {
660 free(s);
661 s = e;
662 }
663 }
664
665 if (prev_ephemeral)
666 IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE);
667 prev_ephemeral = ephemeral;
668
669 if (status) {
670 if (!isempty(status)) {
671 IOVEC_SET_STRING(iovec[n++], "[");
672 IOVEC_SET_STRING(iovec[n++], status);
673 IOVEC_SET_STRING(iovec[n++], "] ");
674 } else
675 IOVEC_SET_STRING(iovec[n++], status_indent);
676 }
677
678 IOVEC_SET_STRING(iovec[n++], s);
679 if (!ephemeral)
680 IOVEC_SET_STRING(iovec[n++], "\n");
681
682 if (writev(fd, iovec, n) < 0)
683 return -errno;
684
685 return 0;
686 }
687
688 int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) {
689 va_list ap;
690 int r;
691
692 assert(format);
693
694 va_start(ap, format);
695 r = status_vprintf(status, ellipse, ephemeral, format, ap);
696 va_end(ap);
697
698 return r;
699 }
700
701 bool tty_is_vc(const char *tty) {
702 assert(tty);
703
704 return vtnr_from_tty(tty) >= 0;
705 }
706
707 bool tty_is_console(const char *tty) {
708 assert(tty);
709
710 if (startswith(tty, "/dev/"))
711 tty += 5;
712
713 return streq(tty, "console");
714 }
715
716 int vtnr_from_tty(const char *tty) {
717 int i, r;
718
719 assert(tty);
720
721 if (startswith(tty, "/dev/"))
722 tty += 5;
723
724 if (!startswith(tty, "tty") )
725 return -EINVAL;
726
727 if (tty[3] < '0' || tty[3] > '9')
728 return -EINVAL;
729
730 r = safe_atoi(tty+3, &i);
731 if (r < 0)
732 return r;
733
734 if (i < 0 || i > 63)
735 return -EINVAL;
736
737 return i;
738 }
739
740 char *resolve_dev_console(char **active) {
741 char *tty;
742
743 /* Resolve where /dev/console is pointing to, if /sys is actually ours
744 * (i.e. not read-only-mounted which is a sign for container setups) */
745
746 if (path_is_read_only_fs("/sys") > 0)
747 return NULL;
748
749 if (read_one_line_file("/sys/class/tty/console/active", active) < 0)
750 return NULL;
751
752 /* If multiple log outputs are configured the last one is what
753 * /dev/console points to */
754 tty = strrchr(*active, ' ');
755 if (tty)
756 tty++;
757 else
758 tty = *active;
759
760 if (streq(tty, "tty0")) {
761 char *tmp;
762
763 /* Get the active VC (e.g. tty1) */
764 if (read_one_line_file("/sys/class/tty/tty0/active", &tmp) >= 0) {
765 free(*active);
766 tty = *active = tmp;
767 }
768 }
769
770 return tty;
771 }
772
773 bool tty_is_vc_resolve(const char *tty) {
774 _cleanup_free_ char *active = NULL;
775
776 assert(tty);
777
778 if (startswith(tty, "/dev/"))
779 tty += 5;
780
781 if (streq(tty, "console")) {
782 tty = resolve_dev_console(&active);
783 if (!tty)
784 return false;
785 }
786
787 return tty_is_vc(tty);
788 }
789
790 const char *default_term_for_tty(const char *tty) {
791 assert(tty);
792
793 return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt220";
794 }
795
796 int fd_columns(int fd) {
797 struct winsize ws = {};
798
799 if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
800 return -errno;
801
802 if (ws.ws_col <= 0)
803 return -EIO;
804
805 return ws.ws_col;
806 }
807
808 unsigned columns(void) {
809 const char *e;
810 int c;
811
812 if (_likely_(cached_columns > 0))
813 return cached_columns;
814
815 c = 0;
816 e = getenv("COLUMNS");
817 if (e)
818 (void) safe_atoi(e, &c);
819
820 if (c <= 0)
821 c = fd_columns(STDOUT_FILENO);
822
823 if (c <= 0)
824 c = 80;
825
826 cached_columns = c;
827 return cached_columns;
828 }
829
830 int fd_lines(int fd) {
831 struct winsize ws = {};
832
833 if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
834 return -errno;
835
836 if (ws.ws_row <= 0)
837 return -EIO;
838
839 return ws.ws_row;
840 }
841
842 unsigned lines(void) {
843 const char *e;
844 int l;
845
846 if (_likely_(cached_lines > 0))
847 return cached_lines;
848
849 l = 0;
850 e = getenv("LINES");
851 if (e)
852 (void) safe_atoi(e, &l);
853
854 if (l <= 0)
855 l = fd_lines(STDOUT_FILENO);
856
857 if (l <= 0)
858 l = 24;
859
860 cached_lines = l;
861 return cached_lines;
862 }
863
864 /* intended to be used as a SIGWINCH sighandler */
865 void columns_lines_cache_reset(int signum) {
866 cached_columns = 0;
867 cached_lines = 0;
868 }
869
870 bool on_tty(void) {
871 static int cached_on_tty = -1;
872
873 if (_unlikely_(cached_on_tty < 0))
874 cached_on_tty = isatty(STDOUT_FILENO) > 0;
875
876 return cached_on_tty;
877 }
878
879 int make_stdio(int fd) {
880 int r, s, t;
881
882 assert(fd >= 0);
883
884 r = dup2(fd, STDIN_FILENO);
885 s = dup2(fd, STDOUT_FILENO);
886 t = dup2(fd, STDERR_FILENO);
887
888 if (fd >= 3)
889 safe_close(fd);
890
891 if (r < 0 || s < 0 || t < 0)
892 return -errno;
893
894 /* Explicitly unset O_CLOEXEC, since if fd was < 3, then
895 * dup2() was a NOP and the bit hence possibly set. */
896 fd_cloexec(STDIN_FILENO, false);
897 fd_cloexec(STDOUT_FILENO, false);
898 fd_cloexec(STDERR_FILENO, false);
899
900 return 0;
901 }
902
903 int make_null_stdio(void) {
904 int null_fd;
905
906 null_fd = open("/dev/null", O_RDWR|O_NOCTTY);
907 if (null_fd < 0)
908 return -errno;
909
910 return make_stdio(null_fd);
911 }
912
913 int getttyname_malloc(int fd, char **ret) {
914 size_t l = 100;
915 int r;
916
917 assert(fd >= 0);
918 assert(ret);
919
920 for (;;) {
921 char path[l];
922
923 r = ttyname_r(fd, path, sizeof(path));
924 if (r == 0) {
925 const char *p;
926 char *c;
927
928 p = startswith(path, "/dev/");
929 c = strdup(p ?: path);
930 if (!c)
931 return -ENOMEM;
932
933 *ret = c;
934 return 0;
935 }
936
937 if (r != ERANGE)
938 return -r;
939
940 l *= 2;
941 }
942
943 return 0;
944 }
945
946 int getttyname_harder(int fd, char **r) {
947 int k;
948 char *s = NULL;
949
950 k = getttyname_malloc(fd, &s);
951 if (k < 0)
952 return k;
953
954 if (streq(s, "tty")) {
955 free(s);
956 return get_ctty(0, NULL, r);
957 }
958
959 *r = s;
960 return 0;
961 }
962
963 int get_ctty_devnr(pid_t pid, dev_t *d) {
964 int r;
965 _cleanup_free_ char *line = NULL;
966 const char *p;
967 unsigned long ttynr;
968
969 assert(pid >= 0);
970
971 p = procfs_file_alloca(pid, "stat");
972 r = read_one_line_file(p, &line);
973 if (r < 0)
974 return r;
975
976 p = strrchr(line, ')');
977 if (!p)
978 return -EIO;
979
980 p++;
981
982 if (sscanf(p, " "
983 "%*c " /* state */
984 "%*d " /* ppid */
985 "%*d " /* pgrp */
986 "%*d " /* session */
987 "%lu ", /* ttynr */
988 &ttynr) != 1)
989 return -EIO;
990
991 if (major(ttynr) == 0 && minor(ttynr) == 0)
992 return -ENXIO;
993
994 if (d)
995 *d = (dev_t) ttynr;
996
997 return 0;
998 }
999
1000 int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
1001 char fn[sizeof("/dev/char/")-1 + 2*DECIMAL_STR_MAX(unsigned) + 1 + 1], *b = NULL;
1002 _cleanup_free_ char *s = NULL;
1003 const char *p;
1004 dev_t devnr;
1005 int k;
1006
1007 assert(r);
1008
1009 k = get_ctty_devnr(pid, &devnr);
1010 if (k < 0)
1011 return k;
1012
1013 sprintf(fn, "/dev/char/%u:%u", major(devnr), minor(devnr));
1014
1015 k = readlink_malloc(fn, &s);
1016 if (k < 0) {
1017
1018 if (k != -ENOENT)
1019 return k;
1020
1021 /* This is an ugly hack */
1022 if (major(devnr) == 136) {
1023 if (asprintf(&b, "pts/%u", minor(devnr)) < 0)
1024 return -ENOMEM;
1025 } else {
1026 /* Probably something like the ptys which have no
1027 * symlink in /dev/char. Let's return something
1028 * vaguely useful. */
1029
1030 b = strdup(fn + 5);
1031 if (!b)
1032 return -ENOMEM;
1033 }
1034 } else {
1035 if (startswith(s, "/dev/"))
1036 p = s + 5;
1037 else if (startswith(s, "../"))
1038 p = s + 3;
1039 else
1040 p = s;
1041
1042 b = strdup(p);
1043 if (!b)
1044 return -ENOMEM;
1045 }
1046
1047 *r = b;
1048 if (_devnr)
1049 *_devnr = devnr;
1050
1051 return 0;
1052 }
1053
1054 int ptsname_malloc(int fd, char **ret) {
1055 size_t l = 100;
1056
1057 assert(fd >= 0);
1058 assert(ret);
1059
1060 for (;;) {
1061 char *c;
1062
1063 c = new(char, l);
1064 if (!c)
1065 return -ENOMEM;
1066
1067 if (ptsname_r(fd, c, l) == 0) {
1068 *ret = c;
1069 return 0;
1070 }
1071 if (errno != ERANGE) {
1072 free(c);
1073 return -errno;
1074 }
1075
1076 free(c);
1077 l *= 2;
1078 }
1079 }
1080
1081 int ptsname_namespace(int pty, char **ret) {
1082 int no = -1, r;
1083
1084 /* Like ptsname(), but doesn't assume that the path is
1085 * accessible in the local namespace. */
1086
1087 r = ioctl(pty, TIOCGPTN, &no);
1088 if (r < 0)
1089 return -errno;
1090
1091 if (no < 0)
1092 return -EIO;
1093
1094 if (asprintf(ret, "/dev/pts/%i", no) < 0)
1095 return -ENOMEM;
1096
1097 return 0;
1098 }
1099
1100 int openpt_in_namespace(pid_t pid, int flags) {
1101 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
1102 _cleanup_close_pair_ int pair[2] = { -1, -1 };
1103 siginfo_t si;
1104 pid_t child;
1105 int r;
1106
1107 assert(pid > 0);
1108
1109 r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
1110 if (r < 0)
1111 return r;
1112
1113 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
1114 return -errno;
1115
1116 child = fork();
1117 if (child < 0)
1118 return -errno;
1119
1120 if (child == 0) {
1121 int master;
1122
1123 pair[0] = safe_close(pair[0]);
1124
1125 r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
1126 if (r < 0)
1127 _exit(EXIT_FAILURE);
1128
1129 master = posix_openpt(flags|O_NOCTTY|O_CLOEXEC);
1130 if (master < 0)
1131 _exit(EXIT_FAILURE);
1132
1133 if (unlockpt(master) < 0)
1134 _exit(EXIT_FAILURE);
1135
1136 if (send_one_fd(pair[1], master, 0) < 0)
1137 _exit(EXIT_FAILURE);
1138
1139 _exit(EXIT_SUCCESS);
1140 }
1141
1142 pair[1] = safe_close(pair[1]);
1143
1144 r = wait_for_terminate(child, &si);
1145 if (r < 0)
1146 return r;
1147 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
1148 return -EIO;
1149
1150 return receive_one_fd(pair[0], 0);
1151 }
1152
1153 int open_terminal_in_namespace(pid_t pid, const char *name, int mode) {
1154 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
1155 _cleanup_close_pair_ int pair[2] = { -1, -1 };
1156 siginfo_t si;
1157 pid_t child;
1158 int r;
1159
1160 r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
1161 if (r < 0)
1162 return r;
1163
1164 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
1165 return -errno;
1166
1167 child = fork();
1168 if (child < 0)
1169 return -errno;
1170
1171 if (child == 0) {
1172 int master;
1173
1174 pair[0] = safe_close(pair[0]);
1175
1176 r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
1177 if (r < 0)
1178 _exit(EXIT_FAILURE);
1179
1180 master = open_terminal(name, mode|O_NOCTTY|O_CLOEXEC);
1181 if (master < 0)
1182 _exit(EXIT_FAILURE);
1183
1184 if (send_one_fd(pair[1], master, 0) < 0)
1185 _exit(EXIT_FAILURE);
1186
1187 _exit(EXIT_SUCCESS);
1188 }
1189
1190 pair[1] = safe_close(pair[1]);
1191
1192 r = wait_for_terminate(child, &si);
1193 if (r < 0)
1194 return r;
1195 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
1196 return -EIO;
1197
1198 return receive_one_fd(pair[0], 0);
1199 }