Import from old repository commit 61ef2b42a9c4ba8e1600f15bb0236765edc2ad45.
[openvswitch] / extras / ezio / vt-linux.c
1 /* Copyright (c) 2008, 2009 Nicira Networks, Inc.
2  *
3  * This program is free software: you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation, either version 3 of the License, or
6  * (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  *
16  * In addition, as a special exception, Nicira Networks gives permission
17  * to link the code of its release of vswitchd with the OpenSSL project's
18  * "OpenSSL" library (or with modified versions of it that use the same
19  * license as the "OpenSSL" library), and distribute the linked
20  * executables.  You must obey the GNU General Public License in all
21  * respects for all of the code used other than "OpenSSL".  If you modify
22  * this file, you may extend this exception to your version of the file,
23  * but you are not obligated to do so.  If you do not wish to do so,
24  * delete this exception statement from your version.
25  *
26  */
27
28 #include <config.h>
29 #include "extras/ezio/vt.h"
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <linux/kd.h>
33 #include <linux/vt.h>
34 #include <stdint.h>
35 #include <string.h>
36 #include <sys/ioctl.h>
37 #include <unistd.h>
38 #include "util.h"
39
40 #define THIS_MODULE VLM_vt
41 #include "vlog.h"
42
43 static bool get_console_fd(int *fd);
44
45 int
46 vt_open(int open_flags)
47 {
48     int console_fd, vt_fd;
49     char name[16];
50     int vt;
51
52     if (!get_console_fd(&console_fd)) {
53         return -EACCES;
54     }
55
56     /* Deallocate all unused virtual terminals, so that we don't proliferate an
57      * excess of empty ones over multiple runs. */
58     if (ioctl(console_fd, VT_DISALLOCATE, 0) < 0) {
59         VLOG_WARN("failed to deallocate empty virtual terminals: %s",
60                   strerror(errno));
61     }
62
63     /* Find a unused virtual terminal. */
64     if (ioctl(console_fd, VT_OPENQRY, &vt) < 0) {
65         int error = errno;
66         VLOG_ERR("failed to find a free virtual terminal: %s",
67                  strerror(error));
68         close(console_fd);
69         return -error;
70     }
71
72     /* Open virtual terminal. */
73     sprintf(name, "/dev/tty%d", vt);
74     vt_fd = open(name, open_flags);
75     if (vt_fd < 0) {
76         int error = errno;
77         VLOG_ERR("failed to open %s: %s", name, strerror(error));
78         close(console_fd);
79         return -error;
80     }
81
82     /* Activate virtual terminal. */
83     if (ioctl(console_fd, VT_ACTIVATE, vt) < 0
84         || ioctl(console_fd, VT_WAITACTIVE, vt) < 0) {
85         int error = errno;
86         VLOG_ERR("could not activate virtual terminal %d: %s",
87                  vt, strerror(error));
88         close(console_fd);
89         close(vt_fd);
90         return -error;
91     }
92
93     /* Success. */
94     VLOG_DBG("allocated virtual terminal %d (%s)", vt, name);
95     close(console_fd);
96     return vt_fd;
97 }
98
99 static bool
100 is_console(int fd)
101 {
102     uint8_t type = 0;
103     return !ioctl(fd, KDGKBTYPE, &type) && (type == KB_101 || type == KB_84);
104 }
105
106 static bool
107 open_console(const char *name, int *fdp)
108 {
109     *fdp = open(name, O_RDWR | O_NOCTTY);
110     if (*fdp >= 0) {
111         if (is_console(*fdp)) {
112             return true;
113         }
114         close(*fdp);
115     }
116     return false;
117 }
118
119 static bool
120 get_console_fd(int *fdp)
121 {
122     int fd;
123
124     if (open_console("/dev/tty", fdp)
125         || open_console("/dev/tty0", fdp)
126         || open_console("/dev/console", fdp)) {
127         return true;
128     }
129     for (fd = 0; fd < 3; fd++) {
130         if (is_console(fd)) {
131             *fdp = dup(fd);
132             if (*fdp >= 0) {
133                 return true;
134             }
135         }
136     }
137     VLOG_ERR("unable to obtain a file descriptor for the console");
138     return false;
139 }