1 /* $Xorg: xinit.c,v 1.5 2001/02/09 02:05:49 xorgcvs Exp $ */
6 Copyright 1986, 1998 The Open Group
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
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
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.
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.
29 /* $XFree86: xc/programs/xinit/xinit.c,v 3.32 2002/05/31 18:46:13 dawes Exp $ */
37 #include <X11/Xatom.h>
42 #ifdef X_POSIX_C_SOURCE
43 #define _POSIX_C_SOURCE X_POSIX_C_SOURCE
45 #undef _POSIX_C_SOURCE
47 #if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE)
63 #if !defined(SIGCHLD) && defined(SIGCLD)
64 #define SIGCHLD SIGCLD
67 #define INCL_DOSMODULEMGR
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
80 extern char **environ;
81 char **newenviron = NULL;
82 char **newenvironlast = NULL;
88 #ifndef HAVE_WORKING_VFORK
90 # define vfork() fork()
98 /* A/UX setpgid incorrectly removes the controlling terminal.
99 Per Posix, only setsid should do that. */
101 #define setpgid setpgrp
109 #define Execvpe(path, argv, envp) execvpe(path, argv, envp)
111 #define Execvpe(path, argv, envp) execvp(path, argv)
114 const char *bindir = BINDIR;
115 const char * const server_names[] = {
116 #if defined(ultrix) && defined(mips)
117 "Xdec Digital color display on DECstation",
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",
125 "Xhp HP monochrome and colors displays on 9000/300 series",
128 "Xibm IBM AED, APA, 8514a, megapel, VGA displays on PC/RT",
130 #ifdef macII /* MacII */
131 "XmacII Apple monochrome display on Macintosh II",
134 "XFree86 XFree86 displays",
137 "Xorg Common X server for most displays",
140 "Xquartz Mac OSX Quartz displays.",
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",
149 #define XINITRC ".xinitrc"
151 char xinitrcbuf[256];
154 #define XSERVERRC ".xserverrc"
156 char xserverrcbuf[256];
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 */
174 #if defined(__CYGWIN__) || defined(SVR4) || defined(_POSIX_SOURCE) || defined(CSRG_BASED) || defined(__UNIXOS2__) || defined(Lynx) || defined(__APPLE__)
182 volatile int gotSignal = 0;
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, ... );
195 #ifdef RETSIGTYPE /* autoconf AC_TYPE_SIGNAL */
196 # define SIGVAL RETSIGTYPE
197 #endif /* RETSIGTYPE */
202 /* On system with POSIX signals, just interrupt the system call */
209 #if defined(SYSV) || defined(SVR4) || defined(linux) || defined(__UNIXOS2__) || defined(__APPLE__)
210 signal (sig, sigAlarm);
217 #if defined(SYSV) || defined(SVR4) || defined(linux) || defined(__UNIXOS2__) || defined(__APPLE__)
218 signal (sig, sigUsr1);
223 Execute(char **vec, /* has room from up above */
226 Execvpe (vec[0], vec, envp);
228 if (access (vec[0], R_OK) == 0) {
229 vec--; /* back it up to stuff shell in */
231 Execvpe (vec[0], vec, envp);
239 main(int argc, char *argv[])
242 main(int argc, char *argv[], char *envp[])
245 register char **sptr = server;
246 register char **cptr = client;
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;
255 envsave = envp; /* circumvent an EMX problem */
257 /* Check whether the system will run at all */
261 char name[CCHMAXPATH];
263 fputs ("This program requires emx.dll revision 50 (0.9c) "
264 "or later.\n", stderr);
265 rc = DosLoadModule (fail, sizeof (fail), "emx", &hmod);
267 rc = DosQueryModuleName (hmod, sizeof (name), name);
269 fprintf (stderr, "Please delete or update `%s'.\n", name);
270 DosFreeModule (hmod);
278 * copy the client args.
282 (**argv != '/' && **argv != '.')) {
284 (**argv != '/' && **argv != '\\' && **argv != '.' &&
285 !(isalpha(**argv) && (*argv)[1]==':'))) {
287 for (ptr = default_client; *ptr; )
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.
295 if ( getenv("WINDOW_PARENT") == NULL )
301 start_of_client_args = (cptr - client);
302 while (argc && strcmp(*argv, "--")) {
314 * Copy the server args.
318 (**argv != '/' && **argv != '.')) {
319 *sptr++ = default_server;
321 (**argv != '/' && **argv != '\\' && **argv != '.' &&
322 !(isalpha(**argv) && (*argv)[1]==':'))) {
323 *sptr = getenv("XSERVER");
325 Error("No XSERVER environment variable set");
335 if (argc > 0 && (argv[0][0] == ':' && isdigit(argv[0][1])))
338 displayNum = *sptr++ = default_display;
340 start_of_server_args = (sptr - server);
341 while (--argc >= 0) {
348 * if no client arguments given, check for a startup file and copy
349 * that into the argument list
353 Bool required = False;
355 xinitrcbuf[0] = '\0';
356 if ((cp = getenv ("XINITRC")) != NULL) {
357 (void) snprintf (xinitrcbuf, sizeof(xinitrcbuf), "%s", cp);
359 } else if ((cp = getenv ("HOME")) != NULL) {
360 (void) snprintf (xinitrcbuf, sizeof(xinitrcbuf),
361 "%s/%s", cp, XINITRC);
364 if (access (xinitrcbuf, F_OK) == 0) {
365 client += start_of_client_args - 1;
366 client[0] = xinitrcbuf;
367 } else if (required) {
369 "%s: warning, no client init file \"%s\"\n",
370 program, xinitrcbuf);
376 * if no server arguments given, check for a startup file and copy
377 * that into the argument list
381 Bool required = False;
383 xserverrcbuf[0] = '\0';
384 if ((cp = getenv ("XSERVERRC")) != NULL) {
385 (void) snprintf (xserverrcbuf, sizeof(xserverrcbuf), "%s", cp);
387 } else if ((cp = getenv ("HOME")) != NULL) {
388 (void) snprintf (xserverrcbuf, sizeof(xserverrcbuf),
389 "%s/%s", cp, XSERVERRC);
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) {
397 "%s: warning, no server init file \"%s\"\n",
398 program, xserverrcbuf);
404 * put the display name into the environment
409 * Start the server and client.
412 signal(SIGCHLD, SIG_DFL); /* Insurance */
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 */
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);
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_
433 #endif//_F_EXIT_AFTER_XORG_AND_XCLIENT_LAUNCHED_
435 while (pid != clientpid && pid != serverpid
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);
448 if (gotSignal != 0) {
449 Error("unexpected signal %d.\n", gotSignal);
454 Fatal("Server error.\n");
456 Fatal("Client error.\n");
462 * waitforserver - wait for X server to start up
467 int ncycles = 120; /* # of cycles to wait */
468 int cycles; /* Wait cycle count */
470 for (cycles = 0; cycles < ncycles; cycles++) {
471 if ((xd = XOpenDisplay(displayNum))) {
475 #define MSG "X server to begin accepting connections"
476 if (!processTimeout (1, MSG))
482 fprintf (stderr, "giving up.\r\n");
487 * return TRUE if we timeout waiting for pid to exit, FALSE otherwise.
490 processTimeout(int timeout, char *string)
492 int i = 0, pidfound = -1;
493 static char *laststring;
496 #if defined(SYSV) || defined(__UNIXOS2__)
498 if ((pidfound = wait(NULL)) == serverpid)
502 #if defined(SVR4) || defined(_POSIX_SOURCE) || defined(Lynx) || defined(__APPLE__)
503 if ((pidfound = waitpid(serverpid, &status, WNOHANG)) == serverpid)
506 if ((pidfound = wait3(&status, WNOHANG, NULL)) == serverpid)
511 if (i == 0 && string != laststring)
512 fprintf(stderr, "\r\nwaiting for %s ", string);
514 fprintf(stderr, ".");
522 if ( i > 0 ) fputc( '\n', stderr ); /* tidy up after message */
524 return( serverpid != pidfound );
528 startServer(char *server[])
536 sigaddset(&mask, SIGUSR1);
537 sigprocmask(SIG_BLOCK, &mask, &old);
544 sigprocmask(SIG_SETMASK, &old, NULL);
547 * don't hang on read/write to control tty
550 (void) signal(SIGTTIN, SIG_IGN);
553 (void) signal(SIGTTOU, SIG_IGN);
556 * ignore SIGUSR1 in child. The server
557 * will notice this and send SIGUSR1 back
558 * at xinit when ready to accept connections
560 (void) signal(SIGUSR1, SIG_IGN);
562 * prevent server from getting sighup from vhangup()
563 * if client is xterm -L
568 Execute (server, environ);
569 Error ("no server \"%s\" in PATH\n", server[0]);
571 const char * const *cpp;
574 "\nUse the -- option, or make sure that %s is in your path and\n",
577 "that \"%s\" is a program or a link to the right type of server\n",
580 "for your display. Possible server names include:\n\n");
581 for (cpp = server_names; *cpp; cpp++) {
582 fprintf (stderr, " %s\n", *cpp);
584 fprintf (stderr, "\n");
596 setpriority( PRIO_PROCESS, serverpid, -1 );
600 if (! processTimeout(0, "")) {
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.
609 * If your machine is substantially slower than 15 seconds,
610 * you can easily adjust this value.
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
621 sigemptyset(&pendings);
622 sigpending(&pendings);
623 if (!sigismember(&pendings, SIGUSR1))
624 #endif /* __UNIXOS2__ */
627 sigprocmask(SIG_SETMASK, &old, NULL);
629 if (waitforserver() == 0) {
630 Error("unable to connect to X server\r\n");
643 /* setting WINDOWPATH for clients */
647 unsigned long nitems;
648 unsigned long bytes_after;
650 const char *windowpath;
656 prop = XInternAtom(xd, "XFree86_VT", False);
659 fprintf(stderr, "no XFree86_VT atom\n");
663 if (XGetWindowProperty(xd, DefaultRootWindow(xd), prop, 0, 1,
664 False, AnyPropertyType, &actualtype, &actualformat,
665 &nitems, &bytes_after, &buf)) {
667 fprintf(stderr, "no XFree86_VT property\n");
673 fprintf(stderr, "%lu items in XFree86_VT property!\n", nitems);
678 switch (actualtype) {
682 switch (actualformat) {
684 num = (*(uint8_t *)(void *)buf);
687 num = (*(uint16_t *)(void *)buf);
690 num = (*(uint32_t *)(void *)buf);
694 fprintf(stderr, "format %d in XFree86_VT property!\n", actualformat);
702 fprintf(stderr, "type %lx in XFree86_VT property!\n", actualtype);
708 windowpath = getenv("WINDOWPATH");
709 numn = snprintf(nums, sizeof(nums), "%lu", num);
711 len = 10 + 1 + numn + 1;
712 newwindowpath = malloc(len);
713 if (newwindowpath == NULL)
715 snprintf(newwindowpath, len, "WINDOWPATH=%s", nums);
717 len = 10 + 1 + strlen(windowpath) + 1 + numn + 1;
718 newwindowpath = malloc(len);
719 if (newwindowpath == NULL)
721 snprintf(newwindowpath, len, "WINDOWPATH=%s:%s",
724 *newenvironlast++ = newwindowpath;
725 *newenvironlast = NULL;
729 startClient(char *client[])
732 if ((clientpid = vfork()) == 0) {
733 if (setuid(getuid()) == -1) {
734 Error("cannot change uid: %s\n", strerror(errno));
737 setpgid(0, getpid());
738 environ = newenviron;
741 environ = newenviron;
742 client[0] = (char*)__XOS2RedirRoot(client[0]);
744 Execute (client,newenviron);
745 Error ("no program named \"%s\" in PATH\r\n", client[0]);
747 "\nSpecify a program on the command line or make sure that %s\r\n", bindir);
749 "is in your path.\r\n");
750 fprintf (stderr, "\n");
757 #define killpg(pgrp, sig) kill(-(pgrp), sig)
760 static jmp_buf close_env;
763 ignorexio(Display *dpy)
765 fprintf (stderr, "%s: connection to X server lost.\r\n", program);
766 longjmp (close_env, 1);
774 /* have kept display opened, so close it now */
776 XSetIOErrorHandler (ignorexio);
777 if (! setjmp(close_env)) {
781 /* HUP all local clients to allow them to clean up */
783 if ((killpg(clientpid, SIGHUP) != 0) &&
785 Error("can't send HUP to process group %d\r\n",
792 if (killpg(serverpid, SIGTERM) < 0) {
794 Fatal("Can't kill X server\r\n");
798 if (! processTimeout(10, "X server to shut down")) {
799 fprintf (stderr, "\r\n");
804 "\r\n%s: X server slow to shut down, sending KILL signal.\r\n",
808 if (killpg(serverpid, SIGKILL) < 0) {
812 if (processTimeout(3, "server to die")) {
813 fprintf (stderr, "\r\n");
814 Fatal("Can't kill server\r\n");
816 fprintf (stderr, "\r\n");
822 * make a new copy of environment that has room for DISPLAY
826 set_environment(void)
829 char **newPtr, **oldPtr;
830 static char displaybuf[512];
832 /* count number of environment variables */
833 for (oldPtr = environ; *oldPtr; oldPtr++) ;
835 nenvvars = (oldPtr - environ);
836 newenviron = (char **) malloc ((nenvvars + 3) * sizeof(char **));
839 "%s: unable to allocate %d pointers for environment\n",
840 program, nenvvars + 3);
844 /* put DISPLAY=displayname as first element */
845 snprintf (displaybuf, sizeof(displaybuf), "DISPLAY=%s", displayNum);
847 *newPtr++ = displaybuf;
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) {
857 newenvironlast=newPtr;
869 Error(char *fmt, ...)
874 fprintf(stderr, "%s: ", program);
876 fprintf (stderr, "%s (errno %d): ", strerror(errno), errno);
877 vfprintf(stderr, fmt, ap);