1 /***
2   This file is part of systemd.
3 
4   Copyright 2010 Lennart Poettering
5 
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10 
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15 
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19 
20 #include <sys/ioctl.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <termios.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <signal.h>
27 #include <time.h>
28 #include <assert.h>
29 #include <poll.h>
30 #include <linux/vt.h>
31 #include <linux/tiocl.h>
32 #include <linux/kd.h>
33 
34 #include "terminal-util.h"
35 #include "time-util.h"
36 #include "process-util.h"
37 #include "util.h"
38 #include "fileio.h"
39 #include "path-util.h"
40 
41 static volatile unsigned cached_columns = 0;
42 static volatile unsigned cached_lines = 0;
43 
open_terminal(const char *name, int mode)44 int open_terminal(const char *name, int mode) {
45         int fd, r;
46         unsigned c = 0;
47 
48         /*
49          * If a TTY is in the process of being closed opening it might
50          * cause EIO. This is horribly awful, but unlikely to be
51          * changed in the kernel. Hence we work around this problem by
52          * retrying a couple of times.
53          *
54          * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245
55          */
56 
57         assert(!(mode & O_CREAT));
58 
59         for (;;) {
60                 fd = open(name, mode, 0);
61                 if (fd >= 0)
62                         break;
63 
64                 if (errno != EIO)
65                         return -errno;
66 
67                 /* Max 1s in total */
68                 if (c >= 20)
69                         return -errno;
70 
71                 usleep(50 * USEC_PER_MSEC);
72                 c++;
73         }
74 
75         r = isatty(fd);
76         if (r < 0) {
77                 safe_close(fd);
78                 return -errno;
79         }
80 
81         if (!r) {
82                 safe_close(fd);
83                 return -ENOTTY;
84         }
85 
86         return fd;
87 }
88