home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Mint / Mgr / VDImgr.zoo / rmgr / rmgr.c < prev    next >
C/C++ Source or Header  |  1993-03-16  |  32KB  |  1,465 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. /* This program Copyright 1990 by Howard Chu.
  12.  *
  13.  * This is rmgr, a remote window manager for Bellcore's MGR window
  14.  * manager, by Howard Chu @ University of Michigan (Ann Arbor, MI).
  15.  * Much of this program consists of Oliver Laumann's code; I have not
  16.  * (usually) highlighted my changes in any way. Oliver didn't use any
  17.  * comments at all; for the most part I have followed his lead...  }-)
  18.  * Suffice to say, some of the routines are original, some are heavily
  19.  * hacked upon versions of his code, and some are untouched from his
  20.  * program. Of course, the volume of code here represents only half
  21.  * of the code used in the screen program; the rest, support for ANSI
  22.  * terminal emulation, was discarded.
  23.  */
  24.  
  25. static char Version[] = "$Header: /usr/src/rmgr/RCS/rmgr.c,v 1.5 90/10/15 03:39:02 hyc Stable $";
  26.  
  27. #include <stdio.h>
  28. #include <sgtty.h>
  29. #include <signal.h>
  30. #include <errno.h>
  31. #include <ctype.h>
  32. #include <utmp.h>
  33. #include <pwd.h>
  34. #include <nlist.h>
  35. #include <fcntl.h>
  36. #include <sys/types.h>
  37. #include <sys/time.h>
  38. #include <sys/file.h>
  39. #include <sys/wait.h>
  40. #include <sys/socket.h>
  41. #include <sys/un.h>
  42. #include <sys/stat.h>
  43. #include <sys/dir.h>
  44. #include "rmgr.h"
  45.  
  46. #ifdef GETTTYENT
  47. #   include <ttyent.h>
  48. #else
  49.     static struct ttyent {
  50.     char *ty_name;
  51.     } *getttyent();
  52.     static char *tt, *ttnext;
  53.     static char ttys[] = "/etc/ttys";
  54. #endif
  55.  
  56. #define MAXWIN     10
  57. #define MSGWAIT     5
  58.  
  59. #define Ctrl(c) ((c)&037)
  60.  
  61. extern char **environ;
  62. extern errno;
  63. extern sys_nerr;
  64. extern char *sys_errlist[];
  65. extern char *index(), *rindex(), *malloc(), *getenv(), *MakeTermcap();
  66. extern char *getlogin(), *ttyname();
  67. static void AttacherFinit(), Finit(), SigHup(), SigChld();
  68. static char *Filename(), **SaveArgs(), *GetTtyName();
  69.  
  70. static char PtyName[32], TtyName[32];
  71. static char *ShellProg;
  72. static char *ShellArgs[2];
  73. static char inbuf[IOSIZE];
  74. static inlen;
  75. static ESCseen;
  76. static GotSignal;
  77. static char DefaultShell[] = "/bin/sh";
  78. static char DefaultPath[] = ":/usr/ucb:/bin:/usr/bin";
  79. static char PtyProto[] = "/dev/ptyXY";
  80. static char TtyProto[] = "/dev/ttyXY";
  81. static int TtyMode = 0622;
  82. static char SockPath[512];
  83. static char SockDir[] = ".rmgr";
  84. static char *SockNamePtr, *SockName;
  85. static ServerSocket;
  86. static char *NewEnv[MAXARGS];
  87. static char Esc = Ctrl('a');
  88. static char *home;
  89. static HasWindow;
  90. static utmp, utmpf;
  91. static char UtmpName[] = "/etc/utmp";
  92. static char *LoginName;
  93. static char HostName[MAXSTR];
  94. static Detached;
  95. static AttacherPid;    /* Non-Zero in child if we have an attacher */
  96. static DevTty;
  97. static char EventStr[]="%c%cA";
  98. static char CommNames[MAXLINE];
  99. static int VoluntaryDetach = 0;
  100.  
  101. struct mode {
  102.     struct sgttyb m_ttyb;
  103.     struct tchars m_tchars;
  104.     struct ltchars m_ltchars;
  105.     int m_ldisc;
  106.     int m_lmode;
  107. } OldMode, NewMode;
  108.  
  109. static struct win *curr, *other;
  110. static CurrNum, OtherNum;
  111. static struct win *wtab[MAXWIN];
  112.  
  113. main (ac, av) char **av; {
  114.     register n, len;
  115.     register struct win **pp, *p;
  116.     char *ap;
  117.     static InitMenu();
  118.     int s, r, w, x = 0;
  119.     int rflag = 0;
  120.     struct timeval tv;
  121.     time_t now;
  122.     char buf[IOSIZE], *myname = (ac == 0) ? "rmgr" : av[0];
  123.     struct stat st;
  124.     char *winname="";
  125.  
  126.     while (ac > 0) {
  127.     ap = *++av;
  128.     if (--ac > 0 && *ap == '-') {
  129.         switch (ap[1]) {
  130.         case 'r':
  131.         rflag = 1;
  132.         if (ap[2]) {
  133.             SockName = ap+2;
  134.             if (ac != 1) goto help;
  135.         } else if (--ac == 1) {
  136.             SockName = *++av;
  137.         } else if (ac != 0) goto help;
  138.         break;
  139.         case 'n':
  140.         if (ap[2]) {
  141.             ap += 2;
  142.         } else {
  143.             if (--ac == 0) goto help;
  144.             ap = *++av;
  145.         }
  146.         winname=ap;
  147.         break;
  148.         default:
  149.         help:
  150.         Msg (0, "Use: %s [-n windowname] [cmd args]\n\
  151.  or: %s -r [host.tty]", myname, myname);
  152.         }
  153.     } else break;
  154.     }
  155.     CommNames[0]='}';
  156.     if ((ShellProg = getenv ("SHELL")) == 0)
  157.     ShellProg = DefaultShell;
  158.     ShellArgs[0] = ShellProg;
  159.     if (ac == 0) {
  160.     ac = 1;
  161.     av = ShellArgs;
  162.     }
  163.     if ((home = getenv ("HOME")) == 0)
  164.     Msg (0, "$HOME is undefined.");
  165.     sprintf (SockPath, "%s/%s", home, SockDir);
  166.     if (stat (SockPath, &st) == -1) {
  167.     if (errno == ENOENT) {
  168.         if (mkdir (SockPath, 0700) == -1)
  169.         Msg (errno, "Cannot make directory %s", SockPath);
  170.         (void) chown (SockPath, getuid (), getgid ());
  171.     } else Msg (errno, "Cannot get status of %s", SockPath);
  172.     } else {
  173.     if ((st.st_mode & S_IFMT) != S_IFDIR)
  174.         Msg (0, "%s is not a directory.", SockPath);
  175.     if ((st.st_mode & 0777) != 0700)
  176.         Msg (0, "Directory %s must have mode 700.", SockPath);
  177.     if (st.st_uid != getuid ())
  178.         Msg (0, "You are not the owner of %s.", SockPath);
  179.     }
  180.     (void) gethostname (HostName, MAXSTR);
  181.     HostName[MAXSTR-1] = '\0';
  182.     if (ap = index (HostName, '.'))
  183.     *ap = '\0';
  184.     strcat (SockPath, "/");
  185.     SockNamePtr = SockPath + strlen (SockPath);
  186.     if ((DevTty = open ("/dev/tty", O_RDWR|O_NDELAY)) == -1)
  187.     Msg (errno, "/dev/tty");
  188.     if (rflag) {
  189.     Attach (MSG_ATTACH);
  190.     Attacher ();
  191.     /*NOTREACHED*/
  192.     }
  193.     if (GetSockName ()) {
  194.     s = MakeClientSocket (1);
  195.     SendCreateMsg (s, ac, av, winname);
  196.     close (s);
  197.     exit (0);
  198.     }
  199.     switch (fork ()) {
  200.     case -1:
  201.     Msg (errno, "fork");
  202.     /*NOTREACHED*/
  203.     case 0:
  204.     break;
  205.     default:
  206.     Attacher ();
  207.     /*NOTREACHED*/
  208.     }
  209.     AttacherPid = getppid ();
  210.     ServerSocket = s = MakeServerSocket ();
  211.     InitTerm ();
  212.     InitMenu ();
  213.     MakeNewEnv ();
  214.     GetTTY (0, &OldMode);
  215.     InitUtmp ();
  216.     signal (SIGHUP, SigHup);
  217.     signal (SIGINT, Finit);
  218.     signal (SIGQUIT, Finit);
  219.     signal (SIGTERM, Finit);
  220.     signal (SIGTTIN, SIG_IGN);
  221.     signal (SIGTTOU, SIG_IGN);
  222.     if ((n = MakeWindow (*av, av, winname, (char *)0)) == -1) {
  223.     SetTTY (0, &OldMode);
  224.     FinitTerm ();
  225.     Kill (AttacherPid, SIGHUP);
  226.     exit (1);
  227.     }
  228.     SetCurrWindow (n);
  229.     HasWindow = 1;
  230.     SetMode (&OldMode, &NewMode);
  231.     SetTTY (0, &NewMode);
  232.     signal (SIGCHLD, SigChld);
  233.     tv.tv_usec = 0;
  234.     while (1) {
  235.     r = 0;
  236.     w = 0;
  237.     if (inlen && curr->wpid>=0)
  238.         w |= 1 << curr->ptyfd;
  239.     else
  240.         r |= 1 << 0;
  241.     for (pp = wtab; pp < wtab+MAXWIN; ++pp) {
  242.         if (!(p = *pp))
  243.         continue;
  244.         if (p->wpid >=0)
  245.             r |= 1 << p->ptyfd;
  246.     }
  247.     r |= 1 << s;
  248.     (void) fflush (stdout);
  249.     if (GotSignal) {
  250.         SigHandler ();
  251.         continue;
  252.     }
  253.     if (select (32, &r, &w, &x, (struct timeval *)0) == -1) {
  254.         if (errno == EINTR)
  255.         continue;
  256.         HasWindow = 0;
  257.         Msg (errno, "select");
  258.         /*NOTREACHED*/
  259.     }
  260.     if (GotSignal) {
  261.         SigHandler ();
  262.         continue;
  263.     }
  264.     if (r & 1 << s) {
  265.         ReceiveMsg (s);
  266.     }
  267.     if (r & 1 << 0) {
  268.         if (ESCseen) {
  269.         inbuf[0] = Esc;
  270.         inlen = read (0, inbuf+1, IOSIZE-1) + 1;
  271.         ESCseen = 0;
  272.         } else {
  273.         inlen = read (0, inbuf, IOSIZE);
  274.         }
  275.         if (inlen > 0)
  276.         inlen = ProcessInput (inbuf, inlen);
  277.         if (inlen > 0)
  278.         continue;
  279.     }
  280.     if (GotSignal) {
  281.         SigHandler ();
  282.         continue;
  283.     }
  284.     if (curr && w & 1 << curr->ptyfd && inlen > 0) {
  285.         if ((len = write (curr->ptyfd, inbuf, inlen)) > 0) {
  286.         inlen -= len;
  287.         bcopy (inbuf+len, inbuf, inlen);
  288.         }
  289.     }
  290.     if (GotSignal) {
  291.         SigHandler ();
  292.         continue;
  293.     }
  294.     for (n=0; n<MAXWIN; n++) {
  295.         if (!(p = wtab[n]))
  296.         continue;
  297.         if (r & 1 << p->ptyfd) {
  298.         if ((len = read (p->ptyfd, buf, IOSIZE)) == -1) {
  299.             if (errno == EWOULDBLOCK)
  300.             len = 0;
  301.         }
  302.         if (len > 0)
  303.             WriteString (n, buf, len);
  304.         }
  305.     }
  306.     if (GotSignal)
  307.         SigHandler ();
  308.     }
  309.     /*NOTREACHED*/
  310. }
  311.  
  312. static InitTerm() {
  313.     register char *s;
  314.  
  315.     if ((s = getenv("TERM")) == 0)
  316.     Msg(0, "No TERM in environment.");
  317.     if (strcmp(s,"mgr"))
  318.     Msg(0, "Only runs on mgr terminals.");
  319.  
  320.     m_setup(M_FLUSH);
  321.     m_push(P_DEFAULT|P_POSITION);
  322.     m_dupkey(Esc);
  323. }
  324.  
  325. static FinitTerm() {
  326.     m_nomenu2(); m_nomenu();
  327.     m_clearmenu(1); m_clearmenu(2);
  328.     m_clearevent(ACTIVATE); m_clearevent(RESHAPE); m_clearevent(DESTROY);
  329.     m_popall();
  330. }
  331.     
  332. static WriteString(n, buf, len) int n, len; char *buf; {
  333.     register int i, j;
  334.     register struct win *p;
  335.  
  336.     p=wtab[n];
  337.  
  338.     if (!Detached) {
  339.     m_selectwin(n);
  340.     write(fileno(m_termout), buf, len);
  341.     } else
  342.     p->win_ok=0;        /* Screen no longer matches reality... */
  343.  
  344.     i=SCRBUFSIZE - (p->outptr - p->outbuf);
  345.     if (i>=len) {
  346.     bcopy(buf,p->outptr,len);
  347.     if (i==len) {
  348.         p->outptr=p->outbuf;
  349.         p->outful=1;
  350.     } else
  351.         p->outptr+=len;
  352.     } else {
  353.     j=len-i;
  354.     bcopy(buf,p->outptr,i);
  355.     bcopy(&buf[i],p->outbuf,j);
  356.     p->outptr=p->outbuf+j;
  357.     p->outful=1;
  358.     }
  359. }
  360.  
  361. static SigHandler () {
  362.     while (GotSignal) {
  363.     GotSignal = 0;
  364.     DoWait ();
  365.     }
  366. }
  367.  
  368. static void SigChld () {
  369.     GotSignal = 1;
  370. }
  371.  
  372. static void SigHup () {
  373.     Detach (0);
  374. }
  375.  
  376. static DoWait () {
  377.     register pid;
  378.     register int n;
  379.     register struct win **pp;
  380.     union wait wstat;
  381.  
  382.     while ((pid = wait3 (&wstat, WNOHANG|WUNTRACED, NULL)) > 0) {
  383.     for (n = 0; n<MAXWIN; n++) {
  384.         if (wtab[n] && pid == wtab[n]->wpid) {
  385.         if (WIFSTOPPED (wstat)) {
  386.             (void) killpg (getpgrp (wtab[n]->wpid), SIGCONT);
  387.         } else
  388.             KillWindow(n);
  389.         }
  390.     }
  391.     }
  392.     for (n=0; n<MAXWIN; n++)
  393.     if (wtab[n] && wtab[n]->wpid >=0)
  394.         break;
  395.     if (n == MAXWIN)
  396.     Finit();
  397. }
  398.  
  399. static KillWindow (n) int n; {
  400.     if (Detached || n!=CurrNum || !n) {
  401.     WriteString(n,"[window shut down]",18);
  402.     wtab[n]->wpid = -1;    /* Shut it down, but don't close */
  403.     if (!n)
  404.             FreeWindow (n);    /* Don't ever close window 0, but free it */
  405.     } else {
  406.     CurrNum = 0;
  407.     curr = 0;
  408.         FreeWindow (n);
  409.     }
  410. }
  411.  
  412. static void Finit () {
  413.     register int n;
  414.     register struct win *p, **pp;
  415.  
  416.     for (n=0; n<MAXWIN; n++) {
  417.     if (wtab[n])
  418.         FreeWindow(n);
  419.     }
  420.     SetTTY (0, &OldMode);
  421.     FinitTerm ();
  422.     printf ("\r[rmgr is terminating]\033c\n");
  423.     Kill (AttacherPid, SIGHUP);
  424.     exit (0);
  425. }
  426.  
  427. static linemode(onoff) int onoff; {
  428.     struct sgttyb buff;
  429.     gtty(0,&buff);
  430.     if (onoff)
  431.         buff.sg_flags &= ~CBREAK;
  432.     else
  433.         buff.sg_flags |= CBREAK;
  434.     stty(0,&buff);
  435. }
  436.  
  437. static ProcessInput (buf, len) char *buf; {
  438.     register n, k;
  439.     register char *s, *p, *q;
  440.     register struct win **pp;
  441.  
  442.     for (s = p = buf; len > 0; len--, s++) {
  443.     if (*s == Esc) {
  444.         if (len > 1) {
  445.         len--; s++;
  446.         if (*s == Esc) {
  447.             *p++ = Esc;
  448.         } else {        /* Process event or menu string */
  449.         if (*s != ' ') {
  450.             n=(*s++)-'!';
  451.             len--;
  452.             if (!len) {        /* Make sure to get 3rd char */
  453.             while(!read(0,s,1));
  454.             len++;
  455.             }
  456.             p=buf;
  457.             switch (*s) {    /* Event Strings */
  458.             case 'A':
  459.                 SetCurrWindow(n);
  460.                 break;
  461.             case 'D':
  462.                 FreeWindow(n);
  463.                 break;
  464.             case 'R':
  465.                 SizeWindow(n);
  466.                 break;
  467.             case 'c':    /* Menu Strings */
  468.                 if ((n=MakeWindow((char *)0, (char *)0,
  469.                     "", (char *)0)) != -1)
  470.                     SetCurrWindow(n);
  471.                 break;
  472.             case 'd':
  473.                 VoluntaryDetach=1;
  474.                 Detach(0);
  475.                 break;
  476.             case 'f':
  477.                 SwitchWindow(n);
  478.                 break;
  479.             case 'k':
  480.                 KillWindow(n);
  481.                 break;
  482.             case 'n':
  483.                 if ((n=MakeWindow(ShellProg, ShellArgs,
  484.                     "", (char *)0)) != -1)
  485.                     SetCurrWindow(n);
  486.                 break;
  487.             case 'q':
  488.                 Finit();
  489.                 break;
  490.             case 's':
  491.                 VoluntaryDetach=1;
  492.                 Detach(1);
  493.                 break;
  494.             }
  495.             }
  496.         } 
  497.         } else ESCseen = 1;
  498.     } else *p++ = *s;
  499.     }
  500.     return p - buf;
  501. }
  502.  
  503. static SwitchWindow(n) {
  504.     if (wtab[n]) {
  505.         SetCurrWindow(n);
  506.         m_setmode(M_ACTIVATE);
  507.     }
  508. }
  509.  
  510. static SetCurrWindow (n) {
  511.     CurrNum = n;
  512.     curr = wtab[n];
  513.     m_selectwin(n);
  514.     if (curr->wpid < 0)
  515.     m_setmode(M_NOINPUT);    /* Dead window, disallow input */
  516. }
  517.  
  518. static SizeWindow (n) int n; {
  519.     struct winsize wbuf;
  520.     char buf[32]; 
  521.  
  522.     m_selectwin(n);
  523.     m_getinfo(G_WINSIZE);
  524.     linemode(1);
  525.     read(0,buf,31);
  526.     linemode(0);
  527.     buf[31]='\0';
  528.     sscanf(buf,"%*c %d %d",&(wtab[n]->cols),&(wtab[n]->rows));
  529. #ifdef    TIOCSWINSZ
  530.     wbuf.ws_row = wtab[n]->rows;
  531.     wbuf.ws_col = wtab[n]->cols;
  532.     ioctl (wtab[n]->ptyfd, TIOCSWINSZ, &wbuf);
  533. #endif
  534. }
  535.  
  536. static FreeWindow (n) register int n; {
  537.     register i;
  538.     register struct win *wp;
  539.  
  540.     wp=wtab[n];
  541.     if (wp) {
  542.         RemoveUtmp (wp->slot);
  543.         (void) chmod (wp->tty, 0666);
  544.         (void) chown (wp->tty, 0, 0);
  545.         close (wp->ptyfd);
  546.         free (wp);
  547.         wtab[n]=0;
  548.     }
  549.     if (n) {
  550.     m_selectwin(n);
  551.     m_clearevent(DESTROY);    /* Avoid redundant calling of FreeWindow */
  552.     m_destroywin(n);
  553.     }
  554.     CollectNames();
  555.     sleep(1);
  556.     UpdateMenu(n);
  557. }
  558.  
  559. static CollectNames() {        /* Collect command names for second menu */
  560.     register struct win **wp;
  561.     register int n;
  562.     char buf[8];
  563.  
  564.     CommNames[1]='\0';
  565.     for (wp=wtab; wp<wtab+MAXWIN; wp++)
  566.     if (*wp) {
  567.         strcat(CommNames,(*wp)->cmd);
  568.         strcat(CommNames,"}");
  569.     }
  570.  
  571.     buf[0]=Esc;
  572.     buf[1]='!';
  573.     buf[2]='f';
  574.     buf[3]='}';
  575.     buf[4]='\0';
  576.     for (n=0;n<MAXWIN;n++)
  577.     if (wtab[n]) {
  578.         buf[1]=n+'!';
  579.         strcat(CommNames,buf);
  580.     }
  581. }
  582.  
  583. static char *MenuNames[]={"MGR Windows =>", "", "-=-=-=-=-=-=-",
  584.     "Shell Window","Other Window","Kill Window","Suspend","Detach","Quit"};
  585. static char MenuNull='\0';
  586. static char MenuActs[24];
  587. static char MenuLabs[8]="ncksdq";
  588. static struct menu_entry MainMenu[9];
  589.  
  590. static InitMenu() {
  591.     register int i;
  592.     register char *ptr;
  593.  
  594.     ptr=MenuActs;
  595.     for (i=3;i<9;i++) {
  596.     MainMenu[i].action=ptr;
  597.     *ptr++=Esc;
  598.     *ptr++='!';
  599.     *ptr++=MenuLabs[i-3];
  600.     *ptr++='\0';
  601.     }
  602.     for (i=0;i<3;i++)
  603.     MainMenu[i].action=(&MenuNull);
  604.  
  605.     for (i=0;i<9;i++)
  606.     MainMenu[i].value=MenuNames[i];
  607. }
  608.  
  609. static MakeMenu(n) int n; {
  610.     MenuActs[9]=n+'!';
  611.     MainMenu[1].value=wtab[n]->cmd;
  612.     menu_load(1,9,MainMenu);
  613.     m_loadmenu(2,CommNames);
  614.     m_linkmenu(1,0,2,MF_SNIP);
  615.     m_selectmenu2(1);
  616. }
  617.  
  618. static UpdateMenu(n) int n; {
  619.     register int i;
  620.  
  621.     for (i=0; i<MAXWIN; i++)
  622.     if (wtab[i] && i!=n) {
  623.         m_selectwin(i);
  624.         m_loadmenu(2,CommNames);
  625.     }
  626. }
  627.  
  628. static Parse (buf, args) char *buf, **args; {
  629.     register char *p = buf, **ap = args;
  630.     register delim, argc = 0;
  631.  
  632.     argc = 0;
  633.     for (;;) {
  634.     while (*p && (*p == ' ' || *p == '\t')) ++p;
  635.     if (*p == '\0' || *p == '#')
  636.         return argc;
  637.     if (argc > MAXARGS-1)
  638.         Msg (0, "Too many tokens.");
  639.     delim = 0;
  640.     if (*p == '"' || *p == '\'') {
  641.         delim = *p; *p = '\0'; ++p;
  642.     }
  643.     ++argc;
  644.     *ap = p; ++ap;
  645.     while (*p && !(delim ? *p == delim : (*p == ' ' || *p == '\t')))
  646.         ++p;
  647.     if (*p == '\0') {
  648.         if (delim)
  649.         Msg (0, "Missing quote.");
  650.         else
  651.         return argc;
  652.     }
  653.     *p++ = '\0';
  654.     }
  655. }
  656.  
  657. static char TermBuf[MAXLINE];
  658.  
  659. static MakeWindow (prog, args, name, dir)
  660.     char *prog, *name, **args, *dir; {
  661.     register struct win *p;
  662.     register char **cp;
  663.     register n, f;
  664.     int tf;
  665.     int mypid;
  666.     char ebuf[16];
  667.     char ibuf[MY_MAXLINE];
  668.     char *av[MAXARGS];
  669.     char *ptr,*index();
  670.  
  671.     if ((f = OpenPTY ()) == -1) {
  672.     Msg (0, "No more PTYs.");
  673.     return -1;
  674.     }
  675.     (void) fcntl (f, F_SETFL, FNDELAY);
  676.     if ((p = (struct win *)malloc (sizeof (struct win))) == 0) {
  677.     Msg (0, "Out of memory.");
  678.     return -1;
  679.     }
  680.     p->outful=0;
  681.     p->outptr=p->outbuf;
  682.  
  683.     m_ttyset();
  684.     if (!wtab[0]) {
  685.     n=0;
  686.     } else {
  687.     m_resetflags(CBREAK);
  688.     m_newwin(0,0,50,50);
  689.     read(0, TermBuf, MAXLINE);
  690.     TermBuf[MAXLINE-1]='\0';
  691.         n = atoi(&TermBuf[2]);
  692.     }
  693.         m_selectwin(n);
  694.         m_dupkey(Esc);
  695.         m_sizeall(n*5,n*5,80,24);
  696.     strcpy(TermBuf,"TERMCAP=");
  697.     m_getinfo(G_TERMCAP);
  698.     read(0, &TermBuf[6], MAXLINE);
  699.     TermBuf[MAXLINE-1]='\0';
  700.     m_setflags(CBREAK);
  701.     TermBuf[6]='P';
  702.     TermBuf[7]='=';
  703.     ptr=index(TermBuf,'\n');
  704.     *ptr='\0';
  705.     m_clear();
  706.     sprintf(ebuf,EventStr,Esc,n+'!');
  707.     m_setevent(ACTIVATE,ebuf);
  708.     ebuf[2]='D';
  709.     m_setevent(DESTROY,ebuf);
  710.     ebuf[2]='R';
  711.     m_setevent(RESHAPE,ebuf);
  712.     m_ttyreset();
  713.     wtab[n]=p;
  714.  
  715.     p->ptyfd = f;
  716.  
  717.     if (!prog) {
  718.     int argc;
  719.  
  720.     SetTTY(0, &OldMode);
  721.     printf("Enter command and arguments: ");
  722.     fflush(stdout);
  723.     ptr=gets(ibuf);
  724.     SetTTY(0, &NewMode);
  725.     if (!ptr || ((argc = Parse(ibuf, av)) == 0)) {
  726.         KillWindow(n);
  727.         return;
  728.     }
  729.     if (strcmp(av[0],"-n") == 0) {
  730.         name=av[1];
  731.         args=(&av[2]);
  732.     } else 
  733.         args=av;
  734.     prog=args[0];
  735.     }
  736.  
  737.     strncpy (p->cmd, *name ? name : Filename (args[0]), MAXSTR-1);
  738.     p->cmd[MAXSTR-1] = '\0';
  739.  
  740.     CollectNames();
  741.     MakeMenu(n);
  742.     UpdateMenu(n);
  743.     strncpy (p->tty, TtyName, MAXSTR-1);
  744.     (void) chown (TtyName, getuid (), getgid ());
  745.     (void) chmod (TtyName, TtyMode);
  746.     p->slot = SetUtmp (TtyName);
  747.     p->rows=24;
  748.     p->cols=80;
  749.     switch (p->wpid = fork ()) {
  750.     case -1:
  751.     Msg (errno, "fork");
  752.     free ((char *)p);
  753.     return -1;
  754.     case 0:
  755.     signal (SIGHUP, SIG_DFL);
  756.     signal (SIGINT, SIG_DFL);
  757.     signal (SIGQUIT, SIG_DFL);
  758.     signal (SIGTERM, SIG_DFL);
  759.     signal (SIGTTIN, SIG_DFL);
  760.     signal (SIGTTOU, SIG_DFL);
  761.     setuid (getuid ());
  762.     setgid (getgid ());
  763.     if (dir && chdir (dir) == -1) {
  764.         SendErrorMsg ("Cannot chdir to %s: %s", dir, sys_errlist[errno]);
  765.         exit (1);
  766.     }
  767.     mypid = getpid ();
  768.     ioctl (DevTty, TIOCNOTTY, (char *)0);
  769.     if ((tf = open (TtyName, O_RDWR)) == -1) {
  770.         SendErrorMsg ("Cannot open %s: %s", TtyName, sys_errlist[errno]);
  771.         exit (1);
  772.     }
  773.     (void) dup2 (tf, 0);
  774.     (void) dup2 (tf, 1);
  775.     (void) dup2 (tf, 2);
  776.     for (f = getdtablesize () - 1; f > 2; f--)
  777.         close (f);
  778.     ioctl (0, TIOCSPGRP, &mypid);
  779.     (void) setpgrp (0, mypid);
  780.     SetTTY (0, &OldMode);
  781. #ifdef    TIOCSWINSZ
  782.     {
  783.         struct winsize wbuf;
  784.         wbuf.ws_row = p->rows;
  785.         wbuf.ws_col=p->cols;
  786.         ioctl (0, TIOCSWINSZ, &wbuf);
  787.     }
  788. #endif
  789.     NewEnv[2] = TermBuf;
  790.     sprintf (ebuf, "WINDOW=%d", n);
  791.     NewEnv[3] = ebuf;
  792.     execvpe (prog, args, NewEnv);
  793.     SendErrorMsg ("Cannot exec %s: %s", prog, sys_errlist[errno]);
  794.     exit (1);
  795.     }
  796.     return n;
  797. }
  798.  
  799. static execvpe (prog, args, env) char *prog, **args, **env; {
  800.     register char *path, *p;
  801.     char buf[1024];
  802.     char *shargs[MAXARGS+1];
  803.     register i, eaccess = 0;
  804.  
  805.     if (prog[0] == '/')
  806.     path = "";
  807.     else if ((path = getenv ("PATH")) == 0)
  808.     path = DefaultPath;
  809.     do {
  810.     p = buf;
  811.     while (*path && *path != ':')
  812.         *p++ = *path++;
  813.     if (p > buf)
  814.         *p++ = '/';
  815.     strcpy (p, prog);
  816.     if (*path)
  817.         ++path;
  818.     execve (buf, args, env);
  819.     switch (errno) {
  820.     case ENOEXEC:
  821.         shargs[0] = DefaultShell;
  822.         shargs[1] = buf;
  823.         for (i = 1; shargs[i+1] = args[i]; ++i)
  824.         ;
  825.         execve (DefaultShell, shargs, env);
  826.         return;
  827.     case EACCES:
  828.         eaccess = 1;
  829.         break;
  830.     case ENOMEM: case E2BIG: case ETXTBSY:
  831.         return;
  832.     }
  833.     } while (*path);
  834.     if (eaccess)
  835.     errno = EACCES;
  836. }
  837.  
  838. static OpenPTY () {
  839.     register char *p, *l, *d;
  840.     register i, f, tf;
  841.  
  842.     strcpy (PtyName, PtyProto);
  843.     strcpy (TtyName, TtyProto);
  844.     for (p = PtyName, i = 0; *p != 'X'; ++p, ++i) ;
  845.     for (l = "qpr"; *p = *l; ++l) {
  846.     for (d = "0123456789abcdef"; p[1] = *d; ++d) {
  847.         if ((f = open (PtyName, O_RDWR)) != -1) {
  848.         TtyName[i] = p[0];
  849.         TtyName[i+1] = p[1];
  850.         if ((tf = open (TtyName, O_RDWR)) != -1) {
  851.             close (tf);
  852.             return f;
  853.         }
  854.         close (f);
  855.         }
  856.     }
  857.     }
  858.     return -1;
  859. }
  860.  
  861. static SetTTY (fd, mp) struct mode *mp; {
  862.     ioctl (fd, TIOCSETP, &mp->m_ttyb);
  863.     ioctl (fd, TIOCSETC, &mp->m_tchars);
  864.     ioctl (fd, TIOCSLTC, &mp->m_ltchars);
  865.     ioctl (fd, TIOCLSET, &mp->m_lmode);
  866.     ioctl (fd, TIOCSETD, &mp->m_ldisc);
  867. }
  868.  
  869. static GetTTY (fd, mp) struct mode *mp; {
  870.     ioctl (fd, TIOCGETP, &mp->m_ttyb);
  871.     ioctl (fd, TIOCGETC, &mp->m_tchars);
  872.     ioctl (fd, TIOCGLTC, &mp->m_ltchars);
  873.     ioctl (fd, TIOCLGET, &mp->m_lmode);
  874.     ioctl (fd, TIOCGETD, &mp->m_ldisc);
  875. }
  876.  
  877. static SetMode (op, np) struct mode *op, *np; {
  878.     *np = *op;
  879.     np->m_ttyb.sg_flags &= ~(CRMOD|ECHO);
  880.     np->m_ttyb.sg_flags |= CBREAK;
  881.     np->m_tchars.t_intrc = -1;
  882.     np->m_tchars.t_quitc = -1;
  883.     np->m_ltchars.t_suspc = -1;
  884.     np->m_ltchars.t_dsuspc = -1;
  885.     np->m_ltchars.t_flushc = -1;
  886.     np->m_ltchars.t_lnextc = -1;
  887. }
  888.  
  889. static char *GetTtyName () {
  890.     register char *p;
  891.     register n;
  892.  
  893.     for (p = 0, n = 0; n <= 2 && !(p = ttyname (n)); n++)
  894.     ;
  895.     if (!p || *p == '\0')
  896.     Msg (0, "rmgr must run on a tty.");
  897.     return p;
  898. }
  899.  
  900. static Attach (how) {
  901.     register s, lasts, found = 0;
  902.     register DIR *dirp;
  903.     register struct direct *dp;
  904.     struct msg m;
  905.     char last[MAXNAMLEN+1];
  906.  
  907.     if (SockName) {
  908.     if ((lasts = MakeClientSocket (0)) == -1)
  909.         if (how == MSG_CONT)
  910.         Msg (0,
  911.             "This session has already been continued from elsewhere.");
  912.         else
  913.         Msg (0, "There is no session to be resumed from %s.", SockName);
  914.     } else {
  915.     if ((dirp = opendir (SockPath)) == NULL)
  916.         Msg (0, "Cannot open %s", SockPath);
  917.     while ((dp = readdir (dirp)) != NULL) {
  918.         SockName = dp->d_name;
  919.         if (SockName[0] == '.')
  920.         continue;
  921.         if ((s = MakeClientSocket (0)) != -1) {
  922.         if (found == 0) {
  923.             strcpy (last, SockName);
  924.             lasts = s;
  925.         } else {
  926.             if (found == 1) {
  927.             printf ("There are detached sessions on:\n");
  928.             printf ("   %s\n", last);
  929.             close (lasts);
  930.             }
  931.             printf ("   %s\n", SockName);
  932.             close (s);
  933.         }
  934.         found++;
  935.         }
  936.     }
  937.     if (found == 0)
  938.         Msg (0, "There is no session to be resumed.");
  939.     if (found > 1)
  940.         Msg (0, "Type \"rmgr -r host.tty\" to resume one of them.");
  941.     closedir (dirp);
  942.     strcpy (SockNamePtr, last);
  943.     SockName = SockNamePtr;
  944.     }
  945.     m.type = how;
  946.     strcpy (m.m.attach.tty, GetTtyName ());
  947.     m.m.attach.apid = getpid ();
  948.     if (write (lasts, (char *)&m, sizeof (m)) != sizeof (m))
  949.     Msg (errno, "write");
  950. }
  951.  
  952. static void AttacherFinit () {
  953.     exit (0);
  954. }
  955.  
  956. static void ReAttach () {
  957.     Attach (MSG_CONT);
  958. }
  959.  
  960. static Attacher () {
  961.     signal (SIGHUP, AttacherFinit);
  962.     signal (SIGCONT, ReAttach);
  963.     while (1)
  964.     pause ();
  965. }
  966.  
  967. static Detach (suspend) {
  968.     register struct win **pp;
  969.     register int i;
  970.  
  971.     if (Detached)
  972.     return;
  973.     signal (SIGHUP, SIG_IGN);
  974.     if (VoluntaryDetach) {    /* Can't save state if line dropped */
  975.     for (i=MAXWIN-1;i>0;i--) {
  976.     if (wtab[i]) {
  977.     m_selectwin(i);
  978.     m_nomenu2();
  979.     m_push(P_EVENT);
  980.         }
  981.     }
  982.     m_selectwin(0);
  983.     m_nomenu2(); m_nomenu();
  984.     m_push(P_ALL);
  985.     m_setmode(M_ACTIVATE);
  986.     }
  987.     SetTTY (0, &OldMode);
  988.     if (suspend) {
  989.     Kill (AttacherPid, SIGTSTP);
  990.     for (pp=wtab; pp < wtab+MAXWIN; ++pp)
  991.         if (*pp) (*pp)->win_ok=1;
  992.     } else {
  993.     for (pp=wtab; pp < wtab+MAXWIN; ++pp)
  994.         if (*pp) RemoveUtmp ((*pp)->slot);
  995.     printf ("\n[detached]\n");
  996.     Kill (AttacherPid, SIGHUP);
  997.     AttacherPid = 0;
  998.     }
  999.     close (0);
  1000.     close (1);
  1001.     close (2);
  1002.     ioctl (DevTty, TIOCNOTTY, (char *)0);
  1003.     Detached = 1;
  1004.     do {
  1005.     ReceiveMsg (ServerSocket); 
  1006.     } while (Detached);
  1007.     if (!suspend) {
  1008.     for (pp = wtab; pp < wtab+MAXWIN; ++pp)
  1009.         if (*pp) (*pp)->slot = SetUtmp ((*pp)->tty);
  1010.     }
  1011.     signal (SIGHUP, SigHup);
  1012. }
  1013.  
  1014. static Kill (pid, sig) {
  1015.     if (pid != 0)
  1016.     (void) kill (pid, sig);
  1017. }
  1018.  
  1019. static GetSockName () {
  1020.     register client;
  1021.     static char buf[2*MAXSTR];
  1022.  
  1023.     if ((SockName = getenv ("STY")) != 0 && *SockName != '\0') {
  1024.     client = 1;
  1025.     setuid (getuid ());
  1026.     setgid (getgid ());
  1027.     } else {
  1028.     sprintf (buf, "%s.%s", HostName, Filename (GetTtyName ()));
  1029.     SockName = buf;
  1030.     client = 0;
  1031.     }
  1032.     return client;
  1033. }
  1034.  
  1035. static MakeServerSocket () {
  1036.     register s;
  1037.     struct sockaddr_un a;
  1038.     char *p;
  1039.  
  1040.     if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1)
  1041.     Msg (errno, "socket");
  1042.     a.sun_family = AF_UNIX;
  1043.     strcpy (SockNamePtr, SockName);
  1044.     strcpy (a.sun_path, SockPath);
  1045.     if (connect (s, (struct sockaddr *)&a, strlen (SockPath)+2) != -1) {
  1046.     p = Filename (SockPath);
  1047.     Msg (0, "You already have a session running on %s.\n\
  1048. If it has been detached, try \"rmgr -r\".", p);
  1049.     /*NOTREACHED*/
  1050.     }
  1051.     (void) unlink (SockPath);
  1052.     if (bind (s, (struct sockaddr *)&a, strlen (SockPath)+2) == -1)
  1053.     Msg (errno, "bind");
  1054.     (void) chown (SockPath, getuid (), getgid ());
  1055.     if (listen (s, 5) == -1)
  1056.     Msg (errno, "listen");
  1057.     return s;
  1058. }
  1059.  
  1060. static MakeClientSocket (err) {
  1061.     register s;
  1062.     struct sockaddr_un a;
  1063.  
  1064.     if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1)
  1065.     Msg (errno, "socket");
  1066.     a.sun_family = AF_UNIX;
  1067.     strcpy (SockNamePtr, SockName);
  1068.     strcpy (a.sun_path, SockPath);
  1069.     if (connect (s, (struct sockaddr *)&a, strlen (SockPath)+2) == -1) {
  1070.     if (err) {
  1071.         Msg (errno, "connect: %s", SockPath);
  1072.     } else {
  1073.         close (s);
  1074.         return -1;
  1075.     }
  1076.     }
  1077.     return s;
  1078. }
  1079.  
  1080. static SendCreateMsg (s, ac, av, name) char **av, *name; {
  1081.     struct msg m;
  1082.     register char *p;
  1083.     register len, n;
  1084.  
  1085.     m.type = MSG_CREATE;
  1086.     p = m.m.create.line;
  1087.     for (n = 0; ac > 0 && n < MAXARGS-1; ++av, --ac, ++n) {
  1088.     len = strlen (*av) + 1;
  1089.     if (p + len >= m.m.create.line+MY_MAXLINE)
  1090.         break;
  1091.     strcpy (p, *av);
  1092.     p += len;
  1093.     }
  1094.     m.m.create.nargs = n;
  1095.     if (name)
  1096.     strcpy(m.m.create.name,name);
  1097.     else
  1098.     m.m.create.name[0]='\0';
  1099.     if (getwd (m.m.create.dir) == 0)
  1100.     Msg (0, "%s", m.m.create.dir);
  1101.     if (write (s, (char *)&m, sizeof (m)) != sizeof (m))
  1102.     Msg (errno, "write");
  1103. }
  1104.  
  1105. /*VARARGS1*/
  1106. static SendErrorMsg (fmt, p1, p2, p3, p4, p5, p6) char *fmt; {
  1107.     register s;
  1108.     struct msg m;
  1109.  
  1110.     s = MakeClientSocket (1);
  1111.     m.type = MSG_ERROR;
  1112.     sprintf (m.m.message, fmt, p1, p2, p3, p4, p5, p6);
  1113.     (void) write (s, (char *)&m, sizeof (m));
  1114.     close (s);
  1115.     sleep (2);
  1116. }
  1117.  
  1118. static char m_rbuf[MAXLINE];
  1119.  
  1120. static char *m_read() {
  1121.     register char *ptr; char *index();
  1122.     register int i;
  1123.  
  1124.     i=read(0,m_rbuf,MAXLINE-1);
  1125.     m_rbuf[i]='\0';
  1126.     ptr=index(m_rbuf,Esc);
  1127.     if (!ptr)
  1128.     ptr=m_rbuf;
  1129.     else
  1130.     ptr++;
  1131.     return(ptr);
  1132. }
  1133.  
  1134. static ReplayWindow(p) struct win *p; {
  1135.     register int n;
  1136.  
  1137.     n=p->outptr-p->outbuf;
  1138.     if (p->outful)        /* Replay last screen of data */
  1139.         write(1,p->outptr,SCRBUFSIZE-n);
  1140.     write(1,p->outbuf,n);
  1141. }
  1142.  
  1143. static RestoreWindows(mt) int mt; {
  1144.     register int i, j=0;
  1145.     struct window_data wd;
  1146.     register char *ptr;
  1147.     register struct win *p;
  1148.     char buf[8];
  1149.     int n, nw;
  1150.     int oldset=1;
  1151.  
  1152.     if (mt != MSG_CONT) {    /* Restore after a detach, not suspend */
  1153.     linemode(1);
  1154.     for (i=MAXWIN-1; i>=0; i--) {
  1155.     m_selectwin(i);
  1156.     m_getinfo(G_ID);
  1157.     ptr=m_read();
  1158.     sscanf(ptr,"%d %d",&n, &nw);
  1159.     if (wtab[i]) {
  1160.         p=wtab[i];
  1161.         if (n!=i) {        /* That one didn't exist, remake it... */
  1162.         oldset=0;    /* Looks like the old context is gone. */
  1163.         m_newwin(j,j,50,50);
  1164.         ptr=m_read();
  1165.         n=atoi(ptr);
  1166.         if (!n) 
  1167.             Msg(0, "Error restoring window.");
  1168.         m_selectwin(n);
  1169.         }
  1170.         if (!oldset) {
  1171.         m_size(p->cols,p->rows);
  1172.             m_dupkey(Esc);
  1173.             sprintf(buf,EventStr,Esc,n+'!');
  1174.             m_setevent(ACTIVATE,buf);
  1175.             buf[2]='D';
  1176.             m_setevent(DESTROY,buf);
  1177.             buf[2]='R';
  1178.             m_setevent(RESHAPE,buf);
  1179.         MakeMenu(n);
  1180.         ReplayWindow(p);
  1181.         } else if (VoluntaryDetach) {
  1182.         m_pop();
  1183.         } else ReplayWindow(p);    /* Redraw for hangup */
  1184.     } else if (i) {        /* Gee, a window we didn't create. Byebye. */
  1185.         oldset=0;        /* Again, we must have lost the old stuff */
  1186.         m_destroywin(i);
  1187.     }
  1188.     }
  1189.     linemode(0);
  1190.     } else {
  1191.     for (i=0;i<MAXWIN;i++) {
  1192.         p=wtab[i];
  1193.         if (p) {
  1194.         m_selectwin(i);
  1195.         m_pop();
  1196.         m_selectmenu2(1);
  1197.         if (!p->win_ok)
  1198.             ReplayWindow(p);
  1199.         }
  1200.     }
  1201.     }
  1202.     VoluntaryDetach=0;
  1203. }
  1204.         
  1205. static ReceiveMsg (s) {
  1206.     register ns;
  1207.     struct sockaddr_un a;
  1208.     int left, len = sizeof (a);
  1209.     struct msg m;
  1210.     char *p;
  1211.  
  1212.     if ((ns = accept (s, (struct sockaddr *)&a, &len)) == -1) {
  1213.     Msg (errno, "accept");
  1214.     return;
  1215.     }
  1216.     p = (char *)&m;
  1217.     left = sizeof (m);
  1218.     while (left > 0 && (len = read (ns, p, left)) > 0) {
  1219.     p += len;
  1220.     left -= len;
  1221.     }
  1222.     close (ns);
  1223.     if (len == -1)
  1224.     Msg (errno, "read");
  1225.     if (left > 0)
  1226.     return;
  1227.     switch (m.type) {
  1228.     case MSG_CREATE:
  1229.     if (!Detached)
  1230.         ExecCreate (&m);
  1231.     break;
  1232.     case MSG_CONT:
  1233.     if (m.m.attach.apid != AttacherPid || !Detached)
  1234.         break;    /* Intruder Alert */
  1235.     /*FALLTHROUGH*/
  1236.     case MSG_ATTACH:
  1237.     if (Detached) {
  1238.         if (kill (m.m.attach.apid, 0) == 0 &&
  1239.             open (m.m.attach.tty, O_RDWR) == 0) {
  1240.         (void) dup (0);
  1241.         (void) dup (0);
  1242.         AttacherPid = m.m.attach.apid;
  1243.         Detached = 0;
  1244.         GetTTY (0, &OldMode);
  1245.         SetMode (&OldMode, &NewMode);
  1246.         SetTTY (0, &NewMode);
  1247.         RestoreWindows(m.type);
  1248.         SwitchWindow(CurrNum);
  1249.         }
  1250.     } else {
  1251.         Kill (m.m.attach.apid, SIGHUP);
  1252.         Msg (0, "Not detached.");
  1253.     }
  1254.     break;
  1255.     case MSG_ERROR:
  1256.     Msg (0, "%s", m.m.message);
  1257.     break;
  1258.     default:
  1259.     Msg (0, "Invalid message (type %d).", m.type);
  1260.     }
  1261. }
  1262.  
  1263. static ExecCreate (mp) struct msg *mp; {
  1264.     char *args[MAXARGS];
  1265.     register n;
  1266.     register char **pp = args, *p = mp->m.create.line;
  1267.  
  1268.     for (n = mp->m.create.nargs; n > 0; --n) {
  1269.     *pp++ = p;
  1270.     p += strlen (p) + 1;
  1271.     }
  1272.     *pp = 0;
  1273.     if ((n = MakeWindow (mp->m.create.line, args, mp->m.create.name,
  1274.         mp->m.create.dir)) != -1)
  1275.     SwitchWindow (n);
  1276. }
  1277.  
  1278. static char **SaveArgs (argc, argv) register argc; register char **argv; {
  1279.     register char **ap, **pp;
  1280.  
  1281.     if ((pp = ap = (char **)malloc ((argc+1) * sizeof (char **))) == 0)
  1282.     Msg (0, "Out of memory.");
  1283.     while (argc--) {
  1284.     if ((*pp = malloc (strlen (*argv)+1)) == 0)
  1285.         Msg (0, "Out of memory.");
  1286.     strcpy (*pp, *argv);
  1287.     ++pp; ++argv;
  1288.     }
  1289.     *pp = 0;
  1290.     return ap;
  1291. }
  1292.  
  1293. static MakeNewEnv () {
  1294.     register char **op, **np = NewEnv;
  1295.     static char buf[MAXSTR];
  1296.  
  1297.     if (strlen (SockName) > MAXSTR-5)
  1298.     SockName = "?";
  1299.     sprintf (buf, "STY=%s", SockName);
  1300.     *np++ = buf;
  1301.     *np++ = "TERM=mgr";
  1302.     np += 2;
  1303.     for (op = environ; *op; ++op) {
  1304.     if (np == NewEnv + MAXARGS - 1)
  1305.         break;
  1306.     if (!IsSymbol (*op, "TERM") && !IsSymbol (*op, "TERMCAP")
  1307.         && !IsSymbol (*op, "STY"))
  1308.         *np++ = *op;
  1309.     }
  1310.     *np = 0;
  1311. }
  1312.  
  1313. static IsSymbol (e, s) register char *e, *s; {
  1314.     register char *p;
  1315.     register n;
  1316.  
  1317.     for (p = e; *p && *p != '='; ++p) ;
  1318.     if (*p) {
  1319.     *p = '\0';
  1320.     n = strcmp (e, s);
  1321.     *p = '=';
  1322.     return n == 0;
  1323.     }
  1324.     return 0;
  1325. }
  1326.  
  1327. /*VARARGS2*/
  1328. Msg (err, fmt, p1, p2, p3, p4, p5, p6) char *fmt; {
  1329.     char buf[1024];
  1330.     register char *p = buf;
  1331.  
  1332.     if (Detached)
  1333.     return;
  1334.     sprintf (p, fmt, p1, p2, p3, p4, p5, p6);
  1335.     if (err) {
  1336.     p += strlen (p);
  1337.     if (err > 0 && err < sys_nerr)
  1338.         sprintf (p, ": %s", sys_errlist[err]);
  1339.     else
  1340.         sprintf (p, ": Error %d", err);
  1341.     }
  1342.     printf ("%s\r\n", buf);
  1343.     if (!HasWindow) {
  1344.     Kill (AttacherPid, SIGHUP);
  1345.     exit (1);
  1346.     }
  1347. }
  1348.  
  1349. static char *Filename (s) char *s; {
  1350.     register char *p;
  1351.  
  1352.     p = s + strlen (s) - 1;
  1353.     while (p >= s && *p != '/') --p;
  1354.     return ++p;
  1355. }
  1356.  
  1357. static IsNum (s, base) register char *s; register base; {
  1358.     for (base += '0'; *s; ++s)
  1359.     if (*s < '0' || *s > base)
  1360.         return 0;
  1361.     return 1;
  1362. }
  1363.  
  1364. static InitUtmp () {
  1365.     struct passwd *p;
  1366.  
  1367.     if ((utmpf = open (UtmpName, O_WRONLY)) == -1) {
  1368.     if (errno != EACCES)
  1369.         Msg (errno, UtmpName);
  1370.     return;
  1371.     }
  1372.     if ((LoginName = getlogin ()) == 0 || LoginName[0] == '\0') {
  1373.     if ((p = getpwuid (getuid ())) == 0)
  1374.         return;
  1375.     LoginName = p->pw_name;
  1376.     }
  1377.     utmp = 1;
  1378. }
  1379.  
  1380. static SetUtmp (name) char *name; {
  1381.     register char *p;
  1382.     register struct ttyent *tp;
  1383.     register slot = 1;
  1384.     struct utmp u;
  1385.  
  1386.     if (!utmp)
  1387.     return 0;
  1388.     if (p = rindex (name, '/'))
  1389.     ++p;
  1390.     else p = name;
  1391.     setttyent ();
  1392.     while ((tp = getttyent ()) != NULL && strcmp (p, tp->ty_name) != 0)
  1393.     ++slot;
  1394.     if (tp == NULL)
  1395.     return 0;
  1396.     strncpy (u.ut_line, p, 8);
  1397.     strncpy (u.ut_name, LoginName, 8);
  1398.     u.ut_host[0] = '\0';
  1399.     time (&u.ut_time);
  1400.     (void) lseek (utmpf, (long)(slot * sizeof (u)), 0);
  1401.     (void) write (utmpf, (char *)&u, sizeof (u));
  1402.     return slot;
  1403. }
  1404.  
  1405. static RemoveUtmp (slot) {
  1406.     struct utmp u;
  1407.  
  1408.     if (slot) {
  1409.     bzero ((char *)&u, sizeof (u));
  1410.     (void) lseek (utmpf, (long)(slot * sizeof (u)), 0);
  1411.     (void) write (utmpf, (char *)&u, sizeof (u));
  1412.     }
  1413. }
  1414.  
  1415. #ifndef GETTTYENT
  1416.  
  1417. static setttyent () {
  1418.     struct stat s;
  1419.     register f;
  1420.     register char *p, *ep;
  1421.  
  1422.     if (ttnext) {
  1423.     ttnext = tt;
  1424.     return;
  1425.     }
  1426.     if ((f = open (ttys, O_RDONLY)) == -1 || fstat (f, &s) == -1)
  1427.     Msg (errno, ttys);
  1428.     if ((tt = malloc (s.st_size + 1)) == 0)
  1429.     Msg (0, "Out of memory.");
  1430.     if (read (f, tt, s.st_size) != s.st_size)
  1431.     Msg (errno, ttys);
  1432.     close (f);
  1433.     for (p = tt, ep = p + s.st_size; p < ep; ++p)
  1434.     if (*p == '\n') *p = '\0';
  1435.     *p = '\0';
  1436.     ttnext = tt;
  1437. }
  1438.  
  1439. static struct ttyent *getttyent () {
  1440.     static struct ttyent t;
  1441.  
  1442.     if (*ttnext == '\0')
  1443.     return NULL;
  1444.     t.ty_name = ttnext + 2;
  1445.     ttnext += strlen (ttnext) + 1;
  1446.     return &t;
  1447. }
  1448.  
  1449. #endif
  1450.  
  1451. #ifndef USEBCOPY
  1452. bcopy (s1, s2, len) register char *s1, *s2; register len; {
  1453.     if (s1 < s2 && s2 < s1 + len) {
  1454.     s1 += len; s2 += len;
  1455.     while (len-- > 0) {
  1456.         *--s2 = *--s1;
  1457.     }
  1458.     } else {
  1459.     while (len-- > 0) {
  1460.         *s2++ = *s1++;
  1461.     }
  1462.     }
  1463. }
  1464. #endif
  1465.