xinit.c revision a73027ba
1/* $Xorg: xinit.c,v 1.5 2001/02/09 02:05:49 xorgcvs Exp $ */ 2/* $XdotOrg: $ */ 3 4/* 5 6Copyright 1986, 1998 The Open Group 7 8Permission to use, copy, modify, distribute, and sell this software and its 9documentation for any purpose is hereby granted without fee, provided that 10the above copyright notice appear in all copies and that both that 11copyright notice and this permission notice appear in supporting 12documentation. 13 14The above copyright notice and this permission notice shall be included in 15all copies or substantial portions of the Software. 16 17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 24Except as contained in this notice, the name of The Open Group shall not be 25used in advertising or otherwise to promote the sale, use or other dealings 26in this Software without prior written authorization from The Open Group. 27 28*/ 29/* $XFree86: xc/programs/xinit/xinit.c,v 3.32 2002/05/31 18:46:13 dawes Exp $ */ 30 31#ifdef HAVE_CONFIG_H 32# include "config.h" 33#endif 34 35#include <X11/Xlib.h> 36#include <X11/Xos.h> 37#include <X11/Xatom.h> 38#include <stdio.h> 39#include <ctype.h> 40#include <stdint.h> 41 42#ifdef X_POSIX_C_SOURCE 43#define _POSIX_C_SOURCE X_POSIX_C_SOURCE 44#include <signal.h> 45#undef _POSIX_C_SOURCE 46#else 47#if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE) 48#include <signal.h> 49#else 50#define _POSIX_SOURCE 51#include <signal.h> 52#undef _POSIX_SOURCE 53#endif 54#endif 55 56#ifndef SYSV 57#include <sys/wait.h> 58#endif 59#include <errno.h> 60#include <setjmp.h> 61#include <stdarg.h> 62 63#if !defined(SIGCHLD) && defined(SIGCLD) 64#define SIGCHLD SIGCLD 65#endif 66#ifdef __UNIXOS2__ 67#define INCL_DOSMODULEMGR 68#include <os2.h> 69#define setpgid(a,b) 70#define setuid(a) 71#define setgid(a) 72#define SHELL "cmd.exe" 73#define XINITRC "xinitrc.cmd" 74#define XSERVERRC "xservrc.cmd" 75char **envsave; /* to circumvent an UNIXOS2 problem */ 76#define environ envsave 77#endif 78 79#include <stdlib.h> 80extern char **environ; 81char **newenviron = NULL; 82char **newenvironlast = NULL; 83 84#ifndef SHELL 85#define SHELL "sh" 86#endif 87 88#ifndef HAVE_WORKING_VFORK 89# ifndef vfork 90# define vfork() fork() 91# endif 92#else 93# ifdef HAVE_VFORK_H 94# include <vfork.h> 95# endif 96#endif 97 98/* A/UX setpgid incorrectly removes the controlling terminal. 99 Per Posix, only setsid should do that. */ 100#ifdef macII 101#define setpgid setpgrp 102#endif 103 104#ifdef __UNIXOS2__ 105#define HAS_EXECVPE 106#endif 107 108#ifdef HAS_EXECVPE 109#define Execvpe(path, argv, envp) execvpe(path, argv, envp) 110#else 111#define Execvpe(path, argv, envp) execvp(path, argv) 112#endif 113 114const char *bindir = BINDIR; 115const char * const server_names[] = { 116#if defined(ultrix) && defined(mips) 117 "Xdec Digital color display on DECstation", 118#endif 119#if defined(sun) && !defined(XORG) /* Sun */ 120 "Xsun Sun BW2, CG2, CG3, CG4, or CG6 on Sun 2, 3, 4, or 386i", 121 "Xsunmono Sun BW2 on Sun 2, 3, 4, or 386i ", 122 "Xsun24 Sun BW2, CG2, CG3, CG4, CG6, or CG8 on Sun 4", 123#endif 124#ifdef hpux /* HP */ 125 "Xhp HP monochrome and colors displays on 9000/300 series", 126#endif 127#ifdef ibm /* IBM */ 128 "Xibm IBM AED, APA, 8514a, megapel, VGA displays on PC/RT", 129#endif 130#ifdef macII /* MacII */ 131 "XmacII Apple monochrome display on Macintosh II", 132#endif 133#ifdef XFREE86 134 "XFree86 XFree86 displays", 135#endif 136#ifdef XORG 137 "Xorg Common X server for most displays", 138#endif 139#ifdef __APPLE__ 140 "Xquartz Mac OSX Quartz displays.", 141#endif 142 "Xvfb Virtual frame buffer", 143 "Xfake kdrive-based virtual frame buffer", 144 "Xnest X server nested in a window on another X server", 145 "Xephyr kdrive-based nested X server", 146 NULL}; 147 148#ifndef XINITRC 149#define XINITRC ".xinitrc" 150#endif 151char xinitrcbuf[256]; 152 153#ifndef XSERVERRC 154#define XSERVERRC ".xserverrc" 155#endif 156char xserverrcbuf[256]; 157 158#define TRUE 1 159#define FALSE 0 160#define OK_EXIT 0 161#define ERR_EXIT 1 162 163static char *default_server = "X"; 164static char *default_display = ":0"; /* choose most efficient */ 165static char *default_client[] = {"xterm", "-geometry", "+1+1", "-n", "login", NULL}; 166static char *serverargv[100]; 167static char *clientargv[100]; 168static char **server = serverargv + 2; /* make sure room for sh .xserverrc args */ 169static char **client = clientargv + 2; /* make sure room for sh .xinitrc args */ 170static char *displayNum = NULL; 171static char *program = NULL; 172static Display *xd = NULL; /* server connection */ 173#ifndef SYSV 174#if defined(__CYGWIN__) || defined(SVR4) || defined(_POSIX_SOURCE) || defined(CSRG_BASED) || defined(__UNIXOS2__) || defined(Lynx) || defined(__APPLE__) 175int status; 176#else 177union wait status; 178#endif 179#endif /* SYSV */ 180int serverpid = -1; 181int clientpid = -1; 182volatile int gotSignal = 0; 183 184static void Execute ( char **vec, char **envp ); 185static Bool waitforserver ( void ); 186static Bool processTimeout ( int timeout, char *string ); 187static int startServer ( char *server[] ); 188static int startClient ( char *client[] ); 189static int ignorexio ( Display *dpy ); 190static void shutdown ( void ); 191static void set_environment ( void ); 192static void Fatal(char *msg); 193static void Error ( char *fmt, ... ); 194 195#ifdef RETSIGTYPE /* autoconf AC_TYPE_SIGNAL */ 196# define SIGVAL RETSIGTYPE 197#endif /* RETSIGTYPE */ 198 199static SIGVAL 200sigCatch(int sig) 201{ 202 /* On system with POSIX signals, just interrupt the system call */ 203 gotSignal = sig; 204} 205 206static SIGVAL 207sigAlarm(int sig) 208{ 209#if defined(SYSV) || defined(SVR4) || defined(linux) || defined(__UNIXOS2__) || defined(__APPLE__) 210 signal (sig, sigAlarm); 211#endif 212} 213 214static SIGVAL 215sigUsr1(int sig) 216{ 217#if defined(SYSV) || defined(SVR4) || defined(linux) || defined(__UNIXOS2__) || defined(__APPLE__) 218 signal (sig, sigUsr1); 219#endif 220} 221 222static void 223Execute(char **vec, /* has room from up above */ 224 char **envp) 225{ 226 Execvpe (vec[0], vec, envp); 227#ifndef __UNIXOS2__ 228 if (access (vec[0], R_OK) == 0) { 229 vec--; /* back it up to stuff shell in */ 230 vec[0] = SHELL; 231 Execvpe (vec[0], vec, envp); 232 } 233#endif 234 return; 235} 236 237#ifndef __UNIXOS2__ 238int 239main(int argc, char *argv[]) 240#else 241int 242main(int argc, char *argv[], char *envp[]) 243#endif 244{ 245 register char **sptr = server; 246 register char **cptr = client; 247 register char **ptr; 248 int pid; 249 int client_given = 0, server_given = 0; 250 int client_args_given = 0, server_args_given = 0; 251 int start_of_client_args, start_of_server_args; 252 struct sigaction sa; 253 254#ifdef __UNIXOS2__ 255 envsave = envp; /* circumvent an EMX problem */ 256 257 /* Check whether the system will run at all */ 258 if (_emx_rev < 50) { 259 APIRET rc; 260 HMODULE hmod; 261 char name[CCHMAXPATH]; 262 char fail[9]; 263 fputs ("This program requires emx.dll revision 50 (0.9c) " 264 "or later.\n", stderr); 265 rc = DosLoadModule (fail, sizeof (fail), "emx", &hmod); 266 if (rc == 0) { 267 rc = DosQueryModuleName (hmod, sizeof (name), name); 268 if (rc == 0) 269 fprintf (stderr, "Please delete or update `%s'.\n", name); 270 DosFreeModule (hmod); 271 } 272 exit (2); 273 } 274#endif 275 program = *argv++; 276 argc--; 277 /* 278 * copy the client args. 279 */ 280 if (argc == 0 || 281#ifndef __UNIXOS2__ 282 (**argv != '/' && **argv != '.')) { 283#else 284 (**argv != '/' && **argv != '\\' && **argv != '.' && 285 !(isalpha(**argv) && (*argv)[1]==':'))) { 286#endif 287 for (ptr = default_client; *ptr; ) 288 *cptr++ = *ptr++; 289#ifdef sun 290 /* 291 * If running on a sun, and if WINDOW_PARENT isn't defined, 292 * that means SunWindows isn't running, so we should pass 293 * the -C flag to xterm so that it sets up a console. 294 */ 295 if ( getenv("WINDOW_PARENT") == NULL ) 296 *cptr++ = "-C"; 297#endif /* sun */ 298 } else { 299 client_given = 1; 300 } 301 start_of_client_args = (cptr - client); 302 while (argc && strcmp(*argv, "--")) { 303 client_args_given++; 304 *cptr++ = *argv++; 305 argc--; 306 } 307 *cptr = NULL; 308 if (argc) { 309 argv++; 310 argc--; 311 } 312 313 /* 314 * Copy the server args. 315 */ 316 if (argc == 0 || 317#ifndef __UNIXOS2__ 318 (**argv != '/' && **argv != '.')) { 319 *sptr++ = default_server; 320#else 321 (**argv != '/' && **argv != '\\' && **argv != '.' && 322 !(isalpha(**argv) && (*argv)[1]==':'))) { 323 *sptr = getenv("XSERVER"); 324 if (!*sptr) { 325 Error("No XSERVER environment variable set"); 326 exit(1); 327 } 328 *sptr++; 329#endif 330 } else { 331 server_given = 1; 332 *sptr++ = *argv++; 333 argc--; 334 } 335 if (argc > 0 && (argv[0][0] == ':' && isdigit(argv[0][1]))) 336 displayNum = *argv; 337 else 338 displayNum = *sptr++ = default_display; 339 340 start_of_server_args = (sptr - server); 341 while (--argc >= 0) { 342 server_args_given++; 343 *sptr++ = *argv++; 344 } 345 *sptr = NULL; 346 347 /* 348 * if no client arguments given, check for a startup file and copy 349 * that into the argument list 350 */ 351 if (!client_given) { 352 char *cp; 353 Bool required = False; 354 355 xinitrcbuf[0] = '\0'; 356 if ((cp = getenv ("XINITRC")) != NULL) { 357 (void) snprintf (xinitrcbuf, sizeof(xinitrcbuf), "%s", cp); 358 required = True; 359 } else if ((cp = getenv ("HOME")) != NULL) { 360 (void) snprintf (xinitrcbuf, sizeof(xinitrcbuf), 361 "%s/%s", cp, XINITRC); 362 } 363 if (xinitrcbuf[0]) { 364 if (access (xinitrcbuf, F_OK) == 0) { 365 client += start_of_client_args - 1; 366 client[0] = xinitrcbuf; 367 } else if (required) { 368 fprintf (stderr, 369 "%s: warning, no client init file \"%s\"\n", 370 program, xinitrcbuf); 371 } 372 } 373 } 374 375 /* 376 * if no server arguments given, check for a startup file and copy 377 * that into the argument list 378 */ 379 if (!server_given) { 380 char *cp; 381 Bool required = False; 382 383 xserverrcbuf[0] = '\0'; 384 if ((cp = getenv ("XSERVERRC")) != NULL) { 385 (void) snprintf (xserverrcbuf, sizeof(xserverrcbuf), "%s", cp); 386 required = True; 387 } else if ((cp = getenv ("HOME")) != NULL) { 388 (void) snprintf (xserverrcbuf, sizeof(xserverrcbuf), 389 "%s/%s", cp, XSERVERRC); 390 } 391 if (xserverrcbuf[0]) { 392 if (access (xserverrcbuf, F_OK) == 0) { 393 server += start_of_server_args - 1; 394 server[0] = xserverrcbuf; 395 } else if (required) { 396 fprintf (stderr, 397 "%s: warning, no server init file \"%s\"\n", 398 program, xserverrcbuf); 399 } 400 } 401 } 402 403 /* 404 * put the display name into the environment 405 */ 406 set_environment (); 407 408 /* 409 * Start the server and client. 410 */ 411#ifdef SIGCHLD 412 signal(SIGCHLD, SIG_DFL); /* Insurance */ 413#endif 414 415 /* Let those signal interrupt the wait() call in the main loop */ 416 memset(&sa, 0, sizeof sa); 417 sa.sa_handler = sigCatch; 418 sigemptyset(&sa.sa_mask); 419 sa.sa_flags = 0; /* do not set SA_RESTART */ 420 421 sigaction(SIGTERM, &sa, NULL); 422 sigaction(SIGQUIT, &sa, NULL); 423 sigaction(SIGINT, &sa, NULL); 424 sigaction(SIGHUP, &sa, NULL); 425 sigaction(SIGPIPE, &sa, NULL); 426 427 signal(SIGALRM, sigAlarm); 428 signal(SIGUSR1, sigUsr1); 429 if (startServer(server) > 0 430 && startClient(client) > 0) { 431 pid = -1; 432 while (pid != clientpid && pid != serverpid 433 && gotSignal == 0 434 ) 435 pid = wait(NULL); 436 } 437 signal(SIGTERM, SIG_IGN); 438 signal(SIGQUIT, SIG_IGN); 439 signal(SIGINT, SIG_IGN); 440 signal(SIGHUP, SIG_IGN); 441 signal(SIGPIPE, SIG_IGN); 442 443 shutdown(); 444 445 if (gotSignal != 0) { 446 Error("unexpected signal %d.\n", gotSignal); 447 exit(ERR_EXIT); 448 } 449 450 if (serverpid < 0 ) 451 Fatal("Server error.\n"); 452 if (clientpid < 0) 453 Fatal("Client error.\n"); 454 exit(OK_EXIT); 455} 456 457 458/* 459 * waitforserver - wait for X server to start up 460 */ 461static Bool 462waitforserver(void) 463{ 464 int ncycles = 120; /* # of cycles to wait */ 465 int cycles; /* Wait cycle count */ 466 467 for (cycles = 0; cycles < ncycles; cycles++) { 468 if ((xd = XOpenDisplay(displayNum))) { 469 return(TRUE); 470 } 471 else { 472#define MSG "X server to begin accepting connections" 473 if (!processTimeout (1, MSG)) 474 break; 475#undef MSG 476 } 477 } 478 479 fprintf (stderr, "giving up.\r\n"); 480 return(FALSE); 481} 482 483/* 484 * return TRUE if we timeout waiting for pid to exit, FALSE otherwise. 485 */ 486static Bool 487processTimeout(int timeout, char *string) 488{ 489 int i = 0, pidfound = -1; 490 static char *laststring; 491 492 for (;;) { 493#if defined(SYSV) || defined(__UNIXOS2__) 494 alarm(1); 495 if ((pidfound = wait(NULL)) == serverpid) 496 break; 497 alarm(0); 498#else /* SYSV */ 499#if defined(SVR4) || defined(_POSIX_SOURCE) || defined(Lynx) || defined(__APPLE__) 500 if ((pidfound = waitpid(serverpid, &status, WNOHANG)) == serverpid) 501 break; 502#else 503 if ((pidfound = wait3(&status, WNOHANG, NULL)) == serverpid) 504 break; 505#endif 506#endif /* SYSV */ 507 if (timeout) { 508 if (i == 0 && string != laststring) 509 fprintf(stderr, "\r\nwaiting for %s ", string); 510 else 511 fprintf(stderr, "."); 512 fflush(stderr); 513 } 514 if (timeout) 515 sleep (1); 516 if (++i > timeout) 517 break; 518 } 519 if ( i > 0 ) fputc( '\n', stderr ); /* tidy up after message */ 520 laststring = string; 521 return( serverpid != pidfound ); 522} 523 524static int 525startServer(char *server[]) 526{ 527 sigset_t mask, old; 528#ifdef __UNIXOS2__ 529 sigset_t pendings; 530#endif 531 532 sigemptyset(&mask); 533 sigaddset(&mask, SIGUSR1); 534 sigprocmask(SIG_BLOCK, &mask, &old); 535 536 serverpid = fork(); 537 538 switch(serverpid) { 539 case 0: 540 /* Unblock */ 541 sigprocmask(SIG_SETMASK, &old, NULL); 542 543 /* 544 * don't hang on read/write to control tty 545 */ 546#ifdef SIGTTIN 547 (void) signal(SIGTTIN, SIG_IGN); 548#endif 549#ifdef SIGTTOU 550 (void) signal(SIGTTOU, SIG_IGN); 551#endif 552 /* 553 * ignore SIGUSR1 in child. The server 554 * will notice this and send SIGUSR1 back 555 * at xinit when ready to accept connections 556 */ 557 (void) signal(SIGUSR1, SIG_IGN); 558 /* 559 * prevent server from getting sighup from vhangup() 560 * if client is xterm -L 561 */ 562#ifndef __UNIXOS2__ 563 setpgid(0,getpid()); 564#endif 565 Execute (server, environ); 566 Error ("no server \"%s\" in PATH\n", server[0]); 567 { 568 const char * const *cpp; 569 570 fprintf (stderr, 571"\nUse the -- option, or make sure that %s is in your path and\n", 572 bindir); 573 fprintf (stderr, 574"that \"%s\" is a program or a link to the right type of server\n", 575 server[0]); 576 fprintf (stderr, 577"for your display. Possible server names include:\n\n"); 578 for (cpp = server_names; *cpp; cpp++) { 579 fprintf (stderr, " %s\n", *cpp); 580 } 581 fprintf (stderr, "\n"); 582 } 583 exit (ERR_EXIT); 584 585 break; 586 case -1: 587 break; 588 default: 589 /* 590 * don't nice server 591 */ 592#ifdef PRIO_PROCESS 593 setpriority( PRIO_PROCESS, serverpid, -1 ); 594#endif 595 596 errno = 0; 597 if (! processTimeout(0, "")) { 598 serverpid = -1; 599 break; 600 } 601 /* 602 * kludge to avoid race with TCP, giving server time to 603 * set his socket options before we try to open it, 604 * either use the 15 second timeout, or await SIGUSR1. 605 * 606 * If your machine is substantially slower than 15 seconds, 607 * you can easily adjust this value. 608 */ 609 alarm (15); 610 611#ifdef __UNIXOS2__ 612 /* 613 * fg2003/05/06: work around a problem in EMX: sigsuspend() 614 * does not deliver pending signals when called but when 615 * returning; so if SIGUSR1 has already been sent by the 616 * server, we would still have to await SIGALRM 617 */ 618 sigemptyset(&pendings); 619 sigpending(&pendings); 620 if (!sigismember(&pendings, SIGUSR1)) 621#endif /* __UNIXOS2__ */ 622 sigsuspend(&old); 623 alarm (0); 624 sigprocmask(SIG_SETMASK, &old, NULL); 625 626 if (waitforserver() == 0) { 627 Error("unable to connect to X server\r\n"); 628 shutdown(); 629 serverpid = -1; 630 } 631 break; 632 } 633 634 return(serverpid); 635} 636 637static void 638setWindowPath(void) 639{ 640 /* setting WINDOWPATH for clients */ 641 Atom prop; 642 Atom actualtype; 643 int actualformat; 644 unsigned long nitems; 645 unsigned long bytes_after; 646 unsigned char *buf; 647 const char *windowpath; 648 char *newwindowpath; 649 unsigned long num; 650 char nums[10]; 651 int numn; 652 size_t len; 653 prop = XInternAtom(xd, "XFree86_VT", False); 654 if (prop == None) { 655#ifdef DEBUG 656 fprintf(stderr, "no XFree86_VT atom\n"); 657#endif 658 return; 659 } 660 if (XGetWindowProperty(xd, DefaultRootWindow(xd), prop, 0, 1, 661 False, AnyPropertyType, &actualtype, &actualformat, 662 &nitems, &bytes_after, &buf)) { 663#ifdef DEBUG 664 fprintf(stderr, "no XFree86_VT property\n"); 665#endif 666 return; 667 } 668 if (nitems != 1) { 669#ifdef DEBUG 670 fprintf(stderr, "%lu items in XFree86_VT property!\n", nitems); 671#endif 672 XFree(buf); 673 return; 674 } 675 switch (actualtype) { 676 case XA_CARDINAL: 677 case XA_INTEGER: 678 case XA_WINDOW: 679 switch (actualformat) { 680 case 8: 681 num = (*(uint8_t *)(void *)buf); 682 break; 683 case 16: 684 num = (*(uint16_t *)(void *)buf); 685 break; 686 case 32: 687 num = (*(uint32_t *)(void *)buf); 688 break; 689 default: 690#ifdef DEBUG 691 fprintf(stderr, "format %d in XFree86_VT property!\n", actualformat); 692#endif 693 XFree(buf); 694 return; 695 } 696 break; 697 default: 698#ifdef DEBUG 699 fprintf(stderr, "type %lx in XFree86_VT property!\n", actualtype); 700#endif 701 XFree(buf); 702 return; 703 } 704 XFree(buf); 705 windowpath = getenv("WINDOWPATH"); 706 numn = snprintf(nums, sizeof(nums), "%lu", num); 707 if (!windowpath) { 708 len = 10 + 1 + numn + 1; 709 newwindowpath = malloc(len); 710 if (newwindowpath == NULL) 711 return; 712 snprintf(newwindowpath, len, "WINDOWPATH=%s", nums); 713 } else { 714 len = 10 + 1 + strlen(windowpath) + 1 + numn + 1; 715 newwindowpath = malloc(len); 716 if (newwindowpath == NULL) 717 return; 718 snprintf(newwindowpath, len, "WINDOWPATH=%s:%s", 719 windowpath, nums); 720 } 721 *newenvironlast++ = newwindowpath; 722 *newenvironlast = NULL; 723} 724 725static int 726startClient(char *client[]) 727{ 728 setWindowPath(); 729 if ((clientpid = vfork()) == 0) { 730 if (setuid(getuid()) == -1) { 731 Error("cannot change uid: %s\n", strerror(errno)); 732 _exit(ERR_EXIT); 733 } 734 setpgid(0, getpid()); 735 environ = newenviron; 736#ifdef __UNIXOS2__ 737#undef environ 738 environ = newenviron; 739 client[0] = (char*)__XOS2RedirRoot(client[0]); 740#endif 741 Execute (client,newenviron); 742 Error ("no program named \"%s\" in PATH\r\n", client[0]); 743 fprintf (stderr, 744"\nSpecify a program on the command line or make sure that %s\r\n", bindir); 745 fprintf (stderr, 746"is in your path.\r\n"); 747 fprintf (stderr, "\n"); 748 _exit (ERR_EXIT); 749 } 750 return (clientpid); 751} 752 753#ifndef HAVE_KILLPG 754#define killpg(pgrp, sig) kill(-(pgrp), sig) 755#endif 756 757static jmp_buf close_env; 758 759static int 760ignorexio(Display *dpy) 761{ 762 fprintf (stderr, "%s: connection to X server lost.\r\n", program); 763 longjmp (close_env, 1); 764 /*NOTREACHED*/ 765 return 0; 766} 767 768static void 769shutdown(void) 770{ 771 /* have kept display opened, so close it now */ 772 if (clientpid > 0) { 773 XSetIOErrorHandler (ignorexio); 774 if (! setjmp(close_env)) { 775 XCloseDisplay(xd); 776 } 777 778 /* HUP all local clients to allow them to clean up */ 779 errno = 0; 780 if ((killpg(clientpid, SIGHUP) != 0) && 781 (errno != ESRCH)) 782 Error("can't send HUP to process group %d\r\n", 783 clientpid); 784 } 785 786 if (serverpid < 0) 787 return; 788 errno = 0; 789 if (killpg(serverpid, SIGTERM) < 0) { 790 if (errno == EPERM) 791 Fatal("Can't kill X server\r\n"); 792 if (errno == ESRCH) 793 return; 794 } 795 if (! processTimeout(10, "X server to shut down")) { 796 fprintf (stderr, "\r\n"); 797 return; 798 } 799 800 fprintf(stderr, 801 "\r\n%s: X server slow to shut down, sending KILL signal.\r\n", 802 program); 803 fflush(stderr); 804 errno = 0; 805 if (killpg(serverpid, SIGKILL) < 0) { 806 if (errno == ESRCH) 807 return; 808 } 809 if (processTimeout(3, "server to die")) { 810 fprintf (stderr, "\r\n"); 811 Fatal("Can't kill server\r\n"); 812 } 813 fprintf (stderr, "\r\n"); 814 return; 815} 816 817 818/* 819 * make a new copy of environment that has room for DISPLAY 820 */ 821 822static void 823set_environment(void) 824{ 825 int nenvvars; 826 char **newPtr, **oldPtr; 827 static char displaybuf[512]; 828 829 /* count number of environment variables */ 830 for (oldPtr = environ; *oldPtr; oldPtr++) ; 831 832 nenvvars = (oldPtr - environ); 833 newenviron = (char **) malloc ((nenvvars + 3) * sizeof(char **)); 834 if (!newenviron) { 835 fprintf (stderr, 836 "%s: unable to allocate %d pointers for environment\n", 837 program, nenvvars + 3); 838 exit (1); 839 } 840 841 /* put DISPLAY=displayname as first element */ 842 snprintf (displaybuf, sizeof(displaybuf), "DISPLAY=%s", displayNum); 843 newPtr = newenviron; 844 *newPtr++ = displaybuf; 845 846 /* copy pointers to other variables */ 847 for (oldPtr = environ; *oldPtr; oldPtr++) { 848 if (strncmp (*oldPtr, "DISPLAY=", 8) != 0 849 && strncmp (*oldPtr, "WINDOWPATH=", 11) != 0) { 850 *newPtr++ = *oldPtr; 851 } 852 } 853 *newPtr = NULL; 854 newenvironlast=newPtr; 855 return; 856} 857 858static void 859Fatal(char *msg) 860{ 861 Error(msg); 862 exit(ERR_EXIT); 863} 864 865static void 866Error(char *fmt, ...) 867{ 868 va_list ap; 869 870 va_start(ap, fmt); 871 fprintf(stderr, "%s: ", program); 872 if (errno > 0) 873 fprintf (stderr, "%s (errno %d): ", strerror(errno), errno); 874 vfprintf(stderr, fmt, ap); 875 va_end(ap); 876} 877