home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / source / layers.zoo / layers.3 < prev    next >
Text File  |  1990-06-11  |  60KB  |  2,243 lines

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