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