1 /* 2 3 Copyright 1988, 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 */ 28 29 /* 30 * xdm - display manager daemon 31 * Author: Keith Packard, MIT X Consortium 32 * 33 * display manager 34 */ 35 36 #include "dm.h" 37 #include "dm_auth.h" 38 #include "dm_error.h" 39 40 #include <stdio.h> 41 #ifdef X_POSIX_C_SOURCE 42 # define _POSIX_C_SOURCE X_POSIX_C_SOURCE 43 # include <signal.h> 44 # undef _POSIX_C_SOURCE 45 #else 46 # if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE) 47 # include <signal.h> 48 # else 49 # define _POSIX_SOURCE 50 # include <signal.h> 51 # undef _POSIX_SOURCE 52 # endif 53 #endif 54 #ifdef __NetBSD__ 55 # include <sys/param.h> 56 #endif 57 58 #ifndef sigmask 59 # define sigmask(m) (1 << ((m - 1))) 60 #endif 61 62 #include <sys/stat.h> 63 #include <errno.h> 64 #include <X11/Xfuncproto.h> 65 #include <X11/Xatom.h> 66 #include <stdarg.h> 67 #include <stdint.h> 68 69 #ifndef F_TLOCK 70 # ifndef X_NOT_POSIX 71 # include <unistd.h> 72 # endif 73 #endif 74 75 #if defined(HAVE_OPENLOG) && defined(HAVE_SYSLOG_H) 76 # define USE_SYSLOG 77 # include <syslog.h> 78 # ifndef LOG_AUTHPRIV 79 # define LOG_AUTHPRIV LOG_AUTH 80 # endif 81 # ifndef LOG_PID 82 # define LOG_PID 0 83 # endif 84 #endif 85 86 static void StopAll (int n), RescanNotify (int n); 87 static void RescanServers (void); 88 static void RestartDisplay (struct display *d, int forceReserver); 89 static void ScanServers (void); 90 static void SetAccessFileTime (void); 91 static void SetConfigFileTime (void); 92 static void StartDisplays (void); 93 static void TerminateProcess (pid_t pid, int signal); 94 95 volatile int Rescan; 96 static long ServersModTime, ConfigModTime, AccessFileModTime; 97 98 int nofork_session = 0; 99 100 #ifndef NOXDMTITLE 101 static char *Title; 102 static int TitleLen; 103 #endif 104 105 static void ChildNotify (int n); 106 107 static long StorePid (void); 108 static void RemovePid (void); 109 110 static pid_t parent_pid = -1; /* PID of parent xdm process */ 111 112 int 113 main (int argc, char **argv) 114 { 115 int oldpid; 116 mode_t oldumask; 117 char cmdbuf[1024]; 118 119 /* make sure at least world write access is disabled */ 120 if (((oldumask = umask(022)) & 002) == 002) 121 (void) umask (oldumask); 122 #ifndef NOXDMTITLE 123 if (argc > 0) { 124 Title = argv[0]; 125 TitleLen = (argv[argc - 1] + strlen(argv[argc - 1])) - Title; 126 } else { 127 Title = NULL; 128 TitleLen = 0; 129 } 130 #endif 131 132 /* 133 * Step 1 - load configuration parameters 134 */ 135 InitResources (argc, argv); 136 SetConfigFileTime (); 137 LoadDMResources (); 138 /* 139 * Only allow root to run in non-debug mode to avoid problems 140 */ 141 if (debugLevel == 0 && getuid() != 0) 142 { 143 fprintf (stderr, "Only root wants to run %s\n", argv[0]); 144 exit (1); 145 } 146 if (debugLevel == 0 && daemonMode) 147 BecomeDaemon (); 148 if (debugLevel == 0) 149 InitErrorLog (); 150 if (debugLevel >= 10) 151 nofork_session = 1; 152 /* SUPPRESS 560 */ 153 if ((oldpid = StorePid ())) 154 { 155 if (oldpid == -1) 156 LogError ("Can't create/lock pid file %s\n", pidFile); 157 else 158 LogError ("Can't lock pid file %s, another xdm is running (pid %d)\n", 159 pidFile, oldpid); 160 exit (1); 161 } 162 163 LogInfo ("Starting %s\n", PACKAGE_STRING); 164 if (debugLevel > 0) 165 { 166 Debug("%s was built with these options:\n", PACKAGE_STRING); 167 #ifdef USE_PAM 168 Debug(" - USE_PAM = yes\n"); 169 #else 170 Debug(" - USE_PAM = no\n"); 171 #endif 172 #ifdef USE_SELINUX 173 Debug(" - USE_SELINUX = yes\n"); 174 #else 175 Debug(" - USE_SELINUX = no\n"); 176 #endif 177 #ifdef USE_SYSTEMD_DAEMON 178 Debug(" - USE_SYSTEMD_DAEMON = yes\n"); 179 #else 180 Debug(" - USE_SYSTEMD_DAEMON = no\n"); 181 #endif 182 #ifdef USE_XFT 183 Debug(" - USE_XFT = yes\n"); 184 #else 185 Debug(" - USE_XFT = no\n"); 186 #endif 187 #ifdef USE_XINERAMA 188 Debug(" - USE_XINERAMA = yes\n"); 189 #else 190 Debug(" - USE_XINERAMA = no\n"); 191 #endif 192 #ifdef XPM 193 Debug(" - XPM = yes\n"); 194 #else 195 Debug(" - XPM = no\n"); 196 #endif 197 #ifdef HAVE_ARC4RANDOM 198 Debug(" - Random number source: arc4random()\n\n"); 199 #elif defined(DEV_RANDOM) 200 Debug(" - Random number source: %s\n", DEV_RANDOM); 201 #else 202 Debug(" - Random number source: built-in PRNG\n\n"); 203 #endif 204 } 205 206 if (atexit (RemovePid)) 207 LogError ("could not register RemovePid() with atexit()\n"); 208 209 if (nofork_session == 0) { 210 /* Clean up any old Authorization files */ 211 /* AUD: all good? */ 212 snprintf(cmdbuf, sizeof(cmdbuf), "/bin/rm -f %s/authdir/authfiles/A*", authDir); 213 system(cmdbuf); 214 } 215 #if!defined(HAVE_ARC4RANDOM) && !defined(DEV_RANDOM) 216 AddOtherEntropy (); 217 #endif 218 #ifdef XDMCP 219 init_session_id (); 220 CreateWellKnownSockets (); 221 #else 222 Debug ("xdm: not compiled for XDMCP\n"); 223 #endif 224 parent_pid = getpid (); 225 (void) Signal (SIGTERM, StopAll); 226 (void) Signal (SIGINT, StopAll); 227 /* 228 * Step 2 - Read /etc/Xservers and set up 229 * the socket. 230 * 231 * Keep a sub-daemon running 232 * for each entry 233 */ 234 SetAccessFileTime (); 235 #ifdef XDMCP 236 ScanAccessDatabase (); 237 UpdateListenSockets (); 238 #endif 239 ScanServers (); 240 StartDisplays (); 241 #if !defined(HAVE_ARC4RANDOM) && !defined(DEV_RANDOM) 242 AddOtherEntropy(); 243 #endif 244 (void) Signal (SIGHUP, RescanNotify); 245 (void) Signal (SIGCHLD, ChildNotify); 246 Debug ("startup successful; entering main loop\n"); 247 while ( 248 #ifdef XDMCP 249 AnyWellKnownSockets() || 250 #endif 251 AnyDisplaysLeft ()) 252 { 253 if (Rescan) 254 { 255 RescanServers (); 256 Rescan = 0; 257 } 258 #ifndef XDMCP 259 WaitForChild (); 260 #else 261 WaitForSomething (); 262 #endif 263 } 264 Debug ("Nothing left to do, exiting\n"); 265 LogInfo ("Exiting\n"); 266 exit(0); 267 /*NOTREACHED*/ 268 } 269 270 /* ARGSUSED */ 271 static void 272 RescanNotify (int n) 273 { 274 int olderrno = errno; 275 276 Debug ("Caught SIGHUP\n"); 277 Rescan = 1; 278 errno = olderrno; 279 } 280 281 static void 282 ScanServers (void) 283 { 284 char lineBuf[10240]; 285 FILE *serversFile; 286 struct stat statb; 287 static DisplayType acceptableTypes[] = 288 { { Local, Permanent, FromFile }, 289 { Foreign, Permanent, FromFile }, 290 }; 291 292 #define NumTypes (sizeof (acceptableTypes) / sizeof (acceptableTypes[0])) 293 294 if (servers[0] == '/') 295 { 296 serversFile = fopen (servers, "r"); 297 if (serversFile == NULL) 298 { 299 LogError ("cannot access servers file %s\n", servers); 300 return; 301 } 302 if (ServersModTime == 0) 303 { 304 fstat (fileno (serversFile), &statb); 305 ServersModTime = statb.st_mtime; 306 } 307 while (fgets (lineBuf, sizeof (lineBuf)-1, serversFile)) 308 { 309 size_t len = strlen (lineBuf); 310 if (len > 0) { 311 if (lineBuf[len-1] == '\n') 312 lineBuf[len-1] = '\0'; 313 ParseDisplay (lineBuf, acceptableTypes, NumTypes); 314 } 315 } 316 fclose (serversFile); 317 } 318 else 319 { 320 ParseDisplay (servers, acceptableTypes, NumTypes); 321 } 322 } 323 324 static void 325 MarkDisplay (struct display *d) 326 { 327 d->state = MissingEntry; 328 } 329 330 static void 331 RescanServers (void) 332 { 333 Debug ("rescanning servers\n"); 334 LogInfo ("Rescanning both config and servers files\n"); 335 ForEachDisplay (MarkDisplay); 336 SetConfigFileTime (); 337 ReinitResources (); 338 LoadDMResources (); 339 ScanServers (); 340 SetAccessFileTime (); 341 #ifdef XDMCP 342 ScanAccessDatabase (); 343 UpdateListenSockets (); 344 #endif 345 StartDisplays (); 346 } 347 348 static void 349 SetConfigFileTime (void) 350 { 351 struct stat statb; 352 353 if (stat (config, &statb) != -1) 354 ConfigModTime = statb.st_mtime; 355 } 356 357 static void 358 SetAccessFileTime (void) 359 { 360 struct stat statb; 361 362 if (stat (accessFile, &statb) != -1) 363 AccessFileModTime = statb.st_mtime; 364 } 365 366 static void 367 RescanIfMod (void) 368 { 369 struct stat statb; 370 371 if (config && stat (config, &statb) != -1) 372 { 373 if (statb.st_mtime != ConfigModTime) 374 { 375 Debug ("Config file %s has changed, rereading\n", config); 376 LogInfo ("Rereading configuration file %s\n", config); 377 ConfigModTime = statb.st_mtime; 378 ReinitResources (); 379 LoadDMResources (); 380 } 381 } 382 if (servers[0] == '/' && stat(servers, &statb) != -1) 383 { 384 if (statb.st_mtime != ServersModTime) 385 { 386 Debug ("Servers file %s has changed, rescanning\n", servers); 387 LogInfo ("Rereading servers file %s\n", servers); 388 ServersModTime = statb.st_mtime; 389 ForEachDisplay (MarkDisplay); 390 ScanServers (); 391 } 392 } 393 #ifdef XDMCP 394 if (accessFile && accessFile[0] && stat (accessFile, &statb) != -1) 395 { 396 if (statb.st_mtime != AccessFileModTime) 397 { 398 Debug ("Access file %s has changed, rereading\n", accessFile); 399 LogInfo ("Rereading access file %s\n", accessFile); 400 AccessFileModTime = statb.st_mtime; 401 ScanAccessDatabase (); 402 UpdateListenSockets(); 403 } 404 } 405 #endif 406 } 407 408 /* 409 * catch a SIGTERM, kill all displays and exit 410 */ 411 412 /* ARGSUSED */ 413 static void 414 StopAll (int n) 415 { 416 int olderrno = errno; 417 418 if (parent_pid != getpid()) 419 { 420 /* 421 * We are a child xdm process that was killed by the 422 * parent xdm before we were able to return from fork() 423 * and remove this signal handler. 424 * 425 * See defect XWSog08655 for more information. 426 */ 427 Debug ("Child xdm caught SIGTERM before it removed that signal.\n"); 428 (void) Signal (n, SIG_DFL); 429 TerminateProcess (getpid(), SIGTERM); 430 errno = olderrno; 431 return; 432 } 433 Debug ("Shutting down entire manager\n"); 434 LogInfo ("Shutting down\n"); 435 #ifdef XDMCP 436 DestroyWellKnownSockets (); 437 #endif 438 ForEachDisplay (StopDisplay); 439 errno = olderrno; 440 } 441 442 /* 443 * notice that a child has died and may need another 444 * sub-daemon started 445 */ 446 447 int ChildReady; 448 449 /* ARGSUSED */ 450 static void 451 ChildNotify (int n) 452 { 453 int olderrno = errno; 454 455 ChildReady = 1; 456 errno = olderrno; 457 } 458 459 void 460 WaitForChild (void) 461 { 462 pid_t pid; 463 struct display *d; 464 waitType status; 465 #if !defined(X_NOT_POSIX) 466 sigset_t mask, omask; 467 #else 468 int omask; 469 #endif 470 471 # ifndef X_NOT_POSIX 472 sigemptyset(&mask); 473 sigaddset(&mask, SIGCHLD); 474 sigaddset(&mask, SIGHUP); 475 sigprocmask(SIG_BLOCK, &mask, &omask); 476 Debug ("signals blocked\n"); 477 # else 478 omask = sigblock (sigmask (SIGCHLD) | sigmask (SIGHUP)); 479 Debug ("signals blocked, mask was 0x%x\n", omask); 480 # endif 481 if (!ChildReady && !Rescan) 482 # ifndef X_NOT_POSIX 483 sigsuspend(&omask); 484 # else 485 sigpause (omask); 486 # endif 487 ChildReady = 0; 488 # ifndef X_NOT_POSIX 489 sigprocmask(SIG_SETMASK, &omask, (sigset_t *)NULL); 490 # else 491 sigsetmask (omask); 492 # endif 493 while ((pid = waitpid (-1, &status, WNOHANG)) > 0) 494 { 495 Debug ("Manager wait returns pid: %d sig %d core %d code %d\n", 496 pid, waitSig(status), waitCore(status), waitCode(status)); 497 if (autoRescan) 498 RescanIfMod (); 499 /* SUPPRESS 560 */ 500 if ((d = FindDisplayByPid (pid))) { 501 d->pid = -1; 502 switch (waitVal (status)) { 503 case UNMANAGE_DISPLAY: 504 Debug ("Display exited with UNMANAGE_DISPLAY\n"); 505 StopDisplay (d); 506 break; 507 case OBEYSESS_DISPLAY: 508 d->startTries = 0; 509 d->reservTries = 0; 510 Debug ("Display exited with OBEYSESS_DISPLAY\n"); 511 if (d->displayType.lifetime != Permanent || 512 d->status == zombie) 513 StopDisplay (d); 514 else 515 RestartDisplay (d, FALSE); 516 break; 517 case OPENFAILED_DISPLAY: 518 Debug ("Display exited with OPENFAILED_DISPLAY, try %d of %d\n", 519 d->startTries, d->startAttempts); 520 LogError ("Display %s cannot be opened\n", d->name); 521 /* 522 * no display connection was ever made, tell the 523 * terminal that the open attempt failed 524 */ 525 #ifdef XDMCP 526 if (d->displayType.origin == FromXDMCP) 527 SendFailed (d, "Cannot open display"); 528 #endif 529 if (d->displayType.origin == FromXDMCP || 530 d->status == zombie || 531 ++d->startTries >= d->startAttempts) 532 { 533 LogError ("Display %s is being disabled\n", d->name); 534 StopDisplay (d); 535 } 536 else 537 { 538 RestartDisplay (d, TRUE); 539 } 540 break; 541 case RESERVER_DISPLAY: 542 d->startTries = 0; 543 Debug ("Display exited with RESERVER_DISPLAY\n"); 544 if (d->displayType.origin == FromXDMCP || d->status == zombie) 545 StopDisplay(d); 546 else { 547 Time_t now; 548 int crash; 549 550 time(&now); 551 crash = d->lastReserv && 552 ((now - d->lastReserv) < XDM_BROKEN_INTERVAL); 553 Debug("time %lli %lli try %i of %i%s\n", 554 (long long)now, (long long)d->lastReserv, 555 d->reservTries, d->reservAttempts, 556 crash ? " crash" : ""); 557 558 if (!crash) 559 d->reservTries = 0; 560 561 if (crash && ++d->reservTries >= d->reservAttempts) { 562 const char *msg = 563 "Server crash frequency too high: stopping display"; 564 Debug("%s %s\n", msg, d->name); 565 LogError("%s %s\n", msg, d->name); 566 #if !defined(HAVE_ARC4RANDOM) && !defined(DEV_RANDOM) 567 AddTimerEntropy(); 568 #endif 569 /* For a local X server either: 570 * 1. The server exit was returned by waitpid(). So 571 * serverPid==-1 => StopDisplay() calls RemoveDisplay() 572 * 573 * 2. The server is in zombie state or still running. So 574 * serverPid>1 => StopDisplay() 575 * a. sets status=zombie, 576 * b. kills the server. 577 * The next waitpid() returns this zombie server pid 578 * and the 'case zombie:' below then calls 579 * RemoveDisplay(). 580 */ 581 StopDisplay(d); 582 } else { 583 RestartDisplay(d, TRUE); 584 } 585 d->lastReserv = now; 586 } 587 break; 588 case waitCompose (SIGTERM,0,0): 589 Debug ("Display exited on SIGTERM, try %d of %d\n", 590 d->startTries, d->startAttempts); 591 if (d->displayType.origin == FromXDMCP || 592 d->status == zombie || 593 ++d->startTries >= d->startAttempts) 594 { 595 /* 596 * During normal xdm shutdown, killed local X servers 597 * can be zombies; this is not an error. 598 */ 599 if (d->status == zombie && 600 (d->startTries < d->startAttempts)) 601 LogInfo ("display %s is being disabled\n", d->name); 602 else 603 LogError ("display %s is being disabled\n", d->name); 604 StopDisplay(d); 605 } else 606 RestartDisplay (d, TRUE); 607 break; 608 case REMANAGE_DISPLAY: 609 d->startTries = 0; 610 Debug ("Display exited with REMANAGE_DISPLAY\n"); 611 /* 612 * XDMCP will restart the session if the display 613 * requests it 614 */ 615 if (d->displayType.origin == FromXDMCP || d->status == zombie) 616 StopDisplay(d); 617 else 618 RestartDisplay (d, FALSE); 619 break; 620 default: 621 Debug ("Display exited with unknown status %d\n", waitVal(status)); 622 LogError ("Unknown session exit code %d from process %d\n", 623 waitVal (status), pid); 624 StopDisplay (d); 625 break; 626 } 627 } 628 /* SUPPRESS 560 */ 629 else if ((d = FindDisplayByServerPid (pid))) 630 { 631 d->serverPid = -1; 632 switch (d->status) 633 { 634 case zombie: 635 Debug ("Zombie server reaped, removing display %s\n", d->name); 636 RemoveDisplay (d); 637 break; 638 case phoenix: 639 Debug ("Phoenix server arises, restarting display %s\n", d->name); 640 d->status = notRunning; 641 break; 642 case running: 643 Debug ("Server for display %s terminated unexpectedly, status %d %d\n", d->name, waitVal (status), status); 644 LogError ("Server for display %s terminated unexpectedly: %d\n", d->name, waitVal (status)); 645 if (d->pid != -1) 646 { 647 Debug ("Terminating session pid %d\n", d->pid); 648 TerminateProcess (d->pid, SIGTERM); 649 } 650 break; 651 case notRunning: 652 Debug ("Server exited for notRunning session on display %s\n", d->name); 653 break; 654 } 655 } 656 else 657 { 658 Debug ("Unknown child termination, status %d\n", waitVal (status)); 659 } 660 } 661 StartDisplays (); 662 } 663 664 static void 665 CheckDisplayStatus (struct display *d) 666 { 667 if (d->displayType.origin == FromFile) 668 { 669 switch (d->state) { 670 case MissingEntry: 671 StopDisplay (d); 672 break; 673 case NewEntry: 674 d->state = OldEntry; 675 case OldEntry: 676 if (d->status == notRunning) 677 StartDisplay (d); 678 break; 679 } 680 } 681 } 682 683 static void 684 StartDisplays (void) 685 { 686 ForEachDisplay (CheckDisplayStatus); 687 } 688 689 static void 690 SetWindowPath(struct display *d) 691 { 692 /* setting WINDOWPATH for clients */ 693 Atom prop; 694 Atom actualtype; 695 int actualformat; 696 unsigned long nitems; 697 unsigned long bytes_after; 698 unsigned char *buf; 699 const char *windowpath; 700 char *newwindowpath; 701 unsigned long num; 702 703 prop = XInternAtom(d->dpy, "XFree86_VT", False); 704 if (prop == None) { 705 fprintf(stderr, "no XFree86_VT atom\n"); 706 return; 707 } 708 if (XGetWindowProperty(d->dpy, DefaultRootWindow(d->dpy), prop, 0, 1, 709 False, AnyPropertyType, &actualtype, &actualformat, 710 &nitems, &bytes_after, &buf)) { 711 fprintf(stderr, "no XFree86_VT property\n"); 712 return; 713 } 714 if (nitems != 1) { 715 fprintf(stderr, "%lu items in XFree86_VT property!\n", nitems); 716 XFree(buf); 717 return; 718 } 719 switch (actualtype) { 720 case XA_CARDINAL: 721 case XA_INTEGER: 722 case XA_WINDOW: 723 switch (actualformat) { 724 case 8: 725 num = (*(uint8_t *)(void *)buf); 726 break; 727 case 16: 728 num = (*(uint16_t *)(void *)buf); 729 break; 730 case 32: 731 num = (*(uint32_t *)(void *)buf); 732 break; 733 default: 734 fprintf(stderr, "format %d in XFree86_VT property!\n", actualformat); 735 XFree(buf); 736 return; 737 } 738 break; 739 default: 740 fprintf(stderr, "type %lx in XFree86_VT property!\n", actualtype); 741 XFree(buf); 742 return; 743 } 744 XFree(buf); 745 windowpath = getenv("WINDOWPATH"); 746 if (!windowpath) { 747 asprintf(&newwindowpath, "%lu", num); 748 } else { 749 asprintf(&newwindowpath, "%s:%lu", windowpath, num); 750 } 751 free(d->windowPath); 752 d->windowPath = newwindowpath; 753 } 754 755 void 756 StartDisplay (struct display *d) 757 { 758 pid_t pid; 759 760 Debug ("StartDisplay %s\n", d->name); 761 LogInfo ("Starting X server on %s\n", d->name); 762 LoadServerResources (d); 763 if (d->displayType.location == Local) 764 { 765 /* don't bother pinging local displays; we'll 766 * certainly notice when they exit 767 */ 768 d->pingInterval = 0; 769 if (d->authorize) 770 { 771 Debug ("SetLocalAuthorization %s, auth %s\n", 772 d->name, d->authNames[0]); 773 SetLocalAuthorization (d); 774 /* 775 * reset the server after writing the authorization information 776 * to make it read the file (for compatibility with old 777 * servers which read auth file only on reset instead of 778 * at first connection) 779 */ 780 if (d->serverPid != -1 && d->resetForAuth && d->resetSignal) 781 kill (d->serverPid, d->resetSignal); 782 } 783 if (d->serverPid == -1 && !StartServer (d)) 784 { 785 LogError ("Server for display %s can't be started, session disabled\n", d->name); 786 RemoveDisplay (d); 787 return; 788 } 789 } 790 else 791 { 792 /* this will only happen when using XDMCP */ 793 if (d->authorizations) 794 SaveServerAuthorizations (d, d->authorizations, d->authNum); 795 } 796 if (!nofork_session) 797 pid = fork (); 798 else 799 pid = 0; 800 switch (pid) 801 { 802 case 0: 803 if (!nofork_session) { 804 CleanUpChild (); 805 (void) Signal (SIGPIPE, SIG_IGN); 806 } 807 #ifdef USE_SYSLOG 808 openlog("xdm", LOG_PID, LOG_AUTHPRIV); 809 #endif 810 LoadSessionResources (d); 811 SetAuthorization (d); 812 if (!WaitForServer (d)) 813 exit (OPENFAILED_DISPLAY); 814 SetWindowPath(d); 815 #ifdef XDMCP 816 if (d->useChooser) 817 RunChooser (d); 818 else 819 #endif 820 ManageSession (d); 821 exit (REMANAGE_DISPLAY); 822 case -1: 823 break; 824 default: 825 Debug ("pid: %d\n", pid); 826 d->pid = pid; 827 d->status = running; 828 break; 829 } 830 } 831 832 static void 833 TerminateProcess (pid_t pid, int signal) 834 { 835 kill (pid, signal); 836 #ifdef SIGCONT 837 kill (pid, SIGCONT); 838 #endif 839 } 840 841 /* 842 * transition from running to zombie or deleted 843 */ 844 845 void 846 StopDisplay (struct display *d) 847 { 848 if (d->serverPid != -1) 849 d->status = zombie; /* be careful about race conditions */ 850 if (d->pid != -1) 851 TerminateProcess (d->pid, SIGTERM); 852 if (d->serverPid != -1) 853 TerminateProcess (d->serverPid, d->termSignal); 854 else 855 RemoveDisplay (d); 856 } 857 858 /* 859 * transition from running to phoenix or notRunning 860 */ 861 862 static void 863 RestartDisplay (struct display *d, int forceReserver) 864 { 865 if (d->serverPid != -1 && (forceReserver || d->terminateServer)) 866 { 867 TerminateProcess (d->serverPid, d->termSignal); 868 d->status = phoenix; 869 } 870 else 871 { 872 d->status = notRunning; 873 } 874 } 875 876 static FD_TYPE CloseMask; 877 static int max; 878 879 void 880 RegisterCloseOnFork (int fd) 881 { 882 FD_SET (fd, &CloseMask); 883 if (fd > max) 884 max = fd; 885 } 886 887 void 888 ClearCloseOnFork (int fd) 889 { 890 FD_CLR (fd, &CloseMask); 891 if (fd == max) { 892 while (--fd >= 0) 893 if (FD_ISSET (fd, &CloseMask)) 894 break; 895 max = fd; 896 } 897 } 898 899 void 900 CloseOnFork (void) 901 { 902 int fd; 903 904 for (fd = 0; fd <= max; fd++) 905 if (FD_ISSET (fd, &CloseMask)) 906 { 907 close (fd); 908 } 909 FD_ZERO (&CloseMask); 910 max = 0; 911 } 912 913 static int pidFd; 914 static FILE *pidFilePtr; 915 916 /* 917 * Create and populate file storing xdm's process ID. 918 */ 919 static long 920 StorePid (void) 921 { 922 long oldpid; 923 char pidstr[11]; /* enough space for a 32-bit pid plus \0 */ 924 size_t pidstrlen; 925 926 if (pidFile[0] != '\0') 927 { 928 Debug ("storing process ID in %s\n", pidFile); 929 pidFd = open (pidFile, O_WRONLY|O_CREAT|O_EXCL, 0666); 930 if (pidFd == -1 && errno == ENOENT) 931 { 932 /* Make sure directory exists if needed 933 Allows setting pidDir to /var/run/xdm 934 */ 935 char *pidDir = strdup(pidFile); 936 937 if (pidDir != NULL) 938 { 939 char *p = strrchr(pidDir, '/'); 940 int r; 941 942 if ((p != NULL) && (p != pidDir)) { 943 *p = '\0'; 944 } 945 r = mkdir(pidDir, 0755); 946 if ( (r < 0) && (errno != EEXIST) ) { 947 LogError ("process-id directory %s cannot be created\n", 948 pidDir); 949 } 950 free(pidDir); 951 } 952 953 pidFd = open (pidFile, O_WRONLY|O_CREAT|O_EXCL, 0666); 954 } 955 if (pidFd == -1) 956 { 957 if (errno == EEXIST) 958 { 959 /* pidFile already exists; see if we can open it */ 960 pidFilePtr = fopen (pidFile, "r"); 961 if (pidFilePtr == NULL) 962 { 963 LogError ("cannot open process ID file %s for reading: " 964 "%s\n", pidFile, _SysErrorMsg (errno)); 965 return -1; 966 } 967 if (fscanf (pidFilePtr, "%ld\n", &oldpid) != 1) 968 { 969 LogError ("existing process ID file %s empty or contains " 970 "garbage\n", pidFile); 971 oldpid = -1; 972 } 973 fclose (pidFilePtr); 974 return oldpid; 975 } 976 else 977 { 978 LogError ("cannot fdopen process ID file %s for writing: " 979 "%s\n", pidFile, _SysErrorMsg (errno)); 980 return -1; 981 } 982 } 983 if ((pidFilePtr = fdopen (pidFd, "w")) == NULL) 984 { 985 LogError ("cannot open process ID file %s for writing: %s\n", 986 pidFile, _SysErrorMsg (errno)); 987 return -1; 988 } 989 (void) snprintf (pidstr, 11, "%ld", (long) getpid ()); 990 pidstrlen = strlen (pidstr); 991 if (fprintf (pidFilePtr, "%s\n", pidstr) != ( pidstrlen + 1)) 992 { 993 LogError ("cannot write to process ID file %s: %s\n", pidFile, 994 _SysErrorMsg (errno)); 995 return -1; 996 } 997 (void) fflush (pidFilePtr); 998 (void) fclose (pidFilePtr); 999 } 1000 return 0; 1001 } 1002 1003 /* 1004 * Remove process ID file. This function is registered with atexit(). 1005 */ 1006 static void 1007 RemovePid (void) 1008 { 1009 if (parent_pid != getpid()) 1010 return; 1011 1012 Debug ("unlinking process ID file %s\n", pidFile); 1013 if (unlink (pidFile)) 1014 if (errno != ENOENT) 1015 LogError ("cannot remove process ID file %s: %s\n", pidFile, 1016 _SysErrorMsg (errno)); 1017 } 1018 1019 #ifndef HAVE_SETPROCTITLE 1020 void SetTitle (char *name, ...) 1021 { 1022 # ifndef NOXDMTITLE 1023 char *p = Title; 1024 int left = TitleLen; 1025 char *s; 1026 va_list args; 1027 1028 if (p != NULL && left > 0) { 1029 va_start(args,name); 1030 *p++ = '-'; 1031 --left; 1032 s = name; 1033 while (s) 1034 { 1035 while (*s && left > 0) 1036 { 1037 *p++ = *s++; 1038 left--; 1039 } 1040 s = va_arg (args, char *); 1041 } 1042 while (left > 0) 1043 { 1044 *p++ = ' '; 1045 --left; 1046 } 1047 va_end(args); 1048 } 1049 # endif 1050 } 1051 #endif 1052