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