1 /*
2 * Copyright 1992 by Orest Zborowski <obz@Kodak.com>
3 * Copyright 1993 by David Wexelblat <dwex@goblin.org>
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the names of Orest Zborowski and David Wexelblat
10 * not be used in advertising or publicity pertaining to distribution of
11 * the software without specific, written prior permission. Orest Zborowski
12 * and David Wexelblat make no representations about the suitability of this
13 * software for any purpose. It is provided "as is" without express or
14 * implied warranty.
15 *
16 * OREST ZBOROWSKI AND DAVID WEXELBLAT DISCLAIMS ALL WARRANTIES WITH REGARD
17 * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
18 * FITNESS, IN NO EVENT SHALL OREST ZBOROWSKI OR DAVID WEXELBLAT BE LIABLE
19 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
21 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
22 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 *
24 */
26 #ifdef HAVE_XORG_CONFIG_H
27 #include <xorg-config.h>
28 #endif
30 #include <X11/X.h>
31 #include <X11/Xmd.h>
33 #include "compiler.h"
35 #include "xf86.h"
36 #include "xf86Priv.h"
37 #include "xf86_OSlib.h"
39 #include <sys/stat.h>
41 static Bool KeepTty = FALSE;
42 static Bool VTSwitch = TRUE;
43 static Bool ShareVTs = FALSE;
44 Bool NoHwAccess = FALSE;
45 static int activeVT = -1;
47 static char vtname[11];
48 static struct termios tty_attr; /* tty state to restore */
49 static int tty_mode; /* kbd mode to restore */
51 static void
52 drain_console(int fd, void *closure)
53 {
54 errno = 0;
55 if (tcflush(fd, TCIOFLUSH) == -1 && errno == EIO) {
56 xf86SetConsoleHandler(NULL, NULL);
57 }
58 }
60 static void
61 switch_to(int vt, const char *from)
62 {
63 int ret;
65 SYSCALL(ret = ioctl(xf86Info.consoleFd, VT_ACTIVATE, vt));
66 if (ret < 0)
67 FatalError("%s: VT_ACTIVATE failed: %s\n", from, strerror(errno));
69 SYSCALL(ret = ioctl(xf86Info.consoleFd, VT_WAITACTIVE, vt));
70 if (ret < 0)
71 FatalError("%s: VT_WAITACTIVE failed: %s\n", from, strerror(errno));
72 }
74 void
75 xf86OpenConsole(void)
76 {
77 int i, fd = -1, ret;
78 struct vt_mode VT;
79 struct vt_stat vts;
80 MessageType from = X_PROBED;
81 char *tty0[] = { "/dev/tty0", "/dev/vc/0", NULL };
82 char *vcs[] = { "/dev/vc/%d", "/dev/tty%d", NULL };
84 if (serverGeneration == 1) {
86 /* when KeepTty check if we're run with euid==0 */
87 if (KeepTty && geteuid() != 0)
88 FatalError("xf86OpenConsole:"
89 " Server must be suid root for option \"KeepTTY\"\n");
91 /*
92 * setup the virtual terminal manager
93 */
94 if (xf86Info.vtno != -1) {
95 from = X_CMDLINE;
96 } else {
98 i=0;
99 while (tty0[i] != NULL) {
100 if ((fd = open(tty0[i],O_WRONLY,0)) >= 0)
101 break;
102 i++;
103 }
105 if (fd < 0)
106 FatalError(
107 "xf86OpenConsole: Cannot open /dev/tty0 (%s)\n",
108 strerror(errno));
110 if (ShareVTs)
111 {
112 SYSCALL(ret = ioctl(fd, VT_GETSTATE, &vts));
113 if (ret < 0)
114 FatalError("xf86OpenConsole: Cannot find the current"
115 " VT (%s)\n", strerror(errno));
116 xf86Info.vtno = vts.v_active;
117 } else {
118 SYSCALL(ret = ioctl(fd, VT_OPENQRY, &xf86Info.vtno));
119 if (ret < 0)
120 FatalError("xf86OpenConsole: Cannot find a free VT: "
121 "%s\n", strerror(errno));
122 if (xf86Info.vtno == -1)
123 FatalError("xf86OpenConsole: Cannot find a free VT\n");
124 }
125 close(fd);
126 }
128 xf86Msg(from, "using VT number %d\n\n", xf86Info.vtno);
130 if (!KeepTty) {
131 pid_t ppid = getppid();
132 pid_t ppgid;
133 ppgid = getpgid(ppid);
135 /*
136 * change to parent process group that pgid != pid so
137 * that setsid() doesn't fail and we become process
138 * group leader
139 */
140 if (setpgid(0,ppgid) < 0)
141 xf86Msg(X_WARNING, "xf86OpenConsole: setpgid failed: %s\n",
142 strerror(errno));
144 /* become process group leader */
145 if ((setsid() < 0))
146 xf86Msg(X_WARNING, "xf86OpenConsole: setsid failed: %s\n",
147 strerror(errno));
148 }
150 i=0;
151 while (vcs[i] != NULL) {
152 sprintf(vtname, vcs[i], xf86Info.vtno); /* /dev/tty1-64 */
153 if ((xf86Info.consoleFd = open(vtname, O_RDWR|O_NDELAY, 0)) >= 0)
154 break;
155 i++;
156 }
158 if (xf86Info.consoleFd < 0)
159 FatalError("xf86OpenConsole: Cannot open virtual console"
160 " %d (%s)\n", xf86Info.vtno, strerror(errno));
162 /*
163 * Linux doesn't switch to an active vt after the last close of a vt,
164 * so we do this ourselves by remembering which is active now.
165 */
166 SYSCALL(ret = ioctl(xf86Info.consoleFd, VT_GETSTATE, &vts));
167 if (ret < 0)
168 xf86Msg(X_WARNING,"xf86OpenConsole: VT_GETSTATE failed: %s\n",
169 strerror(errno));
170 else
171 activeVT = vts.v_active;
173 #if 0
174 if (!KeepTty) {
175 /*
176 * Detach from the controlling tty to avoid char loss
177 */
178 if ((i = open("/dev/tty",O_RDWR)) >= 0) {
179 SYSCALL(ioctl(i, TIOCNOTTY, 0));
180 close(i);
181 }
182 }
183 #endif
185 if (!ShareVTs)
186 {
187 struct termios nTty;
189 /*
190 * now get the VT. This _must_ succeed, or else fail completely.
191 */
192 switch_to(xf86Info.vtno, "xf86OpenConsole");
194 SYSCALL(ret = ioctl(xf86Info.consoleFd, VT_GETMODE, &VT));
195 if (ret < 0)
196 FatalError("xf86OpenConsole: VT_GETMODE failed %s\n",
197 strerror(errno));
199 signal(SIGUSR1, xf86VTRequest);
201 VT.mode = VT_PROCESS;
202 VT.relsig = SIGUSR1;
203 VT.acqsig = SIGUSR1;
205 SYSCALL(ret = ioctl(xf86Info.consoleFd, VT_SETMODE, &VT));
206 if (ret < 0)
207 FatalError("xf86OpenConsole: VT_SETMODE VT_PROCESS failed: %s\n",
208 strerror(errno));
210 SYSCALL(ret = ioctl(xf86Info.consoleFd, KDSETMODE, KD_GRAPHICS));
211 if (ret < 0)
212 FatalError("xf86OpenConsole: KDSETMODE KD_GRAPHICS failed %s\n",
213 strerror(errno));
215 tcgetattr(xf86Info.consoleFd, &tty_attr);
216 SYSCALL(ioctl(xf86Info.consoleFd, KDGKBMODE, &tty_mode));
218 SYSCALL(ret = ioctl(xf86Info.consoleFd, KDSKBMODE, K_RAW));
219 if (ret < 0)
220 FatalError("xf86OpenConsole: KDSKBMODE K_RAW failed %s\n",
221 strerror(errno));
223 nTty = tty_attr;
224 nTty.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP);
225 nTty.c_oflag = 0;
226 nTty.c_cflag = CREAD | CS8;
227 nTty.c_lflag = 0;
228 nTty.c_cc[VTIME]=0;
229 nTty.c_cc[VMIN]=1;
230 cfsetispeed(&nTty, 9600);
231 cfsetospeed(&nTty, 9600);
232 tcsetattr(xf86Info.consoleFd, TCSANOW, &nTty);
234 /* need to keep the buffer clean, else the kernel gets angry */
235 xf86SetConsoleHandler(drain_console, NULL);
237 /* we really should have a InitOSInputDevices() function instead
238 * of Init?$#*&Device(). So I just place it here */
239 }
240 } else { /* serverGeneration != 1 */
241 if (!ShareVTs && VTSwitch)
242 {
243 /* now get the VT */
244 switch_to(xf86Info.vtno, "xf86OpenConsole");
245 }
246 }
247 }
249 void
250 xf86CloseConsole(void)
251 {
252 struct vt_mode VT;
253 int ret;
255 if (ShareVTs) {
256 close(xf86Info.consoleFd);
257 return;
258 }
260 /*
261 * unregister the drain_console handler
262 * - what to do if someone else changed it in the meantime?
263 */
264 xf86SetConsoleHandler(NULL, NULL);
266 /* Back to text mode ... */
267 SYSCALL(ret = ioctl(xf86Info.consoleFd, KDSETMODE, KD_TEXT));
268 if (ret < 0)
269 xf86Msg(X_WARNING, "xf86CloseConsole: KDSETMODE failed: %s\n",
270 strerror(errno));
272 SYSCALL(ioctl(xf86Info.consoleFd, KDSKBMODE, tty_mode));
273 tcsetattr(xf86Info.consoleFd, TCSANOW, &tty_attr);
275 SYSCALL(ret = ioctl(xf86Info.consoleFd, VT_GETMODE, &VT));
276 if (ret < 0)
277 xf86Msg(X_WARNING, "xf86CloseConsole: VT_GETMODE failed: %s\n",
278 strerror(errno));
279 else {
280 /* set dflt vt handling */
281 VT.mode = VT_AUTO;
282 SYSCALL(ret = ioctl(xf86Info.consoleFd, VT_SETMODE, &VT));
283 if (ret < 0)
284 xf86Msg(X_WARNING, "xf86CloseConsole: VT_SETMODE failed: %s\n",
285 strerror(errno));
286 }
288 if (VTSwitch)
289 {
290 /*
291 * Perform a switch back to the active VT when we were started
292 */
293 if (activeVT >= 0) {
294 switch_to(activeVT, "xf86CloseConsole");
295 activeVT = -1;
296 }
297 }
298 close(xf86Info.consoleFd); /* make the vt-manager happy */
299 }
301 int
302 xf86ProcessArgument(int argc, char *argv[], int i)
303 {
304 /*
305 * Keep server from detaching from controlling tty. This is useful
306 * when debugging (so the server can receive keyboard signals.
307 */
308 if (!strcmp(argv[i], "-keeptty"))
309 {
310 KeepTty = TRUE;
311 return 1;
312 }
313 if (!strcmp(argv[i], "-novtswitch"))
314 {
315 VTSwitch = FALSE;
316 return 1;
317 }
318 if (!strcmp(argv[i], "-sharevts"))
319 {
320 ShareVTs = TRUE;
321 return 1;
322 }
323 if (!strcmp(argv[i], "-nohwaccess"))
324 {
325 NoHwAccess = TRUE;
326 return(1);
327 }
328 if ((argv[i][0] == 'v') && (argv[i][1] == 't'))
329 {
330 if (sscanf(argv[i], "vt%2d", &xf86Info.vtno) == 0)
331 {
332 UseMsg();
333 xf86Info.vtno = -1;
334 return 0;
335 }
336 return 1;
337 }
338 return 0;
339 }
341 void
342 xf86UseMsg(void)
343 {
344 ErrorF("vtXX use the specified VT number\n");
345 ErrorF("-keeptty ");
346 ErrorF("don't detach controlling tty (for debugging only)\n");
347 ErrorF("-novtswitch don't immediately switch to new VT\n");
348 ErrorF("-sharevts share VTs with another X server\n");
349 ErrorF("-nohwaccess don't access hardware ports directly\n");
350 }