utils.c revision 6b007147
1/* 2 3Copyright 1987, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included 12in all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall 23not be used in advertising or otherwise to promote the sale, use or 24other dealings in this Software without prior written authorization 25from The Open Group. 26 27Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, 28Copyright 1994 Quarterdeck Office Systems. 29 30 All Rights Reserved 31 32Permission to use, copy, modify, and distribute this software and its 33documentation for any purpose and without fee is hereby granted, 34provided that the above copyright notice appear in all copies and that 35both that copyright notice and this permission notice appear in 36supporting documentation, and that the names of Digital and 37Quarterdeck not be used in advertising or publicity pertaining to 38distribution of the software without specific, written prior 39permission. 40 41DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS 42SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 43FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT 44OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 45OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 46OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE 47OR 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 117Bool noTestExtensions; 118 119#ifdef COMPOSITE 120Bool noCompositeExtension = FALSE; 121#endif 122 123#ifdef DAMAGE 124Bool noDamageExtension = FALSE; 125#endif 126#ifdef DBE 127Bool noDbeExtension = FALSE; 128#endif 129#ifdef DPMSExtension 130#include "dpmsproc.h" 131Bool noDPMSExtension = FALSE; 132#endif 133#ifdef GLXEXT 134Bool noGlxExtension = FALSE; 135#endif 136#ifdef SCREENSAVER 137Bool noScreenSaverExtension = FALSE; 138#endif 139#ifdef MITSHM 140Bool noMITShmExtension = FALSE; 141#endif 142#ifdef RANDR 143Bool noRRExtension = FALSE; 144#endif 145Bool noRenderExtension = FALSE; 146 147#ifdef XCSECURITY 148Bool noSecurityExtension = FALSE; 149#endif 150#ifdef RES 151Bool noResExtension = FALSE; 152#endif 153#ifdef XF86BIGFONT 154Bool noXFree86BigfontExtension = FALSE; 155#endif 156#ifdef XFreeXDGA 157Bool noXFree86DGAExtension = FALSE; 158#endif 159#ifdef XF86DRI 160Bool noXFree86DRIExtension = FALSE; 161#endif 162#ifdef XF86VIDMODE 163Bool noXFree86VidModeExtension = FALSE; 164#endif 165Bool noXFixesExtension = FALSE; 166#ifdef PANORAMIX 167/* Xinerama is disabled by default unless enabled via +xinerama */ 168Bool noPanoramiXExtension = TRUE; 169#endif 170#ifdef XSELINUX 171Bool noSELinuxExtension = FALSE; 172int selinuxEnforcingState = SELINUX_MODE_DEFAULT; 173#endif 174#ifdef XV 175Bool noXvExtension = FALSE; 176#endif 177#ifdef DRI2 178Bool noDRI2Extension = FALSE; 179#endif 180 181Bool noGEExtension = FALSE; 182 183#define X_INCLUDE_NETDB_H 184#include <X11/Xos_r.h> 185 186#include <errno.h> 187 188Bool CoreDump; 189 190Bool enableIndirectGLX = FALSE; 191 192#ifdef PANORAMIX 193Bool PanoramiXExtensionDisabledHack = FALSE; 194#endif 195 196int auditTrailLevel = 1; 197 198char *SeatId = NULL; 199 200sig_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 207static clockid_t clockid; 208#endif 209 210OsSigHandlerPtr 211OsSignal(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 245void 246LockServer(void) 247{} 248 249void 250UnlockServer(void) 251{} 252#else /* LOCK_SERVER */ 253static Bool StillLocking = FALSE; 254static char LockFile[PATH_MAX]; 255static 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 */ 263void 264LockServer(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 */ 396void 397UnlockServer(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 411void 412AutoResetServer(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 423void 424GiveUp(int sig) 425{ 426 int olderrno = errno; 427 428 dispatchException |= DE_TERMINATE; 429 isItTimeToYield = TRUE; 430 errno = olderrno; 431} 432 433#ifdef MONOTONIC_CLOCK 434void 435ForceClockId(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__) 452CARD32 453GetTimeInMillis(void) 454{ 455 return GetTickCount(); 456} 457CARD64 458GetTimeInMicros(void) 459{ 460 return (CARD64) GetTickCount() * 1000; 461} 462#else 463CARD32 464GetTimeInMillis(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 492CARD64 493GetTimeInMicros(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 515void 516UseMsg(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("-noretro start with black background and no cursor\n"); 571 ErrorF("-s # screen-saver timeout (minutes)\n"); 572 ErrorF("-seat string seat to run on\n"); 573 ErrorF("-t # default pointer threshold (pixels/t)\n"); 574 ErrorF("-terminate [delay] terminate at server reset (optional delay in sec)\n"); 575 ErrorF("-tst disable testing extensions\n"); 576 ErrorF("ttyxx server started from init on /dev/ttyxx\n"); 577 ErrorF("v video blanking for screen-saver\n"); 578 ErrorF("-v screen-saver without video blanking\n"); 579 ErrorF("-wr create root window with white background\n"); 580 ErrorF("-maxbigreqsize set maximal bigrequest size \n"); 581#ifdef PANORAMIX 582 ErrorF("+xinerama Enable XINERAMA extension\n"); 583 ErrorF("-xinerama Disable XINERAMA extension\n"); 584#endif 585 ErrorF 586 ("-dumbSched Disable smart scheduling and threaded input, enable old behavior\n"); 587 ErrorF("-schedInterval int Set scheduler interval in msec\n"); 588 ErrorF("-sigstop Enable SIGSTOP based startup\n"); 589 ErrorF("+extension name Enable extension\n"); 590 ErrorF("-extension name Disable extension\n"); 591 ListStaticExtensions(); 592#ifdef XDMCP 593 XdmcpUseMsg(); 594#endif 595 XkbUseMsg(); 596 ddxUseMsg(); 597} 598 599/* This function performs a rudimentary sanity check 600 * on the display name passed in on the command-line, 601 * since this string is used to generate filenames. 602 * It is especially important that the display name 603 * not contain a "/" and not start with a "-". 604 * --kvajk 605 */ 606static int 607VerifyDisplayName(const char *d) 608{ 609 int i; 610 int period_found = FALSE; 611 int after_period = 0; 612 613 if (d == (char *) 0) 614 return 0; /* null */ 615 if (*d == '\0') 616 return 0; /* empty */ 617 if (*d == '-') 618 return 0; /* could be confused for an option */ 619 if (*d == '.') 620 return 0; /* must not equal "." or ".." */ 621 if (strchr(d, '/') != (char *) 0) 622 return 0; /* very important!!! */ 623 624 /* Since we run atoi() on the display later, only allow 625 for digits, or exception of :0.0 and similar (two decimal points max) 626 */ 627 for (i = 0; i < strlen(d); i++) { 628 if (!isdigit(d[i])) { 629 if (d[i] != '.' || period_found) 630 return 0; 631 period_found = TRUE; 632 } else if (period_found) 633 after_period++; 634 635 if (after_period > 2) 636 return 0; 637 } 638 639 /* don't allow for :0. */ 640 if (period_found && after_period == 0) 641 return 0; 642 643 if (atol(d) > INT_MAX) 644 return 0; 645 646 return 1; 647} 648 649static const char *defaultNoListenList[] = { 650#ifndef LISTEN_TCP 651 "tcp", 652#endif 653#ifndef LISTEN_UNIX 654 "unix", 655#endif 656#ifndef LISTEN_LOCAL 657 "local", 658#endif 659 NULL 660}; 661 662/* 663 * This function parses the command line. Handles device-independent fields 664 * and allows ddx to handle additional fields. It is not allowed to modify 665 * argc or any of the strings pointed to by argv. 666 */ 667void 668ProcessCommandLine(int argc, char *argv[]) 669{ 670 int i, skip; 671 672 defaultKeyboardControl.autoRepeat = TRUE; 673 674#ifdef NO_PART_NET 675 PartialNetwork = FALSE; 676#else 677 PartialNetwork = TRUE; 678#endif 679 680 for (i = 0; defaultNoListenList[i] != NULL; i++) { 681 if (_XSERVTransNoListen(defaultNoListenList[i])) 682 ErrorF("Failed to disable listen for %s transport", 683 defaultNoListenList[i]); 684 } 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 if (getrlimit(RLIMIT_CORE, &core_limit) != -1) { 748 core_limit.rlim_cur = core_limit.rlim_max; 749 setrlimit(RLIMIT_CORE, &core_limit); 750 } 751#endif 752 CoreDump = TRUE; 753 } 754 else if (strcmp(argv[i], "-nocursor") == 0) { 755 EnableCursor = FALSE; 756 } 757 else if (strcmp(argv[i], "-dpi") == 0) { 758 if (++i < argc) 759 monitorResolution = atoi(argv[i]); 760 else 761 UseMsg(); 762 } 763 else if (strcmp(argv[i], "-displayfd") == 0) { 764 if (++i < argc) { 765 displayfd = atoi(argv[i]); 766#ifdef LOCK_SERVER 767 nolock = TRUE; 768#endif 769 } 770 else 771 UseMsg(); 772 } 773#ifdef DPMSExtension 774 else if (strcmp(argv[i], "dpms") == 0) 775 /* ignored for compatibility */ ; 776 else if (strcmp(argv[i], "-dpms") == 0) 777 DPMSDisabledSwitch = TRUE; 778#endif 779 else if (strcmp(argv[i], "-deferglyphs") == 0) { 780 if (++i >= argc || !xfont2_parse_glyph_caching_mode(argv[i])) 781 UseMsg(); 782 } 783 else if (strcmp(argv[i], "-f") == 0) { 784 if (++i < argc) 785 defaultKeyboardControl.bell = atoi(argv[i]); 786 else 787 UseMsg(); 788 } 789 else if (strcmp(argv[i], "-fakescreenfps") == 0) { 790#ifdef PRESENT 791 if (++i < argc) { 792 FakeScreenFps = (uint32_t) atoi(argv[i]); 793 if (FakeScreenFps < 1 || FakeScreenFps > 600) 794 FatalError("fakescreenfps must be an integer in [1;600] range\n"); 795 } 796 else 797 UseMsg(); 798#else 799 FatalError("fakescreenfps not available without PRESENT\n"); 800 UseMsg(); 801#endif 802 } 803 else if (strcmp(argv[i], "-fp") == 0) { 804 if (++i < argc) { 805 defaultFontPath = argv[i]; 806 } 807 else 808 UseMsg(); 809 } 810 else if (strcmp(argv[i], "-help") == 0) { 811 UseMsg(); 812 exit(0); 813 } 814 else if (strcmp(argv[i], "+iglx") == 0) 815 enableIndirectGLX = TRUE; 816 else if (strcmp(argv[i], "-iglx") == 0) 817 enableIndirectGLX = FALSE; 818 else if ((skip = XkbProcessArguments(argc, argv, i)) != 0) { 819 if (skip > 0) 820 i += skip - 1; 821 else 822 UseMsg(); 823 } 824#ifdef RLIMIT_DATA 825 else if (strcmp(argv[i], "-ld") == 0) { 826 if (++i < argc) { 827 limitDataSpace = atoi(argv[i]); 828 if (limitDataSpace > 0) 829 limitDataSpace *= 1024; 830 } 831 else 832 UseMsg(); 833 } 834#endif 835#ifdef RLIMIT_NOFILE 836 else if (strcmp(argv[i], "-lf") == 0) { 837 if (++i < argc) 838 limitNoFile = atoi(argv[i]); 839 else 840 UseMsg(); 841 } 842#endif 843#ifdef RLIMIT_STACK 844 else if (strcmp(argv[i], "-ls") == 0) { 845 if (++i < argc) { 846 limitStackSpace = atoi(argv[i]); 847 if (limitStackSpace > 0) 848 limitStackSpace *= 1024; 849 } 850 else 851 UseMsg(); 852 } 853#endif 854#ifdef LOCK_SERVER 855 else if (strcmp(argv[i], "-nolock") == 0) { 856#if !defined(WIN32) && !defined(__CYGWIN__) 857 if (getuid() != 0) 858 ErrorF 859 ("Warning: the -nolock option can only be used by root\n"); 860 else 861#endif 862 nolock = TRUE; 863 } 864#endif 865 else if ( strcmp( argv[i], "-maxclients") == 0) 866 { 867 if (++i < argc) { 868 LimitClients = atoi(argv[i]); 869 if (LimitClients != 64 && 870 LimitClients != 128 && 871 LimitClients != 256 && 872 LimitClients != 512 && 873 LimitClients != 1024 && 874 LimitClients != 2048) { 875 FatalError("maxclients must be one of 64, 128, 256, 512, 1024 or 2048\n"); 876 } 877 } else 878 UseMsg(); 879 } 880 else if (strcmp(argv[i], "-nolisten") == 0) { 881 if (++i < argc) { 882 if (_XSERVTransNoListen(argv[i])) 883 ErrorF("Failed to disable listen for %s transport", 884 argv[i]); 885 } 886 else 887 UseMsg(); 888 } 889 else if (strcmp(argv[i], "-listen") == 0) { 890 if (++i < argc) { 891 if (_XSERVTransListen(argv[i])) 892 ErrorF("Failed to enable listen for %s transport", 893 argv[i]); 894 } 895 else 896 UseMsg(); 897 } 898 else if (strcmp(argv[i], "-noreset") == 0) { 899 dispatchExceptionAtReset = 0; 900 } 901 else if (strcmp(argv[i], "-reset") == 0) { 902 dispatchExceptionAtReset = DE_RESET; 903 } 904 else if (strcmp(argv[i], "-p") == 0) { 905 if (++i < argc) 906 defaultScreenSaverInterval = ((CARD32) atoi(argv[i])) * 907 MILLI_PER_MIN; 908 else 909 UseMsg(); 910 } 911 else if (strcmp(argv[i], "-pogo") == 0) { 912 dispatchException = DE_TERMINATE; 913 } 914 else if (strcmp(argv[i], "-pn") == 0) 915 PartialNetwork = TRUE; 916 else if (strcmp(argv[i], "-nopn") == 0) 917 PartialNetwork = FALSE; 918 else if (strcmp(argv[i], "r") == 0) 919 defaultKeyboardControl.autoRepeat = TRUE; 920 else if (strcmp(argv[i], "-r") == 0) 921 defaultKeyboardControl.autoRepeat = FALSE; 922 else if (strcmp(argv[i], "-retro") == 0) 923 party_like_its_1989 = TRUE; 924 else if (strcmp(argv[i], "-noretro") == 0) 925 party_like_its_1989 = FALSE; 926 else if (strcmp(argv[i], "-s") == 0) { 927 if (++i < argc) 928 defaultScreenSaverTime = ((CARD32) atoi(argv[i])) * 929 MILLI_PER_MIN; 930 else 931 UseMsg(); 932 } 933 else if (strcmp(argv[i], "-seat") == 0) { 934 if (++i < argc) 935 SeatId = argv[i]; 936 else 937 UseMsg(); 938 } 939 else if (strcmp(argv[i], "-t") == 0) { 940 if (++i < argc) 941 defaultPointerControl.threshold = atoi(argv[i]); 942 else 943 UseMsg(); 944 } 945 else if (strcmp(argv[i], "-terminate") == 0) { 946 dispatchExceptionAtReset = DE_TERMINATE; 947 terminateDelay = -1; 948 if ((i + 1 < argc) && (isdigit(*argv[i + 1]))) 949 terminateDelay = atoi(argv[++i]); 950 terminateDelay = max(0, terminateDelay); 951 } 952 else if (strcmp(argv[i], "-tst") == 0) { 953 noTestExtensions = TRUE; 954 } 955 else if (strcmp(argv[i], "v") == 0) 956 defaultScreenSaverBlanking = PreferBlanking; 957 else if (strcmp(argv[i], "-v") == 0) 958 defaultScreenSaverBlanking = DontPreferBlanking; 959 else if (strcmp(argv[i], "-wr") == 0) 960 whiteRoot = TRUE; 961 else if (strcmp(argv[i], "-background") == 0) { 962 if (++i < argc) { 963 if (!strcmp(argv[i], "none")) 964 bgNoneRoot = TRUE; 965 else 966 UseMsg(); 967 } 968 } 969 else if (strcmp(argv[i], "-maxbigreqsize") == 0) { 970 if (++i < argc) { 971 long reqSizeArg = atol(argv[i]); 972 973 /* Request size > 128MB does not make much sense... */ 974 if (reqSizeArg > 0L && reqSizeArg < 128L) { 975 maxBigRequestSize = (reqSizeArg * 1048576L) - 1L; 976 } 977 else { 978 UseMsg(); 979 } 980 } 981 else { 982 UseMsg(); 983 } 984 } 985#ifdef PANORAMIX 986 else if (strcmp(argv[i], "+xinerama") == 0) { 987 noPanoramiXExtension = FALSE; 988 } 989 else if (strcmp(argv[i], "-xinerama") == 0) { 990 noPanoramiXExtension = TRUE; 991 } 992 else if (strcmp(argv[i], "-disablexineramaextension") == 0) { 993 PanoramiXExtensionDisabledHack = TRUE; 994 } 995#endif 996 else if (strcmp(argv[i], "-I") == 0) { 997 /* ignore all remaining arguments */ 998 break; 999 } 1000 else if (strncmp(argv[i], "tty", 3) == 0) { 1001 /* init supplies us with this useless information */ 1002 } 1003#ifdef XDMCP 1004 else if ((skip = XdmcpOptions(argc, argv, i)) != i) { 1005 i = skip - 1; 1006 } 1007#endif 1008 else if (strcmp(argv[i], "-dumbSched") == 0) { 1009 InputThreadEnable = FALSE; 1010#ifdef HAVE_SETITIMER 1011 SmartScheduleSignalEnable = FALSE; 1012#endif 1013 } 1014 else if (strcmp(argv[i], "-schedInterval") == 0) { 1015 if (++i < argc) { 1016 SmartScheduleInterval = atoi(argv[i]); 1017 SmartScheduleSlice = SmartScheduleInterval; 1018 } 1019 else 1020 UseMsg(); 1021 } 1022 else if (strcmp(argv[i], "-schedMax") == 0) { 1023 if (++i < argc) { 1024 SmartScheduleMaxSlice = atoi(argv[i]); 1025 } 1026 else 1027 UseMsg(); 1028 } 1029 else if (strcmp(argv[i], "-render") == 0) { 1030 if (++i < argc) { 1031 int policy = PictureParseCmapPolicy(argv[i]); 1032 1033 if (policy != PictureCmapPolicyInvalid) 1034 PictureCmapPolicy = policy; 1035 else 1036 UseMsg(); 1037 } 1038 else 1039 UseMsg(); 1040 } 1041 else if (strcmp(argv[i], "-sigstop") == 0) { 1042 RunFromSigStopParent = TRUE; 1043 } 1044 else if (strcmp(argv[i], "+extension") == 0) { 1045 if (++i < argc) { 1046 if (!EnableDisableExtension(argv[i], TRUE)) 1047 EnableDisableExtensionError(argv[i], TRUE); 1048 } 1049 else 1050 UseMsg(); 1051 } 1052 else if (strcmp(argv[i], "-extension") == 0) { 1053 if (++i < argc) { 1054 if (!EnableDisableExtension(argv[i], FALSE)) 1055 EnableDisableExtensionError(argv[i], FALSE); 1056 } 1057 else 1058 UseMsg(); 1059 } 1060 else { 1061 ErrorF("Unrecognized option: %s\n", argv[i]); 1062 UseMsg(); 1063 FatalError("Unrecognized option: %s\n", argv[i]); 1064 } 1065 } 1066} 1067 1068/* Implement a simple-minded font authorization scheme. The authorization 1069 name is "hp-hostname-1", the contents are simply the host name. */ 1070int 1071set_font_authorizations(char **authorizations, int *authlen, void *client) 1072{ 1073#define AUTHORIZATION_NAME "hp-hostname-1" 1074#if defined(TCPCONN) 1075 static char *result = NULL; 1076 static char *p = NULL; 1077 1078 if (p == NULL) { 1079 char hname[1024], *hnameptr; 1080 unsigned int len; 1081 1082#if defined(IPv6) && defined(AF_INET6) 1083 struct addrinfo hints, *ai = NULL; 1084#else 1085 struct hostent *host; 1086 1087#ifdef XTHREADS_NEEDS_BYNAMEPARAMS 1088 _Xgethostbynameparams hparams; 1089#endif 1090#endif 1091 1092 gethostname(hname, 1024); 1093#if defined(IPv6) && defined(AF_INET6) 1094 memset(&hints, 0, sizeof(hints)); 1095 hints.ai_flags = AI_CANONNAME; 1096 if (getaddrinfo(hname, NULL, &hints, &ai) == 0) { 1097 hnameptr = ai->ai_canonname; 1098 } 1099 else { 1100 hnameptr = hname; 1101 } 1102#else 1103 host = _XGethostbyname(hname, hparams); 1104 if (host == NULL) 1105 hnameptr = hname; 1106 else 1107 hnameptr = host->h_name; 1108#endif 1109 1110 len = strlen(hnameptr) + 1; 1111 result = malloc(len + sizeof(AUTHORIZATION_NAME) + 4); 1112 1113 p = result; 1114 *p++ = sizeof(AUTHORIZATION_NAME) >> 8; 1115 *p++ = sizeof(AUTHORIZATION_NAME) & 0xff; 1116 *p++ = (len) >> 8; 1117 *p++ = (len & 0xff); 1118 1119 memmove(p, AUTHORIZATION_NAME, sizeof(AUTHORIZATION_NAME)); 1120 p += sizeof(AUTHORIZATION_NAME); 1121 memmove(p, hnameptr, len); 1122 p += len; 1123#if defined(IPv6) && defined(AF_INET6) 1124 if (ai) { 1125 freeaddrinfo(ai); 1126 } 1127#endif 1128 } 1129 *authlen = p - result; 1130 *authorizations = result; 1131 return 1; 1132#else /* TCPCONN */ 1133 return 0; 1134#endif /* TCPCONN */ 1135} 1136 1137void * 1138XNFalloc(unsigned long amount) 1139{ 1140 void *ptr = malloc(amount); 1141 1142 if (!ptr) 1143 FatalError("Out of memory"); 1144 return ptr; 1145} 1146 1147/* The original XNFcalloc was used with the xnfcalloc macro which multiplied 1148 * the arguments at the call site without allowing calloc to check for overflow. 1149 * XNFcallocarray was added to fix that without breaking ABI. 1150 */ 1151void * 1152XNFcalloc(unsigned long amount) 1153{ 1154 return XNFcallocarray(1, amount); 1155} 1156 1157void * 1158XNFcallocarray(size_t nmemb, size_t size) 1159{ 1160 void *ret = calloc(nmemb, size); 1161 1162 if (!ret) 1163 FatalError("XNFcalloc: Out of memory"); 1164 return ret; 1165} 1166 1167void * 1168XNFrealloc(void *ptr, unsigned long amount) 1169{ 1170 void *ret = realloc(ptr, amount); 1171 1172 if (!ret) 1173 FatalError("XNFrealloc: Out of memory"); 1174 return ret; 1175} 1176 1177void * 1178XNFreallocarray(void *ptr, size_t nmemb, size_t size) 1179{ 1180 void *ret = reallocarray(ptr, nmemb, size); 1181 1182 if (!ret) 1183 FatalError("XNFreallocarray: Out of memory"); 1184 return ret; 1185} 1186 1187char * 1188Xstrdup(const char *s) 1189{ 1190 if (s == NULL) 1191 return NULL; 1192 return strdup(s); 1193} 1194 1195char * 1196XNFstrdup(const char *s) 1197{ 1198 char *ret; 1199 1200 if (s == NULL) 1201 return NULL; 1202 1203 ret = strdup(s); 1204 if (!ret) 1205 FatalError("XNFstrdup: Out of memory"); 1206 return ret; 1207} 1208 1209void 1210SmartScheduleStopTimer(void) 1211{ 1212#ifdef HAVE_SETITIMER 1213 struct itimerval timer; 1214 1215 if (!SmartScheduleSignalEnable) 1216 return; 1217 timer.it_interval.tv_sec = 0; 1218 timer.it_interval.tv_usec = 0; 1219 timer.it_value.tv_sec = 0; 1220 timer.it_value.tv_usec = 0; 1221 (void) setitimer(ITIMER_REAL, &timer, 0); 1222#endif 1223} 1224 1225void 1226SmartScheduleStartTimer(void) 1227{ 1228#ifdef HAVE_SETITIMER 1229 struct itimerval timer; 1230 1231 if (!SmartScheduleSignalEnable) 1232 return; 1233 timer.it_interval.tv_sec = 0; 1234 timer.it_interval.tv_usec = SmartScheduleInterval * 1000; 1235 timer.it_value.tv_sec = 0; 1236 timer.it_value.tv_usec = SmartScheduleInterval * 1000; 1237 setitimer(ITIMER_REAL, &timer, 0); 1238#endif 1239} 1240 1241#ifdef HAVE_SETITIMER 1242static void 1243SmartScheduleTimer(int sig) 1244{ 1245 SmartScheduleTime += SmartScheduleInterval; 1246} 1247 1248static int 1249SmartScheduleEnable(void) 1250{ 1251 int ret = 0; 1252 struct sigaction act; 1253 1254 if (!SmartScheduleSignalEnable) 1255 return 0; 1256 1257 memset((char *) &act, 0, sizeof(struct sigaction)); 1258 1259 /* Set up the timer signal function */ 1260 act.sa_flags = SA_RESTART; 1261 act.sa_handler = SmartScheduleTimer; 1262 sigemptyset(&act.sa_mask); 1263 sigaddset(&act.sa_mask, SIGALRM); 1264 ret = sigaction(SIGALRM, &act, 0); 1265 return ret; 1266} 1267 1268static int 1269SmartSchedulePause(void) 1270{ 1271 int ret = 0; 1272 struct sigaction act; 1273 1274 if (!SmartScheduleSignalEnable) 1275 return 0; 1276 1277 memset((char *) &act, 0, sizeof(struct sigaction)); 1278 1279 act.sa_handler = SIG_IGN; 1280 sigemptyset(&act.sa_mask); 1281 ret = sigaction(SIGALRM, &act, 0); 1282 return ret; 1283} 1284#endif 1285 1286void 1287SmartScheduleInit(void) 1288{ 1289#ifdef HAVE_SETITIMER 1290 if (SmartScheduleEnable() < 0) { 1291 perror("sigaction for smart scheduler"); 1292 SmartScheduleSignalEnable = FALSE; 1293 } 1294#endif 1295} 1296 1297#ifdef HAVE_SIGPROCMASK 1298static sigset_t PreviousSignalMask; 1299static int BlockedSignalCount; 1300#endif 1301 1302void 1303OsBlockSignals(void) 1304{ 1305#ifdef HAVE_SIGPROCMASK 1306 if (BlockedSignalCount++ == 0) { 1307 sigset_t set; 1308 1309 sigemptyset(&set); 1310 sigaddset(&set, SIGALRM); 1311 sigaddset(&set, SIGVTALRM); 1312#ifdef SIGWINCH 1313 sigaddset(&set, SIGWINCH); 1314#endif 1315 sigaddset(&set, SIGTSTP); 1316 sigaddset(&set, SIGTTIN); 1317 sigaddset(&set, SIGTTOU); 1318 sigaddset(&set, SIGCHLD); 1319 xthread_sigmask(SIG_BLOCK, &set, &PreviousSignalMask); 1320 } 1321#endif 1322} 1323 1324void 1325OsReleaseSignals(void) 1326{ 1327#ifdef HAVE_SIGPROCMASK 1328 if (--BlockedSignalCount == 0) { 1329 xthread_sigmask(SIG_SETMASK, &PreviousSignalMask, 0); 1330 } 1331#endif 1332} 1333 1334void 1335OsResetSignals(void) 1336{ 1337#ifdef HAVE_SIGPROCMASK 1338 while (BlockedSignalCount > 0) 1339 OsReleaseSignals(); 1340 input_force_unlock(); 1341#endif 1342} 1343 1344/* 1345 * Pending signals may interfere with core dumping. Provide a 1346 * mechanism to block signals when aborting. 1347 */ 1348 1349void 1350OsAbort(void) 1351{ 1352#ifndef __APPLE__ 1353 OsBlockSignals(); 1354#endif 1355#if !defined(WIN32) || defined(__CYGWIN__) 1356 /* abort() raises SIGABRT, so we have to stop handling that to prevent 1357 * recursion 1358 */ 1359 OsSignal(SIGABRT, SIG_DFL); 1360#endif 1361 abort(); 1362} 1363 1364#if !defined(WIN32) 1365/* 1366 * "safer" versions of system(3), popen(3) and pclose(3) which give up 1367 * all privs before running a command. 1368 * 1369 * This is based on the code in FreeBSD 2.2 libc. 1370 * 1371 * XXX It'd be good to redirect stderr so that it ends up in the log file 1372 * as well. As it is now, xkbcomp messages don't end up in the log file. 1373 */ 1374 1375int 1376System(const char *command) 1377{ 1378 int pid, p; 1379 void (*csig) (int); 1380 int status; 1381 1382 if (!command) 1383 return 1; 1384 1385 csig = OsSignal(SIGCHLD, SIG_DFL); 1386 if (csig == SIG_ERR) { 1387 perror("signal"); 1388 return -1; 1389 } 1390 DebugF("System: `%s'\n", command); 1391 1392 switch (pid = fork()) { 1393 case -1: /* error */ 1394 p = -1; 1395 break; 1396 case 0: /* child */ 1397 if (setgid(getgid()) == -1) 1398 _exit(127); 1399 if (setuid(getuid()) == -1) 1400 _exit(127); 1401 execl("/bin/sh", "sh", "-c", command, (char *) NULL); 1402 _exit(127); 1403 default: /* parent */ 1404 do { 1405 p = waitpid(pid, &status, 0); 1406 } while (p == -1 && errno == EINTR); 1407 1408 } 1409 1410 if (OsSignal(SIGCHLD, csig) == SIG_ERR) { 1411 perror("signal"); 1412 return -1; 1413 } 1414 1415 return p == -1 ? -1 : status; 1416} 1417 1418static struct pid { 1419 struct pid *next; 1420 FILE *fp; 1421 int pid; 1422} *pidlist; 1423 1424void * 1425Popen(const char *command, const char *type) 1426{ 1427 struct pid *cur; 1428 FILE *iop; 1429 int pdes[2], pid; 1430 1431 if (command == NULL || type == NULL) 1432 return NULL; 1433 1434 if ((*type != 'r' && *type != 'w') || type[1]) 1435 return NULL; 1436 1437 if ((cur = malloc(sizeof(struct pid))) == NULL) 1438 return NULL; 1439 1440 if (pipe(pdes) < 0) { 1441 free(cur); 1442 return NULL; 1443 } 1444 1445 /* Ignore the smart scheduler while this is going on */ 1446#ifdef HAVE_SETITIMER 1447 if (SmartSchedulePause() < 0) { 1448 close(pdes[0]); 1449 close(pdes[1]); 1450 free(cur); 1451 perror("signal"); 1452 return NULL; 1453 } 1454#endif 1455 1456 switch (pid = fork()) { 1457 case -1: /* error */ 1458 close(pdes[0]); 1459 close(pdes[1]); 1460 free(cur); 1461#ifdef HAVE_SETITIMER 1462 if (SmartScheduleEnable() < 0) 1463 perror("signal"); 1464#endif 1465 return NULL; 1466 case 0: /* child */ 1467 if (setgid(getgid()) == -1) 1468 _exit(127); 1469 if (setuid(getuid()) == -1) 1470 _exit(127); 1471 if (*type == 'r') { 1472 if (pdes[1] != 1) { 1473 /* stdout */ 1474 dup2(pdes[1], 1); 1475 close(pdes[1]); 1476 } 1477 close(pdes[0]); 1478 } 1479 else { 1480 if (pdes[0] != 0) { 1481 /* stdin */ 1482 dup2(pdes[0], 0); 1483 close(pdes[0]); 1484 } 1485 close(pdes[1]); 1486 } 1487 execl("/bin/sh", "sh", "-c", command, (char *) NULL); 1488 _exit(127); 1489 } 1490 1491 /* Avoid EINTR during stdio calls */ 1492 OsBlockSignals(); 1493 1494 /* parent */ 1495 if (*type == 'r') { 1496 iop = fdopen(pdes[0], type); 1497 close(pdes[1]); 1498 } 1499 else { 1500 iop = fdopen(pdes[1], type); 1501 close(pdes[0]); 1502 } 1503 1504 cur->fp = iop; 1505 cur->pid = pid; 1506 cur->next = pidlist; 1507 pidlist = cur; 1508 1509 DebugF("Popen: `%s', fp = %p\n", command, iop); 1510 1511 return iop; 1512} 1513 1514/* fopen that drops privileges */ 1515void * 1516Fopen(const char *file, const char *type) 1517{ 1518 FILE *iop; 1519 1520#ifndef HAS_SAVED_IDS_AND_SETEUID 1521 struct pid *cur; 1522 int pdes[2], pid; 1523 1524 if (file == NULL || type == NULL) 1525 return NULL; 1526 1527 if ((*type != 'r' && *type != 'w') || type[1]) 1528 return NULL; 1529 1530 if ((cur = malloc(sizeof(struct pid))) == NULL) 1531 return NULL; 1532 1533 if (pipe(pdes) < 0) { 1534 free(cur); 1535 return NULL; 1536 } 1537 1538 switch (pid = fork()) { 1539 case -1: /* error */ 1540 close(pdes[0]); 1541 close(pdes[1]); 1542 free(cur); 1543 return NULL; 1544 case 0: /* child */ 1545 if (setgid(getgid()) == -1) 1546 _exit(127); 1547 if (setuid(getuid()) == -1) 1548 _exit(127); 1549 if (*type == 'r') { 1550 if (pdes[1] != 1) { 1551 /* stdout */ 1552 dup2(pdes[1], 1); 1553 close(pdes[1]); 1554 } 1555 close(pdes[0]); 1556 } 1557 else { 1558 if (pdes[0] != 0) { 1559 /* stdin */ 1560 dup2(pdes[0], 0); 1561 close(pdes[0]); 1562 } 1563 close(pdes[1]); 1564 } 1565 execl("/bin/cat", "cat", file, (char *) NULL); 1566 _exit(127); 1567 } 1568 1569 /* Avoid EINTR during stdio calls */ 1570 OsBlockSignals(); 1571 1572 /* parent */ 1573 if (*type == 'r') { 1574 iop = fdopen(pdes[0], type); 1575 close(pdes[1]); 1576 } 1577 else { 1578 iop = fdopen(pdes[1], type); 1579 close(pdes[0]); 1580 } 1581 1582 cur->fp = iop; 1583 cur->pid = pid; 1584 cur->next = pidlist; 1585 pidlist = cur; 1586 1587 DebugF("Fopen(%s), fp = %p\n", file, iop); 1588 1589 return iop; 1590#else 1591 int ruid, euid; 1592 1593 ruid = getuid(); 1594 euid = geteuid(); 1595 1596 if (seteuid(ruid) == -1) { 1597 return NULL; 1598 } 1599 iop = fopen(file, type); 1600 1601 if (seteuid(euid) == -1) { 1602 fclose(iop); 1603 return NULL; 1604 } 1605 return iop; 1606#endif /* HAS_SAVED_IDS_AND_SETEUID */ 1607} 1608 1609int 1610Pclose(void *iop) 1611{ 1612 struct pid *cur, *last; 1613 int pstat; 1614 int pid; 1615 1616 DebugF("Pclose: fp = %p\n", iop); 1617 fclose(iop); 1618 1619 for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next) 1620 if (cur->fp == iop) 1621 break; 1622 if (cur == NULL) 1623 return -1; 1624 1625 do { 1626 pid = waitpid(cur->pid, &pstat, 0); 1627 } while (pid == -1 && errno == EINTR); 1628 1629 if (last == NULL) 1630 pidlist = cur->next; 1631 else 1632 last->next = cur->next; 1633 free(cur); 1634 1635 /* allow EINTR again */ 1636 OsReleaseSignals(); 1637 1638#ifdef HAVE_SETITIMER 1639 if (SmartScheduleEnable() < 0) { 1640 perror("signal"); 1641 return -1; 1642 } 1643#endif 1644 1645 return pid == -1 ? -1 : pstat; 1646} 1647 1648int 1649Fclose(void *iop) 1650{ 1651#ifdef HAS_SAVED_IDS_AND_SETEUID 1652 return fclose(iop); 1653#else 1654 return Pclose(iop); 1655#endif 1656} 1657 1658#endif /* !WIN32 */ 1659 1660#ifdef WIN32 1661 1662#include <X11/Xwindows.h> 1663 1664const char * 1665Win32TempDir(void) 1666{ 1667 static char buffer[PATH_MAX]; 1668 1669 if (GetTempPath(sizeof(buffer), buffer)) { 1670 int len; 1671 1672 buffer[sizeof(buffer) - 1] = 0; 1673 len = strlen(buffer); 1674 if (len > 0) 1675 if (buffer[len - 1] == '\\') 1676 buffer[len - 1] = 0; 1677 return buffer; 1678 } 1679 if (getenv("TEMP") != NULL) 1680 return getenv("TEMP"); 1681 else if (getenv("TMP") != NULL) 1682 return getenv("TMP"); 1683 else 1684 return "/tmp"; 1685} 1686 1687int 1688System(const char *cmdline) 1689{ 1690 STARTUPINFO si; 1691 PROCESS_INFORMATION pi; 1692 DWORD dwExitCode; 1693 char *cmd = strdup(cmdline); 1694 1695 ZeroMemory(&si, sizeof(si)); 1696 si.cb = sizeof(si); 1697 ZeroMemory(&pi, sizeof(pi)); 1698 1699 if (!CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { 1700 LPVOID buffer; 1701 1702 if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 1703 FORMAT_MESSAGE_FROM_SYSTEM | 1704 FORMAT_MESSAGE_IGNORE_INSERTS, 1705 NULL, 1706 GetLastError(), 1707 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 1708 (LPTSTR) &buffer, 0, NULL)) { 1709 ErrorF("[xkb] Starting '%s' failed!\n", cmdline); 1710 } 1711 else { 1712 ErrorF("[xkb] Starting '%s' failed: %s", cmdline, (char *) buffer); 1713 LocalFree(buffer); 1714 } 1715 1716 free(cmd); 1717 return -1; 1718 } 1719 /* Wait until child process exits. */ 1720 WaitForSingleObject(pi.hProcess, INFINITE); 1721 1722 GetExitCodeProcess(pi.hProcess, &dwExitCode); 1723 1724 /* Close process and thread handles. */ 1725 CloseHandle(pi.hProcess); 1726 CloseHandle(pi.hThread); 1727 free(cmd); 1728 1729 return dwExitCode; 1730} 1731#endif 1732 1733Bool 1734PrivsElevated(void) 1735{ 1736 static Bool privsTested = FALSE; 1737 static Bool privsElevated = TRUE; 1738 1739 if (!privsTested) { 1740#if defined(WIN32) 1741 privsElevated = FALSE; 1742#else 1743 if ((getuid() != geteuid()) || (getgid() != getegid())) { 1744 privsElevated = TRUE; 1745 } 1746 else { 1747#if defined(HAVE_ISSETUGID) 1748 privsElevated = issetugid(); 1749#elif defined(HAVE_GETRESUID) 1750 uid_t ruid, euid, suid; 1751 gid_t rgid, egid, sgid; 1752 1753 if ((getresuid(&ruid, &euid, &suid) == 0) && 1754 (getresgid(&rgid, &egid, &sgid) == 0)) { 1755 privsElevated = (euid != suid) || (egid != sgid); 1756 } 1757 else { 1758 printf("Failed getresuid or getresgid"); 1759 /* Something went wrong, make defensive assumption */ 1760 privsElevated = TRUE; 1761 } 1762#else 1763 if (getuid() == 0) { 1764 /* running as root: uid==euid==0 */ 1765 privsElevated = FALSE; 1766 } 1767 else { 1768 /* 1769 * If there are saved ID's the process might still be privileged 1770 * even though the above test succeeded. If issetugid() and 1771 * getresgid() aren't available, test this by trying to set 1772 * euid to 0. 1773 */ 1774 unsigned int oldeuid; 1775 1776 oldeuid = geteuid(); 1777 1778 if (seteuid(0) != 0) { 1779 privsElevated = FALSE; 1780 } 1781 else { 1782 if (seteuid(oldeuid) != 0) { 1783 FatalError("Failed to drop privileges. Exiting\n"); 1784 } 1785 privsElevated = TRUE; 1786 } 1787 } 1788#endif 1789 } 1790#endif 1791 privsTested = TRUE; 1792 } 1793 return privsElevated; 1794} 1795 1796/* 1797 * CheckUserParameters: check for long command line arguments and long 1798 * environment variables. By default, these checks are only done when 1799 * the server's euid != ruid. In 3.3.x, these checks were done in an 1800 * external wrapper utility. 1801 */ 1802 1803/* Consider LD* variables insecure? */ 1804#ifndef REMOVE_ENV_LD 1805#define REMOVE_ENV_LD 1 1806#endif 1807 1808/* Remove long environment variables? */ 1809#ifndef REMOVE_LONG_ENV 1810#define REMOVE_LONG_ENV 1 1811#endif 1812 1813/* 1814 * Disallow stdout or stderr as pipes? It's possible to block the X server 1815 * when piping stdout+stderr to a pipe. 1816 * 1817 * Don't enable this because it looks like it's going to cause problems. 1818 */ 1819#ifndef NO_OUTPUT_PIPES 1820#define NO_OUTPUT_PIPES 0 1821#endif 1822 1823/* Check args and env only if running setuid (euid == 0 && euid != uid) ? */ 1824#ifndef CHECK_EUID 1825#ifndef WIN32 1826#define CHECK_EUID 1 1827#else 1828#define CHECK_EUID 0 1829#endif 1830#endif 1831 1832/* 1833 * Maybe the locale can be faked to make isprint(3) report that everything 1834 * is printable? Avoid it by default. 1835 */ 1836#ifndef USE_ISPRINT 1837#define USE_ISPRINT 0 1838#endif 1839 1840#define MAX_ARG_LENGTH 128 1841#define MAX_ENV_LENGTH 256 1842#define MAX_ENV_PATH_LENGTH 2048 /* Limit for *PATH and TERMCAP */ 1843 1844#if USE_ISPRINT 1845#include <ctype.h> 1846#define checkPrintable(c) isprint(c) 1847#else 1848#define checkPrintable(c) (((c) & 0x7f) >= 0x20 && ((c) & 0x7f) != 0x7f) 1849#endif 1850 1851enum BadCode { 1852 NotBad = 0, 1853 UnsafeArg, 1854 ArgTooLong, 1855 UnprintableArg, 1856 EnvTooLong, 1857 OutputIsPipe, 1858 InternalError 1859}; 1860 1861#if defined(VENDORSUPPORT) 1862#define BUGADDRESS VENDORSUPPORT 1863#elif defined(BUILDERADDR) 1864#define BUGADDRESS BUILDERADDR 1865#else 1866#define BUGADDRESS "xorg@freedesktop.org" 1867#endif 1868 1869void 1870CheckUserParameters(int argc, char **argv, char **envp) 1871{ 1872 enum BadCode bad = NotBad; 1873 int i = 0, j; 1874 char *a, *e = NULL; 1875 1876#if CHECK_EUID 1877 if (PrivsElevated()) 1878#endif 1879 { 1880 /* Check each argv[] */ 1881 for (i = 1; i < argc; i++) { 1882 if (strcmp(argv[i], "-fp") == 0) { 1883 i++; /* continue with next argument. skip the length check */ 1884 if (i >= argc) 1885 break; 1886 } 1887 else { 1888 if (strlen(argv[i]) > MAX_ARG_LENGTH) { 1889 bad = ArgTooLong; 1890 break; 1891 } 1892 } 1893 a = argv[i]; 1894 while (*a) { 1895 if (checkPrintable(*a) == 0) { 1896 bad = UnprintableArg; 1897 break; 1898 } 1899 a++; 1900 } 1901 if (bad) 1902 break; 1903 } 1904 if (!bad) { 1905 /* Check each envp[] */ 1906 for (i = 0; envp[i]; i++) { 1907 1908 /* Check for bad environment variables and values */ 1909#if REMOVE_ENV_LD 1910 while (envp[i] && (strncmp(envp[i], "LD", 2) == 0)) { 1911 for (j = i; envp[j]; j++) { 1912 envp[j] = envp[j + 1]; 1913 } 1914 } 1915#endif 1916 if (envp[i] && (strlen(envp[i]) > MAX_ENV_LENGTH)) { 1917#if REMOVE_LONG_ENV 1918 for (j = i; envp[j]; j++) { 1919 envp[j] = envp[j + 1]; 1920 } 1921 i--; 1922#else 1923 char *eq; 1924 int len; 1925 1926 eq = strchr(envp[i], '='); 1927 if (!eq) 1928 continue; 1929 len = eq - envp[i]; 1930 e = strndup(envp[i], len); 1931 if (!e) { 1932 bad = InternalError; 1933 break; 1934 } 1935 if (len >= 4 && 1936 (strcmp(e + len - 4, "PATH") == 0 || 1937 strcmp(e, "TERMCAP") == 0)) { 1938 if (strlen(envp[i]) > MAX_ENV_PATH_LENGTH) { 1939 bad = EnvTooLong; 1940 break; 1941 } 1942 else { 1943 free(e); 1944 } 1945 } 1946 else { 1947 bad = EnvTooLong; 1948 break; 1949 } 1950#endif 1951 } 1952 } 1953 } 1954#if NO_OUTPUT_PIPES 1955 if (!bad) { 1956 struct stat buf; 1957 1958 if (fstat(fileno(stdout), &buf) == 0 && S_ISFIFO(buf.st_mode)) 1959 bad = OutputIsPipe; 1960 if (fstat(fileno(stderr), &buf) == 0 && S_ISFIFO(buf.st_mode)) 1961 bad = OutputIsPipe; 1962 } 1963#endif 1964 } 1965 switch (bad) { 1966 case NotBad: 1967 return; 1968 case UnsafeArg: 1969 ErrorF("Command line argument number %d is unsafe\n", i); 1970 break; 1971 case ArgTooLong: 1972 ErrorF("Command line argument number %d is too long\n", i); 1973 break; 1974 case UnprintableArg: 1975 ErrorF("Command line argument number %d contains unprintable" 1976 " characters\n", i); 1977 break; 1978 case EnvTooLong: 1979 ErrorF("Environment variable `%s' is too long\n", e); 1980 break; 1981 case OutputIsPipe: 1982 ErrorF("Stdout and/or stderr is a pipe\n"); 1983 break; 1984 case InternalError: 1985 ErrorF("Internal Error\n"); 1986 break; 1987 default: 1988 ErrorF("Unknown error\n"); 1989 break; 1990 } 1991 FatalError("X server aborted because of unsafe environment\n"); 1992} 1993 1994/* 1995 * CheckUserAuthorization: check if the user is allowed to start the 1996 * X server. This usually means some sort of PAM checking, and it is 1997 * usually only done for setuid servers (uid != euid). 1998 */ 1999 2000#ifdef USE_PAM 2001#include <security/pam_appl.h> 2002#include <security/pam_misc.h> 2003#include <pwd.h> 2004#endif /* USE_PAM */ 2005 2006void 2007CheckUserAuthorization(void) 2008{ 2009#ifdef USE_PAM 2010 static struct pam_conv conv = { 2011 misc_conv, 2012 NULL 2013 }; 2014 2015 pam_handle_t *pamh = NULL; 2016 struct passwd *pw; 2017 int retval; 2018 2019 if (getuid() != geteuid()) { 2020 pw = getpwuid(getuid()); 2021 if (pw == NULL) 2022 FatalError("getpwuid() failed for uid %d\n", getuid()); 2023 2024 retval = pam_start("xserver", pw->pw_name, &conv, &pamh); 2025 if (retval != PAM_SUCCESS) 2026 FatalError("pam_start() failed.\n" 2027 "\tMissing or mangled PAM config file or module?\n"); 2028 2029 retval = pam_authenticate(pamh, 0); 2030 if (retval != PAM_SUCCESS) { 2031 pam_end(pamh, retval); 2032 FatalError("PAM authentication failed, cannot start X server.\n" 2033 "\tPerhaps you do not have console ownership?\n"); 2034 } 2035 2036 retval = pam_acct_mgmt(pamh, 0); 2037 if (retval != PAM_SUCCESS) { 2038 pam_end(pamh, retval); 2039 FatalError("PAM authentication failed, cannot start X server.\n" 2040 "\tPerhaps you do not have console ownership?\n"); 2041 } 2042 2043 /* this is not a session, so do not do session management */ 2044 pam_end(pamh, PAM_SUCCESS); 2045 } 2046#endif 2047} 2048 2049/* 2050 * Tokenize a string into a NULL terminated array of strings. Always returns 2051 * an allocated array unless an error occurs. 2052 */ 2053char ** 2054xstrtokenize(const char *str, const char *separators) 2055{ 2056 char **list, **nlist; 2057 char *tok, *tmp; 2058 unsigned num = 0, n; 2059 2060 if (!str) 2061 return NULL; 2062 list = calloc(1, sizeof(*list)); 2063 if (!list) 2064 return NULL; 2065 tmp = strdup(str); 2066 if (!tmp) 2067 goto error; 2068 for (tok = strtok(tmp, separators); tok; tok = strtok(NULL, separators)) { 2069 nlist = reallocarray(list, num + 2, sizeof(*list)); 2070 if (!nlist) 2071 goto error; 2072 list = nlist; 2073 list[num] = strdup(tok); 2074 if (!list[num]) 2075 goto error; 2076 list[++num] = NULL; 2077 } 2078 free(tmp); 2079 return list; 2080 2081 error: 2082 free(tmp); 2083 for (n = 0; n < num; n++) 2084 free(list[n]); 2085 free(list); 2086 return NULL; 2087} 2088 2089/* Format a signed number into a string in a signal safe manner. The string 2090 * should be at least 21 characters in order to handle all int64_t values. 2091 */ 2092void 2093FormatInt64(int64_t num, char *string) 2094{ 2095 if (num < 0) { 2096 string[0] = '-'; 2097 num *= -1; 2098 string++; 2099 } 2100 FormatUInt64(num, string); 2101} 2102 2103/* Format a number into a string in a signal safe manner. The string should be 2104 * at least 21 characters in order to handle all uint64_t values. */ 2105void 2106FormatUInt64(uint64_t num, char *string) 2107{ 2108 uint64_t divisor; 2109 int len; 2110 int i; 2111 2112 for (len = 1, divisor = 10; 2113 len < 20 && num / divisor; 2114 len++, divisor *= 10); 2115 2116 for (i = len, divisor = 1; i > 0; i--, divisor *= 10) 2117 string[i - 1] = '0' + ((num / divisor) % 10); 2118 2119 string[len] = '\0'; 2120} 2121 2122/** 2123 * Format a double number as %.2f. 2124 */ 2125void 2126FormatDouble(double dbl, char *string) 2127{ 2128 int slen = 0; 2129 uint64_t frac; 2130 2131 frac = (dbl > 0 ? dbl : -dbl) * 100.0 + 0.5; 2132 frac %= 100; 2133 2134 /* write decimal part to string */ 2135 if (dbl < 0 && dbl > -1) 2136 string[slen++] = '-'; 2137 FormatInt64((int64_t)dbl, &string[slen]); 2138 2139 while(string[slen] != '\0') 2140 slen++; 2141 2142 /* append fractional part, but only if we have enough characters. We 2143 * expect string to be 21 chars (incl trailing \0) */ 2144 if (slen <= 17) { 2145 string[slen++] = '.'; 2146 if (frac < 10) 2147 string[slen++] = '0'; 2148 2149 FormatUInt64(frac, &string[slen]); 2150 } 2151} 2152 2153 2154/* Format a number into a hexadecimal string in a signal safe manner. The string 2155 * should be at least 17 characters in order to handle all uint64_t values. */ 2156void 2157FormatUInt64Hex(uint64_t num, char *string) 2158{ 2159 uint64_t divisor; 2160 int len; 2161 int i; 2162 2163 for (len = 1, divisor = 0x10; 2164 len < 16 && num / divisor; 2165 len++, divisor *= 0x10); 2166 2167 for (i = len, divisor = 1; i > 0; i--, divisor *= 0x10) { 2168 int val = (num / divisor) % 0x10; 2169 2170 if (val < 10) 2171 string[i - 1] = '0' + val; 2172 else 2173 string[i - 1] = 'a' + val - 10; 2174 } 2175 2176 string[len] = '\0'; 2177} 2178 2179#if !defined(WIN32) || defined(__CYGWIN__) 2180/* Move a file descriptor out of the way of our select mask; this 2181 * is useful for file descriptors which will never appear in the 2182 * select mask to avoid reducing the number of clients that can 2183 * connect to the server 2184 */ 2185int 2186os_move_fd(int fd) 2187{ 2188 int newfd; 2189 2190#ifdef F_DUPFD_CLOEXEC 2191 newfd = fcntl(fd, F_DUPFD_CLOEXEC, MAXCLIENTS); 2192#else 2193 newfd = fcntl(fd, F_DUPFD, MAXCLIENTS); 2194#endif 2195 if (newfd < 0) 2196 return fd; 2197#ifndef F_DUPFD_CLOEXEC 2198 fcntl(newfd, F_SETFD, FD_CLOEXEC); 2199#endif 2200 close(fd); 2201 return newfd; 2202} 2203#endif 2204