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