home *** CD-ROM | disk | FTP | other *** search
- /******** Layers.c
- *********
- ********* Layers - MacLayers Multiwindow BSD Socket Driver
- *********
- ********* Dave Trissel oakhill!davet
- *********
- ********* The sockets handling portion of this control module is based
- ********* upon 'screen' by Oliver Laumann whose copyright remains below.
- ********* The rest is
- *
- * Copyright (C) 1989 by David W. Trissel
- *
- * Not derived from licensed software.
- *
- * Permission is granted to freely use, copy, modify, and redistribute
- * this software, provided that no attempt is made to gain profit from it,
- * the author is not construed to be liable for any results of using the
- * software, alterations are clearly marked as such, and this notice is
- * not modified.
- *
- */
-
- static char LayersVersion[] = "layers 1.00 17-Mar-1990";
-
- /* Layers Changes:
-
- Version .92 22-Mar-1989
-
- Original Distributed version
-
- Version .93 31-Mar-1989
-
- Deleted dl and al termcap entries since they didn't help any
- (al was redundant with sc (scroll) so should never have been created)
-
- SIGINT no longer causes us to quit (left debugging code in by mistake)
-
- Layer #1 is always logged in and takes over as user's login console
- (Real tty disconnected from /etc/utmp file while layers is running)
-
- Version .93b 05-May-1989
-
- Try getenv("PWD") before getwd() so Sun networking won't hang us up
-
- Version .93n 07-Jan-1990
-
- Reset TTY back to normal if initial link handshake fails.
-
- Version 1.00b 22-Jan-1990
-
- Corrected problem of layers forcing all umasks to 000.
-
- Version 1.00 17-Mar-1990
-
- First public release.
- */
-
-
- /* Copyright (c) 1987,1988 Oliver Laumann, Technical University of Berlin.
- * Not derived from licensed software.
- *
- * Permission is granted to freely use, copy, modify, and redistribute
- * this software, provided that no attempt is made to gain profit from it,
- * the author is not construed to be liable for any results of using the
- * software, alterations are clearly marked as such, and this notice is
- * not modified.
- *
- * Modified by Patrick Wolfe (pat@kai.com, kailand!pat)
- * Do whatever you want with (my modifications of) this program, but
- * don't claim you wrote them, don't try to make money from them, and
- * don't remove this notice.
- */
-
- /*
- * Beginning of User Configuration Section
- */
-
- /*
- * SEQUENT -- your host system is Sequent. This changes a setvbuf()
- * call to a setlinebuf(). [Suggested by Peter Newton
- * <newton@cs.utexas.edu>]
- *
- */
- #undef SEQUENT
-
-
- /*
- * GETTTYENT -- your system has the new format /etc/ttys (like 4.3 BSD)
- * and the getttyent(3) library functions.
- *
- */
- #undef GETTTYENT
-
-
- /*
- * LOGINDEFAULT -- if set to 1 (one), windows will login (add entries to
- * /etc/utmp) by default. Set to 0 if you don't want this.
- * (Also see USERLIMIT below). [NOTE: current code always
- * logs layer #1 only unless -l option used on 'layers'
- * command.]
- */
- #define LOGINDEFAULT 0
-
- /*
- * USERLIMIT -- count all non-null entries in /etc/utmp before adding a
- * new entry. Some machine manufacturers (incorrectly) count
- * logins by counting non-null entries in /etc/utmp (instead
- * of counting non-null entries with no hostname and not on
- * a pseudo tty). Sequent does this, so you might reach your
- * limited user license early.
- */
- #define USRLIMIT 32
-
- /*
- * SOCKDIR -- If defined, this directory is where layers sockets will be
- * placed, (actually in a subdirectory by the user's loginid).
- * This is neccessary because NFS doesn't support socket
- * operations, and many people's homes are on NFS mounted
- * partitions. Layers will create this directory if it needs
- * to.
- */
- #define SOCKDIR "/tmp/layers" /* NFS doesn't support named sockets */
-
- /*
- * End of User Configuration Section
- */
-
- #include <stdio.h>
- #include <sgtty.h>
- #include <signal.h>
- #include <errno.h>
- #include <ctype.h>
- #include <utmp.h>
- #include <pwd.h>
- #include <nlist.h>
- #include <fcntl.h>
- #include <sys/types.h>
- #include <sys/time.h>
- #include <sys/file.h>
- #include <sys/wait.h>
- #include <sys/socket.h>
- #include <sys/un.h>
- #include <sys/stat.h>
- #include <sys/dir.h>
- #include <sys/ioctl.h>
-
- #include "layers.h"
-
- #ifdef GETTTYENT
- #include <ttyent.h>
- #else
- static struct ttyent
- { char *ty_name;
- } *getttyent();
- static char *tt, *ttnext;
- static char ttys[] = "/etc/ttys";
- #endif
-
- #ifndef FSCALE
- #define FSCALE 1000.0 /* Sequent doesn't define FSCALE...grrrr */
- #endif
-
- #ifdef USRLIMIT
- struct utmp utmpbuf;
- int UserCount;
- #endif
-
- #define Ctrl(c) ((c)&037)
-
- /* C library items */
- extern char **environ;
- extern errno;
- extern sys_nerr;
- extern char *sys_errlist[];
- extern char *index(), *rindex(), *malloc(), *getenv();
- extern char *getlogin(), *ttyname();
-
- /* Local items */
- static void FAbort(), SigHup(), SigChld(), AddCap(), FinitTerm();
- static char *MakeTermcap(), *Filename(), **SaveArgs(), *GetTtyName();
- static void InitWorld(), ClearShape(), BuildTitle(), KillPG();
- static void SetWindowSize(), WriteUtmp();
- static int ReadUtmp(), FindUtmp(), SetUtmp();
-
- static int loginflag = -1;
- static char PtyName[32], TtyName[32];
- static char *ShellProg;
- static char *ShellArgs[2];
- static inlen;
- static ESCseen;
- static GotSignal;
- static char DefaultShell[] = "/bin/sh";
- static char DefaultPath[] = ":/usr/ucb:/bin:/usr/bin";
- static char PtyProto[] = "/dev/ptyXY";
- static char TtyProto[] = "/dev/ttyXY";
- static int TtyMode = 0622;
- static struct stat RealTtyStat; /* Real tty stat */
- static char RealTtyName[32] = ""; /* Real tty name */
- static int RealSlot = 0; /* Real tty logon slot */
- static struct utmp RealUtmp; /* Real tty logon utmp entry */
- static int RealTtyMode = 0; /* Real tty mode */
- static int Oumask; /* Original user's umask */
- static char SockPath[512];
- #ifdef SOCKDIR
- static char SockDir[] = SOCKDIR;
- #else
- static char SockDir[] = ".layers";
- #endif
- static char *SockNamePtr, *SockName;
- static ServerSocket;
- static char *NewEnv[MAXARGS];
- static char Esc = Ctrl('a');
- static char MetaEsc = 'a';
- static char *home;
- static Abortonmsg;
- static utmp, utmpf;
- static char UtmpName[] = "/etc/utmp";
- static char *LoginName;
- static mflag, nflag, fflag, rflag;
- static char HostName[MAXSTR];
- static char *myname;
- static DevTty;
-
- static struct mode {
- struct sgttyb m_ttyb;
- struct tchars m_tchars;
- struct ltchars m_ltchars;
- int m_ldisc;
- int m_lmode;
- } OldMode, NewMode;
-
- #define MSG_CREATE 0
- #define MSG_ERROR 1
-
- struct msg
- {
- int type;
- union
- { struct
- { int lflag; /* login flag */
- struct Shape shape; /* window shape */
- int nargs;
- char line[MAXLINE];
- char dir[1024];
- } create;
- char message[MAXLINE];
- } m;
- };
-
-
- /* dynamic keyboard input buffer definition */
- struct Kbuff
- { struct Kbuff * next; /* next buffer in chain (or NULL) */
- int size; /* size of data in this buffer */
- int offset; /* start of first data in buffer */
- unsigned char text[IOSIZE]; /* text buffer itself */
- };
-
- /* World layer definition */
- struct Layer {
- int chan; /* channel represented by this layer */
- int allocated; /* layer allocated */
- int ptyfd; /* psuedo tty */
- int ptymask; /* mask for pty descriptor */
- int lpid; /* layer head process ID */
- int slot; /* utmp slot number */
- struct Kbuff *kbuff; /* keyboard input buffers */
- struct Shape shape; /* Shape structure to/from MacLayers */
- char cmd[MAXSTR]; /* command to execute */
- char tty[MAXSTR]; /* psuedo tty ID */
- };
-
- static struct Layer World[MAXPCHAN]; /* all layer structures */
-
- static int rows = 24; /* default window height in lines */
- static int cols = 80; /* default window width in chars */
- static char Termcap[1024];
- static char Term[MAXSTR] = "TERM="; /* window's terminal type */
- static char *UserTerm; /* terminal ID we are mimmicing */
- static int flowctl;
- static tcLineLen = 100;
-
- /* co#80 and li$24 added dynamically for proper window size */
- static char TermcapConst1[] = "TERMCAP=SC|";
- static char TermcapConst3[] = "|MacLayers virtual terminal|\\\n\
- :cr=^M:do=^J:nl=^J:bl=^G:cl=\\E[;H\\E[2J:\\\n\
- :le=^H:bs:am:cm=\\E[%i%d;%dH:nd=\\E[C:up=\\E[A:\\\n\
- :ce=\\E[K:cd=\\E[J:so=\\E[7m:se=\\E[m:us=\\E[4m:ue=\\E[m:\\\n\
- :md=\\E[1m:mr=\\E[7m:mb=\\E[5m:me=\\E[m:is=\\E[1;24r\\E[24;1H:\\\n\
- :rf=/usr/lib/tabset/vt100:\\\n\
- :rs=\\E>\\E[?3l\\E[?4l\\E[?5l\\E[?7h\\E[?8h:ks=\\E[?1h\\E=:ke=\\E[?1l\\E>:\\\n\
- :ku=\\EOA:kd=\\EOB:kr=\\EOC:kl=\\EOD:kb=^H:\\\n\
- :ho=\\E[H:k1=\\EOP:k2=\\EOQ:k3=\\EOR:k4=\\EOS:ta=^I:pt:sr=\\EM:vt#3:xn:\\\n\
- :sc=\\E7:rc=\\E8:cs=\\E[%i%d;%dr:\\\n\
- :dc=\\ED:ic=\\EI:";
- /* NOTE: the above two cababilities are beyond vt100 - unique to MacLayers */
-
- int Dflag; /* debug dump flag */
-
- /* main() */
- main(ac, av)
- char **av;
- {
- register n;
- register len;
- register struct Layer *layer;
- char *ap;
- struct passwd *ppp;
- int s;
- int r; /* read fd test bits */
- int w; /* write fd test bits */
- int stall; /* stall flag for priority channel */
- int fderr; /* error fd test bits */
- struct timeval tv;
- struct Shape shape; /* window shape */
- time_t now;
- char buf[IOSIZE];
- char rc[256];
- struct stat st;
- struct Kbuff *kbptr; /* input keyboard buffer pointer */
-
- Abortonmsg = 1; /* quit if message generated */
- ClearShape(&shape); /* initialize shape structure */
- myname = (ac == 0) ? "layers" : av[0];
- InitWorld(); /* clear World array structures */
-
- while (ac > 0)
- { ap = *++av;
- if (--ac > 0 && *ap == '-')
- { switch (ap[1])
- { case 'l': /* login this command line */
- loginflag = 1;
- break;
-
- case 'd': /* dump debugging flag */
- Dflag = 1;
- (void) freopen("layers.dump", "a", stderr); /* append mode */
- #ifdef SEQUENT
- setlinebuf(stderr);
- #else
- setvbuf(stderr, NULL, _IOLBF, 0);
- #endif
- break;
-
- case 'u': /* do not login this command line */
- loginflag = 0;
- break;
-
- case 'm': /* force this to be master and not a client */
- mflag = 1;
- break;
-
- case 'n': /* no flow control */
- nflag = 1;
- break;
-
- case 'f': /* flow control on */
- fflag = 1;
- break;
-
- case 'v': /* do nothing but issue layers version */
- printf("%s\n", LayersVersion);
- exit(0);
-
- default:
- help:
- Msg (0,"Use: %s [-f] [-l | -u] [-m] [-n] [cmd args]\n", myname);
-
- } /* end switch on '-' option */
-
- } /* end if '-' */
-
- else
- break;
-
- } /* end while parameters */
-
- if (nflag && fflag)
- Msg (0, "-f and -n are conflicting options.");
-
- if ((ShellProg = getenv ("SHELL")) == 0)
- ShellProg = DefaultShell;
- DO DEBUG("ShellProg %s\n", ShellProg);
-
- /* we mimmic the user's $TERM ID */
- if ((UserTerm = getenv("TERM")) == 0)
- UserTerm = "layers"; /* use "layers" if none */
- (void) strcat(Term, UserTerm);
- DO DEBUG("%s\n", Term);
-
- ShellArgs[0] = ShellProg;
- if (ac == 0)
- { ac = 1;
- av = ShellArgs;
- shape.wattr |= Wa_shell; /* indicate a shell window */
- }
-
- if ((home = getenv ("HOME")) == 0)
- Msg (0, "$HOME is undefined.");
- DO DEBUG("home %s\n", home);
-
- if ((LoginName = getlogin ()) == 0 || LoginName[0] == '\0')
- { if ((ppp = getpwuid (getuid ())) == 0)
- return;
- LoginName = ppp->pw_name;
- }
- DO DEBUG("LoginName %s\n", LoginName);
-
- if ((Oumask=umask(0)) == -1)
- Msg (errno, "Cannot change umask to zero");
- DO DEBUG("Original umask o%o\n", Oumask);
-
- #ifdef SOCKDIR
- if (stat (SOCKDIR, &st) == -1)
- { if (errno == ENOENT)
- { if (mkdir (SOCKDIR, 0777) == -1)
- Msg (errno, "Cannot make directory %s", SOCKDIR);
- (void) chown (SOCKDIR, 0, 0);
- }
- else
- Msg (errno, "Cannot get status of %s", SOCKDIR);
- }
- else
- { if ((st.st_mode & S_IFMT) != S_IFDIR)
- Msg (0, "%s is not a directory.", SOCKDIR);
- if ((st.st_mode & 0777) != 0777)
- Msg (0, "Directory %s must have mode 777.", SOCKDIR);
- }
- sprintf (SockPath, "%s/%s", SockDir, LoginName);
- #else
- sprintf (SockPath, "%s/%s", home, SockDir);
- #endif
- DO DEBUG("SockPath %s\n", SockPath);
-
- if (stat (SockPath, &st) == -1)
- { if (errno == ENOENT)
- { if (mkdir (SockPath, 0700) == -1)
- Msg (errno, "Cannot make directory %s", SockPath);
- (void) chown (SockPath, getuid (), getgid ());
- DO DEBUG("SockPath directory made\n");
- }
- else
- Msg (errno, "Cannot get status of %s", SockPath);
- }
- else
- { if ((st.st_mode & S_IFMT) != S_IFDIR)
- Msg (0, "%s is not a directory.", SockPath);
- if ((st.st_mode & 0777) != 0700)
- Msg (0, "Directory %s must have mode 700.", SockPath);
- if (st.st_uid != getuid ())
- Msg (0, "You are not the owner of %s.", SockPath);
- }
-
- (void) strcpy(RealTtyName, GetTtyName()); /* real tty name */
- if (stat(RealTtyName, &RealTtyStat) == -1) /* get current mode */
- Msg(errno, "Cannot get status of %s", RealTtyName);
- DO DEBUG("Mode of %s is %#o\n", RealTtyName, RealTtyStat.st_mode);
- RealTtyMode = RealTtyStat.st_mode; /* save mode for later restore */
-
- (void) gethostname (HostName, MAXSTR);
- HostName[MAXSTR-1] = '\0';
- DO DEBUG("HostName %s\n", HostName);
-
- if (ap = index (HostName, '.'))
- *ap = '\0';
- if (ap)
- DO DEBUG("*ap %s\n", *ap);
-
- strcat (SockPath, "/");
- SockNamePtr = SockPath + strlen (SockPath);
-
- /* if we are a client send create message to startup window and exit */
- if (GetSockName ())
- { DO DEBUG("GetSockName says that we are client\n");
- DO DEBUG("SockName '%s'\n", SockName);
- s = MakeClientSocket (1);
- DO DEBUG("Client socket is %d\n", s);
- DO DEBUG("SendCreateMsg()\n");
- SendCreateMsg (s, ac, av, loginflag, &shape);
- close (s);
- DO DEBUG("after SendCreateMsg(), now exit(0)\n");
- exit (0);
- }
-
- /* we are the server */
- DO DEBUG("SockName '%s'\n", SockName);
- DO DEBUG("We are server\n");
- if ((DevTty = open ("/dev/tty", O_RDWR|O_NDELAY)) == -1)
- Msg (errno, "/dev/tty");
- DO DEBUG("opened /dev/tty fd %d\n", DevTty);
-
- ServerSocket = MakeServerSocket ();
- DO DEBUG("ServerSocket %d\n", ServerSocket);
- s = ServerSocket;
-
- if (fflag)
- flowctl = 1;
- else
- if (nflag)
- flowctl = 0;
-
- if (loginflag == -1)
- loginflag = LOGINDEFAULT;
-
- MakeNewEnv ();
- InitUtmp ();
- RealSlot = FindUtmp(RealTtyName); /* find current logon slot */
- if (RealSlot)
- { if (ReadUtmp(RealSlot, &RealUtmp) > 0) /* read real login utmp */
- RemoveUtmp(RealSlot); /* remove original logon slot */
- else
- RealSlot = 0; /* something's wrong */
- }
-
- signal (SIGHUP, SigHup);
- signal (SIGINT, SIG_IGN); /* we should never see this */
- signal (SIGQUIT, FAbort); /* quit layers on these 2 signals */
- signal (SIGTERM, FAbort);
- signal (SIGTTIN, SIG_IGN);
- signal (SIGTTOU, SIG_IGN);
- signal (SIGALRM, SIG_IGN); /* alarm clock used by protocol.c */
-
- GetTTY (0, &OldMode);
- SetMode (&OldMode, &NewMode);
- SetTTY (0, &NewMode);
-
- if (Initlink() == 0)
- { SetTTY(0, &OldMode); /* revert tty back */
- Msg (0, "\n\n You are not running under MacLayers.");
- }
-
- sprintf (rc, "%.*s/.layersrc", 245, home);
- #if 0 /* NOT YET SUPPORTED */
- /* if no window list start up a default shell window */
- if (ReadRc(rc) == 0)
- #endif
- { n = MakeWindow (0, *av, av, (char *)0, loginflag, &shape);
- if (n == -1)
- { SetTTY (0, &OldMode);
- FQuit(1);
- /* NOT REACHED */
- }
- }
-
- (void) chmod(RealTtyName, 0600); /* lock out broadcasts */
- Abortonmsg = 0; /* don't abort on msg from now on */
- signal (SIGCHLD, SigChld);
- tv.tv_usec = 0;
- tv.tv_sec = 0; /* default no timer wanted */
-
- /* client/Maclayers processing loop */
-
- /* poll .20 secs for new startups */
- #define WUSSTARTUP 200000
- /* stall nonpriority windows .5 seconds when top window I/O active */
- #define WUSSTALL 500000
-
- stall = 0; /* startout no stalled channels */
- fderr = 0; /* startout no error fd's */
-
- while (1)
- { int priochan; /* the top window channel */
-
- priochan = TopChannel(); /* find highest priority channel */
-
- /* check for I/O on all available I/O descriptors */
- r = 1<<0; /* always read MacLayers stream */
- r |= 1<<s; /* always read server socket */
- w = 0; /* initalize to no write tests */
- tv.tv_usec = 0; /* default no startup poll */
-
- /* for all active layers set read and write bits as appropriate */
- if (stall)
- stall = 1; /* start counting output layers */
- for (n=0; n<MAXPCHAN; n++)
- if ((layer = &World[n])->allocated) /* if layer exists ... */
- { /* if not yet started or has just terminated ... */
- if (layer->ptymask & fderr)
- tv.tv_usec = WUSSTARTUP; /* don't spinloop but wait-a-bit */
- else
- { if (layer->kbuff && layer->kbuff->size)
- /* keyboard input for layer */
- w |= layer->ptymask; /* try write to it */
- /* read layer output unless we're being nice to top window */
- if (!stall)
- r |= layer->ptymask; /* read output from layer */
- else
- if (layer->chan == priochan)
- r |= layer->ptymask; /* read top priority output */
- else
- stall++; /* indicate something to stall */
- }
- }
-
- if (stall > 1)
- if (!tv.tv_usec)
- tv.tv_usec = WUSSTALL; /* set stall timout */
-
- /* process signals before trying select */
- if (GotSignal)
- { SigHandler ();
- continue;
- }
-
- DO DEBUG("Select(r %x, w %x, fderr %x, stall %d, prio %d, us %d)\n",
- r, w, fderr, stall, priochan, tv.tv_usec);
-
- switch ( select(32, &r, &w, NULL, tv.tv_usec ? &tv : NULL) )
- { case -1:
- /* errno has report */
- if (errno == EINTR) /* signal delivered or timout */
- { errno = 0;
- tv.tv_usec = 0; /* clear timer wait value */
- fderr = 0; /* turn off error stall */
- stall = 0; /* turn off output priority stall */
- DO DEBUG("select errno EINTR\n");
- continue; /* re-loop */
- }
- Abortonmsg = 1;
- DO DEBUG("select errno %d\n", errno);
- Msg (errno, "select");
- /*NOTREACHED*/
-
- case 0:
- /* timeout reached */
- tv.tv_usec = 0; /* clear timer wait value */
- stall = 0; /* turn off stall */
- fderr = 0; /* turn off error stall */
- continue; /* re-loop */
-
- default:
- /* a channel has read/write status pending */
- break;
- }
-
- DO DEBUG("after select r %x w %x\n", r, w);
-
- /* handle any signal arriving up during select wait */
- if (GotSignal)
- { SigHandler ();
- continue;
- }
-
- /* if server socket has command process that now */
- if (r & 1 << s)
- { ReceiveMsg(s); /* process client control packet */
- continue; /* status may have changed */
- }
-
- /* next process input stream from MacLayers */
- if (r & 1 << 0)
- { ProcessStreamin(); /* key input and control packets */
- continue; /* status may have changed */
- }
-
- /* process keyboard input first so output doesn't hold up
- ** keyboard echo and break/interrupt processing
- */
- priochan = TopChannel(); /* find top priority channel */
- stall = 0; /* assume no stall needed */
- for (n=0; n<MAXPCHAN; n++)
- if ((layer = &World[n])->allocated)
- if (w & layer->ptymask)
- while ((kbptr=layer->kbuff)->size)
- { /* pass as much keyboard as possible */
- if (layer->chan == priochan)
- stall = 1; /* stall lower priority channels */
- len = write(layer->ptyfd, &kbptr->text[kbptr->offset],
- kbptr->size);
- DO DEBUG("keyin len %d to chan %d\n", len, layer->chan);
- if (len <= 0) /* if no data accepted ... */
- { if (errno == EIO) /* if I/O error indicated ... */
- fderr |= layer->ptymask; /* wait-a-bit on this */
- errno = 0; /* clear errno */
- break; /* try again later */
- }
- /* some of buffer accepted */
- kbptr->size -= len; /* length processed */
- kbptr->offset += len; /* bump up offset */
- if (kbptr->size > 0) /* not all buffer accepted ... */
- break; /* try feed again later */
- /* see if another buffer chained */
- if (kbptr->next)
- { /* yes, free up current buffer and queue next */
- layer->kbuff = kbptr->next; /* to next buffer */
- free(kbptr); /* free this buffer up */
- }
- else
- { /* otherwise leave this for next input */
- kbptr->size = 0; /* empty buffer */
- kbptr->offset = 0; /* refill from the start */
- }
- }
-
- /* first process the highest priority channel (top window) */
- if (priochan > 0 && priochan <= MAXPCHAN) /* if valid ... */
- if ((layer = &World[priochan-1])->allocated)
- if (r & layer->ptymask)
- { /* output to send to top MacLayers window */
- len = read(layer->ptyfd, buf, IOSIZE);
- if (len >= 0) /* if no error ... */
- { DO DEBUG("read output len %d chan %d\n", len, layer->chan);
- }
- else
- { /* We expect EIO error if socket not yet open on other end
- ** or if process using socket has terminated. We expect
- ** EWOULDBLOCK also after process terminates.
- **/
- DO DEBUG("read output err chan %d errno %d len %d\n",
- layer->chan, errno, len);
- if (errno == EIO || errno == EWOULDBLOCK)
- DO DEBUG(" ...anticipated\n");
- /* layer not ready or just terminated so wait-a-bit */
- fderr |= layer->ptymask;
- r &= ~layer->ptymask; /* don't read it again below */
- errno = 0; /* clear errno */
- }
- if (len > 0)
- SendData(layer->chan, buf, len);
-
- if (len >= 0)
- /* To keep lower priority channels from hogging the line
- ** we delay any output from them until the primary window
- ** has no more data to be sent to it.
- */
- stall = 1; /* stall output from others */
- }
-
- /* now pass all available output to MacLayers */
- if (!stall)
- for (n=0; n<MAXPCHAN; n++)
- if ((layer = &World[n])->allocated)
- if (r & layer->ptymask)
- { /* output to send to MacLayers window */
- len = read(layer->ptyfd, buf, IOSIZE);
- if (len >= 0) /* if no error ... */
- { DO DEBUG("output chan %d len %d\n", layer->chan, len);
- }
- else
- { /* We expect EIO error if socket not yet open on other end
- ** or if process using socket has terminated. We expect
- ** EWOULDBLOCK also after process terminates.
- **/
- DO DEBUG("read output err chan %d errno %d len %d\n",
- layer->chan, errno, len);
- if (errno == EIO || errno == EWOULDBLOCK)
- { DO DEBUG(" ...anticipated\n");
- }
- /* layer not ready or just terminated so wait-a-bit */
- fderr |= layer->ptymask;
- errno = 0; /* clear errno */
- }
- if (len > 0)
- SendData(layer->chan, buf, len);
- }
-
- /* handle signals again */
- if (GotSignal)
- SigHandler ();
-
- } /* end while (1) */
-
- /* NOT REACHED */
-
- } /* main() */
-
- /* ReceiveQuit() - MacLayers sends Quit packet */
-
- void
- ReceiveQuit()
- {
- /* We completely quit layers cancelling all active processes */
- DO DEBUG("ReceiveQuit()\n");
- FQuit(0); /* normal termination */
- /* NOT REACHED */
-
- } /* ReceiveQuit() */
-
-
- /* ReceiveNew() - MacLayers requests a new shell layer */
-
- void
- ReceiveNew(chanid, shape)
- int chanid; /* channel for new shell layer */
- struct Shape *shape; /* shape for new channel */
- {
- DO DEBUG("ReceiveNew(%d)\n", chanid);
- (void) MakeWindow (chanid, *ShellArgs, ShellArgs,
- (char *) 0, loginflag, shape);
-
- } /* ReceiveNew() */
-
-
- /* ReceiveDelete() - MacLayers has removed a layer */
- void
- ReceiveDelete(chanid)
- int chanid; /* channel which was deleted */
- {
- struct Layer *layer; /* layer pointer */
-
- /* validate channel */
- DO DEBUG("ReceiveDelete(%d)\n", chanid);
- if (chanid <= 0 || chanid > MAXPCHAN)
- return; /* ignore invalid channel */
-
- /* if this layer active then kill it off, else ignore request */
- layer = &World[chanid-1]; /* locate target layer */
- if (layer->allocated)
- KillWindow(layer);
-
- } /* ReceiveDelete() */
-
-
- /* ReceiveSignal() - send signal to layer's process group */
-
- void
- ReceiveSignal(chanid, signal)
- int chanid; /* layer's channel */
- int signal; /* signal.h signal ID */
- {
- struct Layer *layer; /* layer pointer */
-
- DO DEBUG("ReceiveSignal(%d,%d)\n", chanid, signal);
- /* verify channel */
- if (chanid <= 0 || chanid > MAXPCHAN)
- return; /* ignore invalid channel */
-
- /* if this layer is active send the signal to the process group */
- layer = &World[chanid-1]; /* locate target layer */
- if (layer->allocated && layer->lpid)
- KillPG(layer, signal);
-
- } /* ReceiveSignal() */
-
-
- /* ReceiveReshape() - windowsize and location updated */
- void
- ReceiveReshape(chanid, shape)
- int chanid; /* channel having shape */
- struct Shape *shape; /* shape structure */
- {
- struct Layer *layer; /* layer pointer */
-
- DO DEBUG("ReceiveReshape(%d)\n", chanid);
-
- /* verify channel */
- if (chanid <= 0 || chanid > MAXPCHAN)
- return; /* ignore invalid channel */
-
- /* if this layer is active then reshape it's window */
- layer = &World[chanid-1]; /* locate target layer */
- if (layer->allocated && layer->lpid)
- { layer->shape = *shape; /* install as our new shape */
- SetWindowSize(layer); /* udpate the O/S window info */
- }
-
- } /* ReceiveReshape() */
-
-
- /* SetWindowSize() - tell O/S about new window size */
-
- static void
- SetWindowSize(layer)
- struct Layer *layer; /* layer to resize */
- {
- #ifdef TIOCSWINSZ
- struct winsize wsize; /* window size structure */
- int retcode; /* ioctl return code */
-
- wsize.ws_col = layer->shape.wchars; /* character width */
- wsize.ws_row = layer->shape.wlines; /* window height */
- wsize.ws_xpixel = 0; /* necessary? */
- wsize.ws_ypixel = 0;
- /* update O/S window state */
- retcode = ioctl(layer->ptyfd, TIOCSWINSZ, &wsize);
- DO DEBUG("SetWindowSize(chan %d) col %d, row %d iotcl() = %d\n",
- layer->chan, layer->shape.wchars, layer->shape.wlines,
- retcode);
-
- retcode = ioctl(layer->ptyfd, TIOCGWINSZ, &wsize);
- DO DEBUG("TIOCGWINSZ: col %d, row %d iotcl() = %d\n",
- wsize.ws_col, wsize.ws_row, retcode);
-
- #endif
- } /* SetWindowSize() */
-
-
- /* ReceiveData() - received keyboard input for layer */
- void
- ReceiveData(chanid, buff, cnt)
- int chanid; /* channel receiving input */
- char *buff; /* buffer containing data */
- int cnt; /* count of data bytes */
- {
- struct Layer *layer; /* layer pointer */
- struct Kbuff *kb; /* keybuff pointer */
-
- DO DEBUG("ReceiveData(%d, '%.*s')\n", chanid, cnt, buff);
- /* verify channel */
- if (chanid <= 0 || chanid > MAXPCHAN)
- return; /* ignore invalid channel */
- layer = &World[chanid-1]; /* locate target layer */
-
- /* add character stream to layer's input buffers for main loop processing */
- for (kb=layer->kbuff; kb->next; kb=kb->next); /* find oldest buffer */
- while (cnt--)
- {
- /* if current buffer full then chain in a new one */
- if (kb->offset+kb->size >= IOSIZE)
- { kb->next = (struct Kbuff *) malloc(sizeof(struct Kbuff));
- kb = kb->next; /* base new keybuff */
- kb->next = NULL; /* no next yet */
- kb->size = 0; /* this character is first */
- kb->offset = 0; /* at zero offset */
- }
-
- /* add new character to the end of this buffer */
- kb->text[kb->offset+kb->size++] = *buff++; /* insert at end of data */
- }
-
- } /* ReceiveData() */
-
-
-
- /* InitWorld() - initialize layer structures */
-
- static void
- InitWorld()
- {
- struct Layer *layer; /* layer pointer */
- struct Kbuff *kb; /* keybuff pointer */
- int i; /* work variable */
-
- for (i=0; i<MAXPCHAN; i++)
- { layer = &World[i]; /* point to layer */
- layer->chan = i+1; /* channel ID */
- layer->allocated = 0; /* does not exist yet */
- layer->lpid = 0; /* head process */
- layer->ptyfd = 0; /* no pseduo pty yet */
- layer->ptymask = 0; /* no pty mask yet */
- layer->slot = 0; /* no Utmp slot */
- ClearShape(&layer->shape); /* clear shape structure */
-
- /* allocate the primary input keybuffer for this layer */
- layer->kbuff = (struct Kbuff *) malloc(sizeof(struct Kbuff));
- layer->kbuff->next = NULL; /* no next buffer */
- layer->kbuff->size = 0; /* no data in buffer */
- layer->kbuff->offset = 0; /* start filling at front */
-
- } /* end for layer scan */
-
- } /* InitWorld() */
-
-
- /* clearshape() - initialize shape structure */
-
- static void
- ClearShape(shape)
- struct Shape *shape; /* shape structure pointer */
- {
- shape->worigv = 0; /* default window position */
- shape->worigh = 0;
- shape->wlines = 0; /* default size */
- shape->wchars = 0;
- shape->wfont = 0; /* default font size */
- shape->wattr = 0; /* no attributes */
-
- } /* clearshape() */
-
-
- /* SigHandler() - process signals */
-
- SigHandler ()
- {
- DO DEBUG("GotSignal()\n");
- while (GotSignal)
- { GotSignal = 0;
- DoWait (); /* handle dead or stopped children processes */
- }
- }
-
- static void
- SigChld ()
- {
- DO DEBUG("SigChld()\n");
- /* flag child process is stopped or dead */
- GotSignal = 1;
- }
-
- static void
- SigHup ()
- {
- DO DEBUG("SigHup()\n");
- /* Detach (0); */
- FQuit(1); /* stop all processes */
- /* NOT REACHED */
-
- }
-
- /* DoWait() - send SIGCONT to stopped windows, Free dead process windows */
- static
- DoWait()
- {
- register pid;
- register struct Layer *layer;
- union wait wstat;
- int i;
-
- DO DEBUG("DoWait()\n");
- while ((pid = wait3 (&wstat, WNOHANG|WUNTRACED, NULL)) > 0)
- /* dead or stopped child process found */
- for (i=0; i<MAXPCHAN; i++)
- if ((layer = &World[i])->lpid == pid)
- { if (WIFSTOPPED (wstat))
- { /* stopped process so restart it */
- /*** DO WE REALLY NEED TO DO THIS? ***/
- DO DEBUG("killpg(, SIGCONT)\n");
- KillPG(layer, SIGCONT);
- }
- else
- { /* remove dead process's layer */
- DO DEBUG("kill dead process window %d\n", layer->chan);
- KillWindow (layer);
- /* tell MacLayers layer is dead */
- SendDelete(layer->chan);
- }
- }
-
- } /* DoWait() */
-
-
- /* KillPG() - send signal to layer's process group */
-
- static void
- KillPG(layer, signal)
- struct Layer *layer; /* layer to signal */
- int signal; /* signal to send */
- {
- int retcode; /* work variable */
- int pgrp; /* process group for layer */
- int tgrp; /* terminal control process group */
-
- DO DEBUG("KillPG(%d, sig %d)\n", layer->chan, signal);
-
- if (layer->lpid)
- { pgrp = getpgrp(layer->lpid); /* get process group */
- DO DEBUG("getpgrp() = %d\n", pgrp);
- if (pgrp != -1)
- { retcode = killpg(pgrp, signal); /* signal it */
- DO DEBUG("killpg() = %d\n", retcode);
- }
-
- /* After a lot of experimenting it was determined that csh
- ** creates a new terminal control group when it runs a command.
- ** Thus the above code failed to forward SIGINT to such commands.
- ** (Csh would get it but just ignore it.) Thus the following code.
- */
-
- /* forward SIGINT to the terminal control group also */
- if (signal == SIGINT)
- { retcode = ioctl(layer->ptyfd, TIOCGPGRP, &tgrp);
- DO DEBUG("ioctl(ptyfd,TIOCGPGRP) termcntlgrp %d, retcode = %d\n",
- tgrp, retcode);
- /* but only if not the same process group */
- if (retcode != -1 && tgrp != pgrp)
- { retcode = killpg(tgrp, signal); /* signal it */
- DO DEBUG("killpg(%d) = %d\n", tgrp, retcode);
- }
- }
- }
-
- } /* KillPG() */
-
-
- /* KillWindow() - remove a layer from the system */
-
- /* Note: This function does NOT tell MacLayers about the dead layer */
-
- static
- KillWindow (layer)
- struct Layer *layer;
- {
- struct Kbuff *kb; /* work buffer free pointer */
-
- if (layer->allocated)
- { /* SHOULD THIS BE SIGKILL ??? */
- if (layer->lpid) /* if layer process started ... */
- { KillPG(layer, SIGHUP); /* kill processes */
- layer->lpid = 0; /* clear pid field */
- }
- RemoveUtmp(layer->slot);
- (void) chmod(layer->tty, 0666);
- (void) chown(layer->tty, 0, 0);
- close(layer->ptyfd);
- DO DEBUG("chmod/chown %s, SendDelete(%d)\n",layer->tty, layer->chan);
-
- ClearShape(&layer->shape); /* reset the shape structure */
- /* free all keybuffers but one and reprime it */
- for (kb=layer->kbuff; kb->next; kb=kb->next)
- free(kb); /* free input buffers */
- kb->size = 0; /* empty buffer */
- kb->offset = 0; /* start refill from front */
- layer->allocated = 0; /* window no longer allocated */
- }
-
- } /* KillWindow() */
-
-
- /* FAbort() - signal catcher for quitting */
- static void
- FAbort()
- {
- DO DEBUG("FAbort()\n");
- FQuit (1); /* quit with error exit */
-
- } /* FAbort() */
-
-
- /* FQuit() - terminate layers */
- void
- FQuit(exitcode)
- int exitcode;
- {
- int i;
-
- DO DEBUG("FQuit(%d)\n",exitcode);
- for (i=0; i<MAXPCHAN; i++)
- KillWindow(&World[i]); /* kill all windows */
-
- DO DEBUG("SendQuit()\n");
- SendQuit(); /* tell MacLayers to exit layers mode */
- SetTTY (0, &OldMode);
- if (RealTtyMode)
- (void) chmod(RealTtyName, RealTtyMode); /* restore mode */
- if (RealSlot)
- WriteUtmp(RealSlot, &RealUtmp); /* restore original login */
- FinitTerm ();
- sleep(2); /* wait for port to reset */
- printf ("[layers terminated]\n");
-
- exit (exitcode);
-
- } /* FQuit() */
-
-
- /* MakeWindow() - create new layer */
- static
- MakeWindow (chan, prog, args, dir, lflag, shape)
- int chan; /* zero or channel to use for window */
- char *prog;
- char **args;
- char *dir;
- int lflag; /* one if this to be logged in */
- struct Shape *shape; /* shape to use for window */
- {
- register struct Layer *layer;
- register char **cp;
- register f, j;
- int tf;
- int mypid;
- char ebuf[10];
-
- DO DEBUG("MakeWindow(%d, %s, %s, dir %s, ",
- chan, prog, args[0], dir ? dir : "(none)");
- DO DEBUG("login %d\n", lflag);
- DO DEBUG(" origv %d, origh %d, lines %d, chars %d, ",
- shape->worigv, shape->worigh, shape->wlines, shape->wchars);
- DO DEBUG("font %d, attr 0x%x\n", shape->wfont, shape->wattr);
-
- if ((f = OpenPTY ()) == -1)
- { Msg (0, "No more PTYs.");
- return ( -1 );
- }
-
- /* if channel not given obtain one from MacLayers */
- if (chan == 0)
- { chan = SendNew(shape); /* try to get free window */
- if (chan == 0)
- { Msg (0, "No more windows.");
- return ( -1 );
- }
- DO DEBUG("SendNew() == %d\n", chan);
- }
-
- /* verify channel */
- if (chan <= 0 || chan > MAXPCHAN)
- { Msg(0, "Invalid channel %d.", chan);
- return ( -1 );
- }
-
- /* login this window if it's layer #1 */
- if (chan == 1)
- lflag = 1;
-
- if (lflag == -1)
- lflag = loginflag;
-
- #ifdef USRLIMIT
- /*
- * Count current number of users, and if logging windows in,
- */
- if (lflag == 1)
- { (void) lseek (utmpf, 0, 0);
- UserCount = 0;
- while (read(utmpf, &utmpbuf, sizeof(struct utmp)) > 0)
- { if (utmpbuf.ut_name[0] != '\0')
- UserCount++;
- }
- if (UserCount >= USRLIMIT)
- { Msg (0, "User limit reached. Window will not be logged in.");
- lflag = 0;
- }
- }
- #endif USRLIMIT
-
- layer = &World[chan-1]; /* find layer structure */
- layer->shape = *shape; /* install new window shape */
-
- /* ??? What do we do if layer is still active as far as we're concerned? */
- if (layer->allocated)
- { DO DEBUG("??? newlayer not free !!!\n");
- KillWindow(layer); /* kill off old layer */
- SendDelete(layer->chan); /* kill window back off */
- Msg (0, "Makewindow error: Duplicate active layer %d.", chan);
- return ( -1 ); /* return failed */
- }
-
- layer->allocated = 1; /* show layer now in use */
- BuildTitle(chan, prog, args); /* install window title */
-
- (void) fcntl (f, F_SETFL, FNDELAY);
- layer->ptyfd = f; /* pseudo pty for task's I/O */
- layer->ptymask = 1<<f; /* set pty device mask */
- strncpy (layer->cmd, Filename (args[0]), MAXSTR-1);
- layer->cmd[MAXSTR-1] = '\0';
- strncpy (layer->tty, TtyName, MAXSTR-1);
- DO DEBUG("forking %s, tty %s, ptyfd %d, mask %x\n",
- layer->cmd, layer->tty, layer->ptyfd, layer->ptymask);
- (void) chown (TtyName, getuid (), getgid ());
- if (lflag == 1)
- { layer->slot = SetUtmp(TtyName, chan == 1);
- if (chan == 1 && RealTtyMode)
- /* set to original tty umask */
- (void) chmod(TtyName, RealTtyMode);
- else
- /* force to this mode */
- (void) chmod(TtyName, TtyMode);
- }
- else
- { layer->slot = -1;
- /* do not allow any other user access to this device */
- (void) chmod (TtyName, 0600);
- }
- switch (layer->lpid = fork ())
- { case -1:
- Msg (errno, "fork");
- layer->lpid = 0; /* clear pid field */
- return ( -1 ); /* return failed */
-
- case 0:
- signal (SIGHUP, SIG_DFL);
- signal (SIGINT, SIG_DFL);
- signal (SIGQUIT, SIG_DFL);
- signal (SIGTERM, SIG_DFL);
- signal (SIGTTIN, SIG_DFL);
- signal (SIGTTOU, SIG_DFL);
- signal (SIGALRM, SIG_DFL);
- setuid (getuid ());
- setgid (getgid ());
- if (dir && chdir (dir) == -1)
- { SendErrorMsg ("Cannot chdir to %s: %s", dir, sys_errlist[errno]);
- exit (1);
- }
- mypid = getpid ();
- ioctl (DevTty, TIOCNOTTY, (char *)0);
- if ((tf = open (TtyName, O_RDWR)) == -1)
- { SendErrorMsg ("Cannot open %s: %s", TtyName, sys_errlist[errno]);
- exit (1);
- }
- DO DEBUG("Now in new process\n");
- (void) dup2 (tf, 0);
- (void) dup2 (tf, 1);
- (void) dup2 (tf, 2);
- for (f = getdtablesize () - 1; f > 2; f--)
- close (f);
- ioctl (0, TIOCSPGRP, &mypid);
- (void) setpgrp (0, mypid);
- SetTTY (0, &OldMode);
-
- { struct winsize wsize; /* window size structure */
- int retcode; /* ioctl return code */
-
- wsize.ws_col = layer->shape.wchars; /* character width */
- wsize.ws_row = layer->shape.wlines; /* window height */
- wsize.ws_xpixel = 0; /* necessary? */
- wsize.ws_ypixel = 0;
- /* update O/S window state */
- retcode = ioctl(0, TIOCSWINSZ, &wsize);
- }
- (void) umask(Oumask); /* restore user's original umask */
- NewEnv[2] = MakeTermcap(layer->shape.wlines, layer->shape.wchars);
- sprintf (ebuf, "LAYER=%d", chan);
- NewEnv[3] = ebuf;
- execvpe (prog, args, NewEnv);
- printf("%s: cannot exec %s: %s", myname, prog, sys_errlist[errno]);
- exit (1);
- }
-
- return ( chan );
-
- } /* MakeWindow() */
-
- static
- execvpe (prog, args, env)
- char *prog, **args, **env;
- {
- register char *path, *p;
- char buf[1024];
- char *shargs[MAXARGS+1];
- register i;
- register eaccess = 0;
-
- if (prog[0] == '/')
- path = "";
- else
- if ((path = getenv ("PATH")) == 0)
- path = DefaultPath;
- do
- { p = buf;
- while (*path && *path != ':')
- *p++ = *path++;
- if (p > buf)
- *p++ = '/';
- strcpy (p, prog);
- if (*path)
- ++path;
- execve (buf, args, env);
- switch (errno)
- { case ENOEXEC:
- shargs[0] = DefaultShell;
- shargs[1] = buf;
- for (i = 1; shargs[i+1] = args[i]; ++i);
- execve (DefaultShell, shargs, env);
- return;
-
- case EACCES:
- eaccess = 1;
- break;
-
- case ENOMEM: case E2BIG: case ETXTBSY:
- return;
-
- } /* end switch */
-
- } while (*path);
-
- if (eaccess)
- errno = EACCES;
-
- } /* execvpe() */
-
-
- /* BuildTitle() - create and install window title */
-
- static void
- BuildTitle(chan, prog, args)
- int chan; /* channel for title */
- char *prog; /* program being executed */
- char **args; /* arg list */
- {
- int i; /* arg scan index */
- char buff[1024]; /* super huge title buffer */
-
- /* skip any leading "/bin/" */
- if (strncmp(prog, "/bin/", 5) == 0)
- strcpy(buff, prog+5); /* leave /bin off */
- else
- strcpy(buff, prog); /* start with program name */
-
- /* add all aguments but stop if option ("-") seen */
- for (i=1; args[i] && args[i][0] != '-'; i++)
- { strcat(buff, " "); /* delimiter */
- strcat(buff, args[i]); /* add next parameter */
- }
-
- SendTitle(chan, buff, strlen(buff)); /* set new window title */
-
- } /* BuildTitle() */
-
-
- #ifdef sequent
- static
- OpenPTY ()
- {
- char *m, *s;
- register f;
-
- f = getpseudotty (&s, &m);
- strncpy (PtyName, m, sizeof (PtyName));
- strncpy (TtyName, s, sizeof (TtyName));
- ioctl (f, TIOCFLUSH, (char *)0);
- return (f);
- }
-
- #else
-
- static
- OpenPTY ()
- {
- register char *p, *l, *d;
- register i, f, tf;
-
- strcpy (PtyName, PtyProto);
- strcpy (TtyName, TtyProto);
- for (p = PtyName, i = 0; *p != 'X'; ++p, ++i);
- for (l = "qpr"; *p = *l; ++l)
- { for (d = "0123456789abcdef"; p[1] = *d; ++d)
- { if ((f = open (PtyName, O_RDWR)) != -1)
- { TtyName[i] = p[0];
- TtyName[i+1] = p[1];
- if ((tf = open (TtyName, O_RDWR)) != -1)
- { close (tf);
- return f;
- }
- close (f);
- }
- }
- }
-
- return -1;
-
- } /* OpenPTY() */
- #endif
-
- static
- SetTTY (fd, mp)
- struct mode *mp;
- {
- ioctl (fd, TIOCSETP, &mp->m_ttyb);
- ioctl (fd, TIOCSETC, &mp->m_tchars);
- ioctl (fd, TIOCSLTC, &mp->m_ltchars);
- ioctl (fd, TIOCLSET, &mp->m_lmode);
- ioctl (fd, TIOCSETD, &mp->m_ldisc);
-
- } /* SetTTY() */
-
- static
- GetTTY (fd, mp)
- struct mode *mp;
- {
- ioctl (fd, TIOCGETP, &mp->m_ttyb);
- ioctl (fd, TIOCGETC, &mp->m_tchars);
- ioctl (fd, TIOCGLTC, &mp->m_ltchars);
- ioctl (fd, TIOCLGET, &mp->m_lmode);
- ioctl (fd, TIOCGETD, &mp->m_ldisc);
-
- } /* GetTTY() */
-
- static
- SetMode (op, np)
- struct mode *op, *np;
- {
- *np = *op;
- #if 1
- if (flowctl)
- { np->m_ttyb.sg_flags &= ~(CRMOD|ECHO);
- np->m_ttyb.sg_flags |= CBREAK | ANYP;
- }
- else
- np->m_ttyb.sg_flags = RAW | ANYP;
- #else
- np->m_ttyb.sg_flags &= ~(CRMOD|ECHO);
- np->m_ttyb.sg_flags |= CBREAK | ANYP;
- #endif
- np->m_tchars.t_intrc = -1;
- np->m_tchars.t_quitc = -1;
- if (!flowctl)
- { np->m_tchars.t_startc = -1;
- np->m_tchars.t_stopc = -1;
- }
- np->m_ltchars.t_suspc = -1;
- np->m_ltchars.t_dsuspc = -1;
- np->m_ltchars.t_flushc = -1;
- np->m_ltchars.t_lnextc = -1;
-
- } /* SetMode() */
-
- static char *
- GetTtyName ()
- {
- int n;
- char *p;
-
- for (p = 0, n = 0; n <= 2 && !(p = ttyname (n)); n++);
-
- if (!p || *p == '\0')
- Msg (0, "layers must run on a tty.");
-
- return ( p );
-
- } /* GetTtyName() */
-
-
- static
- Kill (pid, sig)
- {
- if (pid != 0)
- (void) kill (pid, sig);
- }
-
- /* GetSockName() - set SockName; if LTY env return 1 else 0 */
- static
- GetSockName ()
- {
- register client;
- static char buf[2*MAXSTR];
-
- if (!mflag && (SockName = getenv ("LTY")) != 0 && *SockName != '\0')
- { client = 1;
- setuid (getuid ());
- setgid (getgid ());
- }
- else
- { sprintf (buf, "%s.%s", HostName, Filename (RealTtyName));
- SockName = buf;
- client = 0;
- }
- return client;
-
- } /* GetSockName() */
-
- static
- MakeServerSocket ()
- {
- register s;
- struct sockaddr_un a;
- char *p;
-
- if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1)
- Msg (errno, "socket");
- a.sun_family = AF_UNIX;
- strcpy (SockNamePtr, SockName);
- strcpy (a.sun_path, SockPath);
- if (connect (s, (struct sockaddr *)&a, strlen (SockPath)+2) != -1)
- { p = Filename (SockPath);
- Msg (0, "You already have a layers running on %s.", p);
- /*NOTREACHED*/
- }
- DO DEBUG("MakeServerSocket: unlink(SockPath)/bind()/chown/listen\n");
- (void) unlink (SockPath);
- if (bind (s, (struct sockaddr *)&a, strlen (SockPath)+2) == -1)
- Msg (errno, "bind");
- (void) chown (SockPath, getuid (), getgid ());
- if (listen (s, 5) == -1)
- Msg (errno, "listen");
- return s;
-
- } /* MakeServerSocket() */
-
- static
- MakeClientSocket (err)
- {
- register s;
- struct sockaddr_un a;
-
- if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1)
- Msg (errno, "socket");
- a.sun_family = AF_UNIX;
- strcpy (SockNamePtr, SockName);
- strcpy (a.sun_path, SockPath);
- if (connect (s, (struct sockaddr *)&a, strlen (SockPath)+2) == -1)
- { if (err)
- { Msg (errno, "connect: %s", SockPath); }
- else
- { close (s);
- return -1;
- }
- }
- return s;
-
- } /* MakeClientSocket() */
-
- static
- SendCreateMsg (s, ac, av, lflag, shape)
- char **av;
- struct Shape *shape;
- {
- struct msg m;
- register char *p;
- register len, n;
- char *pwd; /* PWD environment string */
-
- DO DEBUG("SendCreateMsg(%d, ac %d, lflag %d\n", s, ac, lflag);
- m.type = MSG_CREATE;
- p = m.m.create.line;
- for (n = 0; ac > 0 && n < MAXARGS-1; ++av, --ac, ++n)
- { len = strlen (*av) + 1;
- if (p + len >= m.m.create.line+MAXLINE)
- break;
- strcpy (p, *av);
- p += len;
- }
- DO DEBUG(" nargs %d, create line = '%s'\n", n, m.m.create.line);
- m.m.create.nargs = n;
- m.m.create.lflag = lflag;
- m.m.create.shape = *shape; /* pass window shape */
-
- /* Since Suns can hang up on getwd() [damn their stupid networking]
- ** we try to get the current working directory first from the PWD
- ** environment variable.
- */
- if ((pwd=getenv("PWD")) && strlen(pwd) < 1024)
- (void) strcpy(m.m.create.dir, pwd);
- else
- if (getwd (m.m.create.dir) == 0)
- { DO DEBUG("getwd() failed!!\n");
- Msg (0, "%s", m.m.create.dir);
- }
- DO DEBUG(" create.dir = '%s'\n", m.m.create.dir);
-
- if (write (s, (char *)&m, sizeof (m)) != sizeof (m))
- { DO DEBUG(" write failed!!\n");
- Msg (errno, "write");
- }
- DO DEBUG("SendCreateMsg() done\n");
-
- } /* SendCreateMsg() */
-
- /*VARARGS1*/
- static
- SendErrorMsg (fmt, p1, p2, p3, p4, p5, p6)
- char *fmt;
- {
- register s;
- struct msg m;
-
- s = MakeClientSocket (1);
- m.type = MSG_ERROR;
- sprintf (m.m.message, fmt, p1, p2, p3, p4, p5, p6);
- (void) write (s, (char *)&m, sizeof (m));
- close (s);
- sleep (2);
- }
-
- static
- ReceiveMsg (s)
- {
- register ns;
- struct sockaddr_un a;
- int left, len = sizeof (a);
- struct msg m;
- char *p;
-
- DO DEBUG ("ReceiveMsg()\n");
- if ((ns = accept (s, (struct sockaddr *)&a, &len)) == -1)
- { Msg (errno, "accept");
- return;
- }
- p = (char *)&m;
- left = sizeof (m);
- while (left > 0 && (len = read (ns, p, left)) > 0)
- { p += len;
- left -= len;
- }
- close (ns);
- if (len == -1)
- Msg (errno, "read");
- if (left > 0)
- return;
- switch (m.type)
- { case MSG_CREATE:
- DO DEBUG("MSG_CREATE:\n");
- ExecCreate (&m);
- break;
-
- case MSG_ERROR:
- DO DEBUG("MSG_ERROR:\n");
- Msg (0, "%s", m.m.message);
- break;
-
- default:
- Msg (0, "Invalid message (type %d).", m.type);
-
- } /* end switch */
-
- } /* ReceiveMsg() */
-
- static
- ExecCreate (mp)
- struct msg *mp;
- {
- char *args[MAXARGS];
- register n;
- register char **pp = args, *p = mp->m.create.line;
-
- for (n = mp->m.create.nargs; n > 0; --n)
- { *pp++ = p;
- p += strlen (p) + 1;
- }
- *pp = 0;
- n = MakeWindow (0, mp->m.create.line, args, mp->m.create.dir,
- mp->m.create.lflag, &mp->m.create.shape);
-
- } /* ExecCreate() */
-
- #if 0
- static
- ReadRc (fn)
- char *fn;
- {
- FILE *f;
- register char *p, **pp, **ap;
- register argc, num, c;
- char buf[256];
- char *args[MAXARGS];
- int key;
- struct Shape shape; /* shape for new window */
-
- ClearShape(&shape); /* initialize shape */
- ap = args;
- if (access (fn, R_OK) == -1)
- return;
- if ((f = fopen (fn, "r")) == NULL)
- return;
- while (fgets (buf, 256, f) != NULL)
- { if (p = rindex (buf, '\n'))
- *p = '\0';
- if ((argc = Parse (fn, buf, ap)) == 0)
- continue;
- if (strcmp (ap[0], "escape") == 0)
- { p = ap[1];
- if (argc < 2 || strlen (p) != 2)
- Msg (0, "%s: two characters required after escape.", fn);
- Esc = *p++;
- MetaEsc = *p;
- ktab[Esc].type = KEY_OTHER;
- }
- else
- if (strcmp (ap[0], "login") == 0)
- { loginflag = 1;
- }
- else
- if (strcmp (ap[0], "unlogin") == 0)
- { loginflag = 0; }
- else
- if (strcmp (ap[0], "nologin") == 0)
- { loginflag = 0; }
- else
- if (strcmp (ap[0], "chdir") == 0)
- { p = argc < 2 ? home : ap[1];
- if (chdir (p) == -1)
- Msg (errno, "%s", p);
- }
- else
- if (strcmp (ap[0], "mode") == 0)
- { if (argc != 2)
- { Msg (0, "%s: mode: one argument required.", fn); }
- else
- if (!IsNum (ap[1], 7))
- { Msg (0, "%s: mode: octal number expected.", fn); }
- else
- (void) sscanf (ap[1], "%o", &TtyMode);
- }
- else
- if (strcmp (ap[0], "bell") == 0)
- { if (argc != 2)
- { Msg (0, "%s: bell: one argument required.", fn); }
- else
- { if ((BellString = malloc (strlen (ap[1]) + 1)) == 0)
- Msg (0, "Out of memory.");
- istrcpy (BellString, ap[1]);
- }
- }
- else
- if (strcmp (ap[0], "screen") == 0)
- { num = 0;
- if (argc > 1 && IsNum (ap[1], 10))
- { num = atoi (ap[1]);
- if (num < 0 || num > MAXWIN-1)
- Msg (0, "%s: illegal screen number %d.", fn, num);
- --argc; ++ap;
- }
- if (argc < 2)
- { ap[1] = ShellProg; argc = 2; }
- ap[argc] = 0;
- (void) MakeWindow (0, ap[1], ap+1, (char *)0, loginflag, &shape);
- }
- else
- if (strcmp (ap[0], "bind") == 0)
- { p = ap[1];
- if (argc < 2 || *p == '\0')
- Msg (0, "%s: key expected after bind.", fn);
- if (p[1] == '\0')
- { key = *p; }
- else
- if (p[0] == '^' && p[1] != '\0' && p[2] == '\0')
- { c = p[1];
- if (isupper (c))
- p[1] = tolower (c);
- key = Ctrl(c);
- }
- else
- if (IsNum (p, 7))
- { (void) sscanf (p, "%o", &key);
- }
- else
- { Msg (0, "%s: bind: character, ^x, or octal number expected.", fn); }
- ktab[key].lflag = loginflag;
- if (argc < 3)
- { ktab[key].type = 0;
- }
- else
- { for (pp = KeyNames; *pp; ++pp)
- if (strcmp (ap[2], *pp) == 0) break;
- if (*pp)
- { ktab[key].type = pp-KeyNames+1; }
- else
- { ktab[key].type = KEY_CREATE;
- ktab[key].args = SaveArgs (argc-2, ap+2);
- }
- }
- }
- else
- Msg (0, "%s: unknown keyword \"%s\".", fn, ap[0]);
- }
- (void) fclose (f);
-
- } /* ReadRc() */
-
- static
- Parse (fn, buf, args)
- char *fn, *buf, **args;
- {
- register char *p, **ap;
- register delim, argc;
-
- p = buf;
- ap = args;
- argc = 0;
- for (;;)
- { while (*p && (*p == ' ' || *p == '\t'))
- ++p;
- if (*p == '\0' || *p == '#')
- return argc;
- if (argc > MAXARGS-1)
- Msg (0, "%s: too many tokens.", fn);
- delim = 0;
- if (*p == '"' || *p == '\'')
- { delim = *p; *p = '\0'; ++p; }
- ++argc;
- *ap = p; ++ap;
- while (*p && !(delim ? *p == delim : (*p == ' ' || *p == '\t')))
- ++p;
- if (*p == '\0')
- { if (delim)
- Msg (0, "%s: Missing quote.", fn);
- else
- return argc;
- }
- *p++ = '\0';
- }
-
- } /* Parse() */
-
- static char **
- SaveArgs (argc, argv)
- register argc;
- register char **argv;
- {
- register char **ap, **pp;
-
- if ((pp = ap = (char **)malloc ((argc+1) * sizeof (char **))) == 0)
- Msg (0, "Out of memory.");
- while (argc--)
- { if ((*pp = malloc (strlen (*argv)+1)) == 0)
- Msg (0, "Out of memory.");
- strcpy (*pp, *argv);
- ++pp; ++argv;
- }
- *pp = 0;
- return ap;
-
- } /* SaveArgs() */
- #endif
-
- static
- MakeNewEnv ()
- {
- register char **op, **np = NewEnv;
- static char buf[MAXSTR];
-
- if (strlen (SockName) > MAXSTR-5)
- SockName = "?";
- sprintf (buf, "LTY=%s", SockName);
- *np++ = buf;
- *np++ = Term;
- np += 2;
- for (op = environ; *op; ++op)
- { if (np == NewEnv + MAXARGS - 1)
- break;
- if ( !IsSymbol (*op, "TERM")
- && !IsSymbol (*op, "TERMCAP")
- && !IsSymbol (*op, "LTY")
- )
- *np++ = *op;
- }
- *np = 0;
-
- } /* MakeNewEnv() */
-
- static
- IsSymbol (e, s)
- register char *e, *s;
- {
- register char *p;
- register n;
-
- for (p = e; *p && *p != '='; ++p);
- if (*p)
- { *p = '\0';
- n = strcmp (e, s);
- *p = '=';
- return n == 0;
- }
-
- return 0;
-
- } /* IsSymbol() */
-
- /*VARARGS2*/
- Msg (err, fmt, p1, p2, p3, p4, p5, p6)
- char *fmt;
- {
- char buf[1024];
- register char *p = buf;
-
- sprintf (p, fmt, p1, p2, p3, p4, p5, p6);
- if (err)
- { p += strlen (p);
- if (err > 0 && err < sys_nerr)
- sprintf (p, ": %s", sys_errlist[err]);
- else
- sprintf (p, ": Error %d", err);
- }
- if (!Abortonmsg)
- { /* MakeStatus (buf, curr);*/
- printf("%s\r\n", buf);
- }
- else
- { printf ("%s\r\n", buf);
- exit (1);
- }
-
- } /* Msg() */
-
- static char *
- Filename (s)
- char *s;
- {
- register char *p;
-
- p = s + strlen (s) - 1;
- while (p >= s && *p != '/')
- --p;
- return ++p;
-
- } /* Filename() */
-
- static
- IsNum (s, base)
- register char *s;
- register base;
- {
- for (base += '0'; *s; ++s)
- if (*s < '0' || *s > base)
- return 0;
- return 1;
-
- } /* IsNum() */
-
-
- static
- InitUtmp ()
- {
- if ((utmpf = open (UtmpName, O_RDWR)) == -1)
- { if (errno != EACCES)
- Msg (errno, UtmpName);
- return;
- }
- utmp = 1;
-
- } /* InitUtmp() */
-
-
- static int
- FindUtmp(name)
- char *name;
- {
- register char *p;
- register struct ttyent *tp;
- register slot;
-
- DO DEBUG("FindUtmp(%s)\n", name);
- slot = 1;
- if (!utmp)
- return 0;
- if (p = rindex (name, '/'))
- ++p;
- else
- p = name;
- setttyent ();
- while ( (tp = getttyent ()) != NULL
- && strcmp (p, tp->ty_name) != 0
- )
- ++slot;
- if (tp == NULL)
- return 0;
-
- DO DEBUG(" slot %d\n", slot);
- return slot;
-
- } /* FindUtmp() */
-
-
- static int
- SetUtmp (name, mainlogin)
- char *name; /* tty name */
- int mainlogin; /* this is primary login */
- {
- register char *p;
- register slot;
- struct utmp u;
-
- if ((slot=FindUtmp(name)) == 0)
- return ( 0 );
-
- if (p = rindex (name, '/'))
- ++p;
- else
- p = name;
-
- strncpy (u.ut_line, p, 8);
- strncpy (u.ut_name, LoginName, 8);
- #if 1
- strncpy(u.ut_host, Filename (RealTtyName), 16); /* host is real tty */
- #else
- u.ut_host[0] = '\0';
- #endif
- if (RealSlot && mainlogin)
- u.ut_time = RealUtmp.ut_time; /* use original login time */
- else
- time (&u.ut_time);
- (void) lseek (utmpf, (long)(slot * sizeof (u)), 0);
- (void) write (utmpf, (char *)&u, sizeof (u));
-
- return ( slot );
-
- } /* SetUtmp() */
-
- static int
- ReadUtmp(slot, entry)
- int slot; /* slot to read */
- struct utmp *entry; /* entry to read into */
- {
- int cnt; /* return count */
-
- if (!utmp)
- return; /* no utmp access */
-
- (void) lseek(utmpf, (long)(slot * sizeof(struct utmp)), 0);
- cnt = read(utmpf, (char *)entry, sizeof(struct utmp));
- DO DEBUG("ReadUtmp cnt %d, errno %d, line %.8s, name %.8s, host %.16s\n",
- cnt, errno, entry->ut_line, entry->ut_name, entry->ut_host);
-
- return ( cnt );
-
- } /* ReadUtmp() */
-
- static void
- WriteUtmp(slot, entry)
- int slot; /* slot to write */
- struct utmp *entry; /* entry to write from */
- {
- int cnt; /* write return code */
-
- if (!utmp)
- return; /* no utmp access */
-
- (void) lseek(utmpf, (long)(slot * sizeof(struct utmp)), 0);
- cnt = write(utmpf, (char *)entry, sizeof(struct utmp));
- DO DEBUG("WriteUtmp() slot %d cnt %d line %.8s name %.8s host %.16s\n",
- slot, cnt, entry->ut_line, entry->ut_name, entry->ut_host);
-
- } /* WriteUtmp() */
-
- static
- RemoveUtmp (slot)
- {
- struct utmp u;
-
- if (slot)
- { bzero ((char *)&u, sizeof (u));
- (void) lseek (utmpf, (long)(slot * sizeof (u)), 0);
- (void) write (utmpf, (char *)&u, sizeof (u));
- }
-
- } /* RemoveUtmp() */
-
- #ifndef GETTTYENT
-
- static
- setttyent ()
- {
- struct stat s;
- register f;
- register char *p, *ep;
-
- if (ttnext)
- { ttnext = tt;
- return;
- }
- if ((f = open (ttys, O_RDONLY)) == -1 || fstat (f, &s) == -1)
- Msg (errno, ttys);
- if ((tt = malloc (s.st_size + 1)) == 0)
- Msg (0, "Out of memory.");
- if (read (f, tt, s.st_size) != s.st_size)
- Msg (errno, ttys);
- close (f);
- for (p = tt, ep = p + s.st_size; p < ep; ++p)
- if (*p == '\n')
- *p = '\0';
- *p = '\0';
- ttnext = tt;
-
- } /* setttyent() */
-
- static struct ttyent *
- getttyent ()
- {
- static struct ttyent t;
-
- if (*ttnext == '\0')
- return NULL;
- t.ty_name = ttnext + 2;
- ttnext += strlen (ttnext) + 1;
- return &t;
-
- } /* getttyend() */
-
- #endif
-
-
-
- /* FinitTerm() - reset vt100 terminal */
- static void
- FinitTerm ()
- {
- /* print out termcap 'is' string to reset terminal */
- #if 0
- /* This string sets scroll region 1-24 and puts cursor at bottom line */
- printf("\033[1;24r\033[24;1H");
- #endif
- fflush(stdout);
- }
-
- static void
- AddCap (s)
- char *s;
- {
- register n;
-
- if (tcLineLen + (n = strlen (s)) > 55)
- { strcat (Termcap, "\\\n\t:");
- tcLineLen = 0;
- }
- strcat (Termcap, s);
- tcLineLen += n;
- }
-
- static char *
- MakeTermcap(lines, chars)
- int lines; /* default window lines */
- int chars; /* default window chars */
- {
- char buf[1024];
- register char **pp, *p;
-
- strcpy(Termcap, TermcapConst1); /* start TERMCAP build */
- strcat(Termcap, UserTerm); /* fill in User's terminal type */
- strcat(Termcap, TermcapConst3); /* finish our own definition */
-
- if (lines <= 0 || lines > 200)
- lines = rows; /* force default if none or invalid */
- if (chars <= 0 || chars > 300)
- chars = cols; /* force default if none or invalid */
-
- sprintf(buf, "li#%d:co#%d:", lines, chars);
- AddCap(buf);
-
- return ( Termcap );
-
- } /* MakeTermcap() */
-
-
- /* DEBUG() - dump output routine */
-
- void
- DEBUG(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
- char *format;
- int arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8;
- {
- fprintf(stderr, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
- }
-