home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume10 / screen / part02 / screen.c < prev   
Encoding:
C/C++ Source or Header  |  1987-08-06  |  31.3 KB  |  1,399 lines

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