Update primary code license to Apache 2.0.
[cascardo/ovs.git] / extras / ezio / vt-linux.c
1 /* Copyright (c) 2008, 2009 Nicira Networks, Inc.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <config.h>
17 #include "extras/ezio/vt.h"
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <linux/kd.h>
21 #include <linux/vt.h>
22 #include <stdint.h>
23 #include <string.h>
24 #include <sys/ioctl.h>
25 #include <unistd.h>
26 #include "util.h"
27
28 #define THIS_MODULE VLM_vt
29 #include "vlog.h"
30
31 static bool get_console_fd(int *fd);
32
33 int
34 vt_open(int open_flags)
35 {
36     int console_fd, vt_fd;
37     char name[16];
38     int vt;
39
40     if (!get_console_fd(&console_fd)) {
41         return -EACCES;
42     }
43
44     /* Deallocate all unused virtual terminals, so that we don't proliferate an
45      * excess of empty ones over multiple runs. */
46     if (ioctl(console_fd, VT_DISALLOCATE, 0) < 0) {
47         VLOG_WARN("failed to deallocate empty virtual terminals: %s",
48                   strerror(errno));
49     }
50
51     /* Find a unused virtual terminal. */
52     if (ioctl(console_fd, VT_OPENQRY, &vt) < 0) {
53         int error = errno;
54         VLOG_ERR("failed to find a free virtual terminal: %s",
55                  strerror(error));
56         close(console_fd);
57         return -error;
58     }
59
60     /* Open virtual terminal. */
61     sprintf(name, "/dev/tty%d", vt);
62     vt_fd = open(name, open_flags);
63     if (vt_fd < 0) {
64         int error = errno;
65         VLOG_ERR("failed to open %s: %s", name, strerror(error));
66         close(console_fd);
67         return -error;
68     }
69
70     /* Activate virtual terminal. */
71     if (ioctl(console_fd, VT_ACTIVATE, vt) < 0
72         || ioctl(console_fd, VT_WAITACTIVE, vt) < 0) {
73         int error = errno;
74         VLOG_ERR("could not activate virtual terminal %d: %s",
75                  vt, strerror(error));
76         close(console_fd);
77         close(vt_fd);
78         return -error;
79     }
80
81     /* Success. */
82     VLOG_DBG("allocated virtual terminal %d (%s)", vt, name);
83     close(console_fd);
84     return vt_fd;
85 }
86
87 static bool
88 is_console(int fd)
89 {
90     uint8_t type = 0;
91     return !ioctl(fd, KDGKBTYPE, &type) && (type == KB_101 || type == KB_84);
92 }
93
94 static bool
95 open_console(const char *name, int *fdp)
96 {
97     *fdp = open(name, O_RDWR | O_NOCTTY);
98     if (*fdp >= 0) {
99         if (is_console(*fdp)) {
100             return true;
101         }
102         close(*fdp);
103     }
104     return false;
105 }
106
107 static bool
108 get_console_fd(int *fdp)
109 {
110     int fd;
111
112     if (open_console("/dev/tty", fdp)
113         || open_console("/dev/tty0", fdp)
114         || open_console("/dev/console", fdp)) {
115         return true;
116     }
117     for (fd = 0; fd < 3; fd++) {
118         if (is_console(fd)) {
119             *fdp = dup(fd);
120             if (*fdp >= 0) {
121                 return true;
122             }
123         }
124     }
125     VLOG_ERR("unable to obtain a file descriptor for the console");
126     return false;
127 }