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