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