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