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