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