lnx_init.c (12577B)
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 */ 25 26 #ifdef HAVE_XORG_CONFIG_H 27 #include <xorg-config.h> 28 #endif 29 30 #include <X11/X.h> 31 #include <X11/Xmd.h> 32 33 #include "compiler.h" 34 #include "linux.h" 35 36 #include "xf86.h" 37 #include "xf86Priv.h" 38 #include "xf86_OSlib.h" 39 40 #include <sys/stat.h> 41 #ifdef HAVE_SYS_SYSMACROS_H 42 #include <sys/sysmacros.h> 43 #endif 44 45 #ifndef K_OFF 46 #define K_OFF 0x4 47 #endif 48 49 static Bool KeepTty = FALSE; 50 static int activeVT = -1; 51 52 static char vtname[11]; 53 static struct termios tty_attr; /* tty state to restore */ 54 static int tty_mode; /* kbd mode to restore */ 55 56 static void 57 drain_console(int fd, void *closure) 58 { 59 errno = 0; 60 if (tcflush(fd, TCIOFLUSH) == -1 && errno == EIO) { 61 xf86SetConsoleHandler(NULL, NULL); 62 } 63 } 64 65 static int 66 switch_to(int vt, const char *from) 67 { 68 int ret; 69 70 SYSCALL(ret = ioctl(xf86Info.consoleFd, VT_ACTIVATE, vt)); 71 if (ret < 0) { 72 xf86Msg(X_WARNING, "%s: VT_ACTIVATE failed: %s\n", from, strerror(errno)); 73 return 0; 74 } 75 76 SYSCALL(ret = ioctl(xf86Info.consoleFd, VT_WAITACTIVE, vt)); 77 if (ret < 0) { 78 xf86Msg(X_WARNING, "%s: VT_WAITACTIVE failed: %s\n", from, strerror(errno)); 79 return 0; 80 } 81 82 return 1; 83 } 84 85 #pragma GCC diagnostic push 86 #pragma GCC diagnostic ignored "-Wformat-nonliteral" 87 88 int 89 linux_parse_vt_settings(int may_fail) 90 { 91 int i, fd = -1, ret, current_vt = -1; 92 struct vt_stat vts; 93 struct stat st; 94 MessageType from = X_PROBED; 95 96 /* Only do this once */ 97 static int vt_settings_parsed = 0; 98 99 if (vt_settings_parsed) 100 return 1; 101 102 /* 103 * setup the virtual terminal manager 104 */ 105 if (xf86Info.vtno != -1) { 106 from = X_CMDLINE; 107 } 108 else { 109 fd = open("/dev/tty0", O_WRONLY, 0); 110 if (fd < 0) { 111 if (may_fail) 112 return 0; 113 FatalError("parse_vt_settings: Cannot open /dev/tty0 (%s)\n", 114 strerror(errno)); 115 } 116 117 if (xf86Info.ShareVTs) { 118 SYSCALL(ret = ioctl(fd, VT_GETSTATE, &vts)); 119 if (ret < 0) { 120 if (may_fail) 121 return 0; 122 FatalError("parse_vt_settings: Cannot find the current" 123 " VT (%s)\n", strerror(errno)); 124 } 125 xf86Info.vtno = vts.v_active; 126 } 127 else { 128 SYSCALL(ret = ioctl(fd, VT_OPENQRY, &xf86Info.vtno)); 129 if (ret < 0) { 130 if (may_fail) 131 return 0; 132 FatalError("parse_vt_settings: Cannot find a free VT: " 133 "%s\n", strerror(errno)); 134 } 135 if (xf86Info.vtno == -1) { 136 if (may_fail) 137 return 0; 138 FatalError("parse_vt_settings: Cannot find a free VT\n"); 139 } 140 } 141 close(fd); 142 } 143 144 xf86Msg(from, "using VT number %d\n\n", xf86Info.vtno); 145 146 /* Some of stdin / stdout / stderr maybe redirected to a file */ 147 for (i = STDIN_FILENO; i <= STDERR_FILENO; i++) { 148 ret = fstat(i, &st); 149 if (ret == 0 && S_ISCHR(st.st_mode) && major(st.st_rdev) == 4) { 150 current_vt = minor(st.st_rdev); 151 break; 152 } 153 } 154 155 if (!KeepTty && current_vt == xf86Info.vtno) { 156 xf86Msg(X_PROBED, 157 "controlling tty is VT number %d, auto-enabling KeepTty\n", 158 current_vt); 159 KeepTty = TRUE; 160 } 161 162 vt_settings_parsed = 1; 163 return 1; 164 } 165 166 int 167 linux_get_keeptty(void) 168 { 169 return KeepTty; 170 } 171 172 void 173 xf86OpenConsole(void) 174 { 175 int i, ret; 176 struct vt_stat vts; 177 struct vt_mode VT; 178 const char *vcs[] = { "/dev/vc/%d", "/dev/tty%d", NULL }; 179 180 if (serverGeneration == 1) { 181 linux_parse_vt_settings(FALSE); 182 183 if (!KeepTty) { 184 pid_t ppid = getppid(); 185 pid_t ppgid; 186 187 ppgid = getpgid(ppid); 188 189 /* 190 * change to parent process group that pgid != pid so 191 * that setsid() doesn't fail and we become process 192 * group leader 193 */ 194 if (setpgid(0, ppgid) < 0) 195 xf86Msg(X_WARNING, "xf86OpenConsole: setpgid failed: %s\n", 196 strerror(errno)); 197 198 /* become process group leader */ 199 if ((setsid() < 0)) 200 xf86Msg(X_WARNING, "xf86OpenConsole: setsid failed: %s\n", 201 strerror(errno)); 202 } 203 204 i = 0; 205 while (vcs[i] != NULL) { 206 snprintf(vtname, sizeof(vtname), vcs[i], xf86Info.vtno); /* /dev/tty1-64 */ 207 if ((xf86Info.consoleFd = open(vtname, O_RDWR | O_NDELAY, 0)) >= 0) 208 break; 209 i++; 210 } 211 212 if (xf86Info.consoleFd < 0) 213 FatalError("xf86OpenConsole: Cannot open virtual console" 214 " %d (%s)\n", xf86Info.vtno, strerror(errno)); 215 216 /* 217 * Linux doesn't switch to an active vt after the last close of a vt, 218 * so we do this ourselves by remembering which is active now. 219 */ 220 SYSCALL(ret = ioctl(xf86Info.consoleFd, VT_GETSTATE, &vts)); 221 if (ret < 0) 222 xf86Msg(X_WARNING, "xf86OpenConsole: VT_GETSTATE failed: %s\n", 223 strerror(errno)); 224 else 225 activeVT = vts.v_active; 226 227 if (!xf86Info.ShareVTs) { 228 struct termios nTty; 229 230 /* 231 * now get the VT. This _must_ succeed, or else fail completely. 232 */ 233 if (!switch_to(xf86Info.vtno, "xf86OpenConsole")) 234 FatalError("xf86OpenConsole: Switching VT failed\n"); 235 236 SYSCALL(ret = ioctl(xf86Info.consoleFd, VT_GETMODE, &VT)); 237 if (ret < 0) 238 FatalError("xf86OpenConsole: VT_GETMODE failed %s\n", 239 strerror(errno)); 240 241 OsSignal(SIGUSR1, xf86VTRequest); 242 243 VT.mode = VT_PROCESS; 244 VT.relsig = SIGUSR1; 245 VT.acqsig = SIGUSR1; 246 247 SYSCALL(ret = ioctl(xf86Info.consoleFd, VT_SETMODE, &VT)); 248 if (ret < 0) 249 FatalError 250 ("xf86OpenConsole: VT_SETMODE VT_PROCESS failed: %s\n", 251 strerror(errno)); 252 253 SYSCALL(ret = ioctl(xf86Info.consoleFd, KDSETMODE, KD_GRAPHICS)); 254 if (ret < 0) 255 FatalError("xf86OpenConsole: KDSETMODE KD_GRAPHICS failed %s\n", 256 strerror(errno)); 257 258 tcgetattr(xf86Info.consoleFd, &tty_attr); 259 SYSCALL(ioctl(xf86Info.consoleFd, KDGKBMODE, &tty_mode)); 260 261 /* disable kernel special keys and buffering */ 262 SYSCALL(ret = ioctl(xf86Info.consoleFd, KDSKBMODE, K_OFF)); 263 if (ret < 0) 264 { 265 /* fine, just disable special keys */ 266 SYSCALL(ret = ioctl(xf86Info.consoleFd, KDSKBMODE, K_RAW)); 267 if (ret < 0) 268 FatalError("xf86OpenConsole: KDSKBMODE K_RAW failed %s\n", 269 strerror(errno)); 270 271 /* ... and drain events, else the kernel gets angry */ 272 xf86SetConsoleHandler(drain_console, NULL); 273 } 274 275 nTty = tty_attr; 276 nTty.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP); 277 nTty.c_oflag = 0; 278 nTty.c_cflag = CREAD | CS8; 279 nTty.c_lflag = 0; 280 nTty.c_cc[VTIME] = 0; 281 nTty.c_cc[VMIN] = 1; 282 cfsetispeed(&nTty, 9600); 283 cfsetospeed(&nTty, 9600); 284 tcsetattr(xf86Info.consoleFd, TCSANOW, &nTty); 285 } 286 } 287 else { /* serverGeneration != 1 */ 288 if (!xf86Info.ShareVTs && xf86Info.autoVTSwitch) { 289 /* now get the VT */ 290 if (!switch_to(xf86Info.vtno, "xf86OpenConsole")) 291 FatalError("xf86OpenConsole: Switching VT failed\n"); 292 } 293 } 294 } 295 296 #pragma GCC diagnostic pop 297 298 void 299 xf86CloseConsole(void) 300 { 301 struct vt_mode VT; 302 struct vt_stat vts; 303 int ret; 304 305 if (xf86Info.ShareVTs) { 306 close(xf86Info.consoleFd); 307 return; 308 } 309 310 /* 311 * unregister the drain_console handler 312 * - what to do if someone else changed it in the meantime? 313 */ 314 xf86SetConsoleHandler(NULL, NULL); 315 316 /* Back to text mode ... */ 317 SYSCALL(ret = ioctl(xf86Info.consoleFd, KDSETMODE, KD_TEXT)); 318 if (ret < 0) 319 xf86Msg(X_WARNING, "xf86CloseConsole: KDSETMODE failed: %s\n", 320 strerror(errno)); 321 322 SYSCALL(ioctl(xf86Info.consoleFd, KDSKBMODE, tty_mode)); 323 tcsetattr(xf86Info.consoleFd, TCSANOW, &tty_attr); 324 325 SYSCALL(ret = ioctl(xf86Info.consoleFd, VT_GETMODE, &VT)); 326 if (ret < 0) 327 xf86Msg(X_WARNING, "xf86CloseConsole: VT_GETMODE failed: %s\n", 328 strerror(errno)); 329 else { 330 /* set dflt vt handling */ 331 VT.mode = VT_AUTO; 332 SYSCALL(ret = ioctl(xf86Info.consoleFd, VT_SETMODE, &VT)); 333 if (ret < 0) 334 xf86Msg(X_WARNING, "xf86CloseConsole: VT_SETMODE failed: %s\n", 335 strerror(errno)); 336 } 337 338 if (xf86Info.autoVTSwitch) { 339 /* 340 * Perform a switch back to the active VT when we were started if our 341 * vt is active now. 342 */ 343 if (activeVT >= 0) { 344 SYSCALL(ret = ioctl(xf86Info.consoleFd, VT_GETSTATE, &vts)); 345 if (ret < 0) { 346 xf86Msg(X_WARNING, "xf86OpenConsole: VT_GETSTATE failed: %s\n", 347 strerror(errno)); 348 } else { 349 if (vts.v_active == xf86Info.vtno) { 350 switch_to(activeVT, "xf86CloseConsole"); 351 } 352 } 353 activeVT = -1; 354 } 355 } 356 close(xf86Info.consoleFd); /* make the vt-manager happy */ 357 } 358 359 #define CHECK_FOR_REQUIRED_ARGUMENT() \ 360 if (((i + 1) >= argc) || (!argv[i + 1])) { \ 361 ErrorF("Required argument to %s not specified\n", argv[i]); \ 362 UseMsg(); \ 363 FatalError("Required argument to %s not specified\n", argv[i]); \ 364 } 365 366 int 367 xf86ProcessArgument(int argc, char *argv[], int i) 368 { 369 /* 370 * Keep server from detaching from controlling tty. This is useful 371 * when debugging (so the server can receive keyboard signals. 372 */ 373 if (!strcmp(argv[i], "-keeptty")) { 374 KeepTty = TRUE; 375 return 1; 376 } 377 378 if ((argv[i][0] == 'v') && (argv[i][1] == 't')) { 379 if (sscanf(argv[i], "vt%2d", &xf86Info.vtno) == 0) { 380 UseMsg(); 381 xf86Info.vtno = -1; 382 return 0; 383 } 384 return 1; 385 } 386 387 if (!strcmp(argv[i], "-masterfd")) { 388 CHECK_FOR_REQUIRED_ARGUMENT(); 389 if (xf86PrivsElevated()) 390 FatalError("\nCannot specify -masterfd when server is setuid/setgid\n"); 391 if (sscanf(argv[++i], "%d", &xf86DRMMasterFd) != 1) { 392 UseMsg(); 393 xf86DRMMasterFd = -1; 394 return 0; 395 } 396 return 2; 397 } 398 399 return 0; 400 } 401 402 void 403 xf86UseMsg(void) 404 { 405 ErrorF("vtXX use the specified VT number\n"); 406 ErrorF("-keeptty "); 407 ErrorF("don't detach controlling tty (for debugging only)\n"); 408 ErrorF("-masterfd <fd> use the specified fd as the DRM master fd (not if setuid/gid)\n"); 409 } 410 411 void 412 xf86OSInputThreadInit(void) 413 { 414 return; 415 }