home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume17 / screen2 / part02 / screen.c < prev   
Encoding:
C/C++ Source or Header  |  1989-02-06  |  37.2 KB  |  1,657 lines

  1. /* Copyright (c) 1987,1988 Oliver Laumann, Technical University of Berlin.
  2.  * Not derived from licensed software.
  3.  *
  4.  * Permission is granted to freely use, copy, modify, and redistribute
  5.  * this software, provided that no attempt is made to gain profit from it,
  6.  * the author is not construed to be liable for any results of using the
  7.  * software, alterations are clearly marked as such, and this notice is
  8.  * not modified.
  9.  */
  10.  
  11. static char ScreenVersion[] = "screen 2.0a 19-Oct-88";
  12.  
  13. #include <stdio.h>
  14. #include <sgtty.h>
  15. #include <signal.h>
  16. #include <errno.h>
  17. #include <ctype.h>
  18. #include <utmp.h>
  19. #include <pwd.h>
  20. #include <nlist.h>
  21. #include <fcntl.h>
  22. #include <sys/types.h>
  23. #include <sys/time.h>
  24. #include <sys/file.h>
  25. #include <sys/wait.h>
  26. #include <sys/socket.h>
  27. #include <sys/un.h>
  28. #include <sys/stat.h>
  29. #include <sys/dir.h>
  30. #ifdef SUNLOADAV
  31. #include <sys/param.h>
  32. #endif
  33. #include "screen.h"
  34.  
  35. #ifdef GETTTYENT
  36. #   include <ttyent.h>
  37. #else
  38.     static struct ttyent {
  39.     char *ty_name;
  40.     } *getttyent();
  41.     static char *tt, *ttnext;
  42.     static char ttys[] = "/etc/ttys";
  43. #endif
  44.  
  45. #define MAXWIN     10
  46. #define MSGWAIT     5
  47.  
  48. #define Ctrl(c) ((c)&037)
  49.  
  50. extern char *blank, Term[], **environ;
  51. extern rows, cols;
  52. extern ISO2022;
  53. extern status;
  54. extern time_t TimeDisplayed;
  55. extern char AnsiVersion[];
  56. extern short ospeed;
  57. extern flowctl;
  58. extern errno;
  59. extern sys_nerr;
  60. extern char *sys_errlist[];
  61. extern char *index(), *rindex(), *malloc(), *getenv(), *MakeTermcap();
  62. extern char *getlogin(), *ttyname();
  63. static AttacherFinit(), Finit(), SigHup(), SigChld();
  64. static char *MakeBellMsg(), *Filename(), **SaveArgs(), *GetTtyName();
  65.  
  66. static char PtyName[32], TtyName[32];
  67. static char *ShellProg;
  68. static char *ShellArgs[2];
  69. static char inbuf[IOSIZE];
  70. static inlen;
  71. static ESCseen;
  72. static GotSignal;
  73. static char DefaultShell[] = "/bin/sh";
  74. static char DefaultPath[] = ":/usr/ucb:/bin:/usr/bin";
  75. static char PtyProto[] = "/dev/ptyXY";
  76. static char TtyProto[] = "/dev/ttyXY";
  77. static int TtyMode = 0622;
  78. static char SockPath[512];
  79. static char SockDir[] = ".screen";
  80. static char *SockNamePtr, *SockName;
  81. static ServerSocket;
  82. static char *NewEnv[MAXARGS];
  83. static char Esc = Ctrl('a');
  84. static char MetaEsc = 'a';
  85. static char *home;
  86. static HasWindow;
  87. static utmp, utmpf;
  88. static char UtmpName[] = "/etc/utmp";
  89. static char *LoginName;
  90. static char *BellString = "Bell in window %";
  91. static mflag, nflag, fflag, rflag;
  92. static char HostName[MAXSTR];
  93. static Detached;
  94. static AttacherPid;    /* Non-Zero in child if we have an attacher */
  95. static DevTty;
  96. #ifdef LOADAV
  97.     static char KmemName[] = "/dev/kmem";
  98. #ifdef sequent
  99.     static char UnixName[] = "/dynix";
  100. #else
  101.     static char UnixName[] = "/vmunix";
  102. #endif
  103. #ifdef alliant
  104.     static char AvenrunSym[] = "_Loadavg";
  105. #else
  106.     static char AvenrunSym[] = "_avenrun";
  107. #endif
  108.     static struct nlist nl[2];
  109.     static avenrun, kmemf;
  110. #ifdef SUNLOADAV
  111.     long loadav[3];
  112. #else
  113. #ifdef alliant
  114.     long loadav[4];
  115. #else
  116.     double loadav[3];
  117. #endif
  118. #endif
  119.  
  120. #endif
  121.  
  122. struct mode {
  123.     struct sgttyb m_ttyb;
  124.     struct tchars m_tchars;
  125.     struct ltchars m_ltchars;
  126.     int m_ldisc;
  127.     int m_lmode;
  128. } OldMode, NewMode;
  129.  
  130. static struct win *curr, *other;
  131. static CurrNum, OtherNum;
  132. static struct win *wtab[MAXWIN];
  133.  
  134. #define KEY_IGNORE         0
  135. #define KEY_HARDCOPY       1
  136. #define KEY_SUSPEND        2
  137. #define KEY_SHELL          3
  138. #define KEY_NEXT           4
  139. #define KEY_PREV           5
  140. #define KEY_KILL           6
  141. #define KEY_REDISPLAY      7
  142. #define KEY_WINDOWS        8
  143. #define KEY_VERSION        9
  144. #define KEY_OTHER         10
  145. #define KEY_0             11
  146. #define KEY_1             12
  147. #define KEY_2             13
  148. #define KEY_3             14
  149. #define KEY_4             15
  150. #define KEY_5             16
  151. #define KEY_6             17
  152. #define KEY_7             18
  153. #define KEY_8             19
  154. #define KEY_9             20
  155. #define KEY_XON           21
  156. #define KEY_XOFF          22
  157. #define KEY_INFO          23
  158. #define KEY_TERMCAP       24
  159. #define KEY_QUIT          25
  160. #define KEY_DETACH        26
  161. #define KEY_CREATE        27
  162.  
  163. struct key {
  164.     int type;
  165.     char **args;
  166. } ktab[256];
  167.  
  168. char *KeyNames[] = {
  169.     "hardcopy", "suspend", "shell", "next", "prev", "kill", "redisplay",
  170.     "windows", "version", "other", "select0", "select1", "select2", "select3",
  171.     "select4", "select5", "select6", "select7", "select8", "select9",
  172.     "xon", "xoff", "info", "termcap", "quit", "detach",
  173.     0
  174. };
  175.  
  176. main (ac, av) char **av; {
  177.     register n, len;
  178.     register struct win **pp, *p;
  179.     char *ap;
  180.     int s, r, w, x = 0;
  181.     int aflag = 0;
  182.     struct timeval tv;
  183.     time_t now;
  184.     char buf[IOSIZE], *myname = (ac == 0) ? "screen" : av[0];
  185.     char rc[256];
  186.     struct stat st;
  187.  
  188.     while (ac > 0) {
  189.     ap = *++av;
  190.     if (--ac > 0 && *ap == '-') {
  191.         switch (ap[1]) {
  192.         case 'c':        /* Compatibility with older versions. */
  193.         break;
  194.         case 'a':
  195.         aflag = 1;
  196.         break;
  197.         case 'm':
  198.         mflag = 1;
  199.         break;
  200.         case 'n':
  201.         nflag = 1;
  202.         break;
  203.         case 'f':
  204.         fflag = 1;
  205.         break;
  206.         case 'r':
  207.         rflag = 1;
  208.         if (ap[2]) {
  209.             SockName = ap+2;
  210.             if (ac != 1) goto help;
  211.         } else if (--ac == 1) {
  212.             SockName = *++av;
  213.         } else if (ac != 0) goto help;
  214.         break;
  215.         case 'e':
  216.         if (ap[2]) {
  217.             ap += 2;
  218.         } else {
  219.             if (--ac == 0) goto help;
  220.             ap = *++av;
  221.         }
  222.         if (strlen (ap) != 2)
  223.             Msg (0, "Two characters are required with -e option.");
  224.         Esc = ap[0];
  225.         MetaEsc = ap[1];
  226.         break;
  227.         default:
  228.         help:
  229.         Msg (0, "Use: %s [-a] [-f] [-n] [-e xy] [cmd args]\n\
  230.  or: %s -r [host.tty]", myname, myname);
  231.         }
  232.     } else break;
  233.     }
  234.     if (nflag && fflag)
  235.     Msg (0, "-f and -n are conflicting options.");
  236.     if ((ShellProg = getenv ("SHELL")) == 0)
  237.     ShellProg = DefaultShell;
  238.     ShellArgs[0] = ShellProg;
  239.     if (ac == 0) {
  240.     ac = 1;
  241.     av = ShellArgs;
  242.     }
  243.     if ((home = getenv ("HOME")) == 0)
  244.     Msg (0, "$HOME is undefined.");
  245.     sprintf (SockPath, "%s/%s", home, SockDir);
  246.     if (stat (SockPath, &st) == -1) {
  247.     if (errno == ENOENT) {
  248.         if (mkdir (SockPath, 0700) == -1)
  249.         Msg (errno, "Cannot make directory %s", SockPath);
  250.         (void) chown (SockPath, getuid (), getgid ());
  251.     } else Msg (errno, "Cannot get status of %s", SockPath);
  252.     } else {
  253.     if ((st.st_mode & S_IFMT) != S_IFDIR)
  254.         Msg (0, "%s is not a directory.", SockPath);
  255.     if ((st.st_mode & 0777) != 0700)
  256.         Msg (0, "Directory %s must have mode 700.", SockPath);
  257.     if (st.st_uid != getuid ())
  258.         Msg (0, "You are not the owner of %s.", SockPath);
  259.     }
  260.     (void) gethostname (HostName, MAXSTR);
  261.     HostName[MAXSTR-1] = '\0';
  262.     if (ap = index (HostName, '.'))
  263.     *ap = '\0';
  264.     strcat (SockPath, "/");
  265.     SockNamePtr = SockPath + strlen (SockPath);
  266.     if ((DevTty = open ("/dev/tty", O_RDWR|O_NDELAY)) == -1)
  267.     Msg (errno, "/dev/tty");
  268.     if (rflag) {
  269.     Attach (MSG_ATTACH);
  270.     Attacher ();
  271.     /*NOTREACHED*/
  272.     }
  273.     if (GetSockName ()) {
  274.     s = MakeClientSocket (1);
  275.     SendCreateMsg (s, ac, av, aflag);
  276.     close (s);
  277.     exit (0);
  278.     }
  279.     switch (fork ()) {
  280.     case -1:
  281.     Msg (errno, "fork");
  282.     /*NOTREACHED*/
  283.     case 0:
  284.     break;
  285.     default:
  286.     Attacher ();
  287.     /*NOTREACHED*/
  288.     }
  289.     AttacherPid = getppid ();
  290.     ServerSocket = s = MakeServerSocket ();
  291.     InitTerm ();
  292.     if (fflag)
  293.     flowctl = 1;
  294.     else if (nflag)
  295.     flowctl = 0;
  296.     MakeNewEnv ();
  297.     GetTTY (0, &OldMode);
  298.     ospeed = (short)OldMode.m_ttyb.sg_ospeed;
  299.     InitUtmp ();
  300. #ifdef LOADAV
  301.     InitKmem ();
  302. #endif
  303.     signal (SIGHUP, SigHup);
  304.     signal (SIGINT, Finit);
  305.     signal (SIGQUIT, Finit);
  306.     signal (SIGTERM, Finit);
  307.     signal (SIGTTIN, SIG_IGN);
  308.     signal (SIGTTOU, SIG_IGN);
  309.     InitKeytab ();
  310.     sprintf (rc, "%.*s/.screenrc", 245, home);
  311.     ReadRc (rc);
  312.     if ((n = MakeWindow (*av, av, aflag, 0, (char *)0)) == -1) {
  313.     SetTTY (0, &OldMode);
  314.     FinitTerm ();
  315.     Kill (AttacherPid, SIGHUP);
  316.     exit (1);
  317.     }
  318.     SetCurrWindow (n);
  319.     HasWindow = 1;
  320.     SetMode (&OldMode, &NewMode);
  321.     SetTTY (0, &NewMode);
  322.     signal (SIGCHLD, SigChld);
  323.     tv.tv_usec = 0;
  324.     while (1) {
  325.     if (status) {
  326.         time (&now);
  327.         if (now - TimeDisplayed < MSGWAIT) {
  328.         tv.tv_sec = MSGWAIT - (now - TimeDisplayed);
  329.         } else RemoveStatus (curr);
  330.     }
  331.     r = 0;
  332.     w = 0;
  333.     if (inlen)
  334.         w |= 1 << curr->ptyfd;
  335.     else
  336.         r |= 1 << 0;
  337.     for (pp = wtab; pp < wtab+MAXWIN; ++pp) {
  338.         if (!(p = *pp))
  339.         continue;
  340.         if ((*pp)->active && status)
  341.         continue;
  342.         if ((*pp)->outlen > 0)
  343.         continue;
  344.         r |= 1 << (*pp)->ptyfd;
  345.     }
  346.     r |= 1 << s;
  347.     (void) fflush (stdout);
  348.     if (GotSignal && !status) {
  349.         SigHandler ();
  350.         continue;
  351.     }
  352.     if (select (32, &r, &w, &x, status ? &tv : (struct timeval *)0) == -1) {
  353.         if (errno == EINTR)
  354.         continue;
  355.         HasWindow = 0;
  356.         Msg (errno, "select");
  357.         /*NOTREACHED*/
  358.     }
  359.     if (GotSignal && !status) {
  360.         SigHandler ();
  361.         continue;
  362.     }
  363.     if (r & 1 << s) {
  364.         RemoveStatus (curr);
  365.         ReceiveMsg (s);
  366.     }
  367.     if (r & 1 << 0) {
  368.         RemoveStatus (curr);
  369.         if (ESCseen) {
  370.         inbuf[0] = Esc;
  371.         inlen = read (0, inbuf+1, IOSIZE-1) + 1;
  372.         ESCseen = 0;
  373.         } else {
  374.         inlen = read (0, inbuf, IOSIZE);
  375.         }
  376.         if (inlen > 0)
  377.         inlen = ProcessInput (inbuf, inlen);
  378.         if (inlen > 0)
  379.         continue;
  380.     }
  381.     if (GotSignal && !status) {
  382.         SigHandler ();
  383.         continue;
  384.     }
  385.     if (w & 1 << curr->ptyfd && inlen > 0) {
  386.         if ((len = write (curr->ptyfd, inbuf, inlen)) > 0) {
  387.         inlen -= len;
  388.         bcopy (inbuf+len, inbuf, inlen);
  389.         }
  390.     }
  391.     if (GotSignal && !status) {
  392.         SigHandler ();
  393.         continue;
  394.     }
  395.     for (pp = wtab; pp < wtab+MAXWIN; ++pp) {
  396.         if (!(p = *pp))
  397.         continue;
  398.         if (p->outlen) {
  399.         WriteString (p, p->outbuf, p->outlen);
  400.         } else if (r & 1 << p->ptyfd) {
  401.         if ((len = read (p->ptyfd, buf, IOSIZE)) == -1) {
  402.             if (errno == EWOULDBLOCK)
  403.             len = 0;
  404.         }
  405.         if (len > 0)
  406.             WriteString (p, buf, len);
  407.         }
  408.         if (p->bell) {
  409.         p->bell = 0;
  410.         Msg (0, MakeBellMsg (pp-wtab));
  411.         }
  412.     }
  413.     if (GotSignal && !status)
  414.         SigHandler ();
  415.     }
  416.     /*NOTREACHED*/
  417. }
  418.  
  419. static SigHandler () {
  420.     while (GotSignal) {
  421.     GotSignal = 0;
  422.     DoWait ();
  423.     }
  424. }
  425.  
  426. static SigChld () {
  427.     GotSignal = 1;
  428. }
  429.  
  430. static SigHup () {
  431.     Detach (0);
  432. }
  433.  
  434. static DoWait () {
  435.     register pid;
  436.     register struct win **pp;
  437.     union wait wstat;
  438.  
  439.     while ((pid = wait3 (&wstat, WNOHANG|WUNTRACED, NULL)) > 0) {
  440.     for (pp = wtab; pp < wtab+MAXWIN; ++pp) {
  441.         if (*pp && pid == (*pp)->wpid) {
  442.         if (WIFSTOPPED (wstat)) {
  443.             (void) killpg (getpgrp ((*pp)->wpid), SIGCONT);
  444.         } else {
  445.             KillWindow (pp);
  446.         }
  447.         }
  448.     }
  449.     }
  450.     CheckWindows ();
  451. }
  452.  
  453. static KillWindow (pp) struct win **pp; {
  454.     if (*pp == curr)
  455.     curr = 0;
  456.     if (*pp == other)
  457.     other = 0;
  458.     FreeWindow (*pp);
  459.     *pp = 0;
  460. }
  461.  
  462. static CheckWindows () {
  463.     register struct win **pp;
  464.  
  465.     /* If the current window disappeared and the "other" window is still
  466.      * there, switch to the "other" window, else switch to the window
  467.      * with the lowest index.
  468.      * If there current window is still there, but the "other" window
  469.      * vanished, "SetCurrWindow" is called in order to assign a new value
  470.      * to "other".
  471.      * If no window is alive at all, exit.
  472.      */
  473.     if (!curr && other) {
  474.     SwitchWindow (OtherNum);
  475.     return;
  476.     }
  477.     if (curr && !other) {
  478.     SetCurrWindow (CurrNum);
  479.     return;
  480.     }
  481.     for (pp = wtab; pp < wtab+MAXWIN; ++pp) {
  482.     if (*pp) {
  483.         if (!curr)
  484.         SwitchWindow (pp-wtab);
  485.         return;
  486.     }
  487.     }
  488.     Finit ();
  489. }
  490.  
  491. static Finit () {
  492.     register struct win *p, **pp;
  493.  
  494.     for (pp = wtab; pp < wtab+MAXWIN; ++pp) {
  495.     if (p = *pp)
  496.         FreeWindow (p);
  497.     }
  498.     SetTTY (0, &OldMode);
  499.     FinitTerm ();
  500.     printf ("[screen is terminating]\n");
  501.     Kill (AttacherPid, SIGHUP);
  502.     exit (0);
  503. }
  504.  
  505. static InitKeytab () {
  506.     register i;
  507.  
  508.     ktab['h'].type = ktab[Ctrl('h')].type = KEY_HARDCOPY;
  509.     ktab['z'].type = ktab[Ctrl('z')].type = KEY_SUSPEND;
  510.     ktab['c'].type = ktab[Ctrl('c')].type = KEY_SHELL;
  511.     ktab[' '].type = ktab[Ctrl(' ')].type = 
  512.     ktab['n'].type = ktab[Ctrl('n')].type = KEY_NEXT;
  513.     ktab['-'].type = ktab['p'].type = ktab[Ctrl('p')].type = KEY_PREV;
  514.     ktab['k'].type = ktab[Ctrl('k')].type = KEY_KILL;
  515.     ktab['l'].type = ktab[Ctrl('l')].type = KEY_REDISPLAY;
  516.     ktab['w'].type = ktab[Ctrl('w')].type = KEY_WINDOWS;
  517.     ktab['v'].type = ktab[Ctrl('v')].type = KEY_VERSION;
  518.     ktab['q'].type = ktab[Ctrl('q')].type = KEY_XON;
  519.     ktab['s'].type = ktab[Ctrl('s')].type = KEY_XOFF;
  520.     ktab['t'].type = ktab[Ctrl('t')].type = KEY_INFO;
  521.     ktab['.'].type = KEY_TERMCAP;
  522.     ktab[Ctrl('\\')].type = KEY_QUIT;
  523.     ktab['d'].type = ktab[Ctrl('d')].type = KEY_DETACH;
  524.     ktab[Esc].type = KEY_OTHER;
  525.     for (i = 0; i <= 9; i++)
  526.     ktab[i+'0'].type = KEY_0+i;
  527. }
  528.  
  529. static ProcessInput (buf, len) char *buf; {
  530.     register n, k;
  531.     register char *s, *p;
  532.     register struct win **pp;
  533.  
  534.     for (s = p = buf; len > 0; len--, s++) {
  535.     if (*s == Esc) {
  536.         if (len > 1) {
  537.         len--; s++;
  538.         k = ktab[*s].type;
  539.         if (*s == MetaEsc) {
  540.             *p++ = Esc;
  541.         } else if (k >= KEY_0 && k <= KEY_9) {
  542.             p = buf;
  543.             SwitchWindow (k - KEY_0);
  544.         } else switch (ktab[*s].type) {
  545.         case KEY_TERMCAP:
  546.             p = buf;
  547.             WriteFile (0);
  548.             break;
  549.         case KEY_HARDCOPY:
  550.             p = buf;
  551.             WriteFile (1);
  552.             break;
  553.         case KEY_SUSPEND:
  554.             p = buf;
  555.             Detach (1);
  556.             break;
  557.         case KEY_SHELL:
  558.             p = buf;
  559.             if ((n = MakeWindow (ShellProg, ShellArgs,
  560.                 0, 0, (char *)0)) != -1)
  561.             SwitchWindow (n);
  562.             break;
  563.         case KEY_NEXT:
  564.             p = buf;
  565.             if (MoreWindows ())
  566.             SwitchWindow (NextWindow ());
  567.             break;
  568.         case KEY_PREV:
  569.             p = buf;
  570.             if (MoreWindows ())
  571.             SwitchWindow (PreviousWindow ());
  572.             break;
  573.         case KEY_KILL:
  574.             p = buf;
  575.             FreeWindow (wtab[CurrNum]);
  576.             if (other == curr)
  577.             other = 0;
  578.             curr = wtab[CurrNum] = 0;
  579.             CheckWindows ();
  580.             break;
  581.         case KEY_QUIT:
  582.             for (pp = wtab; pp < wtab+MAXWIN; ++pp)
  583.             if (*pp) FreeWindow (*pp);
  584.             Finit ();
  585.             /*NOTREACHED*/
  586.         case KEY_DETACH:
  587.             p = buf;
  588.             Detach (0);
  589.             break;
  590.         case KEY_REDISPLAY:
  591.             p = buf;
  592.             Activate (wtab[CurrNum]);
  593.             break;
  594.         case KEY_WINDOWS:
  595.             p = buf;
  596.             ShowWindows ();
  597.             break;
  598.         case KEY_VERSION:
  599.             p = buf;
  600.             Msg (0, "%s  %s", ScreenVersion, AnsiVersion);
  601.             break;
  602.         case KEY_INFO:
  603.             p = buf;
  604.             ShowInfo ();
  605.             break;
  606.         case KEY_OTHER:
  607.             p = buf;
  608.             if (MoreWindows ())
  609.             SwitchWindow (OtherNum);
  610.             break;
  611.         case KEY_XON:
  612.             *p++ = Ctrl('q');
  613.             break;
  614.         case KEY_XOFF:
  615.             *p++ = Ctrl('s');
  616.             break;
  617.         case KEY_CREATE:
  618.             p = buf;
  619.             if ((n = MakeWindow (ktab[*s].args[0], ktab[*s].args,
  620.                 0, 0, (char *)0)) != -1)
  621.             SwitchWindow (n);
  622.             break;
  623.         }
  624.         } else ESCseen = 1;
  625.     } else *p++ = *s;
  626.     }
  627.     return p - buf;
  628. }
  629.  
  630. static SwitchWindow (n) {
  631.     if (!wtab[n])
  632.     return;
  633.     SetCurrWindow (n);
  634.     Activate (wtab[n]);
  635. }
  636.  
  637. static SetCurrWindow (n) {
  638.     /*
  639.      * If we come from another window, this window becomes the
  640.      * "other" window:
  641.      */
  642.     if (curr) {
  643.     curr->active = 0;
  644.     other = curr;
  645.     OtherNum = CurrNum;
  646.     }
  647.     CurrNum = n;
  648.     curr = wtab[n];
  649.     curr->active = 1;
  650.     /*
  651.      * If the "other" window is currently undefined (at program start
  652.      * or because it has died), or if the "other" window is equal to the
  653.      * one just selected, we try to find a new one:
  654.      */
  655.     if (other == 0 || other == curr) {
  656.     OtherNum = NextWindow ();
  657.     other = wtab[OtherNum];
  658.     }
  659. }
  660.  
  661. static NextWindow () {
  662.     register struct win **pp;
  663.  
  664.     for (pp = wtab+CurrNum+1; pp != wtab+CurrNum; ++pp) {
  665.     if (pp == wtab+MAXWIN)
  666.         pp = wtab;
  667.     if (*pp)
  668.         break;
  669.     }
  670.     return pp-wtab;
  671. }
  672.  
  673. static PreviousWindow () {
  674.     register struct win **pp;
  675.  
  676.     for (pp = wtab+CurrNum-1; pp != wtab+CurrNum; --pp) {
  677.     if (pp < wtab)
  678.         pp = wtab+MAXWIN-1;
  679.     if (*pp)
  680.         break;
  681.     }
  682.     return pp-wtab;
  683. }
  684.  
  685. static MoreWindows () {
  686.     register struct win **pp;
  687.     register n;
  688.  
  689.     for (n = 0, pp = wtab; pp < wtab+MAXWIN; ++pp)
  690.     if (*pp) ++n;
  691.     if (n <= 1)
  692.     Msg (0, "No other window.");
  693.     return n > 1;
  694. }
  695.  
  696. static FreeWindow (wp) struct win *wp; {
  697.     register i;
  698.  
  699.     RemoveUtmp (wp->slot);
  700.     (void) chmod (wp->tty, 0666);
  701.     (void) chown (wp->tty, 0, 0);
  702.     close (wp->ptyfd);
  703.     for (i = 0; i < rows; ++i) {
  704.     free (wp->image[i]);
  705.     free (wp->attr[i]);
  706.     free (wp->font[i]);
  707.     }
  708.     free (wp->image);
  709.     free (wp->attr);
  710.     free (wp->font);
  711.     free (wp);
  712. }
  713.  
  714. static MakeWindow (prog, args, aflag, StartAt, dir)
  715.     char *prog, **args, *dir; {
  716.     register struct win **pp, *p;
  717.     register char **cp;
  718.     register n, f;
  719.     int tf;
  720.     int mypid;
  721.     char ebuf[10];
  722.  
  723.     pp = wtab+StartAt;
  724.     do {
  725.     if (*pp == 0)
  726.         break;
  727.     if (++pp == wtab+MAXWIN)
  728.         pp = wtab;
  729.     } while (pp != wtab+StartAt);
  730.     if (*pp) {
  731.     Msg (0, "No more windows.");
  732.     return -1;
  733.     }
  734.     n = pp - wtab;
  735.     if ((f = OpenPTY ()) == -1) {
  736.     Msg (0, "No more PTYs.");
  737.     return -1;
  738.     }
  739.     (void) fcntl (f, F_SETFL, FNDELAY);
  740.     if ((p = *pp = (struct win *)malloc (sizeof (struct win))) == 0) {
  741. nomem:
  742.     Msg (0, "Out of memory.");
  743.     return -1;
  744.     }
  745.     if ((p->image = (char **)malloc (rows * sizeof (char *))) == 0)
  746.     goto nomem;
  747.     for (cp = p->image; cp < p->image+rows; ++cp) {
  748.     if ((*cp = malloc (cols)) == 0)
  749.         goto nomem;
  750.     bclear (*cp, cols);
  751.     }
  752.     if ((p->attr = (char **)malloc (rows * sizeof (char *))) == 0)
  753.     goto nomem;
  754.     for (cp = p->attr; cp < p->attr+rows; ++cp) {
  755.     if ((*cp = malloc (cols)) == 0)
  756.         goto nomem;
  757.     bzero (*cp, cols);
  758.     }
  759.     if ((p->font = (char **)malloc (rows * sizeof (char *))) == 0)
  760.     goto nomem;
  761.     for (cp = p->font; cp < p->font+rows; ++cp) {
  762.     if ((*cp = malloc (cols)) == 0)
  763.         goto nomem;
  764.     bzero (*cp, cols);
  765.     }
  766.     if ((p->tabs = malloc (cols+1)) == 0)  /* +1 because 0 <= x <= cols */
  767.     goto nomem;
  768.     ResetScreen (p);
  769.     p->aflag = aflag;
  770.     p->active = 0;
  771.     p->bell = 0;
  772.     p->outlen = 0;
  773.     p->ptyfd = f;
  774.     strncpy (p->cmd, Filename (args[0]), MAXSTR-1);
  775.     p->cmd[MAXSTR-1] = '\0';
  776.     strncpy (p->tty, TtyName, MAXSTR-1);
  777.     (void) chown (TtyName, getuid (), getgid ());
  778.     (void) chmod (TtyName, TtyMode);
  779.     p->slot = SetUtmp (TtyName);
  780.     switch (p->wpid = fork ()) {
  781.     case -1:
  782.     Msg (errno, "fork");
  783.     free ((char *)p);
  784.     return -1;
  785.     case 0:
  786.     signal (SIGHUP, SIG_DFL);
  787.     signal (SIGINT, SIG_DFL);
  788.     signal (SIGQUIT, SIG_DFL);
  789.     signal (SIGTERM, SIG_DFL);
  790.     signal (SIGTTIN, SIG_DFL);
  791.     signal (SIGTTOU, SIG_DFL);
  792.     setuid (getuid ());
  793.     setgid (getgid ());
  794.     if (dir && chdir (dir) == -1) {
  795.         SendErrorMsg ("Cannot chdir to %s: %s", dir, sys_errlist[errno]);
  796.         exit (1);
  797.     }
  798.     mypid = getpid ();
  799.     ioctl (DevTty, TIOCNOTTY, (char *)0);
  800.     if ((tf = open (TtyName, O_RDWR)) == -1) {
  801.         SendErrorMsg ("Cannot open %s: %s", TtyName, sys_errlist[errno]);
  802.         exit (1);
  803.     }
  804.     (void) dup2 (tf, 0);
  805.     (void) dup2 (tf, 1);
  806.     (void) dup2 (tf, 2);
  807.     for (f = getdtablesize () - 1; f > 2; f--)
  808.         close (f);
  809.     ioctl (0, TIOCSPGRP, &mypid);
  810.     (void) setpgrp (0, mypid);
  811.     SetTTY (0, &OldMode);
  812.     NewEnv[2] = MakeTermcap (aflag);
  813.     sprintf (ebuf, "WINDOW=%d", n);
  814.     NewEnv[3] = ebuf;
  815.     execvpe (prog, args, NewEnv);
  816.     SendErrorMsg ("Cannot exec %s: %s", prog, sys_errlist[errno]);
  817.     exit (1);
  818.     }
  819.     return n;
  820. }
  821.  
  822. static execvpe (prog, args, env) char *prog, **args, **env; {
  823.     register char *path, *p;
  824.     char buf[1024];
  825.     char *shargs[MAXARGS+1];
  826.     register i, eaccess = 0;
  827.  
  828.     if (prog[0] == '/')
  829.     path = "";
  830.     else if ((path = getenv ("PATH")) == 0)
  831.     path = DefaultPath;
  832.     do {
  833.     p = buf;
  834.     while (*path && *path != ':')
  835.         *p++ = *path++;
  836.     if (p > buf)
  837.         *p++ = '/';
  838.     strcpy (p, prog);
  839.     if (*path)
  840.         ++path;
  841.     execve (buf, args, env);
  842.     switch (errno) {
  843.     case ENOEXEC:
  844.         shargs[0] = DefaultShell;
  845.         shargs[1] = buf;
  846.         for (i = 1; shargs[i+1] = args[i]; ++i)
  847.         ;
  848.         execve (DefaultShell, shargs, env);
  849.         return;
  850.     case EACCES:
  851.         eaccess = 1;
  852.         break;
  853.     case ENOMEM: case E2BIG: case ETXTBSY:
  854.         return;
  855.     }
  856.     } while (*path);
  857.     if (eaccess)
  858.     errno = EACCES;
  859. }
  860.  
  861. static WriteFile (dump) {   /* dump==0: create .termcap, dump==1: hardcopy */
  862.     register i, j, k;
  863.     register char *p;
  864.     register FILE *f;
  865.     char fn[1024];
  866.     int pid, s;
  867.  
  868.     if (dump)
  869.     sprintf (fn, "hardcopy.%d", CurrNum);
  870.     else
  871.     sprintf (fn, "%s/%s/.termcap", home, SockDir);
  872.     switch (pid = fork ()) {
  873.     case -1:
  874.     Msg (errno, "fork");
  875.     return;
  876.     case 0:
  877.     setuid (getuid ());
  878.     setgid (getgid ());
  879.     if ((f = fopen (fn, "w")) == NULL)
  880.         exit (1);
  881.     if (dump) {
  882.         for (i = 0; i < rows; ++i) {
  883.         p = curr->image[i];
  884.         for (k = cols-1; k >= 0 && p[k] == ' '; --k) ;
  885.         for (j = 0; j <= k; ++j)
  886.             putc (p[j], f);
  887.         putc ('\n', f);
  888.         }
  889.     } else {
  890.         if (p = index (MakeTermcap (curr->aflag), '=')) {
  891.         fputs (++p, f);
  892.         putc ('\n', f);
  893.         }
  894.     }
  895.     (void) fclose (f);
  896.     exit (0);
  897.     default:
  898.     while ((i = wait (&s)) != pid)
  899.         if (i == -1) return;
  900.     if ((s >> 8) & 0377)
  901.         Msg (0, "Cannot open \"%s\".", fn);
  902.     else
  903.         Msg (0, "%s written to \"%s\".", dump ? "Screen image" :
  904.         "Termcap entry", fn);
  905.     }
  906. }
  907.  
  908. static ShowWindows () {
  909.     char buf[1024];
  910.     register char *s;
  911.     register struct win **pp, *p;
  912.  
  913.     for (s = buf, pp = wtab; pp < wtab+MAXWIN; ++pp) {
  914.     if ((p = *pp) == 0)
  915.         continue;
  916.     if (s - buf + 5 + strlen (p->cmd) > cols-1)
  917.         break;
  918.     if (s > buf) {
  919.         *s++ = ' '; *s++ = ' ';
  920.     }
  921.     *s++ = pp - wtab + '0';
  922.     if (p == curr)
  923.         *s++ = '*';
  924.     else if (p == other)
  925.         *s++ = '-';
  926.     *s++ = ' ';
  927.     strcpy (s, p->cmd);
  928.     s += strlen (s);
  929.     }
  930.     Msg (0, buf);
  931. }
  932.  
  933. static ShowInfo () {
  934.     char buf[1024], *p;
  935.     register struct win *wp = curr;
  936.     register i;
  937.     struct tm *tp;
  938.     time_t now;
  939.  
  940.     time (&now);
  941.     tp = localtime (&now);
  942.     sprintf (buf, "%2d:%02.2d:%02.2d %s", tp->tm_hour, tp->tm_min, tp->tm_sec,
  943.     HostName);
  944. #ifdef LOADAV
  945.     if (avenrun && GetAvenrun ()) {
  946.     p = buf + strlen (buf);
  947. #ifdef SUNLOADAV
  948.     sprintf (p, " %2.2f %2.2f %2.2f", (double)loadav[0]/FSCALE,
  949.         (double)loadav[1]/FSCALE, (double)loadav[2]/FSCALE);
  950. #else
  951. #ifdef alliant
  952.     sprintf (p, " %2.2f %2.2f %2.2f %2.2f", (double)loadav[0]/100,
  953.         (double)loadav[1]/100, (double)loadav[2]/100,
  954.         (double)loadav[3]/100);
  955. #else
  956.     sprintf (p, " %2.2f %2.2f %2.2f", loadav[0], loadav[1], loadav[2]);
  957. #endif
  958. #endif
  959.     }
  960. #endif
  961.     p = buf + strlen (buf);
  962.     sprintf (p, " (%d,%d) %cflow %cins %corg %cwrap %cpad", wp->y, wp->x,
  963.     flowctl ? '+' : '-',
  964.     wp->insert ? '+' : '-', wp->origin ? '+' : '-',
  965.     wp->wrap ? '+' : '-', wp->keypad ? '+' : '-');
  966.     if (ISO2022) {
  967.     p = buf + strlen (buf);
  968.     sprintf (p, " G%1d [", wp->LocalCharset);
  969.     for (i = 0; i < 4; i++)
  970.         p[i+5] = wp->charsets[i] ? wp->charsets[i] : 'B';
  971.     p[9] = ']';
  972.     p[10] = '\0';
  973.     }
  974.     Msg (0, buf);
  975. }
  976.  
  977. static OpenPTY () {
  978.     register char *p, *l, *d;
  979.     register i, f, tf;
  980.  
  981.     strcpy (PtyName, PtyProto);
  982.     strcpy (TtyName, TtyProto);
  983.     for (p = PtyName, i = 0; *p != 'X'; ++p, ++i) ;
  984.     for (l = "qpr"; *p = *l; ++l) {
  985.     for (d = "0123456789abcdef"; p[1] = *d; ++d) {
  986.         if ((f = open (PtyName, O_RDWR)) != -1) {
  987.         TtyName[i] = p[0];
  988.         TtyName[i+1] = p[1];
  989.         if ((tf = open (TtyName, O_RDWR)) != -1) {
  990.             close (tf);
  991.             return f;
  992.         }
  993.         close (f);
  994.         }
  995.     }
  996.     }
  997.     return -1;
  998. }
  999.  
  1000. static SetTTY (fd, mp) struct mode *mp; {
  1001.     ioctl (fd, TIOCSETP, &mp->m_ttyb);
  1002.     ioctl (fd, TIOCSETC, &mp->m_tchars);
  1003.     ioctl (fd, TIOCSLTC, &mp->m_ltchars);
  1004.     ioctl (fd, TIOCLSET, &mp->m_lmode);
  1005.     ioctl (fd, TIOCSETD, &mp->m_ldisc);
  1006. }
  1007.  
  1008. static GetTTY (fd, mp) struct mode *mp; {
  1009.     ioctl (fd, TIOCGETP, &mp->m_ttyb);
  1010.     ioctl (fd, TIOCGETC, &mp->m_tchars);
  1011.     ioctl (fd, TIOCGLTC, &mp->m_ltchars);
  1012.     ioctl (fd, TIOCLGET, &mp->m_lmode);
  1013.     ioctl (fd, TIOCGETD, &mp->m_ldisc);
  1014. }
  1015.  
  1016. static SetMode (op, np) struct mode *op, *np; {
  1017.     *np = *op;
  1018.     np->m_ttyb.sg_flags &= ~(CRMOD|ECHO);
  1019.     np->m_ttyb.sg_flags |= CBREAK;
  1020.     np->m_tchars.t_intrc = -1;
  1021.     np->m_tchars.t_quitc = -1;
  1022.     if (!flowctl) {
  1023.     np->m_tchars.t_startc = -1;
  1024.     np->m_tchars.t_stopc = -1;
  1025.     }
  1026.     np->m_ltchars.t_suspc = -1;
  1027.     np->m_ltchars.t_dsuspc = -1;
  1028.     np->m_ltchars.t_flushc = -1;
  1029.     np->m_ltchars.t_lnextc = -1;
  1030. }
  1031.  
  1032. static char *GetTtyName () {
  1033.     register char *p;
  1034.     register n;
  1035.  
  1036.     for (p = 0, n = 0; n <= 2 && !(p = ttyname (n)); n++)
  1037.     ;
  1038.     if (!p || *p == '\0')
  1039.     Msg (0, "screen must run on a tty.");
  1040.     return p;
  1041. }
  1042.  
  1043. static Attach (how) {
  1044.     register s, lasts, found = 0;
  1045.     register DIR *dirp;
  1046.     register struct direct *dp;
  1047.     struct msg m;
  1048.     char last[MAXNAMLEN+1];
  1049.  
  1050.     if (SockName) {
  1051.     if ((lasts = MakeClientSocket (0)) == -1)
  1052.         if (how == MSG_CONT)
  1053.         Msg (0,
  1054.             "This screen has already been continued from elsewhere.");
  1055.         else
  1056.         Msg (0, "There is no screen to be resumed from %s.", SockName);
  1057.     } else {
  1058.     if ((dirp = opendir (SockPath)) == NULL)
  1059.         Msg (0, "Cannot open %s", SockPath);
  1060.     while ((dp = readdir (dirp)) != NULL) {
  1061.         SockName = dp->d_name;
  1062.         if (SockName[0] == '.')
  1063.         continue;
  1064.         if ((s = MakeClientSocket (0)) != -1) {
  1065.         if (found == 0) {
  1066.             strcpy (last, SockName);
  1067.             lasts = s;
  1068.         } else {
  1069.             if (found == 1) {
  1070.             printf ("There are detached screens on:\n");
  1071.             printf ("   %s\n", last);
  1072.             close (lasts);
  1073.             }
  1074.             printf ("   %s\n", SockName);
  1075.             close (s);
  1076.         }
  1077.         found++;
  1078.         }
  1079.     }
  1080.     if (found == 0)
  1081.         Msg (0, "There is no screen to be resumed.");
  1082.     if (found > 1)
  1083.         Msg (0, "Type \"screen -r host.tty\" to resume one of them.");
  1084.     closedir (dirp);
  1085.     strcpy (SockNamePtr, last);
  1086.     SockName = SockNamePtr;
  1087.     }
  1088.     m.type = how;
  1089.     strcpy (m.m.attach.tty, GetTtyName ());
  1090.     m.m.attach.apid = getpid ();
  1091.     if (write (lasts, (char *)&m, sizeof (m)) != sizeof (m))
  1092.     Msg (errno, "write");
  1093. }
  1094.  
  1095. static AttacherFinit () {
  1096.     exit (0);
  1097. }
  1098.  
  1099. static ReAttach () {
  1100.     Attach (MSG_CONT);
  1101. }
  1102.  
  1103. static Attacher () {
  1104.     signal (SIGHUP, AttacherFinit);
  1105.     signal (SIGCONT, ReAttach);
  1106.     while (1)
  1107.     pause ();
  1108. }
  1109.  
  1110. static Detach (suspend) {
  1111.     register struct win **pp;
  1112.  
  1113.     if (Detached)
  1114.     return;
  1115.     signal (SIGHUP, SIG_IGN);
  1116.     SetTTY (0, &OldMode);
  1117.     FinitTerm ();
  1118.     if (suspend) {
  1119.     Kill (AttacherPid, SIGTSTP);
  1120.     } else {
  1121.     for (pp = wtab; pp < wtab+MAXWIN; ++pp)
  1122.         if (*pp) RemoveUtmp ((*pp)->slot);
  1123.     printf ("\n[detached]\n");
  1124.     Kill (AttacherPid, SIGHUP);
  1125.     AttacherPid = 0;
  1126.     }
  1127.     close (0);
  1128.     close (1);
  1129.     close (2);
  1130.     ioctl (DevTty, TIOCNOTTY, (char *)0);
  1131.     Detached = 1;
  1132.     do {
  1133.     ReceiveMsg (ServerSocket); 
  1134.     } while (Detached);
  1135.     if (!suspend)
  1136.     for (pp = wtab; pp < wtab+MAXWIN; ++pp)
  1137.         if (*pp) (*pp)->slot = SetUtmp ((*pp)->tty);
  1138.     signal (SIGHUP, SigHup);
  1139. }
  1140.  
  1141. static Kill (pid, sig) {
  1142.     if (pid != 0)
  1143.     (void) kill (pid, sig);
  1144. }
  1145.  
  1146. static GetSockName () {
  1147.     register client;
  1148.     static char buf[2*MAXSTR];
  1149.  
  1150.     if (!mflag && (SockName = getenv ("STY")) != 0 && *SockName != '\0') {
  1151.     client = 1;
  1152.     setuid (getuid ());
  1153.     setgid (getgid ());
  1154.     } else {
  1155.     sprintf (buf, "%s.%s", HostName, Filename (GetTtyName ()));
  1156.     SockName = buf;
  1157.     client = 0;
  1158.     }
  1159.     return client;
  1160. }
  1161.  
  1162. static MakeServerSocket () {
  1163.     register s;
  1164.     struct sockaddr_un a;
  1165.     char *p;
  1166.  
  1167.     if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1)
  1168.     Msg (errno, "socket");
  1169.     a.sun_family = AF_UNIX;
  1170.     strcpy (SockNamePtr, SockName);
  1171.     strcpy (a.sun_path, SockPath);
  1172.     if (connect (s, (struct sockaddr *)&a, strlen (SockPath)+2) != -1) {
  1173.     p = Filename (SockPath);
  1174.     Msg (0, "You have already a screen running on %s.\n\
  1175. If it has been detached, try \"screen -r\".", p);
  1176.     /*NOTREACHED*/
  1177.     }
  1178.     (void) unlink (SockPath);
  1179.     if (bind (s, (struct sockaddr *)&a, strlen (SockPath)+2) == -1)
  1180.     Msg (errno, "bind");
  1181.     (void) chown (SockPath, getuid (), getgid ());
  1182.     if (listen (s, 5) == -1)
  1183.     Msg (errno, "listen");
  1184.     return s;
  1185. }
  1186.  
  1187. static MakeClientSocket (err) {
  1188.     register s;
  1189.     struct sockaddr_un a;
  1190.  
  1191.     if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1)
  1192.     Msg (errno, "socket");
  1193.     a.sun_family = AF_UNIX;
  1194.     strcpy (SockNamePtr, SockName);
  1195.     strcpy (a.sun_path, SockPath);
  1196.     if (connect (s, (struct sockaddr *)&a, strlen (SockPath)+2) == -1) {
  1197.     if (err) {
  1198.         Msg (errno, "connect: %s", SockPath);
  1199.     } else {
  1200.         close (s);
  1201.         return -1;
  1202.     }
  1203.     }
  1204.     return s;
  1205. }
  1206.  
  1207. static SendCreateMsg (s, ac, av, aflag) char **av; {
  1208.     struct msg m;
  1209.     register char *p;
  1210.     register len, n;
  1211.  
  1212.     m.type = MSG_CREATE;
  1213.     p = m.m.create.line;
  1214.     for (n = 0; ac > 0 && n < MAXARGS-1; ++av, --ac, ++n) {
  1215.     len = strlen (*av) + 1;
  1216.     if (p + len >= m.m.create.line+MAXLINE)
  1217.         break;
  1218.     strcpy (p, *av);
  1219.     p += len;
  1220.     }
  1221.     m.m.create.nargs = n;
  1222.     m.m.create.aflag = aflag;
  1223.     if (getwd (m.m.create.dir) == 0)
  1224.     Msg (0, "%s", m.m.create.dir);
  1225.     if (write (s, (char *)&m, sizeof (m)) != sizeof (m))
  1226.     Msg (errno, "write");
  1227. }
  1228.  
  1229. /*VARARGS1*/
  1230. static SendErrorMsg (fmt, p1, p2, p3, p4, p5, p6) char *fmt; {
  1231.     register s;
  1232.     struct msg m;
  1233.  
  1234.     s = MakeClientSocket (1);
  1235.     m.type = MSG_ERROR;
  1236.     sprintf (m.m.message, fmt, p1, p2, p3, p4, p5, p6);
  1237.     (void) write (s, (char *)&m, sizeof (m));
  1238.     close (s);
  1239.     sleep (2);
  1240. }
  1241.  
  1242. static ReceiveMsg (s) {
  1243.     register ns;
  1244.     struct sockaddr_un a;
  1245.     int left, len = sizeof (a);
  1246.     struct msg m;
  1247.     char *p;
  1248.  
  1249.     if ((ns = accept (s, (struct sockaddr *)&a, &len)) == -1) {
  1250.     Msg (errno, "accept");
  1251.     return;
  1252.     }
  1253.     p = (char *)&m;
  1254.     left = sizeof (m);
  1255.     while (left > 0 && (len = read (ns, p, left)) > 0) {
  1256.     p += len;
  1257.     left -= len;
  1258.     }
  1259.     close (ns);
  1260.     if (len == -1)
  1261.     Msg (errno, "read");
  1262.     if (left > 0)
  1263.     return;
  1264.     switch (m.type) {
  1265.     case MSG_CREATE:
  1266.     if (!Detached)
  1267.         ExecCreate (&m);
  1268.     break;
  1269.     case MSG_CONT:
  1270.     if (m.m.attach.apid != AttacherPid || !Detached)
  1271.         break;    /* Intruder Alert */
  1272.     /*FALLTHROUGH*/
  1273.     case MSG_ATTACH:
  1274.     if (Detached) {
  1275.         if (kill (m.m.attach.apid, 0) == 0 &&
  1276.             open (m.m.attach.tty, O_RDWR) == 0) {
  1277.         (void) dup (0);
  1278.         (void) dup (0);
  1279.         AttacherPid = m.m.attach.apid;
  1280.         Detached = 0;
  1281.         GetTTY (0, &OldMode);
  1282.         SetMode (&OldMode, &NewMode);
  1283.         SetTTY (0, &NewMode);
  1284.         Activate (wtab[CurrNum]);
  1285.         }
  1286.     } else {
  1287.         Kill (m.m.attach.apid, SIGHUP);
  1288.         Msg (0, "Not detached.");
  1289.     }
  1290.     break;
  1291.     case MSG_ERROR:
  1292.     Msg (0, "%s", m.m.message);
  1293.     break;
  1294.     default:
  1295.     Msg (0, "Invalid message (type %d).", m.type);
  1296.     }
  1297. }
  1298.  
  1299. static ExecCreate (mp) struct msg *mp; {
  1300.     char *args[MAXARGS];
  1301.     register n;
  1302.     register char **pp = args, *p = mp->m.create.line;
  1303.  
  1304.     for (n = mp->m.create.nargs; n > 0; --n) {
  1305.     *pp++ = p;
  1306.     p += strlen (p) + 1;
  1307.     }
  1308.     *pp = 0;
  1309.     if ((n = MakeWindow (mp->m.create.line, args, mp->m.create.aflag, 0,
  1310.         mp->m.create.dir)) != -1)
  1311.     SwitchWindow (n);
  1312. }
  1313.  
  1314. static ReadRc (fn) char *fn; {
  1315.     FILE *f;
  1316.     register char *p, **pp, **ap;
  1317.     register argc, num, c;
  1318.     char buf[256];
  1319.     char *args[MAXARGS];
  1320.     int key;
  1321.  
  1322.     ap = args;
  1323.     if (access (fn, R_OK) == -1)
  1324.     return;
  1325.     if ((f = fopen (fn, "r")) == NULL)
  1326.     return;
  1327.     while (fgets (buf, 256, f) != NULL) {
  1328.     if (p = rindex (buf, '\n'))
  1329.         *p = '\0';
  1330.     if ((argc = Parse (fn, buf, ap)) == 0)
  1331.         continue;
  1332.     if (strcmp (ap[0], "escape") == 0) {
  1333.         p = ap[1];
  1334.         if (argc < 2 || strlen (p) != 2)
  1335.         Msg (0, "%s: two characters required after escape.", fn);
  1336.         Esc = *p++;
  1337.         MetaEsc = *p;
  1338.     } else if (strcmp (ap[0], "chdir") == 0) {
  1339.         p = argc < 2 ? home : ap[1];
  1340.         if (chdir (p) == -1)
  1341.         Msg (errno, "%s", p);
  1342.     } else if (strcmp (ap[0], "mode") == 0) {
  1343.         if (argc != 2) {
  1344.         Msg (0, "%s: mode: one argument required.", fn);
  1345.         } else if (!IsNum (ap[1], 7)) {
  1346.         Msg (0, "%s: mode: octal number expected.", fn);
  1347.         } else (void) sscanf (ap[1], "%o", &TtyMode);
  1348.     } else if (strcmp (ap[0], "bell") == 0) {
  1349.         if (argc != 2) {
  1350.         Msg (0, "%s: bell: one argument required.", fn);
  1351.         } else {
  1352.         if ((BellString = malloc (strlen (ap[1]) + 1)) == 0)
  1353.             Msg (0, "Out of memory.");
  1354.         strcpy (BellString, ap[1]);
  1355.         }
  1356.     } else if (strcmp (ap[0], "screen") == 0) {
  1357.         num = 0;
  1358.         if (argc > 1 && IsNum (ap[1], 10)) {
  1359.         num = atoi (ap[1]);
  1360.         if (num < 0 || num > MAXWIN-1)
  1361.             Msg (0, "%s: illegal screen number %d.", fn, num);
  1362.         --argc; ++ap;
  1363.         }
  1364.         if (argc < 2) {
  1365.         ap[1] = ShellProg; argc = 2;
  1366.         }
  1367.         ap[argc] = 0;
  1368.         (void) MakeWindow (ap[1], ap+1, 0, num, (char *)0);
  1369.     } else if (strcmp (ap[0], "bind") == 0) {
  1370.         p = ap[1];
  1371.         if (argc < 2 || *p == '\0')
  1372.         Msg (0, "%s: key expected after bind.", fn);
  1373.         if (p[1] == '\0') {
  1374.         key = *p;
  1375.         } else if (p[0] == '^' && p[1] != '\0' && p[2] == '\0') {
  1376.         c = p[1];
  1377.         if (isupper (c))
  1378.             p[1] = tolower (c);    
  1379.         key = Ctrl(c);
  1380.         } else if (IsNum (p, 7)) {
  1381.         (void) sscanf (p, "%o", &key);
  1382.         } else {
  1383.         Msg (0,
  1384.             "%s: bind: character, ^x, or octal number expected.", fn);
  1385.         }
  1386.         if (argc < 3) {
  1387.         ktab[key].type = 0;
  1388.         } else {
  1389.         for (pp = KeyNames; *pp; ++pp)
  1390.             if (strcmp (ap[2], *pp) == 0) break;
  1391.         if (*pp) {
  1392.             ktab[key].type = pp-KeyNames+1;
  1393.         } else {
  1394.             ktab[key].type = KEY_CREATE;
  1395.             ktab[key].args = SaveArgs (argc-2, ap+2);
  1396.         }
  1397.         }
  1398.     } else Msg (0, "%s: unknown keyword \"%s\".", fn, ap[0]);
  1399.     }
  1400.     (void) fclose (f);
  1401. }
  1402.  
  1403. static Parse (fn, buf, args) char *fn, *buf, **args; {
  1404.     register char *p = buf, **ap = args;
  1405.     register delim, argc = 0;
  1406.  
  1407.     argc = 0;
  1408.     for (;;) {
  1409.     while (*p && (*p == ' ' || *p == '\t')) ++p;
  1410.     if (*p == '\0' || *p == '#')
  1411.         return argc;
  1412.     if (argc > MAXARGS-1)
  1413.         Msg (0, "%s: too many tokens.", fn);
  1414.     delim = 0;
  1415.     if (*p == '"' || *p == '\'') {
  1416.         delim = *p; *p = '\0'; ++p;
  1417.     }
  1418.     ++argc;
  1419.     *ap = p; ++ap;
  1420.     while (*p && !(delim ? *p == delim : (*p == ' ' || *p == '\t')))
  1421.         ++p;
  1422.     if (*p == '\0') {
  1423.         if (delim)
  1424.         Msg (0, "%s: Missing quote.", fn);
  1425.         else
  1426.         return argc;
  1427.     }
  1428.     *p++ = '\0';
  1429.     }
  1430. }
  1431.  
  1432. static char **SaveArgs (argc, argv) register argc; register char **argv; {
  1433.     register char **ap, **pp;
  1434.  
  1435.     if ((pp = ap = (char **)malloc ((argc+1) * sizeof (char **))) == 0)
  1436.     Msg (0, "Out of memory.");
  1437.     while (argc--) {
  1438.     if ((*pp = malloc (strlen (*argv)+1)) == 0)
  1439.         Msg (0, "Out of memory.");
  1440.     strcpy (*pp, *argv);
  1441.     ++pp; ++argv;
  1442.     }
  1443.     *pp = 0;
  1444.     return ap;
  1445. }
  1446.  
  1447. static MakeNewEnv () {
  1448.     register char **op, **np = NewEnv;
  1449.     static char buf[MAXSTR];
  1450.  
  1451.     if (strlen (SockName) > MAXSTR-5)
  1452.     SockName = "?";
  1453.     sprintf (buf, "STY=%s", SockName);
  1454.     *np++ = buf;
  1455.     *np++ = Term;
  1456.     np += 2;
  1457.     for (op = environ; *op; ++op) {
  1458.     if (np == NewEnv + MAXARGS - 1)
  1459.         break;
  1460.     if (!IsSymbol (*op, "TERM") && !IsSymbol (*op, "TERMCAP")
  1461.         && !IsSymbol (*op, "STY"))
  1462.         *np++ = *op;
  1463.     }
  1464.     *np = 0;
  1465. }
  1466.  
  1467. static IsSymbol (e, s) register char *e, *s; {
  1468.     register char *p;
  1469.     register n;
  1470.  
  1471.     for (p = e; *p && *p != '='; ++p) ;
  1472.     if (*p) {
  1473.     *p = '\0';
  1474.     n = strcmp (e, s);
  1475.     *p = '=';
  1476.     return n == 0;
  1477.     }
  1478.     return 0;
  1479. }
  1480.  
  1481. /*VARARGS2*/
  1482. Msg (err, fmt, p1, p2, p3, p4, p5, p6) char *fmt; {
  1483.     char buf[1024];
  1484.     register char *p = buf;
  1485.  
  1486.     if (Detached)
  1487.     return;
  1488.     sprintf (p, fmt, p1, p2, p3, p4, p5, p6);
  1489.     if (err) {
  1490.     p += strlen (p);
  1491.     if (err > 0 && err < sys_nerr)
  1492.         sprintf (p, ": %s", sys_errlist[err]);
  1493.     else
  1494.         sprintf (p, ": Error %d", err);
  1495.     }
  1496.     if (HasWindow) {
  1497.     MakeStatus (buf, curr);
  1498.     } else {
  1499.     printf ("%s\r\n", buf);
  1500.     Kill (AttacherPid, SIGHUP);
  1501.     exit (1);
  1502.     }
  1503. }
  1504.  
  1505. bclear (p, n) char *p; {
  1506.     bcopy (blank, p, n);
  1507. }
  1508.  
  1509. static char *Filename (s) char *s; {
  1510.     register char *p;
  1511.  
  1512.     p = s + strlen (s) - 1;
  1513.     while (p >= s && *p != '/') --p;
  1514.     return ++p;
  1515. }
  1516.  
  1517. static IsNum (s, base) register char *s; register base; {
  1518.     for (base += '0'; *s; ++s)
  1519.     if (*s < '0' || *s > base)
  1520.         return 0;
  1521.     return 1;
  1522. }
  1523.  
  1524. static char *MakeBellMsg (n) {
  1525.     static char buf[MAXSTR];
  1526.     register char *p = buf, *s = BellString;
  1527.  
  1528.     for (s = BellString; *s && p < buf+MAXSTR-1; s++)
  1529.     *p++ = (*s == '%') ? n + '0' : *s;
  1530.     *p = '\0';
  1531.     return buf;
  1532. }
  1533.  
  1534. static InitUtmp () {
  1535.     struct passwd *p;
  1536.  
  1537.     if ((utmpf = open (UtmpName, O_WRONLY)) == -1) {
  1538.     if (errno != EACCES)
  1539.         Msg (errno, UtmpName);
  1540.     return;
  1541.     }
  1542.     if ((LoginName = getlogin ()) == 0 || LoginName[0] == '\0') {
  1543.     if ((p = getpwuid (getuid ())) == 0)
  1544.         return;
  1545.     LoginName = p->pw_name;
  1546.     }
  1547.     utmp = 1;
  1548. }
  1549.  
  1550. static SetUtmp (name) char *name; {
  1551.     register char *p;
  1552.     register struct ttyent *tp;
  1553.     register slot = 1;
  1554.     struct utmp u;
  1555.  
  1556.     if (!utmp)
  1557.     return 0;
  1558.     if (p = rindex (name, '/'))
  1559.     ++p;
  1560.     else p = name;
  1561.     setttyent ();
  1562.     while ((tp = getttyent ()) != NULL && strcmp (p, tp->ty_name) != 0)
  1563.     ++slot;
  1564.     if (tp == NULL)
  1565.     return 0;
  1566.     strncpy (u.ut_line, p, 8);
  1567.     strncpy (u.ut_name, LoginName, 8);
  1568.     u.ut_host[0] = '\0';
  1569.     time (&u.ut_time);
  1570.     (void) lseek (utmpf, (long)(slot * sizeof (u)), 0);
  1571.     (void) write (utmpf, (char *)&u, sizeof (u));
  1572.     return slot;
  1573. }
  1574.  
  1575. static RemoveUtmp (slot) {
  1576.     struct utmp u;
  1577.  
  1578.     if (slot) {
  1579.     bzero ((char *)&u, sizeof (u));
  1580.     (void) lseek (utmpf, (long)(slot * sizeof (u)), 0);
  1581.     (void) write (utmpf, (char *)&u, sizeof (u));
  1582.     }
  1583. }
  1584.  
  1585. #ifndef GETTTYENT
  1586.  
  1587. static setttyent () {
  1588.     struct stat s;
  1589.     register f;
  1590.     register char *p, *ep;
  1591.  
  1592.     if (ttnext) {
  1593.     ttnext = tt;
  1594.     return;
  1595.     }
  1596.     if ((f = open (ttys, O_RDONLY)) == -1 || fstat (f, &s) == -1)
  1597.     Msg (errno, ttys);
  1598.     if ((tt = malloc (s.st_size + 1)) == 0)
  1599.     Msg (0, "Out of memory.");
  1600.     if (read (f, tt, s.st_size) != s.st_size)
  1601.     Msg (errno, ttys);
  1602.     close (f);
  1603.     for (p = tt, ep = p + s.st_size; p < ep; ++p)
  1604.     if (*p == '\n') *p = '\0';
  1605.     *p = '\0';
  1606.     ttnext = tt;
  1607. }
  1608.  
  1609. static struct ttyent *getttyent () {
  1610.     static struct ttyent t;
  1611.  
  1612.     if (*ttnext == '\0')
  1613.     return NULL;
  1614.     t.ty_name = ttnext + 2;
  1615.     ttnext += strlen (ttnext) + 1;
  1616.     return &t;
  1617. }
  1618.  
  1619. #endif
  1620.  
  1621. #ifdef LOADAV
  1622.  
  1623. static InitKmem () {
  1624.     if ((kmemf = open (KmemName, O_RDONLY)) == -1)
  1625.     return;
  1626.     nl[0].n_name = AvenrunSym;
  1627.     nlist (UnixName, nl);
  1628.     if (nl[0].n_type == 0 || nl[0].n_value == 0)
  1629.     return;
  1630.     avenrun = 1;
  1631. }
  1632.  
  1633. static GetAvenrun () {
  1634.     if (lseek (kmemf, nl[0].n_value, 0) == -1)
  1635.     return 0;
  1636.     if (read (kmemf, loadav, sizeof (loadav)) != sizeof (loadav))
  1637.     return 0;
  1638.     return 1;
  1639. }
  1640.  
  1641. #endif
  1642.  
  1643. #ifndef USEBCOPY
  1644. bcopy (s1, s2, len) register char *s1, *s2; register len; {
  1645.     if (s1 < s2 && s2 < s1 + len) {
  1646.     s1 += len; s2 += len;
  1647.     while (len-- > 0) {
  1648.         *--s2 = *--s1;
  1649.     }
  1650.     } else {
  1651.     while (len-- > 0) {
  1652.         *s2++ = *s1++;
  1653.     }
  1654.     }
  1655. }
  1656. #endif
  1657.