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