utils.c (58181B)
1 /* 2 3 Copyright 1987, 1998 The Open Group 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. 10 11 The above copyright notice and this permission notice shall be included 12 in all copies or substantial portions of the Software. 13 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 OTHER DEALINGS IN THE SOFTWARE. 21 22 Except as contained in this notice, the name of The Open Group shall 23 not be used in advertising or otherwise to promote the sale, use or 24 other dealings in this Software without prior written authorization 25 from The Open Group. 26 27 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, 28 Copyright 1994 Quarterdeck Office Systems. 29 30 All Rights Reserved 31 32 Permission to use, copy, modify, and distribute this software and its 33 documentation for any purpose and without fee is hereby granted, 34 provided that the above copyright notice appear in all copies and that 35 both that copyright notice and this permission notice appear in 36 supporting documentation, and that the names of Digital and 37 Quarterdeck not be used in advertising or publicity pertaining to 38 distribution of the software without specific, written prior 39 permission. 40 41 DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS 42 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 43 FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT 44 OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 45 OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 46 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE 47 OR PERFORMANCE OF THIS SOFTWARE. 48 49 */ 50 51 #ifdef HAVE_DIX_CONFIG_H 52 #include <dix-config.h> 53 #endif 54 55 #ifdef __CYGWIN__ 56 #include <stdlib.h> 57 #include <signal.h> 58 /* 59 Sigh... We really need a prototype for this to know it is stdcall, 60 but #include-ing <windows.h> here is not a good idea... 61 */ 62 __stdcall unsigned long GetTickCount(void); 63 #endif 64 65 #if defined(WIN32) && !defined(__CYGWIN__) 66 #include <X11/Xwinsock.h> 67 #endif 68 #include <X11/Xos.h> 69 #include <stdio.h> 70 #include <time.h> 71 #if !defined(WIN32) || !defined(__MINGW32__) 72 #include <sys/time.h> 73 #include <sys/resource.h> 74 #endif 75 #include "misc.h" 76 #include <X11/X.h> 77 #define XSERV_t 78 #define TRANS_SERVER 79 #define TRANS_REOPEN 80 #include <X11/Xtrans/Xtrans.h> 81 #include "input.h" 82 #include "dixfont.h" 83 #include <X11/fonts/libxfont2.h> 84 #include "osdep.h" 85 #include "extension.h" 86 #include <signal.h> 87 #ifndef WIN32 88 #include <sys/wait.h> 89 #endif 90 #if !defined(SYSV) && !defined(WIN32) 91 #include <sys/resource.h> 92 #endif 93 #include <sys/stat.h> 94 #include <ctype.h> /* for isspace */ 95 #include <stdarg.h> 96 97 #include <stdlib.h> /* for malloc() */ 98 99 #if defined(TCPCONN) 100 #ifndef WIN32 101 #include <netdb.h> 102 #endif 103 #endif 104 105 #include "opaque.h" 106 107 #include "dixstruct.h" 108 109 #include "xkbsrv.h" 110 111 #include "picture.h" 112 113 #include "miinitext.h" 114 115 #include "present.h" 116 117 Bool noTestExtensions; 118 119 #ifdef COMPOSITE 120 Bool noCompositeExtension = FALSE; 121 #endif 122 123 #ifdef DAMAGE 124 Bool noDamageExtension = FALSE; 125 #endif 126 #ifdef DBE 127 Bool noDbeExtension = FALSE; 128 #endif 129 #ifdef DPMSExtension 130 #include "dpmsproc.h" 131 Bool noDPMSExtension = FALSE; 132 #endif 133 #ifdef GLXEXT 134 Bool noGlxExtension = FALSE; 135 #endif 136 #ifdef SCREENSAVER 137 Bool noScreenSaverExtension = FALSE; 138 #endif 139 #ifdef MITSHM 140 Bool noMITShmExtension = FALSE; 141 #endif 142 #ifdef RANDR 143 Bool noRRExtension = FALSE; 144 #endif 145 Bool noRenderExtension = FALSE; 146 147 #ifdef XCSECURITY 148 Bool noSecurityExtension = FALSE; 149 #endif 150 #ifdef RES 151 Bool noResExtension = FALSE; 152 #endif 153 #ifdef XF86BIGFONT 154 Bool noXFree86BigfontExtension = FALSE; 155 #endif 156 #ifdef XFreeXDGA 157 Bool noXFree86DGAExtension = FALSE; 158 #endif 159 #ifdef XF86DRI 160 Bool noXFree86DRIExtension = FALSE; 161 #endif 162 #ifdef XF86VIDMODE 163 Bool noXFree86VidModeExtension = FALSE; 164 #endif 165 Bool noXFixesExtension = FALSE; 166 #ifdef PANORAMIX 167 /* Xinerama is disabled by default unless enabled via +xinerama */ 168 Bool noPanoramiXExtension = TRUE; 169 #endif 170 #ifdef XSELINUX 171 Bool noSELinuxExtension = FALSE; 172 int selinuxEnforcingState = SELINUX_MODE_DEFAULT; 173 #endif 174 #ifdef XV 175 Bool noXvExtension = FALSE; 176 #endif 177 #ifdef DRI2 178 Bool noDRI2Extension = FALSE; 179 #endif 180 181 Bool noGEExtension = FALSE; 182 183 #define X_INCLUDE_NETDB_H 184 #include <X11/Xos_r.h> 185 186 #include <errno.h> 187 188 Bool CoreDump; 189 190 Bool enableIndirectGLX = FALSE; 191 192 #ifdef PANORAMIX 193 Bool PanoramiXExtensionDisabledHack = FALSE; 194 #endif 195 196 int auditTrailLevel = 1; 197 198 char *SeatId = NULL; 199 200 sig_atomic_t inSignalContext = FALSE; 201 202 #if defined(SVR4) || defined(__linux__) || defined(CSRG_BASED) 203 #define HAS_SAVED_IDS_AND_SETEUID 204 #endif 205 206 #ifdef MONOTONIC_CLOCK 207 static clockid_t clockid; 208 #endif 209 210 OsSigHandlerPtr 211 OsSignal(int sig, OsSigHandlerPtr handler) 212 { 213 #if defined(WIN32) && !defined(__CYGWIN__) 214 return signal(sig, handler); 215 #else 216 struct sigaction act, oact; 217 218 sigemptyset(&act.sa_mask); 219 if (handler != SIG_IGN) 220 sigaddset(&act.sa_mask, sig); 221 act.sa_flags = 0; 222 act.sa_handler = handler; 223 if (sigaction(sig, &act, &oact)) 224 perror("sigaction"); 225 return oact.sa_handler; 226 #endif 227 } 228 229 /* 230 * Explicit support for a server lock file like the ones used for UUCP. 231 * For architectures with virtual terminals that can run more than one 232 * server at a time. This keeps the servers from stomping on each other 233 * if the user forgets to give them different display numbers. 234 */ 235 #define LOCK_DIR "/tmp" 236 #define LOCK_TMP_PREFIX "/.tX" 237 #define LOCK_PREFIX "/.X" 238 #define LOCK_SUFFIX "-lock" 239 240 #if !defined(WIN32) || defined(__CYGWIN__) 241 #define LOCK_SERVER 242 #endif 243 244 #ifndef LOCK_SERVER 245 void 246 LockServer(void) 247 {} 248 249 void 250 UnlockServer(void) 251 {} 252 #else /* LOCK_SERVER */ 253 static Bool StillLocking = FALSE; 254 static char LockFile[PATH_MAX]; 255 static Bool nolock = FALSE; 256 257 /* 258 * LockServer -- 259 * Check if the server lock file exists. If so, check if the PID 260 * contained inside is valid. If so, then die. Otherwise, create 261 * the lock file containing the PID. 262 */ 263 void 264 LockServer(void) 265 { 266 char tmp[PATH_MAX], pid_str[12]; 267 int lfd, i, haslock, l_pid, t; 268 const char *tmppath = LOCK_DIR; 269 int len; 270 char port[20]; 271 272 if (nolock || NoListenAll) 273 return; 274 /* 275 * Path names 276 */ 277 snprintf(port, sizeof(port), "%d", atoi(display)); 278 len = strlen(LOCK_PREFIX) > strlen(LOCK_TMP_PREFIX) ? strlen(LOCK_PREFIX) : 279 strlen(LOCK_TMP_PREFIX); 280 len += strlen(tmppath) + strlen(port) + strlen(LOCK_SUFFIX) + 1; 281 if (len > sizeof(LockFile)) 282 FatalError("Display name `%s' is too long\n", port); 283 (void) sprintf(tmp, "%s" LOCK_TMP_PREFIX "%s" LOCK_SUFFIX, tmppath, port); 284 (void) sprintf(LockFile, "%s" LOCK_PREFIX "%s" LOCK_SUFFIX, tmppath, port); 285 286 /* 287 * Create a temporary file containing our PID. Attempt three times 288 * to create the file. 289 */ 290 StillLocking = TRUE; 291 i = 0; 292 do { 293 i++; 294 lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644); 295 if (lfd < 0) 296 sleep(2); 297 else 298 break; 299 } while (i < 3); 300 if (lfd < 0) { 301 unlink(tmp); 302 i = 0; 303 do { 304 i++; 305 lfd = open(tmp, O_CREAT | O_EXCL | O_WRONLY, 0644); 306 if (lfd < 0) 307 sleep(2); 308 else 309 break; 310 } while (i < 3); 311 } 312 if (lfd < 0) 313 FatalError("Could not create lock file in %s\n", tmp); 314 snprintf(pid_str, sizeof(pid_str), "%10lu\n", (unsigned long) getpid()); 315 if (write(lfd, pid_str, 11) != 11) 316 FatalError("Could not write pid to lock file in %s\n", tmp); 317 (void) fchmod(lfd, 0444); 318 (void) close(lfd); 319 320 /* 321 * OK. Now the tmp file exists. Try three times to move it in place 322 * for the lock. 323 */ 324 i = 0; 325 haslock = 0; 326 while ((!haslock) && (i++ < 3)) { 327 haslock = (link(tmp, LockFile) == 0); 328 if (haslock) { 329 /* 330 * We're done. 331 */ 332 break; 333 } 334 else if (errno == EEXIST) { 335 /* 336 * Read the pid from the existing file 337 */ 338 lfd = open(LockFile, O_RDONLY | O_NOFOLLOW); 339 if (lfd < 0) { 340 unlink(tmp); 341 FatalError("Can't read lock file %s\n", LockFile); 342 } 343 pid_str[0] = '\0'; 344 if (read(lfd, pid_str, 11) != 11) { 345 /* 346 * Bogus lock file. 347 */ 348 unlink(LockFile); 349 close(lfd); 350 continue; 351 } 352 pid_str[11] = '\0'; 353 sscanf(pid_str, "%d", &l_pid); 354 close(lfd); 355 356 /* 357 * Now try to kill the PID to see if it exists. 358 */ 359 errno = 0; 360 t = kill(l_pid, 0); 361 if ((t < 0) && (errno == ESRCH)) { 362 /* 363 * Stale lock file. 364 */ 365 unlink(LockFile); 366 continue; 367 } 368 else if (((t < 0) && (errno == EPERM)) || (t == 0)) { 369 /* 370 * Process is still active. 371 */ 372 unlink(tmp); 373 FatalError 374 ("Server is already active for display %s\n%s %s\n%s\n", 375 port, "\tIf this server is no longer running, remove", 376 LockFile, "\tand start again."); 377 } 378 } 379 else { 380 unlink(tmp); 381 FatalError 382 ("Linking lock file (%s) in place failed: %s\n", 383 LockFile, strerror(errno)); 384 } 385 } 386 unlink(tmp); 387 if (!haslock) 388 FatalError("Could not create server lock file: %s\n", LockFile); 389 StillLocking = FALSE; 390 } 391 392 /* 393 * UnlockServer -- 394 * Remove the server lock file. 395 */ 396 void 397 UnlockServer(void) 398 { 399 if (nolock || NoListenAll) 400 return; 401 402 if (!StillLocking) { 403 404 (void) unlink(LockFile); 405 } 406 } 407 #endif /* LOCK_SERVER */ 408 409 /* Force connections to close on SIGHUP from init */ 410 411 void 412 AutoResetServer(int sig) 413 { 414 int olderrno = errno; 415 416 dispatchException |= DE_RESET; 417 isItTimeToYield = TRUE; 418 errno = olderrno; 419 } 420 421 /* Force connections to close and then exit on SIGTERM, SIGINT */ 422 423 void 424 GiveUp(int sig) 425 { 426 int olderrno = errno; 427 428 dispatchException |= DE_TERMINATE; 429 isItTimeToYield = TRUE; 430 errno = olderrno; 431 } 432 433 #ifdef MONOTONIC_CLOCK 434 void 435 ForceClockId(clockid_t forced_clockid) 436 { 437 struct timespec tp; 438 439 BUG_RETURN (clockid); 440 441 clockid = forced_clockid; 442 443 if (clock_gettime(clockid, &tp) != 0) { 444 FatalError("Forced clock id failed to retrieve current time: %s\n", 445 strerror(errno)); 446 return; 447 } 448 } 449 #endif 450 451 #if (defined WIN32 && defined __MINGW32__) || defined(__CYGWIN__) 452 CARD32 453 GetTimeInMillis(void) 454 { 455 return GetTickCount(); 456 } 457 CARD64 458 GetTimeInMicros(void) 459 { 460 return (CARD64) GetTickCount() * 1000; 461 } 462 #else 463 CARD32 464 GetTimeInMillis(void) 465 { 466 struct timeval tv; 467 468 #ifdef MONOTONIC_CLOCK 469 struct timespec tp; 470 471 if (!clockid) { 472 #ifdef CLOCK_MONOTONIC_COARSE 473 if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 && 474 (tp.tv_nsec / 1000) <= 1000 && 475 clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0) 476 clockid = CLOCK_MONOTONIC_COARSE; 477 else 478 #endif 479 if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) 480 clockid = CLOCK_MONOTONIC; 481 else 482 clockid = ~0L; 483 } 484 if (clockid != ~0L && clock_gettime(clockid, &tp) == 0) 485 return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L); 486 #endif 487 488 X_GETTIMEOFDAY(&tv); 489 return (tv.tv_sec * 1000) + (tv.tv_usec / 1000); 490 } 491 492 CARD64 493 GetTimeInMicros(void) 494 { 495 struct timeval tv; 496 #ifdef MONOTONIC_CLOCK 497 struct timespec tp; 498 static clockid_t uclockid; 499 500 if (!uclockid) { 501 if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) 502 uclockid = CLOCK_MONOTONIC; 503 else 504 uclockid = ~0L; 505 } 506 if (uclockid != ~0L && clock_gettime(uclockid, &tp) == 0) 507 return (CARD64) tp.tv_sec * (CARD64)1000000 + tp.tv_nsec / 1000; 508 #endif 509 510 X_GETTIMEOFDAY(&tv); 511 return (CARD64) tv.tv_sec * (CARD64)1000000 + (CARD64) tv.tv_usec; 512 } 513 #endif 514 515 void 516 UseMsg(void) 517 { 518 ErrorF("use: X [:<display>] [option]\n"); 519 ErrorF("-a # default pointer acceleration (factor)\n"); 520 ErrorF("-ac disable access control restrictions\n"); 521 ErrorF("-audit int set audit trail level\n"); 522 ErrorF("-auth file select authorization file\n"); 523 ErrorF("-br create root window with black background\n"); 524 ErrorF("+bs enable any backing store support\n"); 525 ErrorF("-bs disable any backing store support\n"); 526 ErrorF("-c turns off key-click\n"); 527 ErrorF("c # key-click volume (0-100)\n"); 528 ErrorF("-cc int default color visual class\n"); 529 ErrorF("-nocursor disable the cursor\n"); 530 ErrorF("-core generate core dump on fatal error\n"); 531 ErrorF("-displayfd fd file descriptor to write display number to when ready to connect\n"); 532 ErrorF("-dpi int screen resolution in dots per inch\n"); 533 #ifdef DPMSExtension 534 ErrorF("-dpms disables VESA DPMS monitor control\n"); 535 #endif 536 ErrorF 537 ("-deferglyphs [none|all|16] defer loading of [no|all|16-bit] glyphs\n"); 538 ErrorF("-f # bell base (0-100)\n"); 539 ErrorF("-fakescreenfps # fake screen default fps (1-600)\n"); 540 ErrorF("-fp string default font path\n"); 541 ErrorF("-help prints message with these options\n"); 542 ErrorF("+iglx Allow creating indirect GLX contexts\n"); 543 ErrorF("-iglx Prohibit creating indirect GLX contexts (default)\n"); 544 ErrorF("-I ignore all remaining arguments\n"); 545 #ifdef RLIMIT_DATA 546 ErrorF("-ld int limit data space to N Kb\n"); 547 #endif 548 #ifdef RLIMIT_NOFILE 549 ErrorF("-lf int limit number of open files to N\n"); 550 #endif 551 #ifdef RLIMIT_STACK 552 ErrorF("-ls int limit stack space to N Kb\n"); 553 #endif 554 #ifdef LOCK_SERVER 555 ErrorF("-nolock disable the locking mechanism\n"); 556 #endif 557 ErrorF("-maxclients n set maximum number of clients (power of two)\n"); 558 ErrorF("-nolisten string don't listen on protocol\n"); 559 ErrorF("-listen string listen on protocol\n"); 560 ErrorF("-noreset don't reset after last client exists\n"); 561 ErrorF("-background [none] create root window with no background\n"); 562 ErrorF("-reset reset after last client exists\n"); 563 ErrorF("-p # screen-saver pattern duration (minutes)\n"); 564 ErrorF("-pn accept failure to listen on all ports\n"); 565 ErrorF("-nopn reject failure to listen on all ports\n"); 566 ErrorF("-r turns off auto-repeat\n"); 567 ErrorF("r turns on auto-repeat \n"); 568 ErrorF("-render [default|mono|gray|color] set render color alloc policy\n"); 569 ErrorF("-retro start with classic stipple and cursor\n"); 570 ErrorF("-s # screen-saver timeout (minutes)\n"); 571 ErrorF("-seat string seat to run on\n"); 572 ErrorF("-t # default pointer threshold (pixels/t)\n"); 573 ErrorF("-terminate [delay] terminate at server reset (optional delay in sec)\n"); 574 ErrorF("-tst disable testing extensions\n"); 575 ErrorF("ttyxx server started from init on /dev/ttyxx\n"); 576 ErrorF("v video blanking for screen-saver\n"); 577 ErrorF("-v screen-saver without video blanking\n"); 578 ErrorF("-wr create root window with white background\n"); 579 ErrorF("-maxbigreqsize set maximal bigrequest size \n"); 580 #ifdef PANORAMIX 581 ErrorF("+xinerama Enable XINERAMA extension\n"); 582 ErrorF("-xinerama Disable XINERAMA extension\n"); 583 #endif 584 ErrorF 585 ("-dumbSched Disable smart scheduling and threaded input, enable old behavior\n"); 586 ErrorF("-schedInterval int Set scheduler interval in msec\n"); 587 ErrorF("-sigstop Enable SIGSTOP based startup\n"); 588 ErrorF("+extension name Enable extension\n"); 589 ErrorF("-extension name Disable extension\n"); 590 ListStaticExtensions(); 591 #ifdef XDMCP 592 XdmcpUseMsg(); 593 #endif 594 XkbUseMsg(); 595 ddxUseMsg(); 596 } 597 598 /* This function performs a rudimentary sanity check 599 * on the display name passed in on the command-line, 600 * since this string is used to generate filenames. 601 * It is especially important that the display name 602 * not contain a "/" and not start with a "-". 603 * --kvajk 604 */ 605 static int 606 VerifyDisplayName(const char *d) 607 { 608 int i; 609 int period_found = FALSE; 610 int after_period = 0; 611 612 if (d == (char *) 0) 613 return 0; /* null */ 614 if (*d == '\0') 615 return 0; /* empty */ 616 if (*d == '-') 617 return 0; /* could be confused for an option */ 618 if (*d == '.') 619 return 0; /* must not equal "." or ".." */ 620 if (strchr(d, '/') != (char *) 0) 621 return 0; /* very important!!! */ 622 623 /* Since we run atoi() on the display later, only allow 624 for digits, or exception of :0.0 and similar (two decimal points max) 625 */ 626 for (i = 0; i < strlen(d); i++) { 627 if (!isdigit(d[i])) { 628 if (d[i] != '.' || period_found) 629 return 0; 630 period_found = TRUE; 631 } else if (period_found) 632 after_period++; 633 634 if (after_period > 2) 635 return 0; 636 } 637 638 /* don't allow for :0. */ 639 if (period_found && after_period == 0) 640 return 0; 641 642 if (atol(d) > INT_MAX) 643 return 0; 644 645 return 1; 646 } 647 648 static const char *defaultNoListenList[] = { 649 #ifndef LISTEN_TCP 650 "tcp", 651 #endif 652 #ifndef LISTEN_UNIX 653 "unix", 654 #endif 655 #ifndef LISTEN_LOCAL 656 "local", 657 #endif 658 NULL 659 }; 660 661 /* 662 * This function parses the command line. Handles device-independent fields 663 * and allows ddx to handle additional fields. It is not allowed to modify 664 * argc or any of the strings pointed to by argv. 665 */ 666 void 667 ProcessCommandLine(int argc, char *argv[]) 668 { 669 int i, skip; 670 671 defaultKeyboardControl.autoRepeat = TRUE; 672 673 #ifdef NO_PART_NET 674 PartialNetwork = FALSE; 675 #else 676 PartialNetwork = TRUE; 677 #endif 678 679 for (i = 0; defaultNoListenList[i] != NULL; i++) { 680 if (_XSERVTransNoListen(defaultNoListenList[i])) 681 ErrorF("Failed to disable listen for %s transport", 682 defaultNoListenList[i]); 683 } 684 SeatId = getenv("XDG_SEAT"); 685 686 for (i = 1; i < argc; i++) { 687 /* call ddx first, so it can peek/override if it wants */ 688 if ((skip = ddxProcessArgument(argc, argv, i))) { 689 i += (skip - 1); 690 } 691 else if (argv[i][0] == ':') { 692 /* initialize display */ 693 display = argv[i]; 694 explicit_display = TRUE; 695 display++; 696 if (!VerifyDisplayName(display)) { 697 ErrorF("Bad display name: %s\n", display); 698 UseMsg(); 699 FatalError("Bad display name, exiting: %s\n", display); 700 } 701 } 702 else if (strcmp(argv[i], "-a") == 0) { 703 if (++i < argc) 704 defaultPointerControl.num = atoi(argv[i]); 705 else 706 UseMsg(); 707 } 708 else if (strcmp(argv[i], "-ac") == 0) { 709 defeatAccessControl = TRUE; 710 } 711 else if (strcmp(argv[i], "-audit") == 0) { 712 if (++i < argc) 713 auditTrailLevel = atoi(argv[i]); 714 else 715 UseMsg(); 716 } 717 else if (strcmp(argv[i], "-auth") == 0) { 718 if (++i < argc) 719 InitAuthorization(argv[i]); 720 else 721 UseMsg(); 722 } 723 else if (strcmp(argv[i], "-br") == 0); /* default */ 724 else if (strcmp(argv[i], "+bs") == 0) 725 enableBackingStore = TRUE; 726 else if (strcmp(argv[i], "-bs") == 0) 727 disableBackingStore = TRUE; 728 else if (strcmp(argv[i], "c") == 0) { 729 if (++i < argc) 730 defaultKeyboardControl.click = atoi(argv[i]); 731 else 732 UseMsg(); 733 } 734 else if (strcmp(argv[i], "-c") == 0) { 735 defaultKeyboardControl.click = 0; 736 } 737 else if (strcmp(argv[i], "-cc") == 0) { 738 if (++i < argc) 739 defaultColorVisualClass = atoi(argv[i]); 740 else 741 UseMsg(); 742 } 743 else if (strcmp(argv[i], "-core") == 0) { 744 #if !defined(WIN32) || !defined(__MINGW32__) 745 struct rlimit core_limit; 746 747 getrlimit(RLIMIT_CORE, &core_limit); 748 core_limit.rlim_cur = core_limit.rlim_max; 749 setrlimit(RLIMIT_CORE, &core_limit); 750 #endif 751 CoreDump = TRUE; 752 } 753 else if (strcmp(argv[i], "-nocursor") == 0) { 754 EnableCursor = FALSE; 755 } 756 else if (strcmp(argv[i], "-dpi") == 0) { 757 if (++i < argc) 758 monitorResolution = atoi(argv[i]); 759 else 760 UseMsg(); 761 } 762 else if (strcmp(argv[i], "-displayfd") == 0) { 763 if (++i < argc) { 764 displayfd = atoi(argv[i]); 765 #ifdef LOCK_SERVER 766 nolock = TRUE; 767 #endif 768 } 769 else 770 UseMsg(); 771 } 772 #ifdef DPMSExtension 773 else if (strcmp(argv[i], "dpms") == 0) 774 /* ignored for compatibility */ ; 775 else if (strcmp(argv[i], "-dpms") == 0) 776 DPMSDisabledSwitch = TRUE; 777 #endif 778 else if (strcmp(argv[i], "-deferglyphs") == 0) { 779 if (++i >= argc || !xfont2_parse_glyph_caching_mode(argv[i])) 780 UseMsg(); 781 } 782 else if (strcmp(argv[i], "-f") == 0) { 783 if (++i < argc) 784 defaultKeyboardControl.bell = atoi(argv[i]); 785 else 786 UseMsg(); 787 } 788 else if (strcmp(argv[i], "-fakescreenfps") == 0) { 789 if (++i < argc) { 790 FakeScreenFps = (uint32_t) atoi(argv[i]); 791 if (FakeScreenFps < 1 || FakeScreenFps > 600) 792 FatalError("fakescreenfps must be an integer in [1;600] range\n"); 793 } 794 else 795 UseMsg(); 796 } 797 else if (strcmp(argv[i], "-fp") == 0) { 798 if (++i < argc) { 799 defaultFontPath = argv[i]; 800 } 801 else 802 UseMsg(); 803 } 804 else if (strcmp(argv[i], "-help") == 0) { 805 UseMsg(); 806 exit(0); 807 } 808 else if (strcmp(argv[i], "+iglx") == 0) 809 enableIndirectGLX = TRUE; 810 else if (strcmp(argv[i], "-iglx") == 0) 811 enableIndirectGLX = FALSE; 812 else if ((skip = XkbProcessArguments(argc, argv, i)) != 0) { 813 if (skip > 0) 814 i += skip - 1; 815 else 816 UseMsg(); 817 } 818 #ifdef RLIMIT_DATA 819 else if (strcmp(argv[i], "-ld") == 0) { 820 if (++i < argc) { 821 limitDataSpace = atoi(argv[i]); 822 if (limitDataSpace > 0) 823 limitDataSpace *= 1024; 824 } 825 else 826 UseMsg(); 827 } 828 #endif 829 #ifdef RLIMIT_NOFILE 830 else if (strcmp(argv[i], "-lf") == 0) { 831 if (++i < argc) 832 limitNoFile = atoi(argv[i]); 833 else 834 UseMsg(); 835 } 836 #endif 837 #ifdef RLIMIT_STACK 838 else if (strcmp(argv[i], "-ls") == 0) { 839 if (++i < argc) { 840 limitStackSpace = atoi(argv[i]); 841 if (limitStackSpace > 0) 842 limitStackSpace *= 1024; 843 } 844 else 845 UseMsg(); 846 } 847 #endif 848 #ifdef LOCK_SERVER 849 else if (strcmp(argv[i], "-nolock") == 0) { 850 #if !defined(WIN32) && !defined(__CYGWIN__) 851 if (getuid() != 0) 852 ErrorF 853 ("Warning: the -nolock option can only be used by root\n"); 854 else 855 #endif 856 nolock = TRUE; 857 } 858 #endif 859 else if ( strcmp( argv[i], "-maxclients") == 0) 860 { 861 if (++i < argc) { 862 LimitClients = atoi(argv[i]); 863 if (LimitClients != 64 && 864 LimitClients != 128 && 865 LimitClients != 256 && 866 LimitClients != 512 && 867 LimitClients != 1024 && 868 LimitClients != 2048) { 869 FatalError("maxclients must be one of 64, 128, 256, 512, 1024 or 2048\n"); 870 } 871 } else 872 UseMsg(); 873 } 874 else if (strcmp(argv[i], "-nolisten") == 0) { 875 if (++i < argc) { 876 if (_XSERVTransNoListen(argv[i])) 877 ErrorF("Failed to disable listen for %s transport", 878 argv[i]); 879 } 880 else 881 UseMsg(); 882 } 883 else if (strcmp(argv[i], "-listen") == 0) { 884 if (++i < argc) { 885 if (_XSERVTransListen(argv[i])) 886 ErrorF("Failed to enable listen for %s transport", 887 argv[i]); 888 } 889 else 890 UseMsg(); 891 } 892 else if (strcmp(argv[i], "-noreset") == 0) { 893 dispatchExceptionAtReset = 0; 894 } 895 else if (strcmp(argv[i], "-reset") == 0) { 896 dispatchExceptionAtReset = DE_RESET; 897 } 898 else if (strcmp(argv[i], "-p") == 0) { 899 if (++i < argc) 900 defaultScreenSaverInterval = ((CARD32) atoi(argv[i])) * 901 MILLI_PER_MIN; 902 else 903 UseMsg(); 904 } 905 else if (strcmp(argv[i], "-pogo") == 0) { 906 dispatchException = DE_TERMINATE; 907 } 908 else if (strcmp(argv[i], "-pn") == 0) 909 PartialNetwork = TRUE; 910 else if (strcmp(argv[i], "-nopn") == 0) 911 PartialNetwork = FALSE; 912 else if (strcmp(argv[i], "r") == 0) 913 defaultKeyboardControl.autoRepeat = TRUE; 914 else if (strcmp(argv[i], "-r") == 0) 915 defaultKeyboardControl.autoRepeat = FALSE; 916 else if (strcmp(argv[i], "-retro") == 0) 917 party_like_its_1989 = TRUE; 918 else if (strcmp(argv[i], "-s") == 0) { 919 if (++i < argc) 920 defaultScreenSaverTime = ((CARD32) atoi(argv[i])) * 921 MILLI_PER_MIN; 922 else 923 UseMsg(); 924 } 925 else if (strcmp(argv[i], "-seat") == 0) { 926 if (++i < argc) 927 SeatId = argv[i]; 928 else 929 UseMsg(); 930 } 931 else if (strcmp(argv[i], "-t") == 0) { 932 if (++i < argc) 933 defaultPointerControl.threshold = atoi(argv[i]); 934 else 935 UseMsg(); 936 } 937 else if (strcmp(argv[i], "-terminate") == 0) { 938 dispatchExceptionAtReset = DE_TERMINATE; 939 terminateDelay = -1; 940 if ((i + 1 < argc) && (isdigit(*argv[i + 1]))) 941 terminateDelay = atoi(argv[++i]); 942 terminateDelay = max(0, terminateDelay); 943 } 944 else if (strcmp(argv[i], "-tst") == 0) { 945 noTestExtensions = TRUE; 946 } 947 else if (strcmp(argv[i], "v") == 0) 948 defaultScreenSaverBlanking = PreferBlanking; 949 else if (strcmp(argv[i], "-v") == 0) 950 defaultScreenSaverBlanking = DontPreferBlanking; 951 else if (strcmp(argv[i], "-wr") == 0) 952 whiteRoot = TRUE; 953 else if (strcmp(argv[i], "-background") == 0) { 954 if (++i < argc) { 955 if (!strcmp(argv[i], "none")) 956 bgNoneRoot = TRUE; 957 else 958 UseMsg(); 959 } 960 } 961 else if (strcmp(argv[i], "-maxbigreqsize") == 0) { 962 if (++i < argc) { 963 long reqSizeArg = atol(argv[i]); 964 965 /* Request size > 128MB does not make much sense... */ 966 if (reqSizeArg > 0L && reqSizeArg < 128L) { 967 maxBigRequestSize = (reqSizeArg * 1048576L) - 1L; 968 } 969 else { 970 UseMsg(); 971 } 972 } 973 else { 974 UseMsg(); 975 } 976 } 977 #ifdef PANORAMIX 978 else if (strcmp(argv[i], "+xinerama") == 0) { 979 noPanoramiXExtension = FALSE; 980 } 981 else if (strcmp(argv[i], "-xinerama") == 0) { 982 noPanoramiXExtension = TRUE; 983 } 984 else if (strcmp(argv[i], "-disablexineramaextension") == 0) { 985 PanoramiXExtensionDisabledHack = TRUE; 986 } 987 #endif 988 else if (strcmp(argv[i], "-I") == 0) { 989 /* ignore all remaining arguments */ 990 break; 991 } 992 else if (strncmp(argv[i], "tty", 3) == 0) { 993 /* init supplies us with this useless information */ 994 } 995 #ifdef XDMCP 996 else if ((skip = XdmcpOptions(argc, argv, i)) != i) { 997 i = skip - 1; 998 } 999 #endif 1000 else if (strcmp(argv[i], "-dumbSched") == 0) { 1001 InputThreadEnable = FALSE; 1002 #ifdef HAVE_SETITIMER 1003 SmartScheduleSignalEnable = FALSE; 1004 #endif 1005 } 1006 else if (strcmp(argv[i], "-schedInterval") == 0) { 1007 if (++i < argc) { 1008 SmartScheduleInterval = atoi(argv[i]); 1009 SmartScheduleSlice = SmartScheduleInterval; 1010 } 1011 else 1012 UseMsg(); 1013 } 1014 else if (strcmp(argv[i], "-schedMax") == 0) { 1015 if (++i < argc) { 1016 SmartScheduleMaxSlice = atoi(argv[i]); 1017 } 1018 else 1019 UseMsg(); 1020 } 1021 else if (strcmp(argv[i], "-render") == 0) { 1022 if (++i < argc) { 1023 int policy = PictureParseCmapPolicy(argv[i]); 1024 1025 if (policy != PictureCmapPolicyInvalid) 1026 PictureCmapPolicy = policy; 1027 else 1028 UseMsg(); 1029 } 1030 else 1031 UseMsg(); 1032 } 1033 else if (strcmp(argv[i], "-sigstop") == 0) { 1034 RunFromSigStopParent = TRUE; 1035 } 1036 else if (strcmp(argv[i], "+extension") == 0) { 1037 if (++i < argc) { 1038 if (!EnableDisableExtension(argv[i], TRUE)) 1039 EnableDisableExtensionError(argv[i], TRUE); 1040 } 1041 else 1042 UseMsg(); 1043 } 1044 else if (strcmp(argv[i], "-extension") == 0) { 1045 if (++i < argc) { 1046 if (!EnableDisableExtension(argv[i], FALSE)) 1047 EnableDisableExtensionError(argv[i], FALSE); 1048 } 1049 else 1050 UseMsg(); 1051 } 1052 else { 1053 ErrorF("Unrecognized option: %s\n", argv[i]); 1054 UseMsg(); 1055 FatalError("Unrecognized option: %s\n", argv[i]); 1056 } 1057 } 1058 } 1059 1060 /* Implement a simple-minded font authorization scheme. The authorization 1061 name is "hp-hostname-1", the contents are simply the host name. */ 1062 int 1063 set_font_authorizations(char **authorizations, int *authlen, void *client) 1064 { 1065 #define AUTHORIZATION_NAME "hp-hostname-1" 1066 #if defined(TCPCONN) 1067 static char *result = NULL; 1068 static char *p = NULL; 1069 1070 if (p == NULL) { 1071 char hname[1024], *hnameptr; 1072 unsigned int len; 1073 1074 #if defined(IPv6) && defined(AF_INET6) 1075 struct addrinfo hints, *ai = NULL; 1076 #else 1077 struct hostent *host; 1078 1079 #ifdef XTHREADS_NEEDS_BYNAMEPARAMS 1080 _Xgethostbynameparams hparams; 1081 #endif 1082 #endif 1083 1084 gethostname(hname, 1024); 1085 #if defined(IPv6) && defined(AF_INET6) 1086 memset(&hints, 0, sizeof(hints)); 1087 hints.ai_flags = AI_CANONNAME; 1088 if (getaddrinfo(hname, NULL, &hints, &ai) == 0) { 1089 hnameptr = ai->ai_canonname; 1090 } 1091 else { 1092 hnameptr = hname; 1093 } 1094 #else 1095 host = _XGethostbyname(hname, hparams); 1096 if (host == NULL) 1097 hnameptr = hname; 1098 else 1099 hnameptr = host->h_name; 1100 #endif 1101 1102 len = strlen(hnameptr) + 1; 1103 result = malloc(len + sizeof(AUTHORIZATION_NAME) + 4); 1104 1105 p = result; 1106 *p++ = sizeof(AUTHORIZATION_NAME) >> 8; 1107 *p++ = sizeof(AUTHORIZATION_NAME) & 0xff; 1108 *p++ = (len) >> 8; 1109 *p++ = (len & 0xff); 1110 1111 memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME)); 1112 p += sizeof(AUTHORIZATION_NAME); 1113 memmove(p, hnameptr, len); 1114 p += len; 1115 #if defined(IPv6) && defined(AF_INET6) 1116 if (ai) { 1117 freeaddrinfo(ai); 1118 } 1119 #endif 1120 } 1121 *authlen = p - result; 1122 *authorizations = result; 1123 return 1; 1124 #else /* TCPCONN */ 1125 return 0; 1126 #endif /* TCPCONN */ 1127 } 1128 1129 void * 1130 XNFalloc(unsigned long amount) 1131 { 1132 void *ptr = malloc(amount); 1133 1134 if (!ptr) 1135 FatalError("Out of memory"); 1136 return ptr; 1137 } 1138 1139 /* The original XNFcalloc was used with the xnfcalloc macro which multiplied 1140 * the arguments at the call site without allowing calloc to check for overflow. 1141 * XNFcallocarray was added to fix that without breaking ABI. 1142 */ 1143 void * 1144 XNFcalloc(unsigned long amount) 1145 { 1146 return XNFcallocarray(1, amount); 1147 } 1148 1149 void * 1150 XNFcallocarray(size_t nmemb, size_t size) 1151 { 1152 void *ret = calloc(nmemb, size); 1153 1154 if (!ret) 1155 FatalError("XNFcalloc: Out of memory"); 1156 return ret; 1157 } 1158 1159 void * 1160 XNFrealloc(void *ptr, unsigned long amount) 1161 { 1162 void *ret = realloc(ptr, amount); 1163 1164 if (!ret) 1165 FatalError("XNFrealloc: Out of memory"); 1166 return ret; 1167 } 1168 1169 void * 1170 XNFreallocarray(void *ptr, size_t nmemb, size_t size) 1171 { 1172 void *ret = reallocarray(ptr, nmemb, size); 1173 1174 if (!ret) 1175 FatalError("XNFreallocarray: Out of memory"); 1176 return ret; 1177 } 1178 1179 char * 1180 Xstrdup(const char *s) 1181 { 1182 if (s == NULL) 1183 return NULL; 1184 return strdup(s); 1185 } 1186 1187 char * 1188 XNFstrdup(const char *s) 1189 { 1190 char *ret; 1191 1192 if (s == NULL) 1193 return NULL; 1194 1195 ret = strdup(s); 1196 if (!ret) 1197 FatalError("XNFstrdup: Out of memory"); 1198 return ret; 1199 } 1200 1201 void 1202 SmartScheduleStopTimer(void) 1203 { 1204 #ifdef HAVE_SETITIMER 1205 struct itimerval timer; 1206 1207 if (!SmartScheduleSignalEnable) 1208 return; 1209 timer.it_interval.tv_sec = 0; 1210 timer.it_interval.tv_usec = 0; 1211 timer.it_value.tv_sec = 0; 1212 timer.it_value.tv_usec = 0; 1213 (void) setitimer(ITIMER_REAL, &timer, 0); 1214 #endif 1215 } 1216 1217 void 1218 SmartScheduleStartTimer(void) 1219 { 1220 #ifdef HAVE_SETITIMER 1221 struct itimerval timer; 1222 1223 if (!SmartScheduleSignalEnable) 1224 return; 1225 timer.it_interval.tv_sec = 0; 1226 timer.it_interval.tv_usec = SmartScheduleInterval * 1000; 1227 timer.it_value.tv_sec = 0; 1228 timer.it_value.tv_usec = SmartScheduleInterval * 1000; 1229 setitimer(ITIMER_REAL, &timer, 0); 1230 #endif 1231 } 1232 1233 #ifdef HAVE_SETITIMER 1234 static void 1235 SmartScheduleTimer(int sig) 1236 { 1237 SmartScheduleTime += SmartScheduleInterval; 1238 } 1239 1240 static int 1241 SmartScheduleEnable(void) 1242 { 1243 int ret = 0; 1244 struct sigaction act; 1245 1246 if (!SmartScheduleSignalEnable) 1247 return 0; 1248 1249 memset((char *) &act, 0, sizeof(struct sigaction)); 1250 1251 /* Set up the timer signal function */ 1252 act.sa_flags = SA_RESTART; 1253 act.sa_handler = SmartScheduleTimer; 1254 sigemptyset(&act.sa_mask); 1255 sigaddset(&act.sa_mask, SIGALRM); 1256 ret = sigaction(SIGALRM, &act, 0); 1257 return ret; 1258 } 1259 1260 static int 1261 SmartSchedulePause(void) 1262 { 1263 int ret = 0; 1264 struct sigaction act; 1265 1266 if (!SmartScheduleSignalEnable) 1267 return 0; 1268 1269 memset((char *) &act, 0, sizeof(struct sigaction)); 1270 1271 act.sa_handler = SIG_IGN; 1272 sigemptyset(&act.sa_mask); 1273 ret = sigaction(SIGALRM, &act, 0); 1274 return ret; 1275 } 1276 #endif 1277 1278 void 1279 SmartScheduleInit(void) 1280 { 1281 #ifdef HAVE_SETITIMER 1282 if (SmartScheduleEnable() < 0) { 1283 perror("sigaction for smart scheduler"); 1284 SmartScheduleSignalEnable = FALSE; 1285 } 1286 #endif 1287 } 1288 1289 #ifdef HAVE_SIGPROCMASK 1290 static sigset_t PreviousSignalMask; 1291 static int BlockedSignalCount; 1292 #endif 1293 1294 void 1295 OsBlockSignals(void) 1296 { 1297 #ifdef HAVE_SIGPROCMASK 1298 if (BlockedSignalCount++ == 0) { 1299 sigset_t set; 1300 1301 sigemptyset(&set); 1302 sigaddset(&set, SIGALRM); 1303 sigaddset(&set, SIGVTALRM); 1304 #ifdef SIGWINCH 1305 sigaddset(&set, SIGWINCH); 1306 #endif 1307 sigaddset(&set, SIGTSTP); 1308 sigaddset(&set, SIGTTIN); 1309 sigaddset(&set, SIGTTOU); 1310 sigaddset(&set, SIGCHLD); 1311 xthread_sigmask(SIG_BLOCK, &set, &PreviousSignalMask); 1312 } 1313 #endif 1314 } 1315 1316 void 1317 OsReleaseSignals(void) 1318 { 1319 #ifdef HAVE_SIGPROCMASK 1320 if (--BlockedSignalCount == 0) { 1321 xthread_sigmask(SIG_SETMASK, &PreviousSignalMask, 0); 1322 } 1323 #endif 1324 } 1325 1326 void 1327 OsResetSignals(void) 1328 { 1329 #ifdef HAVE_SIGPROCMASK 1330 while (BlockedSignalCount > 0) 1331 OsReleaseSignals(); 1332 input_force_unlock(); 1333 #endif 1334 } 1335 1336 /* 1337 * Pending signals may interfere with core dumping. Provide a 1338 * mechanism to block signals when aborting. 1339 */ 1340 1341 void 1342 OsAbort(void) 1343 { 1344 #ifndef __APPLE__ 1345 OsBlockSignals(); 1346 #endif 1347 #if !defined(WIN32) || defined(__CYGWIN__) 1348 /* abort() raises SIGABRT, so we have to stop handling that to prevent 1349 * recursion 1350 */ 1351 OsSignal(SIGABRT, SIG_DFL); 1352 #endif 1353 abort(); 1354 } 1355 1356 #if !defined(WIN32) 1357 /* 1358 * "safer" versions of system(3), popen(3) and pclose(3) which give up 1359 * all privs before running a command. 1360 * 1361 * This is based on the code in FreeBSD 2.2 libc. 1362 * 1363 * XXX It'd be good to redirect stderr so that it ends up in the log file 1364 * as well. As it is now, xkbcomp messages don't end up in the log file. 1365 */ 1366 1367 int 1368 System(const char *command) 1369 { 1370 int pid, p; 1371 void (*csig) (int); 1372 int status; 1373 1374 if (!command) 1375 return 1; 1376 1377 csig = OsSignal(SIGCHLD, SIG_DFL); 1378 if (csig == SIG_ERR) { 1379 perror("signal"); 1380 return -1; 1381 } 1382 DebugF("System: `%s'\n", command); 1383 1384 switch (pid = fork()) { 1385 case -1: /* error */ 1386 p = -1; 1387 break; 1388 case 0: /* child */ 1389 if (setgid(getgid()) == -1) 1390 _exit(127); 1391 if (setuid(getuid()) == -1) 1392 _exit(127); 1393 execl("/bin/sh", "sh", "-c", command, (char *) NULL); 1394 _exit(127); 1395 default: /* parent */ 1396 do { 1397 p = waitpid(pid, &status, 0); 1398 } while (p == -1 && errno == EINTR); 1399 1400 } 1401 1402 if (OsSignal(SIGCHLD, csig) == SIG_ERR) { 1403 perror("signal"); 1404 return -1; 1405 } 1406 1407 return p == -1 ? -1 : status; 1408 } 1409 1410 static struct pid { 1411 struct pid *next; 1412 FILE *fp; 1413 int pid; 1414 } *pidlist; 1415 1416 void * 1417 Popen(const char *command, const char *type) 1418 { 1419 struct pid *cur; 1420 FILE *iop; 1421 int pdes[2], pid; 1422 1423 if (command == NULL || type == NULL) 1424 return NULL; 1425 1426 if ((*type != 'r' && *type != 'w') || type[1]) 1427 return NULL; 1428 1429 if ((cur = malloc(sizeof(struct pid))) == NULL) 1430 return NULL; 1431 1432 if (pipe(pdes) < 0) { 1433 free(cur); 1434 return NULL; 1435 } 1436 1437 /* Ignore the smart scheduler while this is going on */ 1438 #ifdef HAVE_SETITIMER 1439 if (SmartSchedulePause() < 0) { 1440 close(pdes[0]); 1441 close(pdes[1]); 1442 free(cur); 1443 perror("signal"); 1444 return NULL; 1445 } 1446 #endif 1447 1448 switch (pid = fork()) { 1449 case -1: /* error */ 1450 close(pdes[0]); 1451 close(pdes[1]); 1452 free(cur); 1453 #ifdef HAVE_SETITIMER 1454 if (SmartScheduleEnable() < 0) 1455 perror("signal"); 1456 #endif 1457 return NULL; 1458 case 0: /* child */ 1459 if (setgid(getgid()) == -1) 1460 _exit(127); 1461 if (setuid(getuid()) == -1) 1462 _exit(127); 1463 if (*type == 'r') { 1464 if (pdes[1] != 1) { 1465 /* stdout */ 1466 dup2(pdes[1], 1); 1467 close(pdes[1]); 1468 } 1469 close(pdes[0]); 1470 } 1471 else { 1472 if (pdes[0] != 0) { 1473 /* stdin */ 1474 dup2(pdes[0], 0); 1475 close(pdes[0]); 1476 } 1477 close(pdes[1]); 1478 } 1479 execl("/bin/sh", "sh", "-c", command, (char *) NULL); 1480 _exit(127); 1481 } 1482 1483 /* Avoid EINTR during stdio calls */ 1484 OsBlockSignals(); 1485 1486 /* parent */ 1487 if (*type == 'r') { 1488 iop = fdopen(pdes[0], type); 1489 close(pdes[1]); 1490 } 1491 else { 1492 iop = fdopen(pdes[1], type); 1493 close(pdes[0]); 1494 } 1495 1496 cur->fp = iop; 1497 cur->pid = pid; 1498 cur->next = pidlist; 1499 pidlist = cur; 1500 1501 DebugF("Popen: `%s', fp = %p\n", command, iop); 1502 1503 return iop; 1504 } 1505 1506 /* fopen that drops privileges */ 1507 void * 1508 Fopen(const char *file, const char *type) 1509 { 1510 FILE *iop; 1511 1512 #ifndef HAS_SAVED_IDS_AND_SETEUID 1513 struct pid *cur; 1514 int pdes[2], pid; 1515 1516 if (file == NULL || type == NULL) 1517 return NULL; 1518 1519 if ((*type != 'r' && *type != 'w') || type[1]) 1520 return NULL; 1521 1522 if ((cur = malloc(sizeof(struct pid))) == NULL) 1523 return NULL; 1524 1525 if (pipe(pdes) < 0) { 1526 free(cur); 1527 return NULL; 1528 } 1529 1530 switch (pid = fork()) { 1531 case -1: /* error */ 1532 close(pdes[0]); 1533 close(pdes[1]); 1534 free(cur); 1535 return NULL; 1536 case 0: /* child */ 1537 if (setgid(getgid()) == -1) 1538 _exit(127); 1539 if (setuid(getuid()) == -1) 1540 _exit(127); 1541 if (*type == 'r') { 1542 if (pdes[1] != 1) { 1543 /* stdout */ 1544 dup2(pdes[1], 1); 1545 close(pdes[1]); 1546 } 1547 close(pdes[0]); 1548 } 1549 else { 1550 if (pdes[0] != 0) { 1551 /* stdin */ 1552 dup2(pdes[0], 0); 1553 close(pdes[0]); 1554 } 1555 close(pdes[1]); 1556 } 1557 execl("/bin/cat", "cat", file, (char *) NULL); 1558 _exit(127); 1559 } 1560 1561 /* Avoid EINTR during stdio calls */ 1562 OsBlockSignals(); 1563 1564 /* parent */ 1565 if (*type == 'r') { 1566 iop = fdopen(pdes[0], type); 1567 close(pdes[1]); 1568 } 1569 else { 1570 iop = fdopen(pdes[1], type); 1571 close(pdes[0]); 1572 } 1573 1574 cur->fp = iop; 1575 cur->pid = pid; 1576 cur->next = pidlist; 1577 pidlist = cur; 1578 1579 DebugF("Fopen(%s), fp = %p\n", file, iop); 1580 1581 return iop; 1582 #else 1583 int ruid, euid; 1584 1585 ruid = getuid(); 1586 euid = geteuid(); 1587 1588 if (seteuid(ruid) == -1) { 1589 return NULL; 1590 } 1591 iop = fopen(file, type); 1592 1593 if (seteuid(euid) == -1) { 1594 fclose(iop); 1595 return NULL; 1596 } 1597 return iop; 1598 #endif /* HAS_SAVED_IDS_AND_SETEUID */ 1599 } 1600 1601 int 1602 Pclose(void *iop) 1603 { 1604 struct pid *cur, *last; 1605 int pstat; 1606 int pid; 1607 1608 DebugF("Pclose: fp = %p\n", iop); 1609 fclose(iop); 1610 1611 for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next) 1612 if (cur->fp == iop) 1613 break; 1614 if (cur == NULL) 1615 return -1; 1616 1617 do { 1618 pid = waitpid(cur->pid, &pstat, 0); 1619 } while (pid == -1 && errno == EINTR); 1620 1621 if (last == NULL) 1622 pidlist = cur->next; 1623 else 1624 last->next = cur->next; 1625 free(cur); 1626 1627 /* allow EINTR again */ 1628 OsReleaseSignals(); 1629 1630 #ifdef HAVE_SETITIMER 1631 if (SmartScheduleEnable() < 0) { 1632 perror("signal"); 1633 return -1; 1634 } 1635 #endif 1636 1637 return pid == -1 ? -1 : pstat; 1638 } 1639 1640 int 1641 Fclose(void *iop) 1642 { 1643 #ifdef HAS_SAVED_IDS_AND_SETEUID 1644 return fclose(iop); 1645 #else 1646 return Pclose(iop); 1647 #endif 1648 } 1649 1650 #endif /* !WIN32 */ 1651 1652 #ifdef WIN32 1653 1654 #include <X11/Xwindows.h> 1655 1656 const char * 1657 Win32TempDir(void) 1658 { 1659 static char buffer[PATH_MAX]; 1660 1661 if (GetTempPath(sizeof(buffer), buffer)) { 1662 int len; 1663 1664 buffer[sizeof(buffer) - 1] = 0; 1665 len = strlen(buffer); 1666 if (len > 0) 1667 if (buffer[len - 1] == '\\') 1668 buffer[len - 1] = 0; 1669 return buffer; 1670 } 1671 if (getenv("TEMP") != NULL) 1672 return getenv("TEMP"); 1673 else if (getenv("TMP") != NULL) 1674 return getenv("TMP"); 1675 else 1676 return "/tmp"; 1677 } 1678 1679 int 1680 System(const char *cmdline) 1681 { 1682 STARTUPINFO si; 1683 PROCESS_INFORMATION pi; 1684 DWORD dwExitCode; 1685 char *cmd = strdup(cmdline); 1686 1687 ZeroMemory(&si, sizeof(si)); 1688 si.cb = sizeof(si); 1689 ZeroMemory(&pi, sizeof(pi)); 1690 1691 if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { 1692 LPVOID buffer; 1693 1694 if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 1695 FORMAT_MESSAGE_FROM_SYSTEM | 1696 FORMAT_MESSAGE_IGNORE_INSERTS, 1697 NULL, 1698 GetLastError(), 1699 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 1700 (LPTSTR) &buffer, 0, NULL)) { 1701 ErrorF("[xkb] Starting '%s' failed!\n", cmdline); 1702 } 1703 else { 1704 ErrorF("[xkb] Starting '%s' failed: %s", cmdline, (char *) buffer); 1705 LocalFree(buffer); 1706 } 1707 1708 free(cmd); 1709 return -1; 1710 } 1711 /* Wait until child process exits. */ 1712 WaitForSingleObject(pi.hProcess, INFINITE); 1713 1714 GetExitCodeProcess(pi.hProcess, &dwExitCode); 1715 1716 /* Close process and thread handles. */ 1717 CloseHandle(pi.hProcess); 1718 CloseHandle(pi.hThread); 1719 free(cmd); 1720 1721 return dwExitCode; 1722 } 1723 #endif 1724 1725 Bool 1726 PrivsElevated(void) 1727 { 1728 static Bool privsTested = FALSE; 1729 static Bool privsElevated = TRUE; 1730 1731 if (!privsTested) { 1732 #if defined(WIN32) 1733 privsElevated = FALSE; 1734 #else 1735 if ((getuid() != geteuid()) || (getgid() != getegid())) { 1736 privsElevated = TRUE; 1737 } 1738 else { 1739 #if defined(HAVE_ISSETUGID) 1740 privsElevated = issetugid(); 1741 #elif defined(HAVE_GETRESUID) 1742 uid_t ruid, euid, suid; 1743 gid_t rgid, egid, sgid; 1744 1745 if ((getresuid(&ruid, &euid, &suid) == 0) && 1746 (getresgid(&rgid, &egid, &sgid) == 0)) { 1747 privsElevated = (euid != suid) || (egid != sgid); 1748 } 1749 else { 1750 printf("Failed getresuid or getresgid"); 1751 /* Something went wrong, make defensive assumption */ 1752 privsElevated = TRUE; 1753 } 1754 #else 1755 if (getuid() == 0) { 1756 /* running as root: uid==euid==0 */ 1757 privsElevated = FALSE; 1758 } 1759 else { 1760 /* 1761 * If there are saved ID's the process might still be privileged 1762 * even though the above test succeeded. If issetugid() and 1763 * getresgid() aren't available, test this by trying to set 1764 * euid to 0. 1765 */ 1766 unsigned int oldeuid; 1767 1768 oldeuid = geteuid(); 1769 1770 if (seteuid(0) != 0) { 1771 privsElevated = FALSE; 1772 } 1773 else { 1774 if (seteuid(oldeuid) != 0) { 1775 FatalError("Failed to drop privileges. Exiting\n"); 1776 } 1777 privsElevated = TRUE; 1778 } 1779 } 1780 #endif 1781 } 1782 #endif 1783 privsTested = TRUE; 1784 } 1785 return privsElevated; 1786 } 1787 1788 /* 1789 * CheckUserParameters: check for long command line arguments and long 1790 * environment variables. By default, these checks are only done when 1791 * the server's euid != ruid. In 3.3.x, these checks were done in an 1792 * external wrapper utility. 1793 */ 1794 1795 /* Consider LD* variables insecure? */ 1796 #ifndef REMOVE_ENV_LD 1797 #define REMOVE_ENV_LD 1 1798 #endif 1799 1800 /* Remove long environment variables? */ 1801 #ifndef REMOVE_LONG_ENV 1802 #define REMOVE_LONG_ENV 1 1803 #endif 1804 1805 /* 1806 * Disallow stdout or stderr as pipes? It's possible to block the X server 1807 * when piping stdout+stderr to a pipe. 1808 * 1809 * Don't enable this because it looks like it's going to cause problems. 1810 */ 1811 #ifndef NO_OUTPUT_PIPES 1812 #define NO_OUTPUT_PIPES 0 1813 #endif 1814 1815 /* Check args and env only if running setuid (euid == 0 && euid != uid) ? */ 1816 #ifndef CHECK_EUID 1817 #ifndef WIN32 1818 #define CHECK_EUID 1 1819 #else 1820 #define CHECK_EUID 0 1821 #endif 1822 #endif 1823 1824 /* 1825 * Maybe the locale can be faked to make isprint(3) report that everything 1826 * is printable? Avoid it by default. 1827 */ 1828 #ifndef USE_ISPRINT 1829 #define USE_ISPRINT 0 1830 #endif 1831 1832 #define MAX_ARG_LENGTH 128 1833 #define MAX_ENV_LENGTH 256 1834 #define MAX_ENV_PATH_LENGTH 2048 /* Limit for *PATH and TERMCAP */ 1835 1836 #if USE_ISPRINT 1837 #include <ctype.h> 1838 #define checkPrintable(c) isprint(c) 1839 #else 1840 #define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f) 1841 #endif 1842 1843 enum BadCode { 1844 NotBad = 0, 1845 UnsafeArg, 1846 ArgTooLong, 1847 UnprintableArg, 1848 EnvTooLong, 1849 OutputIsPipe, 1850 InternalError 1851 }; 1852 1853 #if defined(VENDORSUPPORT) 1854 #define BUGADDRESS VENDORSUPPORT 1855 #elif defined(BUILDERADDR) 1856 #define BUGADDRESS BUILDERADDR 1857 #else 1858 #define BUGADDRESS "xorg@freedesktop.org" 1859 #endif 1860 1861 void 1862 CheckUserParameters(int argc, char **argv, char **envp) 1863 { 1864 enum BadCode bad = NotBad; 1865 int i = 0, j; 1866 char *a, *e = NULL; 1867 1868 #if CHECK_EUID 1869 if (PrivsElevated()) 1870 #endif 1871 { 1872 /* Check each argv[] */ 1873 for (i = 1; i < argc; i++) { 1874 if (strcmp(argv[i], "-fp") == 0) { 1875 i++; /* continue with next argument. skip the length check */ 1876 if (i >= argc) 1877 break; 1878 } 1879 else { 1880 if (strlen(argv[i]) > MAX_ARG_LENGTH) { 1881 bad = ArgTooLong; 1882 break; 1883 } 1884 } 1885 a = argv[i]; 1886 while (*a) { 1887 if (checkPrintable(*a) == 0) { 1888 bad = UnprintableArg; 1889 break; 1890 } 1891 a++; 1892 } 1893 if (bad) 1894 break; 1895 } 1896 if (!bad) { 1897 /* Check each envp[] */ 1898 for (i = 0; envp[i]; i++) { 1899 1900 /* Check for bad environment variables and values */ 1901 #if REMOVE_ENV_LD 1902 while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) { 1903 for (j = i; envp[j]; j++) { 1904 envp[j] = envp[j + 1]; 1905 } 1906 } 1907 #endif 1908 if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) { 1909 #if REMOVE_LONG_ENV 1910 for (j = i; envp[j]; j++) { 1911 envp[j] = envp[j + 1]; 1912 } 1913 i--; 1914 #else 1915 char *eq; 1916 int len; 1917 1918 eq = strchr(envp[i], '='); 1919 if (!eq) 1920 continue; 1921 len = eq - envp[i]; 1922 e = strndup(envp[i], len); 1923 if (!e) { 1924 bad = InternalError; 1925 break; 1926 } 1927 if (len >= 4 && 1928 (strcmp(e + len - 4, "PATH") == 0 || 1929 strcmp(e, "TERMCAP") == 0)) { 1930 if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) { 1931 bad = EnvTooLong; 1932 break; 1933 } 1934 else { 1935 free(e); 1936 } 1937 } 1938 else { 1939 bad = EnvTooLong; 1940 break; 1941 } 1942 #endif 1943 } 1944 } 1945 } 1946 #if NO_OUTPUT_PIPES 1947 if (!bad) { 1948 struct stat buf; 1949 1950 if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode)) 1951 bad = OutputIsPipe; 1952 if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode)) 1953 bad = OutputIsPipe; 1954 } 1955 #endif 1956 } 1957 switch (bad) { 1958 case NotBad: 1959 return; 1960 case UnsafeArg: 1961 ErrorF("Command line argument number %d is unsafe\n", i); 1962 break; 1963 case ArgTooLong: 1964 ErrorF("Command line argument number %d is too long\n", i); 1965 break; 1966 case UnprintableArg: 1967 ErrorF("Command line argument number %d contains unprintable" 1968 " characters\n", i); 1969 break; 1970 case EnvTooLong: 1971 ErrorF("Environment variable `%s' is too long\n", e); 1972 break; 1973 case OutputIsPipe: 1974 ErrorF("Stdout and/or stderr is a pipe\n"); 1975 break; 1976 case InternalError: 1977 ErrorF("Internal Error\n"); 1978 break; 1979 default: 1980 ErrorF("Unknown error\n"); 1981 break; 1982 } 1983 FatalError("X server aborted because of unsafe environment\n"); 1984 } 1985 1986 /* 1987 * CheckUserAuthorization: check if the user is allowed to start the 1988 * X server. This usually means some sort of PAM checking, and it is 1989 * usually only done for setuid servers (uid != euid). 1990 */ 1991 1992 #ifdef USE_PAM 1993 #include <security/pam_appl.h> 1994 #include <security/pam_misc.h> 1995 #include <pwd.h> 1996 #endif /* USE_PAM */ 1997 1998 void 1999 CheckUserAuthorization(void) 2000 { 2001 #ifdef USE_PAM 2002 static struct pam_conv conv = { 2003 misc_conv, 2004 NULL 2005 }; 2006 2007 pam_handle_t *pamh = NULL; 2008 struct passwd *pw; 2009 int retval; 2010 2011 if (getuid() != geteuid()) { 2012 pw = getpwuid(getuid()); 2013 if (pw == NULL) 2014 FatalError("getpwuid() failed for uid %d\n", getuid()); 2015 2016 retval = pam_start("xserver", pw->pw_name, &conv, &pamh); 2017 if (retval != PAM_SUCCESS) 2018 FatalError("pam_start() failed.\n" 2019 "\tMissing or mangled PAM config file or module?\n"); 2020 2021 retval = pam_authenticate(pamh, 0); 2022 if (retval != PAM_SUCCESS) { 2023 pam_end(pamh, retval); 2024 FatalError("PAM authentication failed, cannot start X server.\n" 2025 "\tPerhaps you do not have console ownership?\n"); 2026 } 2027 2028 retval = pam_acct_mgmt(pamh, 0); 2029 if (retval != PAM_SUCCESS) { 2030 pam_end(pamh, retval); 2031 FatalError("PAM authentication failed, cannot start X server.\n" 2032 "\tPerhaps you do not have console ownership?\n"); 2033 } 2034 2035 /* this is not a session, so do not do session management */ 2036 pam_end(pamh, PAM_SUCCESS); 2037 } 2038 #endif 2039 } 2040 2041 /* 2042 * Tokenize a string into a NULL terminated array of strings. Always returns 2043 * an allocated array unless an error occurs. 2044 */ 2045 char ** 2046 xstrtokenize(const char *str, const char *separators) 2047 { 2048 char **list, **nlist; 2049 char *tok, *tmp; 2050 unsigned num = 0, n; 2051 2052 if (!str) 2053 return NULL; 2054 list = calloc(1, sizeof(*list)); 2055 if (!list) 2056 return NULL; 2057 tmp = strdup(str); 2058 if (!tmp) 2059 goto error; 2060 for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) { 2061 nlist = reallocarray(list, num + 2, sizeof(*list)); 2062 if (!nlist) 2063 goto error; 2064 list = nlist; 2065 list[num] = strdup(tok); 2066 if (!list[num]) 2067 goto error; 2068 list[++num] = NULL; 2069 } 2070 free(tmp); 2071 return list; 2072 2073 error: 2074 free(tmp); 2075 for (n = 0; n < num; n++) 2076 free(list[n]); 2077 free(list); 2078 return NULL; 2079 } 2080 2081 /* Format a signed number into a string in a signal safe manner. The string 2082 * should be at least 21 characters in order to handle all int64_t values. 2083 */ 2084 void 2085 FormatInt64(int64_t num, char *string) 2086 { 2087 if (num < 0) { 2088 string[0] = '-'; 2089 num *= -1; 2090 string++; 2091 } 2092 FormatUInt64(num, string); 2093 } 2094 2095 /* Format a number into a string in a signal safe manner. The string should be 2096 * at least 21 characters in order to handle all uint64_t values. */ 2097 void 2098 FormatUInt64(uint64_t num, char *string) 2099 { 2100 uint64_t divisor; 2101 int len; 2102 int i; 2103 2104 for (len = 1, divisor = 10; 2105 len < 20 && num / divisor; 2106 len++, divisor *= 10); 2107 2108 for (i = len, divisor = 1; i > 0; i--, divisor *= 10) 2109 string[i - 1] = '0' + ((num / divisor) % 10); 2110 2111 string[len] = '\0'; 2112 } 2113 2114 /** 2115 * Format a double number as %.2f. 2116 */ 2117 void 2118 FormatDouble(double dbl, char *string) 2119 { 2120 int slen = 0; 2121 uint64_t frac; 2122 2123 frac = (dbl > 0 ? dbl : -dbl) * 100.0 + 0.5; 2124 frac %= 100; 2125 2126 /* write decimal part to string */ 2127 if (dbl < 0 && dbl > -1) 2128 string[slen++] = '-'; 2129 FormatInt64((int64_t)dbl, &string[slen]); 2130 2131 while(string[slen] != '\0') 2132 slen++; 2133 2134 /* append fractional part, but only if we have enough characters. We 2135 * expect string to be 21 chars (incl trailing \0) */ 2136 if (slen <= 17) { 2137 string[slen++] = '.'; 2138 if (frac < 10) 2139 string[slen++] = '0'; 2140 2141 FormatUInt64(frac, &string[slen]); 2142 } 2143 } 2144 2145 2146 /* Format a number into a hexadecimal string in a signal safe manner. The string 2147 * should be at least 17 characters in order to handle all uint64_t values. */ 2148 void 2149 FormatUInt64Hex(uint64_t num, char *string) 2150 { 2151 uint64_t divisor; 2152 int len; 2153 int i; 2154 2155 for (len = 1, divisor = 0x10; 2156 len < 16 && num / divisor; 2157 len++, divisor *= 0x10); 2158 2159 for (i = len, divisor = 1; i > 0; i--, divisor *= 0x10) { 2160 int val = (num / divisor) % 0x10; 2161 2162 if (val < 10) 2163 string[i - 1] = '0' + val; 2164 else 2165 string[i - 1] = 'a' + val - 10; 2166 } 2167 2168 string[len] = '\0'; 2169 } 2170 2171 #if !defined(WIN32) || defined(__CYGWIN__) 2172 /* Move a file descriptor out of the way of our select mask; this 2173 * is useful for file descriptors which will never appear in the 2174 * select mask to avoid reducing the number of clients that can 2175 * connect to the server 2176 */ 2177 int 2178 os_move_fd(int fd) 2179 { 2180 int newfd; 2181 2182 #ifdef F_DUPFD_CLOEXEC 2183 newfd = fcntl(fd, F_DUPFD_CLOEXEC, MAXCLIENTS); 2184 #else 2185 newfd = fcntl(fd, F_DUPFD, MAXCLIENTS); 2186 #endif 2187 if (newfd < 0) 2188 return fd; 2189 #ifndef F_DUPFD_CLOEXEC 2190 fcntl(newfd, F_SETFD, FD_CLOEXEC); 2191 #endif 2192 close(fd); 2193 return newfd; 2194 } 2195 #endif