home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / clients / xinit / xinit.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-21  |  13.4 KB  |  621 lines

  1. /* $XConsortium: xinit.c,v 11.54 91/12/23 17:26:08 gildea Exp $ */
  2.  
  3. /* Copyright    Massachusetts Institute of Technology    1986    */
  4.  
  5. /*
  6. Permission to use, copy, modify, distribute, and sell this software and its
  7. documentation for any purpose is hereby granted without fee, provided that
  8. the above copyright notice appear in all copies and that both that
  9. copyright notice and this permission notice appear in supporting
  10. documentation, and that the name of M.I.T. not be used in advertising or
  11. publicity pertaining to distribution of the software without specific,
  12. written prior permission.  M.I.T. makes no representations about the
  13. suitability of this software for any purpose.  It is provided "as is"
  14. without express or implied warranty.
  15. */
  16.  
  17. #include <X11/Xlib.h>
  18. #include <X11/Xos.h>
  19. #include <X11/Xmu/SysUtil.h>
  20. #include <stdio.h>
  21. #include <ctype.h>
  22. #include <signal.h>
  23. #ifndef SYSV
  24. #include <sys/wait.h>
  25. #endif
  26. #include <errno.h>
  27. extern int sys_nerr;
  28. #include <setjmp.h>
  29.  
  30. #ifndef X_NOT_STDC_ENV
  31. #include <stdlib.h>
  32. #else
  33. extern char *getenv();
  34. #endif
  35. extern char **environ;
  36. char **newenviron = NULL;
  37.  
  38. #ifndef SHELL
  39. #define SHELL "sh"
  40. #endif
  41.  
  42. #ifdef macII
  43. #define vfork() fork()
  44. #endif /* macII */
  45.  
  46. #if defined(SYSV) && !defined(hpux)
  47. #define vfork() fork()
  48. #endif /* SYSV and not hpux */
  49.  
  50. /* A/UX setpgid incorrectly removes the controlling terminal.
  51.    Per Posix, only setsid should do that. */
  52. #if !defined(X_NOT_POSIX) && !defined(macII)
  53. #define setpgrp setpgid
  54. #endif
  55.  
  56. char *bindir = BINDIR;
  57. char *server_names[] = {
  58. #ifdef vax                /* Digital */
  59.     "Xqvss       Digital monochrome display on Microvax or VAXstation",
  60.     "Xqdss       Digital color display on Microvax of VAXstation",
  61. #endif
  62. #if defined(ultrix) && defined(mips)
  63.     "Xmfbpmax    Digital monochrome display on DECstation 3100",
  64.     "Xcfbpmax    Digital color display on DECstation 3100",
  65. #endif
  66. #ifdef sun                /* Sun */
  67.     "Xsun        Sun monochrome and color displays on Sun 2, 3, or 4 series",
  68. #endif
  69. #ifdef hpux                /* HP */
  70.     "Xhp         HP monochrome and colors displays on 9000/300 series",
  71. #endif
  72. #ifdef apollo                /* Apollo */
  73.     "Xapollo     Apollo monochrome and color displays",
  74. #endif
  75. #ifdef ibm                /* IBM */
  76.     "Xibm        IBM AED, APA, 8514a, megapel, VGA displays on PC/RT",
  77. #endif
  78. #ifdef macII                /* MacII */
  79.     "XmacII      Apple monochrome display on Macintosh II",
  80. #endif
  81. #ifdef M4310                /* Tektronix Pegasus */
  82.     "Xpeg        Tektronix Pegasus display on 431x series",
  83. #endif
  84.     NULL};
  85.  
  86. #ifndef XINITRC
  87. #define XINITRC ".xinitrc"
  88. #endif
  89. char xinitrcbuf[256];
  90.  
  91. #ifndef XSERVERRC
  92. #define XSERVERRC ".xserverrc"
  93. #endif
  94. char xserverrcbuf[256];
  95.  
  96. #define    TRUE        1
  97. #define    FALSE        0
  98. #define    OK_EXIT        0
  99. #define    ERR_EXIT    1
  100.  
  101. char *default_server = "X";
  102. char *default_display = ":0";        /* choose most efficient */
  103. char *default_client[] = {"xterm", "-geometry", "+1+1", "-n", "login", NULL};
  104. char *serverargv[100];
  105. char *clientargv[100];
  106. char **server = serverargv + 2;        /* make sure room for sh .xserverrc args */
  107. char **client = clientargv + 2;        /* make sure room for sh .xinitrc args */
  108. char *displayNum;
  109. char *program;
  110. Display *xd;            /* server connection */
  111. #ifndef SYSV
  112. #if defined(SVR4) || defined(_POSIX_SOURCE)
  113. int status;
  114. #else
  115. union wait    status;
  116. #endif
  117. #endif /* SYSV */
  118. int serverpid = -1;
  119. int clientpid = -1;
  120. extern int    errno;
  121.  
  122. static shutdown();
  123.  
  124. #ifdef SIGNALRETURNSINT
  125. #define SIGVAL int
  126. #else
  127. #define SIGVAL void
  128. #endif
  129.  
  130. SIGVAL sigCatch(sig)
  131.     int    sig;
  132. {
  133.     signal(SIGQUIT, SIG_IGN);
  134.     signal(SIGINT, SIG_IGN);
  135.     signal(SIGHUP, SIG_IGN);
  136.     signal(SIGPIPE, SIG_IGN);
  137.     Error("unexpected signal %d\r\n", sig);
  138.     shutdown();
  139.     exit(1);
  140. }
  141.  
  142. SIGVAL sigAlarm(sig)
  143.     int sig;
  144. {
  145. #ifdef SYSV
  146.     signal (sig, sigAlarm);
  147. #endif
  148. }
  149.  
  150. SIGVAL
  151. sigUsr1(sig)
  152.     int sig;
  153. {
  154. #ifdef SYSV
  155.     signal (sig, sigUsr1);
  156. #endif
  157. }
  158.  
  159. static Execute (vec)
  160.     char **vec;                /* has room from up above */
  161. {
  162.     execvp (vec[0], vec);
  163.     if (access (vec[0], R_OK) == 0) {
  164.     vec--;                /* back it up to stuff shell in */
  165.     vec[0] = SHELL;
  166.     execvp (vec[0], vec);
  167.     }
  168.     return;
  169. }
  170.  
  171. main(argc, argv)
  172. int argc;
  173. register char **argv;
  174. {
  175.     register char **sptr = server;
  176.     register char **cptr = client;
  177.     register char **ptr;
  178.     int pid;
  179.     int client_given = 0, server_given = 0;
  180.     int client_args_given = 0, server_args_given = 0;
  181.     int start_of_client_args, start_of_server_args;
  182.  
  183.     program = *argv++;
  184.     argc--;
  185.  
  186.     /*
  187.      * copy the client args.
  188.      */
  189.     if (argc == 0 ||
  190.         (**argv != '/' && **argv != '.')) {
  191.         for (ptr = default_client; *ptr; )
  192.             *cptr++ = *ptr++;
  193. #ifdef sun
  194.         /* 
  195.          * If running on a sun, and if WINDOW_PARENT isn't defined, 
  196.          * that means SunWindows isn't running, so we should pass 
  197.          * the -C flag to xterm so that it sets up a console.
  198.          */
  199.         if ( getenv("WINDOW_PARENT") == NULL )
  200.             *cptr++ = "-C";
  201. #endif /* sun */
  202.     } else {
  203.         client_given = 1;
  204.     }
  205.     start_of_client_args = (cptr - client);
  206.     while (argc && strcmp(*argv, "--")) {
  207.         client_args_given++;
  208.         *cptr++ = *argv++;
  209.         argc--;
  210.     }
  211.     *cptr = NULL;
  212.     if (argc) {
  213.         argv++;
  214.         argc--;
  215.     }
  216.  
  217.     /*
  218.      * Copy the server args.
  219.      */
  220.     if (argc == 0 ||
  221.         (**argv != '/' && **argv != '.')) {
  222.         *sptr++ = default_server;
  223.     } else {
  224.         server_given = 1;
  225.         *sptr++ = *argv++;
  226.         argc--;
  227.     }
  228.     if (argc > 0 && (argv[0][0] == ':' && isdigit(argv[0][1])))
  229.         displayNum = *argv;
  230.     else
  231.         displayNum = *sptr++ = default_display;
  232.  
  233.     start_of_server_args = (sptr - server);
  234.     while (--argc >= 0) {
  235.         server_args_given++;
  236.         *sptr++ = *argv++;
  237.     }
  238.     *sptr = NULL;
  239.  
  240.     /*
  241.      * if no client arguments given, check for a startup file and copy
  242.      * that into the argument list
  243.      */
  244.     if (!client_given) {
  245.         char *cp;
  246.         Bool required = False;
  247.  
  248.         xinitrcbuf[0] = '\0';
  249.         if ((cp = getenv ("XINITRC")) != NULL) {
  250.         strcpy (xinitrcbuf, cp);
  251.         required = True;
  252.         } else if ((cp = getenv ("HOME")) != NULL) {
  253.         (void) sprintf (xinitrcbuf, "%s/%s", cp, XINITRC);
  254.         }
  255.         if (xinitrcbuf[0]) {
  256.         if (access (xinitrcbuf, F_OK) == 0) {
  257.             client += start_of_client_args - 1;
  258.             client[0] = xinitrcbuf;
  259.         } else if (required) {
  260.             fprintf (stderr,
  261.                  "%s:  warning, no client init file \"%s\"\n",
  262.                  program, xinitrcbuf);
  263.         }
  264.         }
  265.     }
  266.  
  267.     /*
  268.      * if no server arguments given, check for a startup file and copy
  269.      * that into the argument list
  270.      */
  271.     if (!server_given) {
  272.         char *cp;
  273.         Bool required = False;
  274.  
  275.         xserverrcbuf[0] = '\0';
  276.         if ((cp = getenv ("XSERVERRC")) != NULL) {
  277.         strcpy (xserverrcbuf, cp);
  278.         required = True;
  279.         } else if ((cp = getenv ("HOME")) != NULL) {
  280.         (void) sprintf (xserverrcbuf, "%s/%s", cp, XSERVERRC);
  281.         }
  282.         if (xserverrcbuf[0]) {
  283.         if (access (xserverrcbuf, F_OK) == 0) {
  284.             server += start_of_server_args - 1;
  285.             server[0] = xserverrcbuf;
  286.         } else if (required) {
  287.             fprintf (stderr,
  288.                  "%s:  warning, no server init file \"%s\"\n",
  289.                  program, xserverrcbuf);
  290.         }
  291.         }
  292.     }
  293.  
  294.  
  295.     /*
  296.      * put the display name into the environment
  297.      */
  298.     set_environment ();
  299.  
  300.     /*
  301.      * Start the server and client.
  302.      */
  303.     signal(SIGQUIT, sigCatch);
  304.     signal(SIGINT, sigCatch);
  305.     signal(SIGHUP, sigCatch);
  306.     signal(SIGPIPE, sigCatch);
  307.     signal(SIGALRM, sigAlarm);
  308.     signal(SIGUSR1, sigUsr1);
  309.     if (startServer(server) > 0
  310.      && startClient(client) > 0) {
  311.         pid = -1;
  312.         while (pid != clientpid && pid != serverpid)
  313.             pid = wait(NULL);
  314.     }
  315.     signal(SIGQUIT, SIG_IGN);
  316.     signal(SIGINT, SIG_IGN);
  317.     signal(SIGHUP, SIG_IGN);
  318.     signal(SIGPIPE, SIG_IGN);
  319.  
  320.     shutdown();
  321.  
  322.     if (serverpid < 0 )
  323.         Fatal("Server error.\n");
  324.     if (clientpid < 0)
  325.         Fatal("Client error.\n");
  326.     exit(OK_EXIT);
  327. }
  328.  
  329.  
  330. /*
  331.  *    waitforserver - wait for X server to start up
  332.  */
  333.  
  334. waitforserver()
  335. {
  336.     int    ncycles     = 120;        /* # of cycles to wait */
  337.     int    cycles;            /* Wait cycle count */
  338.  
  339.     for (cycles = 0; cycles < ncycles; cycles++) {
  340.         if (xd = XOpenDisplay(displayNum)) {
  341.             return(TRUE);
  342.         }
  343.         else {
  344. #define MSG "X server to begin accepting connections"
  345.             if (!processTimeout (1, MSG)) 
  346.               break;
  347. #undef MSG
  348.         }
  349.     }
  350.  
  351.     fprintf (stderr, "giving up.\r\n");
  352.     return(FALSE);
  353. }
  354.  
  355. /*
  356.  * return TRUE if we timeout waiting for pid to exit, FALSE otherwise.
  357.  */
  358. processTimeout(timeout, string)
  359.     int    timeout;
  360.     char    *string;
  361. {
  362.     int    i = 0, pidfound = -1;
  363.     static char    *laststring;
  364.  
  365.     for (;;) {
  366. #ifdef SYSV
  367.         alarm(1);
  368.         if ((pidfound = wait(NULL)) == serverpid)
  369.             break;
  370.         alarm(0);
  371. #else /* SYSV */
  372. #if defined(SVR4) || defined(_POSIX_SOURCE)
  373.         if ((pidfound = waitpid(serverpid, &status, WNOHANG)) == serverpid)
  374.             break;
  375. #else
  376.         if ((pidfound = wait3(&status, WNOHANG, NULL)) == serverpid)
  377.             break;
  378. #endif
  379. #endif /* SYSV */
  380.         if (timeout) {
  381.             if (i == 0 && string != laststring)
  382.                 fprintf(stderr, "\r\nwaiting for %s ", string);
  383.             else
  384.                 fprintf(stderr, ".");
  385.             fflush(stderr);
  386.         }
  387.         if (timeout)
  388.             sleep (1);
  389.         if (++i > timeout)
  390.             break;
  391.     }
  392.     if ( i > 0 ) fputc( '\n', stderr );     /* tidy up after message */
  393.     laststring = string;
  394.     return( serverpid != pidfound );
  395. }
  396.  
  397. startServer(server)
  398.     char *server[];
  399. {
  400.     serverpid = vfork();
  401.     switch(serverpid) {
  402.     case 0:
  403.         /*
  404.          * don't hang on read/write to control tty
  405.          */
  406. #ifdef SIGTTIN
  407.         (void) signal(SIGTTIN, SIG_IGN);
  408. #endif
  409. #ifdef SIGTTOU
  410.         (void) signal(SIGTTOU, SIG_IGN);
  411. #endif
  412.         /*
  413.          * ignore SIGUSR1 in child.  The server
  414.          * will notice this and send SIGUSR1 back
  415.          * at xinit when ready to accept connections
  416.          */
  417.         (void) signal(SIGUSR1, SIG_IGN);
  418.         /*
  419.          * prevent server from getting sighup from vhangup()
  420.          * if client is xterm -L
  421.          */
  422.         setpgrp(0,getpid());
  423.  
  424.         Execute (server);
  425.         Error ("no server \"%s\" in PATH\n", server[0]);
  426.         {
  427.             char **cpp;
  428.  
  429.             fprintf (stderr,
  430. "\nUse the -- option, or make sure that %s is in your path and\n",
  431.                  bindir);
  432.             fprintf (stderr,
  433. "that \"%s\" is a program or a link to the right type of server\n",
  434.                  server[0]);
  435.             fprintf (stderr,
  436. "for your display.  Possible server names include:\n\n");
  437.             for (cpp = server_names; *cpp; cpp++) {
  438.             fprintf (stderr, "    %s\n", *cpp);
  439.             }
  440.             fprintf (stderr, "\n");
  441.         }
  442.         exit (ERR_EXIT);
  443.  
  444.         break;
  445.     case -1:
  446.         break;
  447.     default:
  448.         /*
  449.          * don't nice server
  450.          */
  451. #ifdef PRIO_PROCESS
  452.         setpriority( PRIO_PROCESS, serverpid, -1 );
  453. #endif
  454.  
  455.         errno = 0;
  456.         if (! processTimeout(0, "")) {
  457.             serverpid = -1;
  458.             break;
  459.         }
  460.         /*
  461.          * kludge to avoid race with TCP, giving server time to
  462.          * set his socket options before we try to open it,
  463.          * either use the 15 second timeout, or await SIGUSR1.
  464.          *
  465.          * If your machine is substantially slower than 15 seconds,
  466.          * you can easily adjust this value.
  467.          */
  468.         alarm (15);
  469.         pause ();
  470.         alarm (0);
  471.  
  472.         if (waitforserver() == 0) {
  473.             Error("unable to connect to X server\r\n");
  474.             shutdown();
  475.             serverpid = -1;
  476.         }
  477.         break;
  478.     }
  479.  
  480.     return(serverpid);
  481. }
  482.  
  483. startClient(client)
  484.     char *client[];
  485. {
  486.     if ((clientpid = vfork()) == 0) {
  487.         setuid(getuid());
  488.         setpgrp(0, getpid());
  489.         environ = newenviron;
  490.         Execute (client);
  491.         Error ("no program named \"%s\" in PATH\r\n", client[0]);
  492.         fprintf (stderr,
  493. "\nSpecify a program on the command line or make sure that %s\r\n", bindir);
  494.         fprintf (stderr,
  495. "is in your path.\r\n");
  496.         fprintf (stderr, "\n");
  497.         exit (ERR_EXIT);
  498.     }
  499.     return (clientpid);
  500. }
  501.  
  502. #if !defined(X_NOT_POSIX) || defined(SYSV)
  503. #define killpg(pgrp, sig) kill(-(pgrp), sig)
  504. #endif
  505.  
  506. static jmp_buf close_env;
  507.  
  508. static int ignorexio (dpy)
  509.     Display *dpy;
  510. {
  511.     fprintf (stderr, "%s:  connection to X server lost.\r\n", program);
  512.     longjmp (close_env, 1);
  513.     /*NOTREACHED*/
  514. }
  515.  
  516. static
  517. shutdown()
  518. {
  519.     /* have kept display opened, so close it now */
  520.     if (clientpid > 0) {
  521.         XSetIOErrorHandler (ignorexio);
  522.         if (! setjmp(close_env)) {
  523.             XCloseDisplay(xd);
  524.         }
  525.  
  526.         /* HUP all local clients to allow them to clean up */
  527.         errno = 0;
  528.         if ((killpg(clientpid, SIGHUP) != 0) &&
  529.             (errno != ESRCH))
  530.             Error("can't send HUP to process group %d\r\n",
  531.                 clientpid);
  532.     }
  533.  
  534.     if (serverpid < 0)
  535.         return;
  536.     errno = 0;
  537.     if (killpg(serverpid, SIGTERM) < 0) {
  538.         if (errno == EPERM)
  539.             Fatal("Can't kill X server\r\n");
  540.         if (errno == ESRCH)
  541.             return;
  542.     }
  543.     if (! processTimeout(10, "X server to shut down")) {
  544.         fprintf (stderr, "\r\n");
  545.         return;
  546.     }
  547.  
  548.     fprintf(stderr, 
  549.     "\r\n%s:  X server slow to shut down, sending KILL signal.\r\n",
  550.         program);
  551.     fflush(stderr);
  552.     errno = 0;
  553.     if (killpg(serverpid, SIGKILL) < 0) {
  554.         if (errno == ESRCH)
  555.             return;
  556.     }
  557.     if (processTimeout(3, "server to die")) {
  558.         fprintf (stderr, "\r\n");
  559.         Fatal("Can't kill server\r\n");
  560.     }
  561.     fprintf (stderr, "\r\n");
  562.     return;
  563. }
  564.  
  565.  
  566. /*
  567.  * make a new copy of environment that has room for DISPLAY
  568.  */
  569.  
  570. set_environment ()
  571. {
  572.     int nenvvars;
  573.     char **newPtr, **oldPtr;
  574.     static char displaybuf[256];
  575.  
  576.     /* count number of environment variables */
  577.     for (oldPtr = environ; *oldPtr; oldPtr++) ;
  578.  
  579.     nenvvars = (oldPtr - environ);
  580.     newenviron = (char **) malloc ((nenvvars + 2) * sizeof(char **));
  581.     if (!newenviron) {
  582.     fprintf (stderr,
  583.          "%s:  unable to allocate %d pointers for environment\n",
  584.          program, nenvvars + 2);
  585.     exit (1);
  586.     }
  587.  
  588.     /* put DISPLAY=displayname as first element */
  589.     strcpy (displaybuf, "DISPLAY=");
  590.     strcpy (displaybuf + 8, displayNum);
  591.     newPtr = newenviron;
  592.     *newPtr++ = displaybuf;
  593.  
  594.     /* copy pointers to other variables */
  595.     for (oldPtr = environ; *oldPtr; oldPtr++) {
  596.     if (strncmp (*oldPtr, "DISPLAY=", 8) != 0) {
  597.         *newPtr++ = *oldPtr;
  598.     }
  599.     }
  600.     *newPtr = NULL;
  601.     return;
  602. }
  603.  
  604. Fatal(fmt, x0,x1,x2,x3,x4,x5,x6,x7,x8,x9)
  605.     char    *fmt;
  606. {
  607.     Error(fmt, x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);
  608.     exit(ERR_EXIT);
  609. }
  610.  
  611. Error(fmt, x0,x1,x2,x3,x4,x5,x6,x7,x8,x9)
  612.     char    *fmt;
  613. {
  614.     extern char    *sys_errlist[];
  615.  
  616.     fprintf(stderr, "%s:  ", program);
  617.     if (errno > 0 && errno < sys_nerr)
  618.       fprintf (stderr, "%s (errno %d):  ", sys_errlist[errno], errno);
  619.     fprintf(stderr, fmt, x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);
  620. }
  621.