home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / MODEM / UWPC201.ZIP / UWSERVER.TAR / server / uw_main.c < prev   
Encoding:
C/C++ Source or Header  |  1991-01-25  |  8.7 KB  |  376 lines

  1. /*
  2.  *    uw - UNIX windows program for the Macintosh (host end)
  3.  *
  4.  * Copyright 1985,1986 by John D. Bruner.  All rights reserved.  Permission to
  5.  * copy this program is given provided that the copy is not sold and that
  6.  * this copyright notice is included.
  7.  */
  8.  
  9. #include <sys/types.h>
  10. #include <sys/file.h>
  11. #include <sys/wait.h>
  12. #include <sys/time.h>
  13. #include <sys/resource.h>
  14. #include <sys/ioctl.h>
  15. #include <pwd.h>
  16. #include <signal.h>
  17. #include <errno.h>
  18. #include <strings.h>
  19. #include <stdio.h>
  20.  
  21. #include "uw_param.h"
  22. #include "uw_clk.h"
  23. #include "uw_opt.h"
  24. #include "uw_win.h"
  25. #include "uw_fd.h"
  26. #include "uw_pcl.h"
  27. #include "uw_ipc.h"
  28. #include "openpty.h"
  29.  
  30. int nflag;            /* no startup file */
  31. int sflag;            /* "secure" (hee hee) -- no network requests */
  32. int errflag;            /* argument error */
  33. char *rcfile;            /* ".uwrc" file name */
  34.  
  35. extern void rc_kludge();    /* horrible hack (see rc_kludge()) */
  36.  
  37. main(argc, argv)
  38. char **argv;
  39. {
  40.     register int c;
  41.     register fildes_t fd;
  42.     extern int calloptscan;
  43.     extern int errno;
  44.     extern int optind;
  45.     extern char *optarg;
  46.  
  47.     /*
  48.      * Make sure we don't accidentally try to run this inside itself.
  49.      */
  50.     if (getenv(UIPC_ENV)) {
  51.         fprintf(stderr, "%s is already running\n", *argv);
  52.         exit(1);
  53.     }
  54.  
  55.     /*
  56.      * Process command-line arguments.
  57.      */
  58.     while ((c=getopt(argc, argv, "f:ns")) != EOF) {
  59.         switch (c) {
  60.         case 'f':
  61.             if (nflag) {
  62.                 fprintf(stderr,
  63.                     "Cannot specify both \"-f\" and \"-n\"\n");
  64.                 nflag = 0;
  65.             }
  66.             rcfile = optarg;
  67.             break;
  68.         case 'n':
  69.             if (rcfile != (char *)0) {
  70.                 fprintf(stderr,
  71.                     "Cannot specify both \"-f\" and \"-n\"\n");
  72.                 rcfile = (char *)0;
  73.             }
  74.             nflag = 1;
  75.             break;
  76.         case 's':
  77.             sflag = 1;
  78.             break;
  79.         case '?':
  80.         default:
  81.             errflag = 1;
  82.             break;
  83.         }
  84.     }
  85.     if (errflag) {
  86.         fprintf(stderr, "Usage: \"%s [-f file] [-n] [-s]\"\n", *argv);
  87.         exit(1);
  88.     }
  89.  
  90.     /*
  91.      * Initialize the file descriptor table.
  92.      */
  93.     fd_init();
  94.     FD_SET(0, &selmask[0].sm_rd);
  95.  
  96.     /*
  97.      * If we can open the "/etc/utmp" for write, do so.
  98.      * Immediately afterwards, we lose any magic powers that
  99.      * might have allowed us to do this.
  100.      */
  101. #ifdef UTMP
  102.     fd = open("/etc/utmp", O_WRONLY);
  103.     (void)setgid(getgid());
  104.     (void)setuid(getuid());
  105.     if (fd >= 0)
  106.         fdmap[fd].f_type = FDT_OTHER;
  107.     utmp_init(fd);
  108. #endif
  109.  
  110.     /*
  111.      * Initialize the window structures.
  112.      */
  113.     win_init();
  114.  
  115.     /*
  116.      * Initialize timeouts.
  117.      */
  118.     clk_init();
  119.  
  120.  
  121.     /*
  122.      * Create a UNIX-domain network address, and put its name into
  123.      * the environment so that descendents can contact us with new
  124.      * window requests.  If we want to be "secure", we don't allow
  125.      * any UNIX-domain messages to come in.
  126.      */
  127.     ipc_init(!sflag);
  128.     if (!sflag)
  129.         clk_timeout(5, rc_kludge, (toarg_t)0);
  130.  
  131.  
  132.     /*
  133.      * Ignore interrupts, quits, and terminal stops.  Clean up and exit
  134.      * if a hangup or termination is received.  Also catch changes in
  135.      * child status (so that we can wait for them).  Set up the terminal
  136.      * modes.
  137.      */
  138.     (void)signal(SIGHUP, done);
  139.     (void)signal(SIGINT, SIG_IGN);
  140.     (void)signal(SIGQUIT, SIG_IGN);
  141.     (void)signal(SIGTERM, done);
  142.     (void)signal(SIGTSTP, SIG_IGN);
  143.     (void)signal(SIGCHLD, cwait);
  144.  
  145.     tty_mode(1);
  146.  
  147.  
  148.     /*
  149.      * Tell the Macintosh to initialize.
  150.      */
  151.     pcl_entry(0);
  152.  
  153.     
  154.     /*
  155.      * Create window 1 (to start things off) and wait for input.
  156.      * When input is available, process it.
  157.      */
  158.     if (!nflag)
  159.         finduwrc();
  160.  
  161.     while (1) {
  162.         CLK_CHECK();
  163.         if (calloptscan && protocol->p_chkopt) {
  164.             calloptscan = 0;
  165.             (*protocol->p_chkopt)(0);
  166.         }
  167.         selmask[1] = selmask[0];
  168.         if (select(nfds, &selmask[1].sm_rd, &selmask[1].sm_wt,
  169.             &selmask[1].sm_ex, (struct timeval *)0) < 0) {
  170.             if (errno == EINTR)
  171.                 continue;
  172.             perror("select");
  173.             done(1);    /* for now -- fix this! */
  174.         }
  175.         for (fd=0; fd < nfds; fd++) {
  176.             if (FD_ISSET(fd, &selmask[1].sm_rd)) {
  177.                 switch (fdmap[fd].f_type) {
  178.                 case FDT_MAC:
  179.                     PCL_RECV(0, (char *)0, 0);
  180.                     break;
  181.                 case FDT_UDSOCK:
  182.                     ipc_udrecv(fd);
  183.                     break;
  184.                 case FDT_ISSOCK:
  185.                     ipc_isrecv(fd);
  186.                     break;
  187.                 case FDT_DATA:
  188.                     PCL_XMIT(0, fdmap[fd].f_win);
  189.                     break;
  190.                 case FDT_CTL:
  191.                     ipc_ctlrecv(0, fd, fdmap[fd].f_win);
  192.                     break;
  193.                 default:
  194.                     /* "can't happen" */
  195.                     FD_CLR(fd, &selmask[0].sm_rd);
  196.                     break;
  197.                 }
  198.             }
  199.             if (FD_ISSET(fd, &selmask[1].sm_wt)) {
  200.                 /* "can't happen" */
  201.                 FD_CLR(fd, &selmask[0].sm_wt);
  202.                 break;
  203.             }
  204.             if (FD_ISSET(fd, &selmask[1].sm_ex)) {
  205.                 /* "can't happen" */
  206.                 FD_CLR(fd, &selmask[0].sm_ex);
  207.                 break;
  208.             }
  209.         }
  210.     }
  211. }
  212.  
  213. finduwrc()
  214. {
  215.     register struct passwd *pw;
  216.     register char *homedir;
  217.  
  218.     /*
  219.      * If the global variable "rcfile" is non-NULL, then it specifies
  220.      * the name of the startup file.  Otherwise, the name of the startup
  221.      * file is "$HOME/.uwrc".  If $HOME is undefined or null, the password
  222.      * file is consulted.  The ".uwrc" file is an executable program or
  223.      * "/bin/sh" command file.  (For "csh" (ugh) use "#! /bin/csh".)
  224.      *
  225.      * Returns 0 if the ".uwrc" file doesn't exist, 1 if it does.  As
  226.      * a side-effect, this routine sets the global variable "rcfile"
  227.      * to the name of the ".uwrc" file.
  228.      */
  229.     if (rcfile == (char *)0) {
  230.         if ((homedir=getenv("HOME")) == NULL || !*homedir) {
  231.             if ((pw = getpwuid(getuid())) != NULL)
  232.                 homedir = pw->pw_dir;
  233.             else
  234.                 return;
  235.         }
  236.         rcfile = malloc((unsigned)(strlen(homedir) + sizeof "/.uwrc"));
  237.         if (rcfile == (char *)0)
  238.             return;
  239.         (void)strcpy(rcfile, homedir);
  240.         (void)strcat(rcfile, "/.uwrc");
  241.     }
  242.     if (access(rcfile, F_OK) < 0)
  243.         rcfile = (char *)0;
  244. }
  245.  
  246. runuwrc()
  247. {
  248.     register int pid;
  249.     register fildes_t fd;
  250.     struct ptydesc pt;
  251.  
  252.     /*
  253.      * We use a real fork (rather than a vfork()) because the parent
  254.      * doesn't wait for the child.  The caller knows that the file
  255.      * exists; however, it cannot determine whether or not it is
  256.      * successfully executed.
  257.      *
  258.      * We acquire a pseudo-terminal for rather convoluted reasons.
  259.      * Programs such as "uwtool" expect to be able to inherit tty
  260.      * modes from their controlling terminal.  By the time that we
  261.      * reach this point, we've already changed our controlling
  262.      * terminal to use cbreak mode with no special characters except
  263.      * XON/XOFF.  Therefore, we obtain a pseudo-terminal and
  264.      * restore our original modes onto it.  We double-fork (sigh,
  265.      * another miserable kludge) so that the server does not have
  266.      * to wait for the completion of the ".uwrc" file.  (The child
  267.      * waits for the grandchild so that the master side of the pty
  268.      * remains open until the grandchild is finished.)
  269.      */
  270.     if (openpty(&pt) < 0)
  271.         return;
  272.     while ((pid = fork()) < 0)
  273.         sleep(5);
  274.     if (pid > 0) {
  275.         (void)close(pt.pt_pfd);
  276.         (void)close(pt.pt_tfd);
  277.     } else {
  278.         /* child */
  279.         while ((pid = fork()) < 0)
  280.             sleep(5);
  281.         if (pid > 0) {
  282.             while (wait((int *)0) < 0 && errno == EINTR)
  283.                 ;
  284.             _exit(1);
  285.             /*NOTREACHED*/
  286.         } else {
  287.             /* grandchild */
  288.             (void)setgid(getgid());
  289.             (void)setuid(getuid());
  290.             (void)close(pt.pt_pfd);
  291.             if (pt.pt_tfd != 0)
  292.                 (void)dup2(pt.pt_tfd, 0);
  293.             if (pt.pt_tfd != 1);
  294.                 (void)dup2(pt.pt_tfd, 1);
  295.             if (pt.pt_tfd != 2)
  296.                 (void)dup2(pt.pt_tfd, 2);
  297.             win_envinit(defwtype, (long)0);
  298.             (void)signal(SIGHUP, SIG_DFL);
  299.             (void)signal(SIGINT, SIG_DFL);
  300.             (void)signal(SIGQUIT, SIG_DFL);
  301.             (void)signal(SIGTERM, SIG_DFL);
  302.             (void)signal(SIGTSTP, SIG_IGN);
  303.             (void)signal(SIGCHLD, SIG_DFL);
  304.             (void)ioctl(open("/dev/tty",O_RDWR),
  305.                 (int)TIOCNOTTY, (char *)0);
  306.             (void)open(pt.pt_tname, O_RDONLY);
  307.             for (fd=3; fd < nfds; fd++)
  308.                 (void)close(fd);
  309.             tty_mode(0);
  310.             (void)execlp(rcfile, rcfile, (char *)0);
  311.             (void)execl("/bin/sh", "sh", rcfile, (char *)0);
  312.             _exit(1);
  313.             /*NOTREACHED*/
  314.         }
  315.     }
  316. }
  317.  
  318. void
  319. rc_kludge()
  320. {
  321.     static int firsttime = 1;
  322.  
  323.     /*
  324.      * A problem which occurs with ".uwrc" file handling is that
  325.      * the "rc" file is interpreted immediately after the server
  326.      * begins, i.e. before it and the Macintosh have (possibly)
  327.      * changed from the default protocol to an extended one.
  328.      *
  329.      * To get around this problem, if a ".uwrc" file exists, it
  330.      * is not executed immediately.  Instead, it will be executed
  331.      * when this routine is called, either directly by pcl_newpcl()
  332.      * when the protocol changes, or after an initial timeout.
  333.      *
  334.      * It is most unfortunate that "pcl_newpcl" must call "upwards"
  335.      * into this source file.
  336.      */
  337.     if (firsttime) {
  338.         firsttime = 0;
  339.         if (rcfile != (char *)0)
  340.             runuwrc();
  341.         else
  342.             (void)PCL_NEWW(0, WC_INTERNAL, defwtype, (nwin_t)1, 0L,
  343.                 (fildes_t)-1, (fildes_t)-1);
  344.     }
  345. }
  346.  
  347. void
  348. done(s)
  349. {
  350.     /*
  351.      * Clean up and exit.  It is overkill to close all of the file
  352.      * descriptors, but it causes no harm.
  353.      */
  354.     pcl_exit(0);
  355.     utmp_exit();
  356.     fd_exit();
  357.     ipc_exit();
  358.     tty_mode(0);
  359.     exit(s);
  360. }
  361.  
  362. void
  363. cwait()
  364. {
  365.     register int pid;
  366.     union wait status;
  367.     struct rusage rusage;
  368.  
  369.     /*
  370.      * Collect dead children.  Restart any children that have stopped.
  371.      */
  372.     while ((pid=wait3(&status, WNOHANG|WUNTRACED, &rusage)) > 0)
  373.         if (WIFSTOPPED(status))
  374.             (void)kill(pid, SIGCONT);
  375. }
  376.