xinit.c revision bf4a254e
1/* 2 3Copyright 1986, 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 in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 25*/ 26 27#ifdef HAVE_CONFIG_H 28# include "config.h" 29#endif 30 31#include <X11/Xlib.h> 32#include <X11/Xos.h> 33#include <X11/Xatom.h> 34#include <stdio.h> 35#include <ctype.h> 36#include <stdint.h> 37 38#ifdef X_POSIX_C_SOURCE 39#define _POSIX_C_SOURCE X_POSIX_C_SOURCE 40#include <signal.h> 41#undef _POSIX_C_SOURCE 42#else 43#if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE) 44#include <signal.h> 45#else 46#define _POSIX_SOURCE 47#include <signal.h> 48#undef _POSIX_SOURCE 49#endif 50#endif 51 52#ifndef SYSV 53#include <sys/wait.h> 54#endif 55#include <errno.h> 56#include <setjmp.h> 57#include <stdarg.h> 58 59#ifdef __APPLE__ 60#include <AvailabilityMacros.h> 61#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 62#include <vproc.h> 63#endif 64#endif 65 66#if !defined(SIGCHLD) && defined(SIGCLD) 67#define SIGCHLD SIGCLD 68#endif 69#ifdef __UNIXOS2__ 70#define INCL_DOSMODULEMGR 71#include <os2.h> 72#define setpgid(a,b) 73#define setuid(a) 74#define setgid(a) 75#define SHELL "cmd.exe" 76#define XINITRC "xinitrc.cmd" 77#define XSERVERRC "xservrc.cmd" 78char **envsave; /* to circumvent an UNIXOS2 problem */ 79#define environ envsave 80#endif 81 82#include <stdlib.h> 83extern char **environ; 84char **newenviron = NULL; 85char **newenvironlast = NULL; 86 87#ifndef SHELL 88#define SHELL "sh" 89#endif 90 91#ifndef HAVE_WORKING_VFORK 92# ifndef vfork 93# define vfork() fork() 94# endif 95#else 96# ifdef HAVE_VFORK_H 97# include <vfork.h> 98# endif 99#endif 100 101#ifdef __UNIXOS2__ 102#define HAS_EXECVPE 103#endif 104 105#ifdef HAS_EXECVPE 106#define Execvpe(path, argv, envp) execvpe(path, argv, envp) 107#else 108#define Execvpe(path, argv, envp) execvp(path, argv) 109#endif 110 111const char *bindir = BINDIR; 112const char * const server_names[] = { 113#ifdef __APPLE__ 114 "Xquartz Mac OSX Quartz displays.", 115#else 116# ifdef __CYGWIN__ 117 "XWin X Server for the Cygwin environment on Microsoft Windows", 118# else 119 "Xorg Common X server for most displays", 120# endif 121#endif 122 "Xvfb Virtual frame buffer", 123 "Xfake kdrive-based virtual frame buffer", 124 "Xnest X server nested in a window on another X server", 125 "Xephyr kdrive-based nested X server", 126 "Xvnc X server accessed over VNC's RFB protocol", 127 "Xdmx Distributed Multi-head X server", 128 NULL}; 129 130#ifndef XINITRC 131#define XINITRC ".xinitrc" 132#endif 133char xinitrcbuf[256]; 134 135#ifndef XSERVERRC 136#define XSERVERRC ".xserverrc" 137#endif 138char xserverrcbuf[256]; 139 140#define TRUE 1 141#define FALSE 0 142#define OK_EXIT 0 143#define ERR_EXIT 1 144 145static char *default_server = "X"; 146static char *default_display = ":0"; /* choose most efficient */ 147static char *default_client[] = {"xterm", "-geometry", "+1+1", "-n", "login", NULL}; 148static char *serverargv[100]; 149static char *clientargv[100]; 150static char **server = serverargv + 2; /* make sure room for sh .xserverrc args */ 151static char **client = clientargv + 2; /* make sure room for sh .xinitrc args */ 152static char *displayNum = NULL; 153static char *program = NULL; 154static Display *xd = NULL; /* server connection */ 155#ifndef SYSV 156#if defined(__CYGWIN__) || defined(SVR4) || defined(_POSIX_SOURCE) || defined(CSRG_BASED) || defined(__UNIXOS2__) || defined(Lynx) || defined(__APPLE__) 157int status; 158#else 159union wait status; 160#endif 161#endif /* SYSV */ 162int serverpid = -1; 163int clientpid = -1; 164volatile int gotSignal = 0; 165 166static void Execute ( char **vec, char **envp ); 167static Bool waitforserver ( void ); 168static Bool processTimeout ( int timeout, char *string ); 169static int startServer ( char *server[] ); 170static int startClient ( char *client[] ); 171static int ignorexio ( Display *dpy ); 172static void shutdown ( void ); 173static void set_environment ( void ); 174static void Fatal(char *msg); 175static void Error ( char *fmt, ... ); 176 177#ifdef RETSIGTYPE /* autoconf AC_TYPE_SIGNAL */ 178# define SIGVAL RETSIGTYPE 179#endif /* RETSIGTYPE */ 180 181static SIGVAL 182sigCatch(int sig) 183{ 184 /* On system with POSIX signals, just interrupt the system call */ 185 gotSignal = sig; 186} 187 188static SIGVAL 189sigAlarm(int sig) 190{ 191#if defined(SYSV) || defined(SVR4) || defined(linux) || defined(__UNIXOS2__) || defined(__APPLE__) 192 signal (sig, sigAlarm); 193#endif 194} 195 196static SIGVAL 197sigUsr1(int sig) 198{ 199#if defined(SYSV) || defined(SVR4) || defined(linux) || defined(__UNIXOS2__) || defined(__APPLE__) 200 signal (sig, sigUsr1); 201#endif 202} 203 204static void 205Execute(char **vec, /* has room from up above */ 206 char **envp) 207{ 208 Execvpe (vec[0], vec, envp); 209#ifndef __UNIXOS2__ 210 if (access (vec[0], R_OK) == 0) { 211 vec--; /* back it up to stuff shell in */ 212 vec[0] = SHELL; 213 Execvpe (vec[0], vec, envp); 214 } 215#endif 216 return; 217} 218 219#ifndef __UNIXOS2__ 220int 221main(int argc, char *argv[]) 222#else 223int 224main(int argc, char *argv[], char *envp[]) 225#endif 226{ 227 register char **sptr = server; 228 register char **cptr = client; 229 register char **ptr; 230 int pid; 231 int client_given = 0, server_given = 0; 232 int client_args_given = 0, server_args_given = 0; 233 int start_of_client_args, start_of_server_args; 234 struct sigaction sa; 235#ifdef __APPLE__ 236#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 237 vproc_transaction_t vt; 238#endif 239#endif 240 241#ifdef __UNIXOS2__ 242 envsave = envp; /* circumvent an EMX problem */ 243 244 /* Check whether the system will run at all */ 245 if (_emx_rev < 50) { 246 APIRET rc; 247 HMODULE hmod; 248 char name[CCHMAXPATH]; 249 char fail[9]; 250 fputs ("This program requires emx.dll revision 50 (0.9c) " 251 "or later.\n", stderr); 252 rc = DosLoadModule (fail, sizeof (fail), "emx", &hmod); 253 if (rc == 0) { 254 rc = DosQueryModuleName (hmod, sizeof (name), name); 255 if (rc == 0) 256 fprintf (stderr, "Please delete or update `%s'.\n", name); 257 DosFreeModule (hmod); 258 } 259 exit (2); 260 } 261#endif 262 program = *argv++; 263 argc--; 264 /* 265 * copy the client args. 266 */ 267 if (argc == 0 || 268#ifndef __UNIXOS2__ 269 (**argv != '/' && **argv != '.')) { 270#else 271 (**argv != '/' && **argv != '\\' && **argv != '.' && 272 !(isalpha(**argv) && (*argv)[1]==':'))) { 273#endif 274 for (ptr = default_client; *ptr; ) 275 *cptr++ = *ptr++; 276 } else { 277 client_given = 1; 278 } 279 start_of_client_args = (cptr - client); 280 while (argc && strcmp(*argv, "--")) { 281 client_args_given++; 282 *cptr++ = *argv++; 283 argc--; 284 } 285 *cptr = NULL; 286 if (argc) { 287 argv++; 288 argc--; 289 } 290 291 /* 292 * Copy the server args. 293 */ 294 if (argc == 0 || 295#ifndef __UNIXOS2__ 296 (**argv != '/' && **argv != '.')) { 297 *sptr++ = default_server; 298#else 299 (**argv != '/' && **argv != '\\' && **argv != '.' && 300 !(isalpha(**argv) && (*argv)[1]==':'))) { 301 *sptr = getenv("XSERVER"); 302 if (!*sptr) { 303 Error("No XSERVER environment variable set"); 304 exit(1); 305 } 306 *sptr++; 307#endif 308 } else { 309 server_given = 1; 310 *sptr++ = *argv++; 311 argc--; 312 } 313 if (argc > 0 && (argv[0][0] == ':' && isdigit(argv[0][1]))) 314 displayNum = *argv; 315 else 316 displayNum = *sptr++ = default_display; 317 318 start_of_server_args = (sptr - server); 319 while (--argc >= 0) { 320 server_args_given++; 321 *sptr++ = *argv++; 322 } 323 *sptr = NULL; 324 325 /* 326 * if no client arguments given, check for a startup file and copy 327 * that into the argument list 328 */ 329 if (!client_given) { 330 char *cp; 331 Bool required = False; 332 333 xinitrcbuf[0] = '\0'; 334 if ((cp = getenv ("XINITRC")) != NULL) { 335 (void) snprintf (xinitrcbuf, sizeof(xinitrcbuf), "%s", cp); 336 required = True; 337 } else if ((cp = getenv ("HOME")) != NULL) { 338 (void) snprintf (xinitrcbuf, sizeof(xinitrcbuf), 339 "%s/%s", cp, XINITRC); 340 } 341 if (xinitrcbuf[0]) { 342 if (access (xinitrcbuf, F_OK) == 0) { 343 client += start_of_client_args - 1; 344 client[0] = xinitrcbuf; 345 } else if (required) { 346 fprintf (stderr, 347 "%s: warning, no client init file \"%s\"\n", 348 program, xinitrcbuf); 349 } 350 } 351 } 352 353 /* 354 * if no server arguments given, check for a startup file and copy 355 * that into the argument list 356 */ 357 if (!server_given) { 358 char *cp; 359 Bool required = False; 360 361 xserverrcbuf[0] = '\0'; 362 if ((cp = getenv ("XSERVERRC")) != NULL) { 363 (void) snprintf (xserverrcbuf, sizeof(xserverrcbuf), "%s", cp); 364 required = True; 365 } else if ((cp = getenv ("HOME")) != NULL) { 366 (void) snprintf (xserverrcbuf, sizeof(xserverrcbuf), 367 "%s/%s", cp, XSERVERRC); 368 } 369 if (xserverrcbuf[0]) { 370 if (access (xserverrcbuf, F_OK) == 0) { 371 server += start_of_server_args - 1; 372 server[0] = xserverrcbuf; 373 } else if (required) { 374 fprintf (stderr, 375 "%s: warning, no server init file \"%s\"\n", 376 program, xserverrcbuf); 377 } 378 } 379 } 380 381 /* 382 * put the display name into the environment 383 */ 384 set_environment (); 385 386 /* 387 * Start the server and client. 388 */ 389#ifdef SIGCHLD 390 signal(SIGCHLD, SIG_DFL); /* Insurance */ 391#endif 392 393 /* Let those signal interrupt the wait() call in the main loop */ 394 memset(&sa, 0, sizeof sa); 395 sa.sa_handler = sigCatch; 396 sigemptyset(&sa.sa_mask); 397 sa.sa_flags = 0; /* do not set SA_RESTART */ 398 399 sigaction(SIGTERM, &sa, NULL); 400 sigaction(SIGQUIT, &sa, NULL); 401 sigaction(SIGINT, &sa, NULL); 402 sigaction(SIGHUP, &sa, NULL); 403 sigaction(SIGPIPE, &sa, NULL); 404 405 signal(SIGALRM, sigAlarm); 406 signal(SIGUSR1, sigUsr1); 407 408#ifdef __APPLE__ 409#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 410 vt = vproc_transaction_begin(NULL); 411#endif 412#endif 413 414 if (startServer(server) > 0 415 && startClient(client) > 0) { 416 pid = -1; 417 while (pid != clientpid && pid != serverpid 418 && gotSignal == 0 419 ) 420 pid = wait(NULL); 421 } 422 423#ifdef __APPLE__ 424#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 425 vproc_transaction_end(NULL, vt); 426#endif 427#endif 428 429 signal(SIGTERM, SIG_IGN); 430 signal(SIGQUIT, SIG_IGN); 431 signal(SIGINT, SIG_IGN); 432 signal(SIGHUP, SIG_IGN); 433 signal(SIGPIPE, SIG_IGN); 434 435 shutdown(); 436 437 if (gotSignal != 0) { 438 Error("unexpected signal %d.\n", gotSignal); 439 exit(ERR_EXIT); 440 } 441 442 if (serverpid < 0 ) 443 Fatal("Server error.\n"); 444 if (clientpid < 0) 445 Fatal("Client error.\n"); 446 exit(OK_EXIT); 447} 448 449 450/* 451 * waitforserver - wait for X server to start up 452 */ 453static Bool 454waitforserver(void) 455{ 456 int ncycles = 120; /* # of cycles to wait */ 457 int cycles; /* Wait cycle count */ 458 459#ifdef __APPLE__ 460 /* For Apple, we don't get signaled by the server when it's ready, so we just 461 * want to sleep now since we're going to sleep later anyways and this allows us 462 * to avoid the awkard, "why is there an error message in the log" questions 463 * from users. 464 */ 465 466 sleep(2); 467#endif 468 469 for (cycles = 0; cycles < ncycles; cycles++) { 470 if ((xd = XOpenDisplay(displayNum))) { 471 return(TRUE); 472 } 473 else { 474 if (!processTimeout (1, "X server to begin accepting connections")) 475 break; 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