home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / source / layers.zoo / layers.3 / layers.c
Encoding:
C/C++ Source or Header  |  1990-06-11  |  55.5 KB  |  2,214 lines

  1. /********                    Layers.c
  2. *********
  3. *********    Layers - MacLayers Multiwindow BSD Socket Driver
  4. *********
  5. *********          Dave Trissel oakhill!davet
  6. *********
  7. ********* The sockets handling portion of this control module is based 
  8. ********* upon 'screen' by Oliver Laumann whose copyright remains below. 
  9. ********* The rest is
  10.  *
  11.  *             Copyright (C) 1989 by David W. Trissel
  12.  *
  13.  *              Not derived from licensed software.
  14.  *
  15.  * Permission is granted to freely use, copy, modify, and redistribute
  16.  * this software, provided that no attempt is made to gain profit from it,
  17.  * the author is not construed to be liable for any results of using the
  18.  * software, alterations are clearly marked as such, and this notice is
  19.  * not modified.
  20.  *
  21.  */
  22.  
  23. static char LayersVersion[] = "layers 1.00 17-Mar-1990";
  24.  
  25. /* Layers Changes:
  26.  
  27.     Version .92 22-Mar-1989
  28.  
  29.         Original Distributed version
  30.  
  31.     Version .93 31-Mar-1989
  32.  
  33.         Deleted dl and al termcap entries since they didn't help any
  34.         (al was redundant with sc (scroll) so should never have been created)
  35.  
  36.         SIGINT no longer causes us to quit (left debugging code in by mistake)
  37.  
  38.         Layer #1 is always logged in and takes over as user's login console
  39.         (Real tty disconnected from /etc/utmp file while layers is running)
  40.  
  41.     Version .93b 05-May-1989
  42.  
  43.         Try getenv("PWD") before getwd() so Sun networking won't hang us up
  44.  
  45.     Version .93n 07-Jan-1990
  46.  
  47.         Reset TTY back to normal if initial link handshake fails.
  48.  
  49.     Version 1.00b 22-Jan-1990
  50.  
  51.         Corrected problem of layers forcing all umasks to 000.
  52.  
  53.     Version 1.00  17-Mar-1990
  54.  
  55.         First public release.
  56. */
  57.  
  58.  
  59. /* Copyright (c) 1987,1988 Oliver Laumann, Technical University of Berlin.
  60.  * Not derived from licensed software.
  61.  *
  62.  * Permission is granted to freely use, copy, modify, and redistribute
  63.  * this software, provided that no attempt is made to gain profit from it,
  64.  * the author is not construed to be liable for any results of using the
  65.  * software, alterations are clearly marked as such, and this notice is
  66.  * not modified.
  67.  *
  68.  *    Modified by Patrick Wolfe (pat@kai.com, kailand!pat)
  69.  *    Do whatever you want with (my modifications of) this program, but
  70.  *    don't claim you wrote them, don't try to make money from them, and
  71.  *    don't remove this notice.
  72.  */
  73.  
  74. /*
  75.  *    Beginning of User Configuration Section
  76.  */
  77.  
  78. /*
  79.  * SEQUENT   -- your host system is Sequent. This changes a setvbuf()
  80.  *              call to a setlinebuf(). [Suggested by Peter Newton 
  81.  *              <newton@cs.utexas.edu>]
  82.  *
  83.  */
  84. #undef SEQUENT
  85.  
  86.  
  87. /*
  88.  * GETTTYENT -- your system has the new format /etc/ttys (like 4.3 BSD)
  89.  *              and the getttyent(3) library functions.
  90.  *
  91.  */
  92. #undef GETTTYENT
  93.  
  94.  
  95. /*
  96.  * LOGINDEFAULT -- if set to 1 (one), windows will login (add entries to
  97.  *                 /etc/utmp) by default.  Set to 0 if you don't want this.
  98.  *                 (Also see USERLIMIT below). [NOTE: current code always
  99.  *                 logs layer #1 only unless -l option used on 'layers'
  100.  *                 command.]
  101.  */
  102. #define LOGINDEFAULT 0
  103.  
  104. /*
  105.  * USERLIMIT  --   count all non-null entries in /etc/utmp before adding a 
  106.  *                   new entry. Some machine manufacturers (incorrectly) count 
  107.  *                   logins by counting non-null entries in /etc/utmp (instead 
  108.  *                   of counting non-null entries with no hostname and not on 
  109.  *                   a pseudo tty). Sequent does this, so you might reach your 
  110.  *                   limited user license early.
  111.  */
  112. #define USRLIMIT 32
  113.  
  114. /*
  115.  * SOCKDIR      -- If defined, this directory is where layers sockets will be 
  116.  *                   placed, (actually in a subdirectory by the user's loginid).
  117.  *                   This is neccessary because NFS doesn't support socket 
  118.  *                   operations, and many people's homes are on NFS mounted 
  119.  *                   partitions.  Layers will create this directory if it needs 
  120.  *                   to.
  121.  */
  122. #define SOCKDIR "/tmp/layers"    /* NFS doesn't support named sockets */
  123.  
  124. /*
  125.  *    End of User Configuration Section
  126.  */
  127.  
  128. #include <stdio.h>
  129. #include <sgtty.h>
  130. #include <signal.h>
  131. #include <errno.h>
  132. #include <ctype.h>
  133. #include <utmp.h>
  134. #include <pwd.h>
  135. #include <nlist.h>
  136. #include <fcntl.h>
  137. #include <sys/types.h>
  138. #include <sys/time.h>
  139. #include <sys/file.h>
  140. #include <sys/wait.h>
  141. #include <sys/socket.h>
  142. #include <sys/un.h>
  143. #include <sys/stat.h>
  144. #include <sys/dir.h>
  145. #include <sys/ioctl.h>
  146.  
  147. #include "layers.h"
  148.  
  149. #ifdef GETTTYENT
  150. #include <ttyent.h>
  151. #else
  152. static struct ttyent
  153.   { char *ty_name;
  154.   } *getttyent();
  155. static char *tt, *ttnext;
  156. static char ttys[] = "/etc/ttys";
  157. #endif
  158.  
  159. #ifndef FSCALE
  160. #define FSCALE 1000.0        /* Sequent doesn't define FSCALE...grrrr */
  161. #endif
  162.  
  163. #ifdef  USRLIMIT
  164. struct utmp utmpbuf;
  165. int UserCount;
  166. #endif
  167.  
  168. #define Ctrl(c) ((c)&037)
  169.  
  170. /* C library items */
  171. extern char **environ;
  172. extern errno;
  173. extern sys_nerr;
  174. extern char *sys_errlist[];
  175. extern char *index(), *rindex(), *malloc(), *getenv();
  176. extern char *getlogin(), *ttyname();
  177.  
  178. /* Local items */
  179. static void FAbort(), SigHup(), SigChld(), AddCap(), FinitTerm();
  180. static char  *MakeTermcap(), *Filename(), **SaveArgs(), *GetTtyName();
  181. static void    InitWorld(), ClearShape(), BuildTitle(), KillPG();
  182. static void SetWindowSize(), WriteUtmp();
  183. static int    ReadUtmp(), FindUtmp(), SetUtmp();
  184.  
  185. static int    loginflag = -1;
  186. static char PtyName[32], TtyName[32];
  187. static char *ShellProg;
  188. static char *ShellArgs[2];
  189. static inlen;
  190. static ESCseen;
  191. static GotSignal;
  192. static char DefaultShell[] = "/bin/sh";
  193. static char DefaultPath[] = ":/usr/ucb:/bin:/usr/bin";
  194. static char PtyProto[] = "/dev/ptyXY";
  195. static char TtyProto[] = "/dev/ttyXY";
  196. static int TtyMode = 0622;
  197. static struct stat RealTtyStat;                    /* Real tty stat */
  198. static char RealTtyName[32] = "";                /* Real tty name */
  199. static int    RealSlot = 0;                        /* Real tty logon slot */
  200. static struct utmp    RealUtmp;                    /* Real tty logon utmp entry */
  201. static int    RealTtyMode = 0;                    /* Real tty mode */
  202. static int    Oumask;                                /* Original user's umask */
  203. static char SockPath[512];
  204. #ifdef SOCKDIR
  205. static char SockDir[] = SOCKDIR;
  206. #else
  207. static char SockDir[] = ".layers";
  208. #endif
  209. static char *SockNamePtr, *SockName;
  210. static ServerSocket;
  211. static char *NewEnv[MAXARGS];
  212. static char Esc = Ctrl('a');
  213. static char MetaEsc = 'a';
  214. static char *home;
  215. static Abortonmsg;
  216. static utmp, utmpf;
  217. static char UtmpName[] = "/etc/utmp";
  218. static char *LoginName;
  219. static mflag, nflag, fflag, rflag;
  220. static char HostName[MAXSTR];
  221. static char *myname;
  222. static DevTty;
  223.  
  224. static struct mode {
  225.     struct sgttyb m_ttyb;
  226.     struct tchars m_tchars;
  227.     struct ltchars m_ltchars;
  228.     int m_ldisc;
  229.     int m_lmode;
  230. } OldMode, NewMode;
  231.  
  232. #define MSG_CREATE    0
  233. #define MSG_ERROR     1
  234.  
  235. struct msg
  236.   {
  237.     int type;
  238.     union
  239.       { struct
  240.           {    int    lflag;                /* login flag */
  241.             struct Shape shape;        /* window shape */
  242.             int nargs;
  243.             char line[MAXLINE];
  244.             char dir[1024];
  245.           } create;
  246.         char message[MAXLINE];
  247.       } m;
  248.   };
  249.  
  250.  
  251.             /* dynamic keyboard input buffer definition */
  252. struct Kbuff
  253.   {    struct Kbuff * next;            /* next buffer in chain (or NULL) */
  254.     int            size;                /* size of data in this buffer */
  255.     int            offset;                /* start of first data in buffer */
  256.     unsigned char text[IOSIZE];        /* text buffer itself */
  257.   };
  258.  
  259.             /* World layer definition */
  260. struct Layer {
  261.     int        chan;                    /* channel represented by this layer */
  262.     int        allocated;                /* layer allocated */
  263.     int        ptyfd;                    /* psuedo tty */
  264.     int        ptymask;                /* mask for pty descriptor */
  265.     int        lpid;                    /* layer head process ID */
  266.     int        slot;                    /* utmp slot number */
  267.     struct Kbuff *kbuff;            /* keyboard input buffers */
  268.     struct Shape shape;                /* Shape structure to/from MacLayers */
  269.     char    cmd[MAXSTR];            /* command to execute */
  270.     char    tty[MAXSTR];            /* psuedo tty ID */
  271.     };
  272.  
  273. static struct Layer World[MAXPCHAN]; /* all layer structures */
  274.  
  275. static int rows = 24;                /* default window height in lines */
  276. static int cols = 80;                /* default window width in chars */
  277. static char Termcap[1024];
  278. static char Term[MAXSTR] = "TERM=";    /* window's terminal type */
  279. static char    *UserTerm;                /* terminal ID we are mimmicing */
  280. static int flowctl;
  281. static tcLineLen = 100;
  282.  
  283. /* co#80 and li$24 added dynamically for proper window size */
  284. static char TermcapConst1[] = "TERMCAP=SC|";
  285. static char TermcapConst3[] = "|MacLayers virtual terminal|\\\n\
  286.     :cr=^M:do=^J:nl=^J:bl=^G:cl=\\E[;H\\E[2J:\\\n\
  287.     :le=^H:bs:am:cm=\\E[%i%d;%dH:nd=\\E[C:up=\\E[A:\\\n\
  288.     :ce=\\E[K:cd=\\E[J:so=\\E[7m:se=\\E[m:us=\\E[4m:ue=\\E[m:\\\n\
  289.     :md=\\E[1m:mr=\\E[7m:mb=\\E[5m:me=\\E[m:is=\\E[1;24r\\E[24;1H:\\\n\
  290.     :rf=/usr/lib/tabset/vt100:\\\n\
  291.     :rs=\\E>\\E[?3l\\E[?4l\\E[?5l\\E[?7h\\E[?8h:ks=\\E[?1h\\E=:ke=\\E[?1l\\E>:\\\n\
  292.     :ku=\\EOA:kd=\\EOB:kr=\\EOC:kl=\\EOD:kb=^H:\\\n\
  293.     :ho=\\E[H:k1=\\EOP:k2=\\EOQ:k3=\\EOR:k4=\\EOS:ta=^I:pt:sr=\\EM:vt#3:xn:\\\n\
  294.     :sc=\\E7:rc=\\E8:cs=\\E[%i%d;%dr:\\\n\
  295.     :dc=\\ED:ic=\\EI:";
  296. /* NOTE: the above two cababilities are beyond vt100 - unique to MacLayers */
  297.  
  298. int        Dflag;                            /* debug dump flag */
  299.  
  300.                             /* main() */
  301. main(ac, av)
  302. char **av;
  303. {
  304.     register n;
  305.     register len;
  306.     register struct Layer *layer;
  307.     char    *ap;
  308.     struct passwd *ppp;
  309.     int        s;
  310.     int        r;                            /* read fd test bits */
  311.     int        w;                            /* write fd test bits */
  312.     int        stall;                        /* stall flag for priority channel */
  313.     int        fderr;                        /* error fd test bits */
  314.     struct timeval tv;
  315.     struct Shape shape;                    /* window shape */
  316.     time_t    now;
  317.     char    buf[IOSIZE];
  318.     char    rc[256];
  319.     struct stat st;
  320.     struct Kbuff *kbptr;                /* input keyboard buffer pointer */
  321.  
  322.     Abortonmsg = 1;                        /* quit if message generated */
  323.     ClearShape(&shape);                    /* initialize shape structure */
  324.     myname = (ac == 0) ? "layers" : av[0];
  325.     InitWorld();                        /* clear World array structures */
  326.  
  327.     while (ac > 0)
  328.       {    ap = *++av;
  329.         if (--ac > 0 && *ap == '-')
  330.           {    switch (ap[1])
  331.             { case 'l':        /* login this command line */
  332.                 loginflag = 1;
  333.                 break;
  334.  
  335.               case 'd':        /* dump debugging flag */
  336.                 Dflag = 1;
  337.                 (void) freopen("layers.dump", "a", stderr); /* append mode */
  338. #ifdef SEQUENT
  339.                 setlinebuf(stderr);
  340. #else
  341.                 setvbuf(stderr, NULL, _IOLBF, 0);
  342. #endif
  343.                 break;
  344.  
  345.               case 'u':        /* do not login this command line */
  346.                 loginflag = 0;
  347.                 break;
  348.  
  349.               case 'm':        /* force this to be master and not a client */
  350.                 mflag = 1;
  351.                 break;
  352.  
  353.               case 'n':        /* no flow control */
  354.                 nflag = 1;
  355.                 break;
  356.  
  357.               case 'f':        /* flow control on */
  358.                 fflag = 1;
  359.                 break;
  360.  
  361.               case 'v':        /* do nothing but issue layers version */
  362.                 printf("%s\n", LayersVersion);
  363.                 exit(0);
  364.  
  365.               default:
  366.             help:
  367.                 Msg (0,"Use: %s [-f] [-l | -u] [-m] [-n] [cmd args]\n", myname);
  368.  
  369.             } /* end switch on '-' option */
  370.  
  371.         } /* end if '-' */
  372.  
  373.         else
  374.             break;
  375.  
  376.       } /* end while parameters */
  377.  
  378.     if (nflag && fflag)
  379.         Msg (0, "-f and -n are conflicting options.");
  380.  
  381.     if ((ShellProg = getenv ("SHELL")) == 0)
  382.         ShellProg = DefaultShell;
  383.     DO DEBUG("ShellProg %s\n", ShellProg);
  384.  
  385.     /* we mimmic the user's $TERM ID */
  386.     if ((UserTerm = getenv("TERM")) == 0)
  387.         UserTerm = "layers";                /* use "layers" if none */
  388.     (void) strcat(Term, UserTerm);
  389.     DO DEBUG("%s\n", Term);
  390.  
  391.     ShellArgs[0] = ShellProg;
  392.     if (ac == 0)
  393.       { ac = 1;
  394.         av = ShellArgs;
  395.         shape.wattr |= Wa_shell;            /* indicate a shell window */
  396.       }
  397.  
  398.     if ((home = getenv ("HOME")) == 0)
  399.         Msg (0, "$HOME is undefined.");
  400.     DO DEBUG("home %s\n", home);
  401.  
  402.     if ((LoginName = getlogin ()) == 0 || LoginName[0] == '\0')
  403.       { if ((ppp = getpwuid (getuid ())) == 0)
  404.                return;
  405.         LoginName = ppp->pw_name;
  406.       }
  407.     DO DEBUG("LoginName %s\n", LoginName);
  408.  
  409.     if ((Oumask=umask(0)) == -1)
  410.         Msg (errno, "Cannot change umask to zero");
  411.     DO DEBUG("Original umask o%o\n", Oumask);
  412.  
  413. #ifdef SOCKDIR
  414.     if (stat (SOCKDIR, &st) == -1)
  415.       {    if (errno == ENOENT)
  416.           { if (mkdir (SOCKDIR, 0777) == -1)
  417.                 Msg (errno, "Cannot make directory %s", SOCKDIR);
  418.             (void) chown (SOCKDIR, 0, 0);
  419.           }
  420.         else
  421.             Msg (errno, "Cannot get status of %s", SOCKDIR);
  422.       }
  423.     else
  424.       { if ((st.st_mode & S_IFMT) != S_IFDIR)
  425.             Msg (0, "%s is not a directory.", SOCKDIR);
  426.         if ((st.st_mode & 0777) != 0777)
  427.             Msg (0, "Directory %s must have mode 777.", SOCKDIR);
  428.       }
  429.     sprintf (SockPath, "%s/%s", SockDir, LoginName);
  430. #else
  431.     sprintf (SockPath, "%s/%s", home, SockDir);
  432. #endif
  433.     DO DEBUG("SockPath %s\n", SockPath);
  434.  
  435.     if (stat (SockPath, &st) == -1)
  436.       { if (errno == ENOENT)
  437.           { if (mkdir (SockPath, 0700) == -1)
  438.                 Msg (errno, "Cannot make directory %s", SockPath);
  439.             (void) chown (SockPath, getuid (), getgid ());
  440.             DO DEBUG("SockPath directory made\n");
  441.           }
  442.         else
  443.             Msg (errno, "Cannot get status of %s", SockPath);
  444.       }
  445.     else
  446.       { if ((st.st_mode & S_IFMT) != S_IFDIR)
  447.                Msg (0, "%s is not a directory.", SockPath);
  448.         if ((st.st_mode & 0777) != 0700)
  449.             Msg (0, "Directory %s must have mode 700.", SockPath);
  450.         if (st.st_uid != getuid ())
  451.             Msg (0, "You are not the owner of %s.", SockPath);
  452.       }
  453.  
  454.     (void) strcpy(RealTtyName, GetTtyName());        /* real tty name */
  455.     if (stat(RealTtyName, &RealTtyStat) == -1)        /* get current mode */
  456.         Msg(errno, "Cannot get status of %s", RealTtyName);
  457.     DO DEBUG("Mode of %s is %#o\n", RealTtyName, RealTtyStat.st_mode);
  458.     RealTtyMode = RealTtyStat.st_mode;        /* save mode for later restore */
  459.  
  460.     (void) gethostname (HostName, MAXSTR);
  461.     HostName[MAXSTR-1] = '\0';
  462.     DO DEBUG("HostName %s\n", HostName);
  463.  
  464.     if (ap = index (HostName, '.'))
  465.         *ap = '\0';
  466.     if (ap)
  467.         DO DEBUG("*ap %s\n", *ap);
  468.  
  469.     strcat (SockPath, "/");
  470.     SockNamePtr = SockPath + strlen (SockPath);
  471.  
  472.     /* if we are a client send create message to startup window and exit */
  473.     if (GetSockName ())
  474.       {    DO DEBUG("GetSockName says that we are client\n");
  475.         DO DEBUG("SockName '%s'\n", SockName);
  476.         s = MakeClientSocket (1);
  477.         DO DEBUG("Client socket is %d\n", s);
  478.         DO DEBUG("SendCreateMsg()\n");
  479.         SendCreateMsg (s, ac, av, loginflag, &shape);
  480.         close (s);
  481.         DO DEBUG("after SendCreateMsg(), now exit(0)\n");
  482.         exit (0);
  483.       }
  484.  
  485.     /* we are the server */
  486.     DO DEBUG("SockName '%s'\n", SockName);
  487.     DO DEBUG("We are server\n");
  488.     if ((DevTty = open ("/dev/tty", O_RDWR|O_NDELAY)) == -1)
  489.         Msg (errno, "/dev/tty");
  490.     DO DEBUG("opened /dev/tty fd %d\n", DevTty);
  491.  
  492.     ServerSocket = MakeServerSocket ();
  493.     DO DEBUG("ServerSocket %d\n", ServerSocket);
  494.     s = ServerSocket;
  495.  
  496.     if (fflag)
  497.         flowctl = 1;
  498.     else
  499.     if (nflag)
  500.         flowctl = 0;
  501.  
  502.     if (loginflag == -1)
  503.         loginflag = LOGINDEFAULT;
  504.  
  505.     MakeNewEnv ();
  506.     InitUtmp ();
  507.     RealSlot = FindUtmp(RealTtyName);    /* find current logon slot */
  508.     if (RealSlot)
  509.       {    if (ReadUtmp(RealSlot, &RealUtmp) > 0)    /* read real login utmp */
  510.             RemoveUtmp(RealSlot);        /* remove original logon slot */
  511.         else
  512.             RealSlot = 0;                /* something's wrong */
  513.       }
  514.  
  515.     signal (SIGHUP, SigHup);
  516.     signal (SIGINT, SIG_IGN);            /* we should never see this */
  517.     signal (SIGQUIT, FAbort);            /* quit layers on these 2 signals */
  518.     signal (SIGTERM, FAbort);
  519.     signal (SIGTTIN, SIG_IGN);
  520.     signal (SIGTTOU, SIG_IGN);
  521.     signal (SIGALRM, SIG_IGN);            /* alarm clock used by protocol.c */
  522.  
  523.     GetTTY (0, &OldMode);
  524.     SetMode (&OldMode, &NewMode);
  525.     SetTTY (0, &NewMode);
  526.  
  527.     if (Initlink() == 0)
  528.       {    SetTTY(0, &OldMode);            /* revert tty back */
  529.         Msg (0, "\n\n  You are not running under MacLayers.");
  530.       }
  531.         
  532.     sprintf (rc, "%.*s/.layersrc", 245, home);
  533. #if 0 /* NOT YET SUPPORTED */
  534.     /* if no window list start up a default shell window */
  535.     if (ReadRc(rc) == 0)            
  536. #endif
  537.       {    n = MakeWindow (0, *av, av, (char *)0, loginflag, &shape);
  538.         if (n == -1)
  539.             { SetTTY (0, &OldMode);
  540.             FQuit(1);
  541.             /* NOT REACHED */
  542.             }
  543.       }
  544.  
  545.     (void) chmod(RealTtyName, 0600);        /* lock out broadcasts */
  546.     Abortonmsg = 0;                            /* don't abort on msg from now on */
  547.     signal (SIGCHLD, SigChld);
  548.     tv.tv_usec = 0;
  549.     tv.tv_sec = 0;                            /* default no timer wanted */
  550.  
  551.     /* client/Maclayers processing loop */
  552.  
  553.     /* poll .20 secs for new startups */
  554. #define WUSSTARTUP    200000                
  555.     /* stall nonpriority windows .5 seconds when top window I/O active */
  556. #define WUSSTALL    500000
  557.  
  558.     stall = 0;                                /* startout no stalled channels */
  559.     fderr = 0;                                /* startout no error fd's */
  560.  
  561.     while (1)
  562.       {    int            priochan;                /* the top window channel */
  563.  
  564.         priochan = TopChannel();            /* find highest priority channel */
  565.  
  566.         /* check for I/O on all available I/O descriptors */
  567.         r = 1<<0;                            /* always read MacLayers stream */
  568.         r |= 1<<s;                            /* always read server socket */
  569.         w = 0;                                /* initalize to no write tests */
  570.         tv.tv_usec = 0;                        /* default no startup poll */
  571.  
  572.         /* for all active layers set read and write bits as appropriate */
  573.         if (stall)
  574.             stall = 1;                        /* start counting output layers */
  575.         for (n=0; n<MAXPCHAN; n++)
  576.          if ((layer = &World[n])->allocated) /* if layer exists ... */
  577.           {    /* if not yet started or has just terminated ... */
  578.             if (layer->ptymask & fderr)
  579.                 tv.tv_usec = WUSSTARTUP;    /* don't spinloop but wait-a-bit */
  580.             else
  581.                 {    if (layer->kbuff && layer->kbuff->size)
  582.                     /* keyboard input for layer */
  583.                     w |= layer->ptymask;    /* try write to it */
  584.                 /* read layer output unless we're being nice to top window */
  585.                 if (!stall)
  586.                     r |= layer->ptymask;    /* read output from layer */
  587.                 else
  588.                 if (layer->chan == priochan)
  589.                     r |= layer->ptymask;    /* read top priority output */
  590.                 else
  591.                     stall++;                /* indicate something to stall */
  592.                }
  593.             }
  594.  
  595.         if (stall > 1)
  596.             if (!tv.tv_usec)
  597.                 tv.tv_usec = WUSSTALL;        /* set stall timout */
  598.  
  599.         /* process signals before trying select */
  600.         if (GotSignal)
  601.           { SigHandler ();
  602.             continue;
  603.           }
  604.  
  605.         DO DEBUG("Select(r %x, w %x, fderr %x, stall %d, prio %d, us %d)\n",
  606.                     r, w, fderr, stall, priochan, tv.tv_usec);
  607.  
  608.         switch ( select(32, &r, &w, NULL, tv.tv_usec ? &tv : NULL) )
  609.         { case -1:
  610.             /* errno has report */
  611.             if (errno == EINTR)                /* signal delivered or timout */
  612.               { errno = 0;
  613.                 tv.tv_usec = 0;                /* clear timer wait value */
  614.                 fderr = 0;                    /* turn off error stall */
  615.                 stall = 0;                    /* turn off output priority stall */
  616.                 DO DEBUG("select errno EINTR\n");
  617.                 continue;                    /* re-loop */
  618.               }
  619.             Abortonmsg = 1;
  620.             DO DEBUG("select errno %d\n", errno);
  621.             Msg (errno, "select");
  622.             /*NOTREACHED*/
  623.  
  624.           case 0:
  625.             /* timeout reached */
  626.             tv.tv_usec = 0;                    /* clear timer wait value */
  627.             stall = 0;                        /* turn off stall */
  628.             fderr = 0;                        /* turn off error stall */
  629.             continue;                        /* re-loop */
  630.  
  631.           default:
  632.             /* a channel has read/write status pending */
  633.             break;
  634.         }
  635.  
  636.         DO DEBUG("after select r %x w %x\n", r, w);
  637.  
  638.         /* handle any signal arriving up during select wait */
  639.         if (GotSignal)
  640.           { SigHandler ();
  641.             continue;
  642.           }
  643.  
  644.         /* if server socket has command process that now */
  645.         if (r & 1 << s)
  646.           {    ReceiveMsg(s);                    /* process client control packet */
  647.             continue;                        /* status may have changed */
  648.           }
  649.  
  650.         /* next process input stream from MacLayers */
  651.         if (r & 1 << 0)
  652.           { ProcessStreamin();                /* key input and control packets */
  653.             continue;                        /* status may have changed */
  654.           }
  655.  
  656.         /* process keyboard input first so output doesn't hold up
  657.         ** keyboard echo and break/interrupt processing
  658.         */
  659.         priochan = TopChannel();            /* find top priority channel */
  660.         stall = 0;                            /* assume no stall needed */
  661.         for (n=0; n<MAXPCHAN; n++)
  662.           if ((layer = &World[n])->allocated)
  663.             if (w & layer->ptymask)
  664.                 while ((kbptr=layer->kbuff)->size)
  665.                   {    /* pass as much keyboard as possible */
  666.                     if (layer->chan == priochan)
  667.                         stall = 1;            /* stall lower priority channels */
  668.                     len = write(layer->ptyfd, &kbptr->text[kbptr->offset],
  669.                                  kbptr->size);
  670.                     DO DEBUG("keyin len %d to chan %d\n", len, layer->chan);
  671.                     if (len <= 0)            /* if no data accepted ... */
  672.                       {    if (errno == EIO)    /* if I/O error indicated ... */
  673.                             fderr |= layer->ptymask; /* wait-a-bit on this */
  674.                         errno = 0;            /* clear errno */
  675.                         break;                /* try again later */
  676.                       }
  677.                     /* some of buffer accepted */
  678.                     kbptr->size -= len;        /* length processed */
  679.                     kbptr->offset += len;    /* bump up offset */
  680.                     if (kbptr->size > 0)    /* not all buffer accepted ... */
  681.                         break;                /* try feed again later */
  682.                     /* see if another buffer chained */
  683.                     if (kbptr->next)
  684.                       {    /* yes, free up current buffer and queue next */
  685.                         layer->kbuff = kbptr->next; /* to next buffer */
  686.                         free(kbptr);    /* free this buffer up */
  687.                       }
  688.                     else
  689.                       {    /* otherwise leave this for next input */
  690.                         kbptr->size = 0;    /* empty buffer */
  691.                         kbptr->offset = 0;    /* refill from the start */
  692.                       }
  693.                   }
  694.  
  695.         /* first process the highest priority channel (top window) */
  696.         if (priochan > 0 && priochan <= MAXPCHAN) /* if valid ... */
  697.           if ((layer = &World[priochan-1])->allocated)
  698.             if (r & layer->ptymask)
  699.               {    /* output to send to top MacLayers window */
  700.                 len = read(layer->ptyfd, buf, IOSIZE);
  701.                 if (len >= 0)                /* if no error ... */
  702.                   {    DO DEBUG("read output len %d chan %d\n", len, layer->chan);
  703.                   }
  704.                 else
  705.                   {    /* We expect EIO error if socket not yet open on other end
  706.                     ** or if process using socket has terminated. We expect
  707.                     ** EWOULDBLOCK also after process terminates.
  708.                     **/
  709.                     DO DEBUG("read output err chan %d errno %d len %d\n",
  710.                                 layer->chan, errno, len);
  711.                     if (errno == EIO || errno == EWOULDBLOCK)
  712.                         DO DEBUG(" ...anticipated\n");
  713.                     /* layer not ready or just terminated so wait-a-bit */
  714.                     fderr |= layer->ptymask;
  715.                     r &= ~layer->ptymask; /* don't read it again below */
  716.                     errno = 0;                /* clear errno */
  717.                   }
  718.                 if (len > 0)
  719.                     SendData(layer->chan, buf, len);
  720.  
  721.                 if (len >= 0)
  722.                     /* To keep lower priority channels from hogging the line
  723.                     ** we delay any output from them until the primary window 
  724.                     ** has no more data to be sent to it.
  725.                     */
  726.                     stall = 1;                /* stall output from others */
  727.               }
  728.  
  729.         /* now pass all available output to MacLayers */
  730.         if (!stall)
  731.          for (n=0; n<MAXPCHAN; n++)
  732.           if ((layer = &World[n])->allocated)
  733.             if (r & layer->ptymask)
  734.               {    /* output to send to MacLayers window */
  735.                 len = read(layer->ptyfd, buf, IOSIZE);
  736.                 if (len >= 0)                /* if no error ... */
  737.                   {    DO DEBUG("output chan %d len %d\n", layer->chan, len);
  738.                   }
  739.                 else
  740.                   {    /* We expect EIO error if socket not yet open on other end
  741.                     ** or if process using socket has terminated. We expect
  742.                     ** EWOULDBLOCK also after process terminates.
  743.                     **/
  744.                     DO DEBUG("read output err chan %d errno %d len %d\n",
  745.                                 layer->chan, errno, len);
  746.                     if (errno == EIO || errno == EWOULDBLOCK)
  747.                       {    DO DEBUG(" ...anticipated\n");
  748.                       }
  749.                     /* layer not ready or just terminated so wait-a-bit */
  750.                     fderr |= layer->ptymask;
  751.                     errno = 0;                /* clear errno */
  752.                   }
  753.                 if (len > 0)
  754.                     SendData(layer->chan, buf, len);
  755.               }
  756.  
  757.         /* handle signals again */
  758.         if (GotSignal)
  759.             SigHandler ();
  760.  
  761.       } /* end while (1) */
  762.  
  763.     /* NOT REACHED */
  764.  
  765. } /* main() */
  766.  
  767.                     /* ReceiveQuit() - MacLayers sends Quit packet */
  768.  
  769. void
  770. ReceiveQuit()
  771. {
  772.     /* We completely quit layers cancelling all active processes */
  773.     DO DEBUG("ReceiveQuit()\n");
  774.     FQuit(0);                                /* normal termination */
  775.     /* NOT REACHED */
  776.  
  777. } /* ReceiveQuit() */
  778.  
  779.  
  780.                 /* ReceiveNew() - MacLayers requests a new shell layer */
  781.  
  782. void
  783. ReceiveNew(chanid, shape)
  784. int        chanid;                                /* channel for new shell layer */
  785. struct Shape *shape;                        /* shape for new channel */
  786. {
  787.     DO DEBUG("ReceiveNew(%d)\n", chanid);
  788.     (void) MakeWindow (chanid, *ShellArgs, ShellArgs,
  789.                     (char *) 0, loginflag, shape);
  790.  
  791. } /* ReceiveNew() */
  792.  
  793.  
  794.                 /* ReceiveDelete() - MacLayers has removed a layer */
  795. void
  796. ReceiveDelete(chanid)
  797. int        chanid;                                /* channel which was deleted */
  798. {
  799.     struct Layer *layer;                    /* layer pointer */
  800.  
  801.     /* validate channel */
  802.     DO DEBUG("ReceiveDelete(%d)\n", chanid);
  803.     if (chanid <= 0 || chanid > MAXPCHAN)
  804.         return;                                /* ignore invalid channel */
  805.  
  806.     /* if this layer active then kill it off, else ignore request */
  807.     layer = &World[chanid-1];                /* locate target layer */
  808.     if (layer->allocated)
  809.         KillWindow(layer);
  810.  
  811. } /* ReceiveDelete() */
  812.     
  813.     
  814.         /* ReceiveSignal() - send signal to layer's process group */
  815.  
  816. void
  817. ReceiveSignal(chanid, signal)
  818. int            chanid;                            /* layer's channel */
  819. int            signal;                            /* signal.h signal ID */
  820. {
  821.     struct Layer *layer;                    /* layer pointer */
  822.  
  823.     DO DEBUG("ReceiveSignal(%d,%d)\n", chanid, signal);
  824.     /* verify channel */
  825.     if (chanid <= 0 || chanid > MAXPCHAN)
  826.         return;                                /* ignore invalid channel */
  827.  
  828.     /* if this layer is active send the signal to the process group */
  829.     layer = &World[chanid-1];                /* locate target layer */
  830.     if (layer->allocated && layer->lpid)
  831.         KillPG(layer, signal);
  832.  
  833. } /* ReceiveSignal() */
  834.  
  835.  
  836.                 /* ReceiveReshape() - windowsize and location updated */
  837. void
  838. ReceiveReshape(chanid, shape)
  839. int                chanid;                    /* channel having shape */
  840. struct Shape    *shape;                    /* shape structure */
  841. {
  842.     struct Layer *layer;                /* layer pointer */
  843.  
  844.     DO DEBUG("ReceiveReshape(%d)\n", chanid);
  845.  
  846.     /* verify channel */
  847.     if (chanid <= 0 || chanid > MAXPCHAN)
  848.         return;                                /* ignore invalid channel */
  849.  
  850.     /* if this layer is active then reshape it's window */
  851.     layer = &World[chanid-1];                /* locate target layer */
  852.     if (layer->allocated && layer->lpid)
  853.       {    layer->shape = *shape;                /* install as our new shape */
  854.         SetWindowSize(layer);                /* udpate the O/S window info */
  855.       }
  856.  
  857. } /* ReceiveReshape() */
  858.  
  859.  
  860.             /* SetWindowSize() - tell O/S about new window size */
  861.  
  862. static void
  863. SetWindowSize(layer)
  864. struct Layer    *layer;                    /* layer to resize */
  865. {
  866. #ifdef TIOCSWINSZ
  867.     struct    winsize    wsize;                /* window size structure */
  868.     int            retcode;                /* ioctl return code */
  869.  
  870.     wsize.ws_col = layer->shape.wchars; /* character width */
  871.     wsize.ws_row = layer->shape.wlines; /* window height */
  872.     wsize.ws_xpixel = 0;                /* necessary? */
  873.     wsize.ws_ypixel = 0;
  874.     /* update O/S window state */
  875.     retcode = ioctl(layer->ptyfd, TIOCSWINSZ, &wsize);
  876.     DO DEBUG("SetWindowSize(chan %d) col %d, row %d iotcl() = %d\n",
  877.             layer->chan, layer->shape.wchars, layer->shape.wlines,
  878.             retcode);
  879.  
  880.     retcode = ioctl(layer->ptyfd, TIOCGWINSZ, &wsize);
  881.     DO DEBUG("TIOCGWINSZ: col %d, row %d iotcl() = %d\n",
  882.             wsize.ws_col, wsize.ws_row, retcode);
  883.  
  884. #endif
  885. }  /* SetWindowSize() */
  886.  
  887.  
  888.                 /* ReceiveData() - received keyboard input for layer */
  889. void
  890. ReceiveData(chanid, buff, cnt)
  891. int        chanid;                            /* channel receiving input */
  892. char    *buff;                            /* buffer containing data */
  893. int        cnt;                            /* count of data bytes */
  894. {
  895.     struct Layer *layer;                /* layer pointer */
  896.     struct Kbuff *kb;                    /* keybuff pointer */
  897.  
  898.     DO DEBUG("ReceiveData(%d, '%.*s')\n", chanid, cnt, buff);
  899.     /* verify channel */
  900.     if (chanid <= 0 || chanid > MAXPCHAN)
  901.         return;                                /* ignore invalid channel */
  902.     layer = &World[chanid-1];                /* locate target layer */
  903.  
  904.     /* add character stream to layer's input buffers for main loop processing */
  905.     for (kb=layer->kbuff; kb->next; kb=kb->next); /* find oldest buffer */
  906.     while (cnt--)
  907.       {    
  908.         /* if current buffer full then chain in a new one */
  909.         if (kb->offset+kb->size >= IOSIZE)
  910.           { kb->next = (struct Kbuff *) malloc(sizeof(struct Kbuff));
  911.             kb = kb->next;                    /* base new keybuff */
  912.             kb->next = NULL;                /* no next yet */
  913.             kb->size = 0;                    /* this character is first */
  914.             kb->offset = 0;                    /* at zero offset */
  915.           }
  916.  
  917.         /* add new character to the end of this buffer */
  918.         kb->text[kb->offset+kb->size++] = *buff++; /* insert at end of data */
  919.       }
  920.  
  921. } /* ReceiveData() */
  922.  
  923.  
  924.  
  925.                     /* InitWorld() - initialize layer structures */
  926.  
  927. static void
  928. InitWorld()
  929. {
  930.     struct Layer *layer;                /* layer pointer */
  931.     struct Kbuff *kb;                    /* keybuff pointer */
  932.     int        i;                            /* work variable */
  933.  
  934.     for (i=0; i<MAXPCHAN; i++)
  935.       {    layer = &World[i];                /* point to layer */
  936.         layer->chan = i+1;                /* channel ID */
  937.         layer->allocated = 0;            /* does not exist yet */
  938.         layer->lpid = 0;                /* head process */
  939.         layer->ptyfd = 0;                /* no pseduo pty yet */
  940.         layer->ptymask = 0;                /* no pty mask yet */
  941.         layer->slot = 0;                /* no Utmp slot */
  942.         ClearShape(&layer->shape);        /* clear shape structure */
  943.  
  944.         /* allocate the primary input keybuffer for this layer */
  945.         layer->kbuff = (struct Kbuff *) malloc(sizeof(struct Kbuff));
  946.         layer->kbuff->next = NULL;        /* no next buffer */
  947.         layer->kbuff->size = 0;            /* no data in buffer */
  948.         layer->kbuff->offset = 0;        /* start filling at front */
  949.  
  950.       } /* end for layer scan */
  951.  
  952. } /* InitWorld() */
  953.  
  954.  
  955.                     /* clearshape() - initialize shape structure */
  956.  
  957. static void
  958. ClearShape(shape)
  959. struct Shape    *shape;                    /* shape structure pointer */
  960. {
  961.     shape->worigv = 0;                    /* default window position */
  962.     shape->worigh = 0;
  963.     shape->wlines = 0;                    /* default size */
  964.     shape->wchars = 0;
  965.     shape->wfont = 0;                    /* default font size */
  966.     shape->wattr = 0;                    /* no attributes */
  967.  
  968. } /* clearshape() */
  969.  
  970.  
  971.                     /* SigHandler() - process signals */
  972.  
  973. SigHandler ()
  974. {
  975.     DO DEBUG("GotSignal()\n");
  976.     while (GotSignal)
  977.       { GotSignal = 0;
  978.         DoWait ();        /* handle dead or stopped children processes */
  979.       }
  980. }
  981.  
  982. static void
  983. SigChld ()
  984. {
  985.     DO DEBUG("SigChld()\n");
  986.     /* flag child process is stopped or dead */
  987.     GotSignal = 1;
  988. }
  989.  
  990. static void
  991. SigHup ()
  992. {
  993.     DO DEBUG("SigHup()\n");
  994.     /* Detach (0); */
  995.     FQuit(1);            /* stop all processes */
  996.     /* NOT REACHED */
  997.  
  998. }
  999.  
  1000.     /* DoWait() -  send SIGCONT to stopped windows, Free dead process windows */
  1001. static
  1002. DoWait()
  1003. {
  1004.     register pid;
  1005.     register struct Layer *layer;
  1006.     union wait wstat;
  1007.     int        i;
  1008.  
  1009.     DO DEBUG("DoWait()\n");
  1010.     while ((pid = wait3 (&wstat, WNOHANG|WUNTRACED, NULL)) > 0)
  1011.         /* dead or stopped child process found */
  1012.         for (i=0; i<MAXPCHAN; i++)
  1013.             if ((layer = &World[i])->lpid == pid)
  1014.               { if (WIFSTOPPED (wstat))
  1015.                   {    /* stopped process so restart it */
  1016.                     /*** DO WE REALLY NEED TO DO THIS? ***/
  1017.                     DO DEBUG("killpg(, SIGCONT)\n");
  1018.                     KillPG(layer, SIGCONT);
  1019.                   }
  1020.                 else
  1021.                   {    /* remove dead process's layer */
  1022.                     DO DEBUG("kill dead process window %d\n", layer->chan);
  1023.                      KillWindow (layer);
  1024.                     /* tell MacLayers layer is dead */
  1025.                     SendDelete(layer->chan);
  1026.                   }
  1027.               }
  1028.  
  1029. } /* DoWait() */
  1030.  
  1031.  
  1032.                 /* KillPG() - send signal to layer's process group */
  1033.  
  1034. static void
  1035. KillPG(layer, signal)
  1036. struct Layer    *layer;                    /* layer to signal */
  1037. int                signal;                    /* signal to send */
  1038. {
  1039.     int            retcode;                /* work variable */
  1040.     int            pgrp;                    /* process group for layer */
  1041.     int            tgrp;                    /* terminal control process group */
  1042.  
  1043.     DO DEBUG("KillPG(%d, sig %d)\n", layer->chan, signal);
  1044.  
  1045.     if (layer->lpid)
  1046.       {    pgrp = getpgrp(layer->lpid);    /* get process group */
  1047.         DO DEBUG("getpgrp() = %d\n", pgrp);
  1048.         if (pgrp != -1)
  1049.           {    retcode = killpg(pgrp, signal);    /* signal it */
  1050.             DO DEBUG("killpg() = %d\n", retcode);
  1051.           }
  1052.  
  1053.         /* After a lot of experimenting it was determined that csh
  1054.         ** creates a new terminal control group when it runs a command.
  1055.         ** Thus the above code failed to forward SIGINT to such commands.
  1056.         ** (Csh would get it but just ignore it.) Thus the following code.
  1057.         */ 
  1058.  
  1059.         /* forward SIGINT to the terminal control group also */
  1060.         if (signal == SIGINT)
  1061.           {    retcode = ioctl(layer->ptyfd, TIOCGPGRP, &tgrp);
  1062.             DO DEBUG("ioctl(ptyfd,TIOCGPGRP) termcntlgrp %d, retcode = %d\n",
  1063.                             tgrp, retcode);
  1064.             /* but only if not the same process group */
  1065.             if (retcode != -1 && tgrp != pgrp)
  1066.               {    retcode = killpg(tgrp, signal);    /* signal it */
  1067.                 DO DEBUG("killpg(%d) = %d\n", tgrp, retcode);
  1068.                 }
  1069.           }
  1070.       }
  1071.  
  1072. } /* KillPG() */
  1073.  
  1074.  
  1075.                 /* KillWindow() - remove a layer from the system */
  1076.  
  1077. /* Note: This function does NOT tell MacLayers about the dead layer */
  1078.  
  1079. static
  1080. KillWindow (layer)
  1081. struct Layer *layer;
  1082. {
  1083.     struct Kbuff    *kb;                /* work buffer free pointer */
  1084.  
  1085.     if (layer->allocated)
  1086.       {                                 /* SHOULD THIS BE SIGKILL ??? */
  1087.         if (layer->lpid)                /* if layer process started ... */
  1088.           {    KillPG(layer, SIGHUP);        /* kill processes */
  1089.             layer->lpid = 0;            /* clear pid field */
  1090.           }
  1091.         RemoveUtmp(layer->slot);
  1092.         (void) chmod(layer->tty, 0666);
  1093.         (void) chown(layer->tty, 0, 0);
  1094.         close(layer->ptyfd);
  1095.         DO DEBUG("chmod/chown %s, SendDelete(%d)\n",layer->tty, layer->chan);
  1096.  
  1097.         ClearShape(&layer->shape);        /* reset the shape structure */
  1098.         /* free all keybuffers but one and reprime it */
  1099.         for (kb=layer->kbuff; kb->next; kb=kb->next)
  1100.             free(kb);                    /* free input buffers */
  1101.         kb->size = 0;                    /* empty buffer */
  1102.         kb->offset = 0;                    /* start refill from front */
  1103.         layer->allocated = 0;            /* window no longer allocated */
  1104.       }
  1105.  
  1106. } /* KillWindow() */
  1107.  
  1108.  
  1109.                     /* FAbort() - signal catcher for quitting */
  1110. static void
  1111. FAbort()
  1112. {
  1113.     DO DEBUG("FAbort()\n");
  1114.     FQuit (1);                            /* quit with error exit */
  1115.  
  1116. } /* FAbort() */
  1117.  
  1118.  
  1119.                     /* FQuit() - terminate layers */
  1120. void
  1121. FQuit(exitcode)
  1122. int        exitcode;
  1123. {
  1124.     int            i;
  1125.  
  1126.     DO DEBUG("FQuit(%d)\n",exitcode);
  1127.     for (i=0; i<MAXPCHAN; i++)
  1128.         KillWindow(&World[i]);            /* kill all windows */
  1129.  
  1130.     DO DEBUG("SendQuit()\n");
  1131.     SendQuit();                            /* tell MacLayers to exit layers mode */
  1132.     SetTTY (0, &OldMode);
  1133.     if (RealTtyMode)
  1134.         (void) chmod(RealTtyName, RealTtyMode);    /* restore mode */
  1135.     if (RealSlot)
  1136.         WriteUtmp(RealSlot, &RealUtmp);    /* restore original login */
  1137.     FinitTerm ();
  1138.     sleep(2);                            /* wait for port to reset */
  1139.     printf ("[layers terminated]\n");
  1140.  
  1141.     exit (exitcode);
  1142.  
  1143. } /* FQuit() */
  1144.  
  1145.  
  1146.                     /* MakeWindow() - create new layer */
  1147. static
  1148. MakeWindow (chan, prog, args, dir, lflag, shape)
  1149. int        chan;                            /* zero or channel to use for window */
  1150. char    *prog;
  1151. char     **args;
  1152. char    *dir;
  1153. int        lflag;                            /* one if this to be logged in */
  1154. struct Shape *shape;                    /* shape to use for window */
  1155. {
  1156.     register struct Layer *layer;
  1157.     register char **cp;
  1158.     register f, j;
  1159.     int tf;
  1160.     int mypid;
  1161.     char ebuf[10];
  1162.  
  1163.     DO DEBUG("MakeWindow(%d, %s, %s, dir %s, ",
  1164.                 chan, prog, args[0], dir ? dir : "(none)");
  1165.     DO DEBUG("login %d\n", lflag);
  1166.     DO DEBUG("    origv %d, origh %d, lines %d, chars %d, ",
  1167.                 shape->worigv, shape->worigh, shape->wlines, shape->wchars);
  1168.     DO DEBUG("font %d, attr 0x%x\n", shape->wfont, shape->wattr);
  1169.                     
  1170.     if ((f = OpenPTY ()) == -1)
  1171.       { Msg (0, "No more PTYs.");
  1172.         return ( -1 );
  1173.       }
  1174.  
  1175.     /* if channel not given obtain one from MacLayers */
  1176.     if (chan == 0)
  1177.       {    chan = SendNew(shape);                /* try to get free window */
  1178.         if (chan == 0)
  1179.             {    Msg (0, "No more windows.");
  1180.             return ( -1 );
  1181.             }
  1182.         DO DEBUG("SendNew() == %d\n", chan);
  1183.       }
  1184.  
  1185.     /* verify channel */
  1186.     if (chan <= 0 || chan > MAXPCHAN)
  1187.       {    Msg(0, "Invalid channel %d.", chan);
  1188.         return ( -1 );
  1189.       }
  1190.  
  1191.     /* login this window if it's layer #1 */
  1192.     if (chan == 1)
  1193.         lflag = 1;
  1194.                     
  1195.     if (lflag == -1)
  1196.         lflag = loginflag;
  1197.     
  1198. #ifdef USRLIMIT
  1199.     /*
  1200.      *    Count current number of users, and if logging windows in,
  1201.      */
  1202.     if (lflag == 1)
  1203.       { (void) lseek (utmpf, 0, 0);
  1204.         UserCount = 0;
  1205.         while (read(utmpf, &utmpbuf, sizeof(struct utmp)) > 0)
  1206.           { if (utmpbuf.ut_name[0] != '\0')
  1207.                 UserCount++;
  1208.           }
  1209.         if (UserCount >= USRLIMIT)
  1210.           { Msg (0, "User limit reached.  Window will not be logged in.");
  1211.             lflag = 0;
  1212.           }
  1213.       }
  1214. #endif USRLIMIT
  1215.  
  1216.     layer = &World[chan-1];                    /* find layer structure */
  1217.     layer->shape = *shape;                    /* install new window shape */
  1218.  
  1219.     /* ??? What do we do if layer is still active as far as we're concerned? */
  1220.     if (layer->allocated)
  1221.       {    DO DEBUG("??? newlayer not free !!!\n");
  1222.         KillWindow(layer);                    /* kill off old layer */
  1223.         SendDelete(layer->chan);            /* kill window back off */
  1224.         Msg (0, "Makewindow error: Duplicate active layer %d.", chan);
  1225.         return ( -1 );                        /* return failed */
  1226.       }
  1227.  
  1228.     layer->allocated = 1;                    /* show layer now in use */
  1229.     BuildTitle(chan, prog, args);            /* install window title */
  1230.  
  1231.     (void) fcntl (f, F_SETFL, FNDELAY);
  1232.     layer->ptyfd = f;                        /* pseudo pty for task's I/O */
  1233.     layer->ptymask = 1<<f;                    /* set pty device mask */
  1234.     strncpy (layer->cmd, Filename (args[0]), MAXSTR-1);
  1235.     layer->cmd[MAXSTR-1] = '\0';
  1236.     strncpy (layer->tty, TtyName, MAXSTR-1);
  1237.     DO DEBUG("forking %s, tty %s, ptyfd %d, mask %x\n",
  1238.                 layer->cmd, layer->tty, layer->ptyfd, layer->ptymask);
  1239.     (void) chown (TtyName, getuid (), getgid ());
  1240.     if (lflag == 1)
  1241.       { layer->slot = SetUtmp(TtyName, chan == 1);
  1242.         if (chan == 1 && RealTtyMode)
  1243.             /* set to original tty umask */
  1244.             (void) chmod(TtyName, RealTtyMode);
  1245.         else
  1246.             /* force to this mode */
  1247.             (void) chmod(TtyName, TtyMode);
  1248.       }
  1249.     else
  1250.       { layer->slot = -1;
  1251.         /* do not allow any other user access to this device */
  1252.         (void) chmod (TtyName, 0600);
  1253.       }
  1254.     switch (layer->lpid = fork ())
  1255.     { case -1:
  1256.         Msg (errno, "fork");
  1257.         layer->lpid = 0;                    /* clear pid field */
  1258.         return ( -1 );                        /* return failed */
  1259.  
  1260.       case 0:
  1261.         signal (SIGHUP, SIG_DFL);
  1262.         signal (SIGINT, SIG_DFL);
  1263.         signal (SIGQUIT, SIG_DFL);
  1264.         signal (SIGTERM, SIG_DFL);
  1265.         signal (SIGTTIN, SIG_DFL);
  1266.         signal (SIGTTOU, SIG_DFL);
  1267.         signal (SIGALRM, SIG_DFL);
  1268.         setuid (getuid ());
  1269.         setgid (getgid ());
  1270.         if (dir && chdir (dir) == -1)
  1271.           { SendErrorMsg ("Cannot chdir to %s: %s", dir, sys_errlist[errno]);
  1272.             exit (1);
  1273.           }
  1274.         mypid = getpid ();
  1275.         ioctl (DevTty, TIOCNOTTY, (char *)0);
  1276.         if ((tf = open (TtyName, O_RDWR)) == -1)
  1277.           { SendErrorMsg ("Cannot open %s: %s", TtyName, sys_errlist[errno]);
  1278.             exit (1);
  1279.           }
  1280.         DO DEBUG("Now in new process\n");
  1281.         (void) dup2 (tf, 0);
  1282.         (void) dup2 (tf, 1);
  1283.         (void) dup2 (tf, 2);
  1284.         for (f = getdtablesize () - 1; f > 2; f--)
  1285.             close (f);
  1286.         ioctl (0, TIOCSPGRP, &mypid);
  1287.         (void) setpgrp (0, mypid);
  1288.         SetTTY (0, &OldMode);
  1289.  
  1290.           {    struct    winsize    wsize;        /* window size structure */
  1291.             int            retcode;        /* ioctl return code */
  1292.  
  1293.             wsize.ws_col = layer->shape.wchars; /* character width */
  1294.             wsize.ws_row = layer->shape.wlines; /* window height */
  1295.             wsize.ws_xpixel = 0;                /* necessary? */
  1296.             wsize.ws_ypixel = 0;
  1297.             /* update O/S window state */
  1298.             retcode = ioctl(0, TIOCSWINSZ, &wsize);
  1299.           }
  1300.         (void) umask(Oumask);            /* restore user's original umask */
  1301.         NewEnv[2] = MakeTermcap(layer->shape.wlines, layer->shape.wchars);
  1302.         sprintf (ebuf, "LAYER=%d", chan);
  1303.         NewEnv[3] = ebuf;
  1304.         execvpe (prog, args, NewEnv);
  1305.         printf("%s: cannot exec %s: %s", myname, prog, sys_errlist[errno]);
  1306.         exit (1);
  1307.     }
  1308.  
  1309.     return ( chan );
  1310.  
  1311. } /* MakeWindow() */
  1312.  
  1313. static
  1314. execvpe (prog, args, env)
  1315. char *prog, **args, **env;
  1316. {
  1317.     register char *path, *p;
  1318.     char buf[1024];
  1319.     char *shargs[MAXARGS+1];
  1320.     register i;
  1321.     register eaccess = 0;
  1322.  
  1323.     if (prog[0] == '/')
  1324.         path = "";
  1325.     else
  1326.     if ((path = getenv ("PATH")) == 0)
  1327.         path = DefaultPath;
  1328.     do
  1329.       { p = buf;
  1330.         while (*path && *path != ':')
  1331.             *p++ = *path++;
  1332.         if (p > buf)
  1333.             *p++ = '/';
  1334.         strcpy (p, prog);
  1335.         if (*path)
  1336.             ++path;
  1337.         execve (buf, args, env);
  1338.         switch (errno)
  1339.         { case ENOEXEC:
  1340.             shargs[0] = DefaultShell;
  1341.             shargs[1] = buf;
  1342.             for (i = 1; shargs[i+1] = args[i]; ++i);
  1343.             execve (DefaultShell, shargs, env);
  1344.             return;
  1345.  
  1346.           case EACCES:
  1347.             eaccess = 1;
  1348.             break;
  1349.  
  1350.           case ENOMEM: case E2BIG: case ETXTBSY:
  1351.             return;
  1352.  
  1353.         } /* end switch */
  1354.  
  1355.     } while (*path);
  1356.  
  1357.     if (eaccess)
  1358.         errno = EACCES;
  1359.  
  1360. } /* execvpe() */
  1361.  
  1362.  
  1363.                 /* BuildTitle() - create and install window title */
  1364.  
  1365. static void
  1366. BuildTitle(chan, prog, args)
  1367. int            chan;                        /* channel for title */
  1368. char        *prog;                        /* program being executed */
  1369. char        **args;                        /* arg list */
  1370. {
  1371.     int        i;                            /* arg scan index */
  1372.     char    buff[1024];                    /* super huge title buffer */
  1373.  
  1374.     /* skip any leading "/bin/" */
  1375.     if (strncmp(prog, "/bin/", 5) == 0)
  1376.         strcpy(buff, prog+5);            /* leave /bin off */
  1377.     else
  1378.         strcpy(buff, prog);                /* start with program name */
  1379.  
  1380.     /* add all aguments but stop if option ("-") seen */
  1381.     for (i=1; args[i] && args[i][0] != '-'; i++)
  1382.       {    strcat(buff, " ");                /* delimiter */
  1383.         strcat(buff, args[i]);            /* add next parameter */
  1384.       }
  1385.  
  1386.     SendTitle(chan, buff, strlen(buff)); /* set new window title */
  1387.  
  1388. } /* BuildTitle() */
  1389.  
  1390.  
  1391. #ifdef sequent
  1392. static
  1393. OpenPTY ()
  1394. {
  1395.     char *m, *s;
  1396.     register f;
  1397.  
  1398.     f = getpseudotty (&s, &m);
  1399.     strncpy (PtyName, m, sizeof (PtyName));
  1400.     strncpy (TtyName, s, sizeof (TtyName));
  1401.     ioctl (f, TIOCFLUSH, (char *)0);
  1402.     return (f);
  1403. }
  1404.  
  1405. #else
  1406.  
  1407. static
  1408. OpenPTY ()
  1409. {
  1410.     register char *p, *l, *d;
  1411.     register i, f, tf;
  1412.  
  1413.     strcpy (PtyName, PtyProto);
  1414.     strcpy (TtyName, TtyProto);
  1415.     for (p = PtyName, i = 0; *p != 'X'; ++p, ++i);
  1416.     for (l = "qpr"; *p = *l; ++l)
  1417.       { for (d = "0123456789abcdef"; p[1] = *d; ++d)
  1418.           { if ((f = open (PtyName, O_RDWR)) != -1)
  1419.               { TtyName[i] = p[0];
  1420.                 TtyName[i+1] = p[1];
  1421.                 if ((tf = open (TtyName, O_RDWR)) != -1)
  1422.                   { close (tf);
  1423.                     return f;
  1424.                   }
  1425.                 close (f);
  1426.               }
  1427.           }
  1428.       }
  1429.  
  1430.     return -1;
  1431.  
  1432. } /* OpenPTY() */
  1433. #endif
  1434.  
  1435. static
  1436. SetTTY (fd, mp)
  1437. struct mode *mp;
  1438. {
  1439.     ioctl (fd, TIOCSETP, &mp->m_ttyb);
  1440.     ioctl (fd, TIOCSETC, &mp->m_tchars);
  1441.     ioctl (fd, TIOCSLTC, &mp->m_ltchars);
  1442.     ioctl (fd, TIOCLSET, &mp->m_lmode);
  1443.     ioctl (fd, TIOCSETD, &mp->m_ldisc);
  1444.  
  1445. } /* SetTTY() */
  1446.  
  1447. static
  1448. GetTTY (fd, mp)
  1449. struct mode *mp;
  1450. {
  1451.     ioctl (fd, TIOCGETP, &mp->m_ttyb);
  1452.     ioctl (fd, TIOCGETC, &mp->m_tchars);
  1453.     ioctl (fd, TIOCGLTC, &mp->m_ltchars);
  1454.     ioctl (fd, TIOCLGET, &mp->m_lmode);
  1455.     ioctl (fd, TIOCGETD, &mp->m_ldisc);
  1456.  
  1457. } /* GetTTY() */
  1458.  
  1459. static
  1460. SetMode (op, np)
  1461. struct mode *op, *np;
  1462. {
  1463.     *np = *op;
  1464. #if 1
  1465.     if (flowctl)
  1466.       {    np->m_ttyb.sg_flags &= ~(CRMOD|ECHO);
  1467.         np->m_ttyb.sg_flags |= CBREAK | ANYP;
  1468.       }
  1469.     else
  1470.         np->m_ttyb.sg_flags = RAW | ANYP;
  1471. #else
  1472.     np->m_ttyb.sg_flags &= ~(CRMOD|ECHO);
  1473.     np->m_ttyb.sg_flags |= CBREAK | ANYP;
  1474. #endif
  1475.     np->m_tchars.t_intrc = -1;
  1476.     np->m_tchars.t_quitc = -1;
  1477.     if (!flowctl)
  1478.       { np->m_tchars.t_startc = -1;
  1479.         np->m_tchars.t_stopc = -1;
  1480.       }
  1481.     np->m_ltchars.t_suspc = -1;
  1482.     np->m_ltchars.t_dsuspc = -1;
  1483.     np->m_ltchars.t_flushc = -1;
  1484.     np->m_ltchars.t_lnextc = -1;
  1485.  
  1486. } /* SetMode() */
  1487.  
  1488. static char *
  1489. GetTtyName ()
  1490. {
  1491.     int n;
  1492.     char *p;
  1493.  
  1494.     for (p = 0, n = 0; n <= 2 && !(p = ttyname (n)); n++);
  1495.  
  1496.     if (!p || *p == '\0')
  1497.         Msg (0, "layers must run on a tty.");
  1498.  
  1499.     return ( p );
  1500.  
  1501. } /* GetTtyName() */
  1502.  
  1503.  
  1504. static
  1505. Kill (pid, sig)
  1506. {
  1507.     if (pid != 0)
  1508.         (void) kill (pid, sig);
  1509. }
  1510.  
  1511.             /* GetSockName() - set SockName; if LTY env return 1 else 0 */
  1512. static
  1513. GetSockName ()
  1514. {
  1515.     register client;
  1516.     static char buf[2*MAXSTR];
  1517.  
  1518.     if (!mflag && (SockName = getenv ("LTY")) != 0 && *SockName != '\0')
  1519.       { client = 1;
  1520.         setuid (getuid ());
  1521.         setgid (getgid ());
  1522.       }
  1523.     else
  1524.       { sprintf (buf, "%s.%s", HostName, Filename (RealTtyName));
  1525.         SockName = buf;
  1526.         client = 0;
  1527.       }
  1528.     return client;
  1529.  
  1530. } /* GetSockName() */
  1531.  
  1532. static
  1533. MakeServerSocket ()
  1534. {
  1535.     register s;
  1536.     struct sockaddr_un a;
  1537.     char *p;
  1538.  
  1539.     if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1)
  1540.         Msg (errno, "socket");
  1541.     a.sun_family = AF_UNIX;
  1542.     strcpy (SockNamePtr, SockName);
  1543.     strcpy (a.sun_path, SockPath);
  1544.     if (connect (s, (struct sockaddr *)&a, strlen (SockPath)+2) != -1)
  1545.       { p = Filename (SockPath);
  1546.         Msg (0, "You already have a layers running on %s.", p);
  1547.         /*NOTREACHED*/
  1548.       }
  1549.     DO DEBUG("MakeServerSocket: unlink(SockPath)/bind()/chown/listen\n");
  1550.     (void) unlink (SockPath);
  1551.     if (bind (s, (struct sockaddr *)&a, strlen (SockPath)+2) == -1)
  1552.         Msg (errno, "bind");
  1553.     (void) chown (SockPath, getuid (), getgid ());
  1554.     if (listen (s, 5) == -1)
  1555.         Msg (errno, "listen");
  1556.     return s;
  1557.  
  1558. } /* MakeServerSocket() */
  1559.  
  1560. static
  1561. MakeClientSocket (err)
  1562. {
  1563.     register s;
  1564.     struct sockaddr_un a;
  1565.  
  1566.     if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1)
  1567.         Msg (errno, "socket");
  1568.     a.sun_family = AF_UNIX;
  1569.     strcpy (SockNamePtr, SockName);
  1570.     strcpy (a.sun_path, SockPath);
  1571.     if (connect (s, (struct sockaddr *)&a, strlen (SockPath)+2) == -1)
  1572.       { if (err)
  1573.           { Msg (errno, "connect: %s", SockPath); }
  1574.         else
  1575.           { close (s);
  1576.             return -1;
  1577.           }
  1578.       }
  1579.     return s;
  1580.  
  1581. } /* MakeClientSocket() */
  1582.  
  1583. static
  1584. SendCreateMsg (s, ac, av, lflag, shape)
  1585. char **av;
  1586. struct Shape *shape;
  1587. {
  1588.     struct msg m;
  1589.     register char *p;
  1590.     register len, n;
  1591.     char    *pwd;                    /* PWD environment string */
  1592.  
  1593.     DO DEBUG("SendCreateMsg(%d, ac %d, lflag %d\n", s, ac, lflag);
  1594.     m.type = MSG_CREATE;
  1595.     p = m.m.create.line;
  1596.     for (n = 0; ac > 0 && n < MAXARGS-1; ++av, --ac, ++n)
  1597.       { len = strlen (*av) + 1;
  1598.         if (p + len >= m.m.create.line+MAXLINE)
  1599.             break;
  1600.         strcpy (p, *av);
  1601.         p += len;
  1602.       }
  1603.     DO DEBUG("  nargs %d, create line = '%s'\n", n, m.m.create.line);
  1604.     m.m.create.nargs = n;
  1605.     m.m.create.lflag = lflag;
  1606.     m.m.create.shape = *shape;            /* pass window shape */
  1607.  
  1608.     /* Since Suns can hang up on getwd() [damn their stupid networking]
  1609.     ** we try to get the current working directory first from the PWD
  1610.     ** environment variable.
  1611.     */
  1612.     if ((pwd=getenv("PWD")) && strlen(pwd) < 1024)
  1613.         (void) strcpy(m.m.create.dir, pwd);
  1614.     else
  1615.     if (getwd (m.m.create.dir) == 0)
  1616.       {    DO DEBUG("getwd() failed!!\n");
  1617.         Msg (0, "%s", m.m.create.dir);
  1618.       }
  1619.     DO DEBUG("  create.dir = '%s'\n", m.m.create.dir);
  1620.  
  1621.     if (write (s, (char *)&m, sizeof (m)) != sizeof (m))
  1622.       {    DO DEBUG("  write failed!!\n");
  1623.         Msg (errno, "write");
  1624.       }
  1625.     DO DEBUG("SendCreateMsg() done\n");
  1626.  
  1627. } /* SendCreateMsg() */
  1628.  
  1629. /*VARARGS1*/
  1630. static
  1631. SendErrorMsg (fmt, p1, p2, p3, p4, p5, p6)
  1632. char *fmt;
  1633. {
  1634.     register s;
  1635.     struct msg m;
  1636.  
  1637.     s = MakeClientSocket (1);
  1638.     m.type = MSG_ERROR;
  1639.     sprintf (m.m.message, fmt, p1, p2, p3, p4, p5, p6);
  1640.     (void) write (s, (char *)&m, sizeof (m));
  1641.     close (s);
  1642.     sleep (2);
  1643. }
  1644.  
  1645. static
  1646. ReceiveMsg (s)
  1647. {
  1648.     register ns;
  1649.     struct sockaddr_un a;
  1650.     int left, len = sizeof (a);
  1651.     struct msg m;
  1652.     char *p;
  1653.  
  1654.     DO DEBUG ("ReceiveMsg()\n");
  1655.     if ((ns = accept (s, (struct sockaddr *)&a, &len)) == -1)
  1656.       { Msg (errno, "accept");
  1657.         return;
  1658.       }
  1659.     p = (char *)&m;
  1660.     left = sizeof (m);
  1661.     while (left > 0 && (len = read (ns, p, left)) > 0)
  1662.       { p += len;
  1663.         left -= len;
  1664.       }
  1665.     close (ns);
  1666.     if (len == -1)
  1667.         Msg (errno, "read");
  1668.     if (left > 0)
  1669.         return;
  1670.     switch (m.type)
  1671.     { case MSG_CREATE:
  1672.         DO DEBUG("MSG_CREATE:\n");
  1673.         ExecCreate (&m);
  1674.         break;
  1675.  
  1676.       case MSG_ERROR:
  1677.         DO DEBUG("MSG_ERROR:\n");
  1678.         Msg (0, "%s", m.m.message);
  1679.         break;
  1680.  
  1681.       default:
  1682.         Msg (0, "Invalid message (type %d).", m.type);
  1683.  
  1684.     } /* end switch */
  1685.  
  1686. } /* ReceiveMsg() */
  1687.  
  1688. static
  1689. ExecCreate (mp)
  1690. struct msg *mp;
  1691. {
  1692.     char *args[MAXARGS];
  1693.     register n;
  1694.     register char **pp = args, *p = mp->m.create.line;
  1695.  
  1696.     for (n = mp->m.create.nargs; n > 0; --n)
  1697.       { *pp++ = p;
  1698.         p += strlen (p) + 1;
  1699.       }
  1700.     *pp = 0;
  1701.     n = MakeWindow (0, mp->m.create.line, args, mp->m.create.dir,
  1702.                         mp->m.create.lflag, &mp->m.create.shape);
  1703.  
  1704. } /* ExecCreate() */
  1705.  
  1706. #if 0
  1707. static
  1708. ReadRc (fn)
  1709. char *fn;
  1710. {
  1711.     FILE *f;
  1712.     register char *p, **pp, **ap;
  1713.     register argc, num, c;
  1714.     char buf[256];
  1715.     char *args[MAXARGS];
  1716.     int key;
  1717.     struct Shape shape;                        /* shape for new window */
  1718.  
  1719.     ClearShape(&shape);                        /* initialize shape */
  1720.     ap = args;
  1721.     if (access (fn, R_OK) == -1)
  1722.         return;
  1723.     if ((f = fopen (fn, "r")) == NULL)
  1724.         return;
  1725.     while (fgets (buf, 256, f) != NULL)
  1726.       { if (p = rindex (buf, '\n'))
  1727.             *p = '\0';
  1728.         if ((argc = Parse (fn, buf, ap)) == 0)
  1729.             continue;
  1730.         if (strcmp (ap[0], "escape") == 0)
  1731.           { p = ap[1];
  1732.             if (argc < 2 || strlen (p) != 2)
  1733.                 Msg (0, "%s: two characters required after escape.", fn);
  1734.             Esc = *p++;
  1735.             MetaEsc = *p;
  1736.             ktab[Esc].type = KEY_OTHER;
  1737.           }
  1738.         else
  1739.         if (strcmp (ap[0], "login") == 0)
  1740.           { loginflag = 1;
  1741.           }
  1742.         else
  1743.         if (strcmp (ap[0], "unlogin") == 0)
  1744.           { loginflag = 0; }
  1745.         else
  1746.         if (strcmp (ap[0], "nologin") == 0)
  1747.           { loginflag = 0; }
  1748.         else
  1749.         if (strcmp (ap[0], "chdir") == 0)
  1750.            { p = argc < 2 ? home : ap[1];
  1751.             if (chdir (p) == -1)
  1752.             Msg (errno, "%s", p);
  1753.           }
  1754.         else
  1755.         if (strcmp (ap[0], "mode") == 0)
  1756.           { if (argc != 2)
  1757.               { Msg (0, "%s: mode: one argument required.", fn); }
  1758.             else
  1759.             if (!IsNum (ap[1], 7))
  1760.               { Msg (0, "%s: mode: octal number expected.", fn); }
  1761.             else
  1762.                 (void) sscanf (ap[1], "%o", &TtyMode);
  1763.           }
  1764.         else
  1765.         if (strcmp (ap[0], "bell") == 0)
  1766.           { if (argc != 2)
  1767.               { Msg (0, "%s: bell: one argument required.", fn); }
  1768.             else
  1769.               { if ((BellString = malloc (strlen (ap[1]) + 1)) == 0)
  1770.                     Msg (0, "Out of memory.");
  1771.                 istrcpy (BellString, ap[1]);
  1772.               }
  1773.           }
  1774.         else
  1775.         if (strcmp (ap[0], "screen") == 0)
  1776.           { num = 0;
  1777.             if (argc > 1 && IsNum (ap[1], 10))
  1778.               { num = atoi (ap[1]);
  1779.                 if (num < 0 || num > MAXWIN-1)
  1780.                     Msg (0, "%s: illegal screen number %d.", fn, num);
  1781.                 --argc; ++ap;
  1782.               }
  1783.             if (argc < 2)
  1784.               { ap[1] = ShellProg; argc = 2; }
  1785.             ap[argc] = 0;
  1786.             (void) MakeWindow (0, ap[1], ap+1, (char *)0, loginflag, &shape);
  1787.           }
  1788.         else
  1789.         if (strcmp (ap[0], "bind") == 0)
  1790.           { p = ap[1];
  1791.             if (argc < 2 || *p == '\0')
  1792.                 Msg (0, "%s: key expected after bind.", fn);
  1793.             if (p[1] == '\0')
  1794.               { key = *p; }
  1795.             else
  1796.             if (p[0] == '^' && p[1] != '\0' && p[2] == '\0')
  1797.               { c = p[1];
  1798.                 if (isupper (c))
  1799.                     p[1] = tolower (c);    
  1800.                 key = Ctrl(c);
  1801.               }
  1802.             else
  1803.             if (IsNum (p, 7))
  1804.               { (void) sscanf (p, "%o", &key);
  1805.               }
  1806.             else
  1807.               { Msg (0, "%s: bind: character, ^x, or octal number expected.", fn); }
  1808.             ktab[key].lflag = loginflag;
  1809.             if (argc < 3)
  1810.               { ktab[key].type = 0;
  1811.               }
  1812.             else
  1813.               { for (pp = KeyNames; *pp; ++pp)
  1814.                 if (strcmp (ap[2], *pp) == 0) break;
  1815.                 if (*pp)
  1816.                   { ktab[key].type = pp-KeyNames+1; }
  1817.                 else
  1818.                   { ktab[key].type = KEY_CREATE;
  1819.                     ktab[key].args = SaveArgs (argc-2, ap+2);
  1820.                   }
  1821.               }
  1822.           }
  1823.         else
  1824.             Msg (0, "%s: unknown keyword \"%s\".", fn, ap[0]);
  1825.       }
  1826.     (void) fclose (f);
  1827.  
  1828. } /* ReadRc() */
  1829.  
  1830. static
  1831. Parse (fn, buf, args)
  1832. char *fn, *buf, **args;
  1833. {
  1834.     register char *p, **ap;
  1835.     register delim, argc;
  1836.  
  1837.     p = buf;
  1838.     ap = args;
  1839.     argc = 0;
  1840.     for (;;)
  1841.       { while (*p && (*p == ' ' || *p == '\t'))
  1842.             ++p;
  1843.         if (*p == '\0' || *p == '#')
  1844.             return argc;
  1845.         if (argc > MAXARGS-1)
  1846.             Msg (0, "%s: too many tokens.", fn);
  1847.         delim = 0;
  1848.         if (*p == '"' || *p == '\'')
  1849.           { delim = *p; *p = '\0'; ++p; }
  1850.         ++argc;
  1851.         *ap = p; ++ap;
  1852.         while (*p && !(delim ? *p == delim : (*p == ' ' || *p == '\t')))
  1853.             ++p;
  1854.         if (*p == '\0')
  1855.           { if (delim)
  1856.                 Msg (0, "%s: Missing quote.", fn);
  1857.             else
  1858.                 return argc;
  1859.           }
  1860.         *p++ = '\0';
  1861.       }
  1862.  
  1863. } /* Parse() */
  1864.  
  1865. static char **
  1866. SaveArgs (argc, argv)
  1867. register argc;
  1868. register char **argv;
  1869. {
  1870.     register char **ap, **pp;
  1871.  
  1872.     if ((pp = ap = (char **)malloc ((argc+1) * sizeof (char **))) == 0)
  1873.         Msg (0, "Out of memory.");
  1874.     while (argc--)
  1875.       { if ((*pp = malloc (strlen (*argv)+1)) == 0)
  1876.             Msg (0, "Out of memory.");
  1877.         strcpy (*pp, *argv);
  1878.         ++pp; ++argv;
  1879.       }
  1880.     *pp = 0;
  1881.     return ap;
  1882.  
  1883. } /* SaveArgs() */
  1884. #endif
  1885.  
  1886. static
  1887. MakeNewEnv ()
  1888. {
  1889.     register char **op, **np = NewEnv;
  1890.     static char buf[MAXSTR];
  1891.  
  1892.     if (strlen (SockName) > MAXSTR-5)
  1893.         SockName = "?";
  1894.     sprintf (buf, "LTY=%s", SockName);
  1895.     *np++ = buf;
  1896.     *np++ = Term;
  1897.     np += 2;
  1898.     for (op = environ; *op; ++op)
  1899.       { if (np == NewEnv + MAXARGS - 1)
  1900.             break;
  1901.         if (   !IsSymbol (*op, "TERM")
  1902.             && !IsSymbol (*op, "TERMCAP")
  1903.             && !IsSymbol (*op, "LTY")
  1904.            )
  1905.             *np++ = *op;
  1906.       }
  1907.     *np = 0;
  1908.  
  1909. } /* MakeNewEnv() */
  1910.  
  1911. static
  1912. IsSymbol (e, s)
  1913. register char *e, *s;
  1914. {
  1915.     register char *p;
  1916.     register n;
  1917.  
  1918.     for (p = e; *p && *p != '='; ++p);
  1919.     if (*p)
  1920.       { *p = '\0';
  1921.         n = strcmp (e, s);
  1922.         *p = '=';
  1923.         return n == 0;
  1924.       }
  1925.  
  1926.     return 0;
  1927.  
  1928. } /* IsSymbol() */
  1929.  
  1930. /*VARARGS2*/
  1931. Msg (err, fmt, p1, p2, p3, p4, p5, p6)
  1932. char *fmt;
  1933. {
  1934.     char buf[1024];
  1935.     register char *p = buf;
  1936.  
  1937.     sprintf (p, fmt, p1, p2, p3, p4, p5, p6);
  1938.     if (err)
  1939.       { p += strlen (p);
  1940.         if (err > 0 && err < sys_nerr)
  1941.             sprintf (p, ": %s", sys_errlist[err]);
  1942.         else
  1943.             sprintf (p, ": Error %d", err);
  1944.       }
  1945.     if (!Abortonmsg)
  1946.       { /* MakeStatus (buf, curr);*/
  1947.         printf("%s\r\n", buf);
  1948.       } 
  1949.     else
  1950.       { printf ("%s\r\n", buf);
  1951.         exit (1);
  1952.       }
  1953.  
  1954. } /* Msg() */
  1955.  
  1956. static char *
  1957. Filename (s)
  1958. char *s;
  1959. {
  1960.     register char *p;
  1961.  
  1962.     p = s + strlen (s) - 1;
  1963.     while (p >= s && *p != '/')
  1964.         --p;
  1965.     return ++p;
  1966.  
  1967. } /* Filename() */
  1968.  
  1969. static
  1970. IsNum (s, base)
  1971. register char *s;
  1972. register base;
  1973. {
  1974.     for (base += '0'; *s; ++s)
  1975.         if (*s < '0' || *s > base)
  1976.             return 0;
  1977.     return 1;
  1978.  
  1979. } /* IsNum() */
  1980.  
  1981.  
  1982. static
  1983. InitUtmp ()
  1984. {
  1985.     if ((utmpf = open (UtmpName, O_RDWR)) == -1)
  1986.       { if (errno != EACCES)
  1987.             Msg (errno, UtmpName);
  1988.         return;
  1989.       }
  1990.     utmp = 1;
  1991.  
  1992. } /* InitUtmp() */
  1993.  
  1994.  
  1995. static int
  1996. FindUtmp(name)
  1997. char *name;
  1998. {
  1999.     register char *p;
  2000.     register struct ttyent *tp;
  2001.     register slot;
  2002.  
  2003.     DO DEBUG("FindUtmp(%s)\n", name);
  2004.     slot = 1;
  2005.     if (!utmp)
  2006.         return 0;
  2007.     if (p = rindex (name, '/'))
  2008.         ++p;
  2009.     else
  2010.         p = name;
  2011.     setttyent ();
  2012.     while (   (tp = getttyent ()) != NULL
  2013.            && strcmp (p, tp->ty_name) != 0
  2014.           )
  2015.         ++slot;
  2016.     if (tp == NULL)
  2017.         return 0;
  2018.  
  2019.     DO DEBUG(" slot %d\n", slot);
  2020.     return slot;
  2021.  
  2022. } /* FindUtmp() */
  2023.  
  2024.  
  2025. static int
  2026. SetUtmp (name, mainlogin)
  2027. char    *name;                            /* tty name */
  2028. int        mainlogin;                        /* this is primary login */
  2029. {
  2030.     register char *p;
  2031.     register slot;
  2032.     struct utmp u;
  2033.  
  2034.     if ((slot=FindUtmp(name)) == 0)
  2035.         return ( 0 );
  2036.  
  2037.     if (p = rindex (name, '/'))
  2038.         ++p;
  2039.     else
  2040.         p = name;
  2041.  
  2042.     strncpy (u.ut_line, p, 8);
  2043.     strncpy (u.ut_name, LoginName, 8);
  2044. #if 1
  2045.     strncpy(u.ut_host,  Filename (RealTtyName), 16); /* host is real tty */
  2046. #else
  2047.     u.ut_host[0] = '\0';
  2048. #endif
  2049.     if (RealSlot && mainlogin)
  2050.         u.ut_time = RealUtmp.ut_time;        /* use original login time */
  2051.     else
  2052.         time (&u.ut_time);
  2053.     (void) lseek (utmpf, (long)(slot * sizeof (u)), 0);
  2054.     (void) write (utmpf, (char *)&u, sizeof (u));
  2055.  
  2056.     return ( slot );
  2057.  
  2058. } /* SetUtmp() */
  2059.  
  2060. static int
  2061. ReadUtmp(slot, entry)
  2062. int        slot;                                /* slot to read */
  2063. struct utmp    *entry;                            /* entry to read into */
  2064. {
  2065.     int        cnt;                            /* return count */
  2066.  
  2067.     if (!utmp)
  2068.         return;                                /* no utmp access */
  2069.  
  2070.     (void) lseek(utmpf, (long)(slot * sizeof(struct utmp)), 0);
  2071.     cnt =  read(utmpf, (char *)entry, sizeof(struct utmp));
  2072.     DO DEBUG("ReadUtmp cnt %d, errno %d, line %.8s, name %.8s, host %.16s\n",
  2073.         cnt, errno, entry->ut_line, entry->ut_name, entry->ut_host);
  2074.  
  2075.     return ( cnt );
  2076.  
  2077. } /* ReadUtmp() */
  2078.  
  2079. static void
  2080. WriteUtmp(slot, entry)
  2081. int        slot;                                /* slot to write */
  2082. struct utmp    *entry;                            /* entry to write from */
  2083. {
  2084.     int        cnt;                            /* write return code */
  2085.  
  2086.     if (!utmp)
  2087.         return;                                /* no utmp access */
  2088.  
  2089.     (void) lseek(utmpf, (long)(slot * sizeof(struct utmp)), 0);
  2090.     cnt = write(utmpf, (char *)entry, sizeof(struct utmp));
  2091.     DO DEBUG("WriteUtmp() slot %d cnt %d line %.8s name %.8s host %.16s\n",
  2092.                 slot, cnt, entry->ut_line, entry->ut_name, entry->ut_host);
  2093.  
  2094. } /* WriteUtmp() */
  2095.  
  2096. static
  2097. RemoveUtmp (slot)
  2098. {
  2099.     struct utmp u;
  2100.  
  2101.     if (slot)
  2102.       { bzero ((char *)&u, sizeof (u));
  2103.         (void) lseek (utmpf, (long)(slot * sizeof (u)), 0);
  2104.         (void) write (utmpf, (char *)&u, sizeof (u));
  2105.       }
  2106.  
  2107. } /* RemoveUtmp() */
  2108.  
  2109. #ifndef GETTTYENT
  2110.  
  2111. static
  2112. setttyent ()
  2113. {
  2114.     struct stat s;
  2115.     register f;
  2116.     register char *p, *ep;
  2117.  
  2118.     if (ttnext)
  2119.       { ttnext = tt;
  2120.         return;
  2121.       }
  2122.     if ((f = open (ttys, O_RDONLY)) == -1 || fstat (f, &s) == -1)
  2123.         Msg (errno, ttys);
  2124.     if ((tt = malloc (s.st_size + 1)) == 0)
  2125.         Msg (0, "Out of memory.");
  2126.     if (read (f, tt, s.st_size) != s.st_size)
  2127.         Msg (errno, ttys);
  2128.     close (f);
  2129.     for (p = tt, ep = p + s.st_size; p < ep; ++p)
  2130.         if (*p == '\n')
  2131.             *p = '\0';
  2132.     *p = '\0';
  2133.     ttnext = tt;
  2134.  
  2135. } /* setttyent() */
  2136.  
  2137. static struct ttyent *
  2138. getttyent ()
  2139. {
  2140.     static struct ttyent t;
  2141.  
  2142.     if (*ttnext == '\0')
  2143.         return NULL;
  2144.     t.ty_name = ttnext + 2;
  2145.     ttnext += strlen (ttnext) + 1;
  2146.     return &t;
  2147.  
  2148. } /* getttyend() */
  2149.  
  2150. #endif
  2151.  
  2152.  
  2153.  
  2154.                     /* FinitTerm() - reset vt100 terminal */
  2155. static void
  2156. FinitTerm ()
  2157. {
  2158.     /* print out termcap 'is' string to reset terminal */
  2159. #if 0
  2160.     /* This string sets scroll region 1-24 and puts cursor at bottom line */
  2161.     printf("\033[1;24r\033[24;1H");
  2162. #endif
  2163.     fflush(stdout);
  2164. }
  2165.  
  2166. static void
  2167. AddCap (s)
  2168. char *s;
  2169. {
  2170.     register n;
  2171.  
  2172.     if (tcLineLen + (n = strlen (s)) > 55)
  2173.       { strcat (Termcap, "\\\n\t:");
  2174.         tcLineLen = 0;
  2175.       }
  2176.     strcat (Termcap, s);
  2177.     tcLineLen += n;
  2178. }
  2179.  
  2180. static char *
  2181. MakeTermcap(lines, chars)
  2182. int        lines;                            /* default window lines */
  2183. int        chars;                            /* default window chars */
  2184. {
  2185.     char buf[1024];
  2186.     register char **pp, *p;
  2187.  
  2188.     strcpy(Termcap, TermcapConst1);        /* start TERMCAP build */
  2189.     strcat(Termcap, UserTerm);            /* fill in User's terminal type */
  2190.     strcat(Termcap, TermcapConst3);        /* finish our own definition */
  2191.  
  2192.     if (lines <= 0 || lines > 200)
  2193.         lines = rows;                    /* force default if none or invalid */
  2194.     if (chars <= 0 || chars > 300)
  2195.         chars = cols;                    /* force default if none or invalid */
  2196.  
  2197.     sprintf(buf, "li#%d:co#%d:", lines, chars);
  2198.     AddCap(buf);
  2199.  
  2200.     return ( Termcap );
  2201.  
  2202. } /* MakeTermcap() */
  2203.  
  2204.  
  2205.                 /* DEBUG() - dump output routine */
  2206.  
  2207. void
  2208. DEBUG(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
  2209. char        *format;
  2210. int            arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8;
  2211. {
  2212.     fprintf(stderr, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
  2213. }
  2214.