jmb@patton.sgi.com (Jim Barton) (08/04/89)
"screen" for the IRIS 4D series, Part 3/3 #--------------------------------CUT HERE------------------------------------- #! /bin/sh # # This is a shell archive. Save this into a file, edit it # and delete all lines above this comment. Then give this # file to sh by executing the command "sh file". The files # will be extracted into the current directory owned by # you with default permissions. # # The files contained herein are: # # -r--r--r-- 1 jmb sys 43860 Aug 3 11:24 screen.c # -r--r--r-- 1 jmb sys 2247 Aug 3 11:24 screen.h # -r--r--r-- 1 jmb sys 633 Aug 3 11:24 screen.tic # echo 'x - screen.c' if test -f screen.c; then echo 'shar: not overwriting screen.c'; else sed 's/^X//' << '________This_Is_The_END________' > screen.c X/* Copyright (c) 1987,1988 Oliver Laumann, Technical University of Berlin. X * Not derived from licensed software. X * X * Permission is granted to freely use, copy, modify, and redistribute X * this software, provided that no attempt is made to gain profit from it, X * the author is not construed to be liable for any results of using the X * software, alterations are clearly marked as such, and this notice is X * not modified. X */ X Xstatic char ScreenVersion[] = "screen 2.0a 19-Oct-88 SGI 4D Series"; X X#include <sys/types.h> X#include <sys/time.h> X#include <sys/file.h> X#include <sys/wait.h> X#include <sys/socket.h> X# ifndef sgi X#include <sys/un.h> X# endif X#include <sys/stat.h> X#include <sys/dir.h> X#ifdef SUNLOADAV X#ifndef sgi X#include <sys/param.h> X#endif X#endif X#ifdef sgi X#include <sys/sysmacros.h> X#include <sys/utsname.h> Xstatic char is3_3 = 0; X#define setpgrp BSDsetpgrp X#define getpgrp BSDgetpgrp X#endif X X#include <stdio.h> X#ifndef SYSV X#include <sgtty.h> X#endif X#include <signal.h> X#include <errno.h> X#include <ctype.h> X#include <utmp.h> X#include <pwd.h> X#include <nlist.h> X#include <fcntl.h> X#ifdef SYSV X# include <termio.h> X# include <string.h> X#endif X X#include "screen.h" X X#ifndef SYSV X#ifdef GETTTYENT X# include <ttyent.h> X#else X static struct ttyent { X char *ty_name; X } *getttyent(); X static char *tt, *ttnext; X static char ttys[] = "/etc/ttys"; X#endif X#endif X X#define MAXWIN 10 X#define MSGWAIT 5 X X#define Ctrl(c) ((c)&037) X Xextern char *blank, Term[], **environ; Xextern rows, cols; Xextern ISO2022; Xextern status; Xextern time_t TimeDisplayed; Xextern char AnsiVersion[]; Xextern short ospeed; Xextern flowctl; Xextern errno; Xextern sys_nerr; Xextern char *sys_errlist[]; Xextern char *index(), *rindex(), *malloc(), *getenv(), *MakeTermcap(); Xextern char *getlogin(), *ttyname(); Xstatic AttacherFinit(), Finit(), SigHup(), SigChld(); Xstatic char *MakeBellMsg(), *Filename(), **SaveArgs(), *GetTtyName(); X Xstatic char PtyName[32], TtyName[32]; Xstatic char *ShellProg; Xstatic char *ShellArgs[2]; Xstatic char inbuf[IOSIZE]; Xstatic inlen; Xstatic ESCseen; Xstatic GotSignal; Xstatic char DefaultShell[] = "/bin/sh"; Xstatic char DefaultPath[] = ":/usr/ucb:/bin:/usr/bin"; Xstatic char PtyProto[] = "/dev/ptyXY"; Xstatic char TtyProto[] = "/dev/ttyXY"; Xstatic int TtyMode = 0622; Xstatic char SockPath[512]; Xstatic char SockDir[] = ".screen"; Xstatic char *SockNamePtr, *SockName; Xstatic ServerSocket; Xstatic char *NewEnv[MAXARGS]; Xstatic char Esc = Ctrl('a'); Xstatic char MetaEsc = 'a'; Xstatic char *home; Xstatic HasWindow; Xstatic utmp, utmpf; Xstatic char UtmpName[] = "/etc/utmp"; Xstatic char *LoginName; Xstatic char *BellString = "Bell in window %"; Xstatic mflag, nflag, fflag, rflag; Xstatic char HostName[MAXSTR]; Xstatic Detached; Xstatic AttacherPid; /* Non-Zero in child if we have an attacher */ Xstatic DevTty; X#ifdef SYSV Xstatic char proexec = 0; Xstatic char chanopen = 0; X#endif X#ifdef LOADAV X static char KmemName[] = "/dev/kmem"; X#ifdef sequent X static char UnixName[] = "/dynix"; X#else X#ifdef sgi X static char UnixName[] = "/unix"; X#else X static char UnixName[] = "/vmunix"; X#endif X#endif X#ifdef alliant X static char AvenrunSym[] = "_Loadavg"; X#else X#ifdef sgi X static char AvenrunSym[] = "avenrun"; X#else X static char AvenrunSym[] = "_avenrun"; X#endif X#endif X static struct nlist nl[2]; X static avenrun, kmemf; X#ifdef SUNLOADAV X long loadav[3]; X#else X#ifdef alliant X long loadav[4]; X#else X double loadav[3]; X#endif X#endif X X#ifdef sgi X#ifndef FSCALE X#define FSCALE 1000 X#endif X#endif X X#endif X Xstruct mode { X#ifdef SYSV X struct termio m_tty; X int m_oldpgrp; X#else X struct sgttyb m_ttyb; X struct tchars m_tchars; X struct ltchars m_ltchars; X int m_ldisc; X int m_lmode; X#endif X} OldMode, NewMode; X Xstatic struct win *curr, *other; Xstatic CurrNum, OtherNum; Xstatic struct win *wtab[MAXWIN]; X X#define KEY_IGNORE 0 X#define KEY_HARDCOPY 1 X#define KEY_SUSPEND 2 X#define KEY_SHELL 3 X#define KEY_NEXT 4 X#define KEY_PREV 5 X#define KEY_KILL 6 X#define KEY_REDISPLAY 7 X#define KEY_WINDOWS 8 X#define KEY_VERSION 9 X#define KEY_OTHER 10 X#define KEY_0 11 X#define KEY_1 12 X#define KEY_2 13 X#define KEY_3 14 X#define KEY_4 15 X#define KEY_5 16 X#define KEY_6 17 X#define KEY_7 18 X#define KEY_8 19 X#define KEY_9 20 X#define KEY_XON 21 X#define KEY_XOFF 22 X#define KEY_INFO 23 X#define KEY_TERMCAP 24 X#define KEY_QUIT 25 X#define KEY_DETACH 26 X#define KEY_CREATE 27 X Xstruct key { X int type; X char **args; X} ktab[256]; X Xchar *KeyNames[] = { X "hardcopy", "suspend", "shell", "next", "prev", "kill", "redisplay", X "windows", "version", "other", "select0", "select1", "select2", "select3", X "select4", "select5", "select6", "select7", "select8", "select9", X "xon", "xoff", "info", "termcap", "quit", "detach", X 0 X}; X Xmain (ac, av) char **av; { X register n, len; X register struct win **pp, *p; X char *ap; X int s, r, w, x = 0; X int aflag = 0; X struct timeval tv; X time_t now; X char buf[IOSIZE], *myname = (ac == 0) ? "screen" : av[0]; X char rc[256]; X struct stat st; X X while (ac > 0) { X ap = *++av; X if (--ac > 0 && *ap == '-') { X switch (ap[1]) { X case 'c': /* Compatibility with older versions. */ X break; X case 'a': X aflag = 1; X break; X case 'm': X mflag = 1; X break; X case 'n': X nflag = 1; X break; X case 'f': X fflag = 1; X break; X case 'r': X rflag = 1; X if (ap[2]) { X SockName = ap+2; X if (ac != 1) goto help; X } else if (--ac == 1) { X SockName = *++av; X } else if (ac != 0) goto help; X break; X case 'e': X if (ap[2]) { X ap += 2; X } else { X if (--ac == 0) goto help; X ap = *++av; X } X if (strlen (ap) != 2) X Msg (0, "Two characters are required with -e option."); X Esc = ap[0]; X MetaEsc = ap[1]; X break; X default: X help: X Msg (0, "Use: %s [-a] [-f] [-n] [-e xy] [cmd args]\n\ X or: %s -r [host.tty.pid]", myname, myname); X } X } else break; X } X if (nflag && fflag) X Msg (0, "-f and -n are conflicting options."); X if ((ShellProg = getenv ("SHELL")) == 0) X ShellProg = DefaultShell; X#ifdef SYSV X#define MINUSMAX 32 X if (ac == 0) { X char shbuf[MINUSMAX]; X char *s; X X if ((s = strrchr(ShellProg, '/')) == NULL) s = ShellProg; else s++; X strcpy(shbuf, "-"); X if (strlen(s) + 2 > MINUSMAX) X Msg(0, "Path to shell in SHELL variable is too long."); X strcat(shbuf, s); X ShellArgs[0] = shbuf; X ac = 1; X av = ShellArgs; X proexec = 1; X } X#else X ShellArgs[0] = ShellProg; X if (ac == 0) { X ac = 1; X av = ShellArgs; X } X#endif X if ((home = getenv ("HOME")) == 0) X Msg (0, "$HOME is undefined."); X#ifdef sgi X { X struct utsname ubuf; X X /* X * Releases eariler than 3.3 don't handle X * SIGCONT properly, so disable the facility. X */ X uname(&ubuf); X if (strncmp(ubuf.release, "4D1-", 4) == 0) { X if (ubuf.release[4] >= '3' && X ubuf.release[6] >= '3') X is3_3 = 1; X } X } X#endif X sprintf (SockPath, "%s/%s", home, SockDir); X if (stat (SockPath, &st) == -1) { X if (errno == ENOENT) { X if (mkdir (SockPath, 0700) == -1) X Msg (errno, "Cannot make directory %s", SockPath); X (void) chown (SockPath, getuid (), getgid ()); X } else Msg (errno, "Cannot get status of %s", SockPath); X } else { X if ((st.st_mode & S_IFMT) != S_IFDIR) X Msg (0, "%s is not a directory.", SockPath); X if ((st.st_mode & 0777) != 0700) X Msg (0, "Directory %s must have mode 700.", SockPath); X if (st.st_uid != getuid ()) X Msg (0, "You are not the owner of %s.", SockPath); X } X (void) gethostname (HostName, MAXSTR); X HostName[MAXSTR-1] = '\0'; X if (ap = index (HostName, '.')) X *ap = '\0'; X strcat (SockPath, "/"); X SockNamePtr = SockPath + strlen (SockPath); X if ((DevTty = open ("/dev/tty", O_RDWR|O_NDELAY)) == -1) X Msg (errno, "/dev/tty"); X if (rflag) { X Attach (MSG_ATTACH); X Attacher (); X /*NOTREACHED*/ X } X if (GetSockName ()) { X s = MakeClientSocket (1); X SendCreateMsg (s, ac, av, aflag); X close (s); X exit (0); X } X switch (fork ()) { X case -1: X Msg (errno, "fork"); X /*NOTREACHED*/ X case 0: X break; X default: X Attacher (); X /*NOTREACHED*/ X } X AttacherPid = getppid (); X ServerSocket = s = MakeServerSocket (); X InitTerm (); X if (fflag) X flowctl = 1; X else if (nflag) X flowctl = 0; X MakeNewEnv (); X GetTTY (0, &OldMode); X#ifdef SYSV X ospeed = (short)(OldMode.m_tty.c_cflag & CBAUD); X#else X ospeed = (short)OldMode.m_ttyb.sg_ospeed; X#endif X InitUtmp (); X#ifdef LOADAV X InitKmem (); X#endif X signal (SIGHUP, SigHup); X signal (SIGINT, Finit); X signal (SIGQUIT, Finit); X signal (SIGTERM, Finit); X signal (SIGTTIN, SIG_IGN); X signal (SIGTTOU, SIG_IGN); X InitKeytab (); X sprintf (rc, "%.*s/.screenrc", 245, home); X ReadRc (rc); X#ifdef SYSV X if ((n = MakeWindow ((proexec ? ShellProg : *av), X av, aflag, 0, (char *)0)) == -1) { X#else X if ((n = MakeWindow (ShellProg, av, aflag, 0, (char *)0)) == -1) { X#endif X SetTTY (0, &OldMode); X FinitTerm (); X Kill (AttacherPid, SIGHUP); X#ifdef SYSV X if (chanopen) X unlink(SockPath); X#endif X exit (1); X } X SetCurrWindow (n); X HasWindow = 1; X SetMode (&OldMode, &NewMode); X SetTTY (0, &NewMode); X signal (SIGCHLD, SigChld); X tv.tv_usec = 0; X while (1) { X if (status) { X time (&now); X if (now - TimeDisplayed < MSGWAIT) { X tv.tv_sec = MSGWAIT - (now - TimeDisplayed); X } else RemoveStatus (curr); X } X r = 0; X w = 0; X if (inlen) X w |= 1 << curr->ptyfd; X else X r |= 1 << 0; X for (pp = wtab; pp < wtab+MAXWIN; ++pp) { X if (!(p = *pp)) X continue; X if ((*pp)->active && status) X continue; X if ((*pp)->outlen > 0) X continue; X r |= 1 << (*pp)->ptyfd; X } X r |= 1 << s; X (void) fflush (stdout); X if (GotSignal && !status) { X SigHandler (); X continue; X } X if (select (32, &r, &w, &x, status ? &tv : (struct timeval *)0) == -1) { X if (errno == EINTR) X continue; X HasWindow = 0; X Msg (errno, "select"); X /*NOTREACHED*/ X } X if (GotSignal && !status) { X SigHandler (); X continue; X } X if (r & (1 << s)) { X RemoveStatus (curr); X ReceiveMsg (s); X } X if (r & (1 << 0)) { X RemoveStatus (curr); X if (ESCseen) { X inbuf[0] = Esc; X inlen = read (0, inbuf+1, IOSIZE-1) + 1; X ESCseen = 0; X } else { X inlen = read (0, inbuf, IOSIZE); X } X if (inlen > 0) X inlen = ProcessInput (inbuf, inlen); X if (inlen > 0) X continue; X } X if (GotSignal && !status) { X SigHandler (); X continue; X } X if (w & (1 << curr->ptyfd) && inlen > 0) { X if ((len = write (curr->ptyfd, inbuf, inlen)) > 0) { X inlen -= len; X bcopy (inbuf+len, inbuf, inlen); X } X } X if (GotSignal && !status) { X SigHandler (); X continue; X } X for (pp = wtab; pp < wtab+MAXWIN; ++pp) { X if (!(p = *pp)) X continue; X if (p->outlen) { X WriteString (p, p->outbuf, p->outlen); X } else if (r & 1 << p->ptyfd) { X if ((len = read (p->ptyfd, buf, IOSIZE)) == -1) { X if (errno == EWOULDBLOCK) X len = 0; X } X if (len > 0) X WriteString (p, buf, len); X } X if (p->bell) { X p->bell = 0; X Msg (0, MakeBellMsg (pp-wtab)); X } X } X if (GotSignal && !status) X SigHandler (); X } X /*NOTREACHED*/ X} X Xstatic SigHandler () { X while (GotSignal) { X GotSignal = 0; X DoWait (); X } X} X Xstatic SigChld () { X GotSignal = 1; X} X Xstatic SigHup () { X Detach (0); X} X Xstatic DoWait () { X register pid; X register struct win **pp; X union wait wstat; X X while ((pid = wait3 (&wstat, WNOHANG|WUNTRACED, NULL)) > 0) { X for (pp = wtab; pp < wtab+MAXWIN; ++pp) { X if (*pp && pid == (*pp)->wpid) { X if (WIFSTOPPED (wstat)) { X (void) killpg (getpgrp ((*pp)->wpid), SIGCONT); X } else { X KillWindow (pp); X } X } X } X } X#ifdef SYSV X signal(SIGCHLD, SigChld); X#endif X CheckWindows (); X} X Xstatic KillWindow (pp) struct win **pp; { X if (*pp == curr) X curr = 0; X if (*pp == other) X other = 0; X FreeWindow (*pp); X *pp = 0; X} X Xstatic CheckWindows () { X register struct win **pp; X X /* If the current window disappeared and the "other" window is still X * there, switch to the "other" window, else switch to the window X * with the lowest index. X * If there current window is still there, but the "other" window X * vanished, "SetCurrWindow" is called in order to assign a new value X * to "other". X * If no window is alive at all, exit. X */ X if (!curr && other) { X SwitchWindow (OtherNum); X return; X } X if (curr && !other) { X SetCurrWindow (CurrNum); X return; X } X for (pp = wtab; pp < wtab+MAXWIN; ++pp) { X if (*pp) { X if (!curr) X SwitchWindow (pp-wtab); X return; X } X } X Finit (); X} X Xstatic Finit () { X register struct win *p, **pp; X X for (pp = wtab; pp < wtab+MAXWIN; ++pp) { X if (p = *pp) X FreeWindow (p); X } X SetTTY (0, &OldMode); X FinitTerm (); X printf ("[screen is terminating]\n"); X Kill (AttacherPid, SIGHUP); X#ifdef SYSV X if (chanopen) X unlink(SockPath); X#endif X exit (0); X} X Xstatic InitKeytab () { X register i; X X ktab['h'].type = ktab[Ctrl('h')].type = KEY_HARDCOPY; X ktab['z'].type = ktab[Ctrl('z')].type = KEY_SUSPEND; X ktab['c'].type = ktab[Ctrl('c')].type = KEY_SHELL; X ktab[' '].type = ktab[Ctrl(' ')].type = X ktab['n'].type = ktab[Ctrl('n')].type = KEY_NEXT; X ktab['-'].type = ktab['p'].type = ktab[Ctrl('p')].type = KEY_PREV; X ktab['k'].type = ktab[Ctrl('k')].type = KEY_KILL; X ktab['l'].type = ktab[Ctrl('l')].type = KEY_REDISPLAY; X ktab['w'].type = ktab[Ctrl('w')].type = KEY_WINDOWS; X ktab['v'].type = ktab[Ctrl('v')].type = KEY_VERSION; X ktab['q'].type = ktab[Ctrl('q')].type = KEY_XON; X ktab['s'].type = ktab[Ctrl('s')].type = KEY_XOFF; X ktab['t'].type = ktab[Ctrl('t')].type = KEY_INFO; X ktab['.'].type = KEY_TERMCAP; X ktab[Ctrl('\\')].type = KEY_QUIT; X ktab['d'].type = ktab[Ctrl('d')].type = KEY_DETACH; X ktab[Esc].type = KEY_OTHER; X for (i = 0; i <= 9; i++) X ktab[i+'0'].type = KEY_0+i; X} X Xstatic ProcessInput (buf, len) char *buf; { X register n, k; X register char *s, *p; X register struct win **pp; X X for (s = p = buf; len > 0; len--, s++) { X if (*s == Esc) { X if (len > 1) { X len--; s++; X k = ktab[*s].type; X if (*s == MetaEsc) { X *p++ = Esc; X } else if (k >= KEY_0 && k <= KEY_9) { X p = buf; X SwitchWindow (k - KEY_0); X } else switch (ktab[*s].type) { X case KEY_TERMCAP: X p = buf; X WriteFile (0); X break; X case KEY_HARDCOPY: X p = buf; X WriteFile (1); X break; X case KEY_SUSPEND: X#ifdef sgi X if (!is3_3) { X Msg(0,"Suspend not supported on this release"); X break; X } X#endif X p = buf; X Detach (1); X break; X case KEY_SHELL: X p = buf; X if ((n = MakeWindow (ShellProg, ShellArgs, X 0, 0, (char *)0)) != -1) X SwitchWindow (n); X break; X case KEY_NEXT: X p = buf; X if (MoreWindows ()) X SwitchWindow (NextWindow ()); X break; X case KEY_PREV: X p = buf; X if (MoreWindows ()) X SwitchWindow (PreviousWindow ()); X break; X case KEY_KILL: X p = buf; X FreeWindow (wtab[CurrNum]); X if (other == curr) X other = 0; X curr = wtab[CurrNum] = 0; X CheckWindows (); X break; X case KEY_QUIT: X for (pp = wtab; pp < wtab+MAXWIN; ++pp) X if (*pp) FreeWindow (*pp); X Finit (); X /*NOTREACHED*/ X case KEY_DETACH: X p = buf; X Detach (0); X break; X case KEY_REDISPLAY: X p = buf; X Activate (wtab[CurrNum]); X break; X case KEY_WINDOWS: X p = buf; X ShowWindows (); X break; X case KEY_VERSION: X p = buf; X Msg (0, "%s %s", ScreenVersion, AnsiVersion); X break; X case KEY_INFO: X p = buf; X ShowInfo (); X break; X case KEY_OTHER: X p = buf; X if (MoreWindows ()) X SwitchWindow (OtherNum); X break; X case KEY_XON: X *p++ = Ctrl('q'); X break; X case KEY_XOFF: X *p++ = Ctrl('s'); X break; X case KEY_CREATE: X p = buf; X if ((n = MakeWindow (ktab[*s].args[0], ktab[*s].args, X 0, 0, (char *)0)) != -1) X SwitchWindow (n); X break; X } X } else ESCseen = 1; X } else *p++ = *s; X } X return p - buf; X} X Xstatic SwitchWindow (n) { X if (!wtab[n]) X return; X SetCurrWindow (n); X Activate (wtab[n]); X} X Xstatic SetCurrWindow (n) { X /* X * If we come from another window, this window becomes the X * "other" window: X */ X if (curr) { X curr->active = 0; X other = curr; X OtherNum = CurrNum; X } X CurrNum = n; X curr = wtab[n]; X curr->active = 1; X /* X * If the "other" window is currently undefined (at program start X * or because it has died), or if the "other" window is equal to the X * one just selected, we try to find a new one: X */ X if (other == 0 || other == curr) { X OtherNum = NextWindow (); X other = wtab[OtherNum]; X } X} X Xstatic NextWindow () { X register struct win **pp; X X for (pp = wtab+CurrNum+1; pp != wtab+CurrNum; ++pp) { X if (pp == wtab+MAXWIN) X pp = wtab; X if (*pp) X break; X } X return pp-wtab; X} X Xstatic PreviousWindow () { X register struct win **pp; X X for (pp = wtab+CurrNum-1; pp != wtab+CurrNum; --pp) { X if (pp < wtab) X pp = wtab+MAXWIN-1; X if (*pp) X break; X } X return pp-wtab; X} X Xstatic MoreWindows () { X register struct win **pp; X register n; X X for (n = 0, pp = wtab; pp < wtab+MAXWIN; ++pp) X if (*pp) ++n; X if (n <= 1) X Msg (0, "No other window."); X return n > 1; X} X Xstatic FreeWindow (wp) struct win *wp; { X register i; X X RemoveUtmp (wp->slot); X (void) chmod (wp->tty, 0666); X (void) chown (wp->tty, 0, 0); X close (wp->ptyfd); X for (i = 0; i < rows; ++i) { X free (wp->image[i]); X free (wp->attr[i]); X free (wp->font[i]); X } X free (wp->image); X free (wp->attr); X free (wp->font); X free (wp); X} X Xstatic MakeWindow (prog, args, aflag, StartAt, dir) X char *prog, **args, *dir; { X register struct win **pp, *p; X register char **cp; X register n, f; X int tf; X int mypid; X char ebuf[10]; X X pp = wtab+StartAt; X do { X if (*pp == 0) X break; X if (++pp == wtab+MAXWIN) X pp = wtab; X } while (pp != wtab+StartAt); X if (*pp) { X Msg (0, "No more windows."); X return -1; X } X n = pp - wtab; X if ((f = OpenPTY ()) == -1) { X Msg (0, "No more PTYs."); X return -1; X } X (void) fcntl (f, F_SETFL, FNDELAY); X if ((p = *pp = (struct win *)malloc (sizeof (struct win))) == 0) { Xnomem: X Msg (0, "Out of memory."); X return -1; X } X if ((p->image = (char **)malloc (rows * sizeof (char *))) == 0) X goto nomem; X for (cp = p->image; cp < p->image+rows; ++cp) { X if ((*cp = malloc (cols)) == 0) X goto nomem; X bclear (*cp, cols); X } X if ((p->attr = (char **)malloc (rows * sizeof (char *))) == 0) X goto nomem; X for (cp = p->attr; cp < p->attr+rows; ++cp) { X if ((*cp = malloc (cols)) == 0) X goto nomem; X bzero (*cp, cols); X } X if ((p->font = (char **)malloc (rows * sizeof (char *))) == 0) X goto nomem; X for (cp = p->font; cp < p->font+rows; ++cp) { X if ((*cp = malloc (cols)) == 0) X goto nomem; X bzero (*cp, cols); X } X if ((p->tabs = malloc (cols+1)) == 0) /* +1 because 0 <= x <= cols */ X goto nomem; X ResetScreen (p); X p->aflag = aflag; X p->active = 0; X p->bell = 0; X p->outlen = 0; X p->ptyfd = f; X strncpy (p->cmd, Filename (args[0]), MAXSTR-1); X p->cmd[MAXSTR-1] = '\0'; X strncpy (p->tty, TtyName, MAXSTR-1); X (void) chown (TtyName, getuid (), getgid ()); X (void) chmod (TtyName, TtyMode); X p->slot = SetUtmp (TtyName); X switch (p->wpid = fork ()) { X case -1: X Msg (errno, "fork"); X free ((char *)p); X return -1; X case 0: X signal (SIGHUP, SIG_DFL); X signal (SIGINT, SIG_DFL); X signal (SIGQUIT, SIG_DFL); X signal (SIGTERM, SIG_DFL); X signal (SIGTTIN, SIG_DFL); X signal (SIGTTOU, SIG_DFL); X setuid (getuid ()); X setgid (getgid ()); X if (dir && chdir (dir) == -1) { X SendErrorMsg ("Cannot chdir to %s: %s", dir, sys_errlist[errno]); X exit (1); X } X mypid = getpid (); X ioctl (DevTty, TIOCNOTTY, (char *)0); X if ((tf = open (TtyName, O_RDWR)) == -1) { X SendErrorMsg ("Cannot open %s: %s", TtyName, sys_errlist[errno]); X exit (1); X } X (void) dup2 (tf, 0); X (void) dup2 (tf, 1); X (void) dup2 (tf, 2); X for (f = getdtablesize () - 1; f > 2; f--) X close (f); X ioctl (0, TIOCSPGRP, &mypid); X (void) setpgrp (0, mypid); X SetTTY (0, &OldMode); X NewEnv[2] = MakeTermcap (aflag); X sprintf (ebuf, "WINDOW=%d", n); X NewEnv[3] = ebuf; X execvpe (prog, args, NewEnv); X SendErrorMsg ("Cannot exec %s: %s", prog, sys_errlist[errno]); X exit (1); X } X return n; X} X Xstatic execvpe (prog, args, env) char *prog, **args, **env; { X register char *path, *p; X char buf[1024]; X char *shargs[MAXARGS+1]; X register i, eaccess = 0; X X if (prog[0] == '/') X path = ""; X else if ((path = getenv ("PATH")) == 0) X path = DefaultPath; X do { X p = buf; X while (*path && *path != ':') X *p++ = *path++; X if (p > buf) X *p++ = '/'; X strcpy (p, prog); X if (*path) X ++path; X execve (buf, args, env); X switch (errno) { X case ENOEXEC: X shargs[0] = DefaultShell; X shargs[1] = buf; X for (i = 1; shargs[i+1] = args[i]; ++i) X ; X execve (DefaultShell, shargs, env); X return; X case EACCES: X eaccess = 1; X break; X case ENOMEM: case E2BIG: case ETXTBSY: X return; X } X } while (*path); X if (eaccess) X errno = EACCES; X} X Xstatic WriteFile (dump) { /* dump==0: create .termcap, dump==1: hardcopy */ X register i, j, k; X register char *p; X register FILE *f; X char fn[1024]; X int pid, s; X X if (dump) X sprintf (fn, "hardcopy.%d", CurrNum); X else X sprintf (fn, "%s/%s/.termcap", home, SockDir); X switch (pid = fork ()) { X case -1: X Msg (errno, "fork"); X return; X case 0: X setuid (getuid ()); X setgid (getgid ()); X if ((f = fopen (fn, "w")) == NULL) X exit (1); X if (dump) { X for (i = 0; i < rows; ++i) { X p = curr->image[i]; X for (k = cols-1; k >= 0 && p[k] == ' '; --k) ; X for (j = 0; j <= k; ++j) X putc (p[j], f); X putc ('\n', f); X } X } else { X if (p = index (MakeTermcap (curr->aflag), '=')) { X fputs (++p, f); X putc ('\n', f); X } X } X (void) fclose (f); X exit (0); X default: X while ((i = wait (&s)) != pid) X if (i == -1) return; X if ((s >> 8) & 0377) X Msg (0, "Cannot open \"%s\".", fn); X else X Msg (0, "%s written to \"%s\".", dump ? "Screen image" : X "Termcap entry", fn); X } X} X Xstatic ShowWindows () { X char buf[1024]; X register char *s; X register struct win **pp, *p; X X for (s = buf, pp = wtab; pp < wtab+MAXWIN; ++pp) { X if ((p = *pp) == 0) X continue; X if (s - buf + 5 + strlen (p->cmd) > cols-1) X break; X if (s > buf) { X *s++ = ' '; *s++ = ' '; X } X *s++ = pp - wtab + '0'; X if (p == curr) X *s++ = '*'; X else if (p == other) X *s++ = '-'; X *s++ = ' '; X strcpy (s, p->cmd); X s += strlen (s); X } X Msg (0, buf); X} X Xstatic ShowInfo () { X char buf[1024], *p; X register struct win *wp = curr; X register i; X struct tm *tp; X time_t now; X X time (&now); X tp = localtime (&now); X sprintf (buf, "%2d:%02.2d:%02.2d %s", tp->tm_hour, tp->tm_min, tp->tm_sec, X HostName); X#ifdef LOADAV X if (avenrun && GetAvenrun ()) { X p = buf + strlen (buf); X#ifdef SUNLOADAV X sprintf (p, " %2.2f %2.2f %2.2f", (double)loadav[0]/FSCALE, X (double)loadav[1]/FSCALE, (double)loadav[2]/FSCALE); X#else X#ifdef alliant X sprintf (p, " %2.2f %2.2f %2.2f %2.2f", (double)loadav[0]/100, X (double)loadav[1]/100, (double)loadav[2]/100, X (double)loadav[3]/100); X#else X sprintf (p, " %2.2f %2.2f %2.2f", loadav[0], loadav[1], loadav[2]); X#endif X#endif X } X#endif X p = buf + strlen (buf); X sprintf (p, " (%d,%d) %cflow %cins %corg %cwrap %cpad", wp->y, wp->x, X flowctl ? '+' : '-', X wp->insert ? '+' : '-', wp->origin ? '+' : '-', X wp->wrap ? '+' : '-', wp->keypad ? '+' : '-'); X if (ISO2022) { X p = buf + strlen (buf); X sprintf (p, " G%1d [", wp->LocalCharset); X for (i = 0; i < 4; i++) X p[i+5] = wp->charsets[i] ? wp->charsets[i] : 'B'; X p[9] = ']'; X p[10] = '\0'; X } X Msg (0, buf); X} X X#ifdef sgi Xstatic int XOpenPTY() X{ X int fd; X int pnum; X struct stat sb; X X fd = open("/dev/ptc", O_RDWR|O_NDELAY); X if (fd >= 0) { X if (fstat(fd, &sb) < 0) { X close(fd); X return -1; X } X pnum = minor(sb.st_rdev); X sprintf(TtyName, "/dev/ttyq%d", pnum); X } X return fd; X} X#else Xstatic OpenPTY () { X register char *p, *l, *d; X register i, f, tf; X X strcpy (PtyName, PtyProto); X strcpy (TtyName, TtyProto); X for (p = PtyName, i = 0; *p != 'X'; ++p, ++i) ; X for (l = "qpr"; *p = *l; ++l) { X for (d = "0123456789abcdef"; p[1] = *d; ++d) { X if ((f = open (PtyName, O_RDWR)) != -1) { X TtyName[i] = p[0]; X TtyName[i+1] = p[1]; X if ((tf = open (TtyName, O_RDWR)) != -1) { X close (tf); X return f; X } X close (f); X } X } X } X return -1; X} X#endif X Xstatic SetTTY (fd, mp) struct mode *mp; { X#ifdef SYSV X ioctl (fd, TCSETA, &mp->m_tty); X#else X ioctl (fd, TIOCSETP, &mp->m_ttyb); X ioctl (fd, TIOCSETC, &mp->m_tchars); X ioctl (fd, TIOCSLTC, &mp->m_ltchars); X ioctl (fd, TIOCLSET, &mp->m_lmode); X ioctl (fd, TIOCSETD, &mp->m_ldisc); X#endif X} X Xstatic GetTTY (fd, mp) struct mode *mp; { X#ifdef SYSV X ioctl (fd, TCGETA, &mp->m_tty); X#else X ioctl (fd, TIOCGETP, &mp->m_ttyb); X ioctl (fd, TIOCGETC, &mp->m_tchars); X ioctl (fd, TIOCGLTC, &mp->m_ltchars); X ioctl (fd, TIOCLGET, &mp->m_lmode); X ioctl (fd, TIOCGETD, &mp->m_ldisc); X#endif X} X Xstatic SetMode (op, np) struct mode *op, *np; { X *np = *op; X#ifdef SYSV X np->m_tty.c_lflag = 0; X np->m_tty.c_iflag = IGNBRK; X np->m_tty.c_oflag = 0; X if (flowctl) X np->m_tty.c_iflag |= IXON|IXOFF; X np->m_tty.c_cc[VMIN] = 1; X np->m_tty.c_cc[VTIME] = 0; X#else X np->m_ttyb.sg_flags &= ~(CRMOD|ECHO); X np->m_ttyb.sg_flags |= CBREAK; X np->m_tchars.t_intrc = -1; X np->m_tchars.t_quitc = -1; X if (!flowctl) { X np->m_tchars.t_startc = -1; X np->m_tchars.t_stopc = -1; X } X np->m_ltchars.t_suspc = -1; X np->m_ltchars.t_dsuspc = -1; X np->m_ltchars.t_flushc = -1; X np->m_ltchars.t_lnextc = -1; X#endif X} X Xstatic char *GetTtyName () { X register char *p; X register n; X X for (p = 0, n = 0; n <= 2 && !(p = ttyname (n)); n++) X ; X if (!p || *p == '\0') X Msg (0, "screen must run on a tty."); X return p; X} X Xstatic ScreenInUse () { X Msg (0, "The screen is already attached elsewhere."); X} X Xstatic Attach (how) { X register s, lasts, found = 0; X register DIR *dirp; X register struct direct *dp; X struct msg m; X char last[MAXNAMLEN+1]; X X if (SockName) { X if ((lasts = MakeClientSocket (0)) == -1) X if (how == MSG_CONT) X Msg (0, X "This screen has already been continued from elsewhere."); X else X Msg (0, "There is no screen to be resumed from %s", SockName); X } else { X if ((dirp = opendir (SockPath)) == NULL) X Msg (0, "Cannot open %s", SockPath); X while ((dp = readdir (dirp)) != NULL) { X SockName = dp->d_name; X if (SockName[0] == '.') X continue; X if ((s = MakeClientSocket (0)) != -1) { X if (found == 0) { X strcpy (last, SockName); X lasts = s; X } else { X if (found == 1) { X printf ("There are detached screens on:\n"); X printf (" %s\n", last); X close (lasts); X } X printf (" %s\n", SockName); X close (s); X#ifdef SYSV X chanopen = 0; X#endif X } X found++; X } X } X if (found == 0) X Msg (0, "There is no screen to be resumed."); X if (found > 1) X#ifdef SYSV X Msg (0, "Type \"screen -r host.tty.pid\" to resume one of them."); X#else X Msg (0, "Type \"screen -r host.tty\" to resume one of them."); X#endif X closedir (dirp); X strcpy (SockNamePtr, last); X SockName = SockNamePtr; X } X m.type = how; X strcpy (m.m.attach.tty, GetTtyName ()); X m.m.attach.apid = getpid (); X /* X * Don't overlook the fact that we could get SIGHUP as a result X * of this call, if we attempt to attach to a window which is X * not detached. If we do, issue a meaningful message. X */ X signal(SIGHUP, ScreenInUse); X if (write (lasts, (char *)&m, sizeof (m)) != sizeof (m)) X Msg (errno, "write"); X} X Xstatic AttacherFinit () { X exit (0); X} X Xstatic ReAttach () { X Attach (MSG_CONT); X#ifdef SYSV X signal(SIGCONT, ReAttach); X#endif X} X Xstatic Attacher () { X signal (SIGHUP, AttacherFinit); X signal (SIGCONT, ReAttach); X while (1) X pause (); X} X Xstatic Detach (suspend) { X register struct win **pp; X X if (Detached) X return; X signal (SIGHUP, SIG_IGN); X SetTTY (0, &OldMode); X FinitTerm (); X if (suspend) { X Kill (AttacherPid, SIGTSTP); X } else { X for (pp = wtab; pp < wtab+MAXWIN; ++pp) X if (*pp) RemoveUtmp ((*pp)->slot); X printf ("\n[detached]\n"); X Kill (AttacherPid, SIGHUP); X AttacherPid = 0; X } X close (0); X close (1); X close (2); X ioctl (DevTty, TIOCNOTTY, (char *)0); X Detached = 1; X do { X ReceiveMsg (ServerSocket); X } while (Detached); X if (!suspend) X for (pp = wtab; pp < wtab+MAXWIN; ++pp) X if (*pp) (*pp)->slot = SetUtmp ((*pp)->tty); X signal (SIGHUP, SigHup); X} X Xstatic Kill (pid, sig) { X if (pid != 0) X (void) kill (pid, sig); X} X Xstatic GetSockName () { X register client; X static char buf[3*MAXSTR]; X X if (!mflag && (SockName = getenv ("STY")) != 0 && *SockName != '\0') { X client = 1; X setuid (getuid ()); X setgid (getgid ()); X } else { X#ifdef SYSV X sprintf (buf, "%s.%s.%d", HostName, Filename (GetTtyName ()), X getpid()); X#else X sprintf (buf, "%s.%s", HostName, Filename (GetTtyName ())); X#endif X SockName = buf; X client = 0; X } X return client; X} X Xstatic MakeServerSocket () { X register s; X#ifndef SYSV X struct sockaddr_un a; X#endif X char *p; X X#ifdef SYSV X int oflags; X X strcpy (SockNamePtr, SockName); X if (access(SockPath, 06) != -1) { X p = Filename (SockPath); X Msg (0, "You have already a screen running on %s.\n\ XIf it has been detached, try \"screen -r\".", p); X /*NOTREACHED*/ X } X if (mknod(SockPath, 010600) == -1) X Msg (errno, "named pipe"); X if ((s = open(SockPath, O_RDWR)) == -1) X Msg (errno, "named pipe open"); X chanopen = 1; X (void) chown (SockPath, getuid (), getgid ()); X return(s); X#else X if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1) X Msg (errno, "socket"); X a.sun_family = AF_UNIX; X strcpy (SockNamePtr, SockName); X strcpy (a.sun_path, SockPath); X if (connect (s, (struct sockaddr *)&a, strlen (SockPath)+2) != -1) { X p = Filename (SockPath); X Msg (0, "You have already a screen running on %s.\n\ XIf it has been detached, try \"screen -r\".", p); X /*NOTREACHED*/ X } X if (bind (s, (struct sockaddr *)&a, strlen (SockPath)+2) == -1) X Msg (errno, "bind"); X (void) chown (SockPath, getuid (), getgid ()); X if (listen (s, 5) == -1) X Msg (errno, "listen"); X return s; X#endif X} X Xstatic MakeClientSocket (err) { X register s; X#ifndef SYSV X struct sockaddr_un a; X#endif X X#ifdef SYSV X int oflags; X X strcpy (SockNamePtr, SockName); X if ((s = open(SockPath, O_WRONLY|O_NDELAY)) == -1) { X if (err) { X Msg (errno, "connect: %s", SockPath); X } else { X close (s); X return -1; X } X } X chanopen = 1; X (void) chown (SockPath, getuid (), getgid ()); X oflags = fcntl(s, F_GETFL); X oflags &= ~O_NDELAY; X fcntl(s, F_SETFL, oflags); X#else X if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1) X Msg (errno, "socket"); X a.sun_family = AF_UNIX; X strcpy (SockNamePtr, SockName); X strcpy (a.sun_path, SockPath); X if (connect (s, (struct sockaddr *)&a, strlen (SockPath)+2) == -1) { X if (err) { X Msg (errno, "connect: %s", SockPath); X } else { X close (s); X return -1; X } X } X#endif X return s; X} X Xstatic SendCreateMsg (s, ac, av, aflag) char **av; { X struct msg m; X register char *p; X register len, n; X X m.type = MSG_CREATE; X p = m.m.create.line; X#ifdef SYSV X if (proexec) X strcpy(p, ShellProg); X else X strcpy(p, *av); X p = p + strlen(p) + 1; X#endif X for (n = 0; ac > 0 && n < MAXARGS-1; ++av, --ac, ++n) { X len = strlen (*av) + 1; X if (p + len >= m.m.create.line+MAXLINE) X break; X strcpy (p, *av); X p += len; X } X m.m.create.nargs = n; X m.m.create.aflag = aflag; X if (getwd (m.m.create.dir) == 0) X Msg (0, "%s", m.m.create.dir); X if (write (s, (char *)&m, sizeof (m)) != sizeof (m)) X Msg (errno, "write"); X} X X/*VARARGS1*/ Xstatic SendErrorMsg (fmt, p1, p2, p3, p4, p5, p6) char *fmt; { X register s; X struct msg m; X X s = MakeClientSocket (1); X m.type = MSG_ERROR; X sprintf (m.m.message, fmt, p1, p2, p3, p4, p5, p6); X (void) write (s, (char *)&m, sizeof (m)); X close (s); X sleep (2); X} X Xstatic ReceiveMsg (s) { X#ifndef SYSV X register ns; X struct sockaddr_un a; X int left, len = sizeof (a); X#else X int left, len; X#endif X struct msg m; X char *p; X X#ifndef SYSV X if ((ns = accept (s, (struct sockaddr *)&a, &len)) == -1) { X Msg (errno, "accept"); X return; X } X p = (char *)&m; X left = sizeof (m); X while (left > 0 && (len = read (ns, p, left)) > 0) { X p += len; X left -= len; X } X close (ns); X#else X p = (char *)&m; X len = read (s, p, sizeof(m)); X left = sizeof(m) - len; X#endif X if (len == -1) X Msg (errno, "read"); X if (left > 0) X return; X switch (m.type) { X case MSG_CREATE: X if (!Detached) X ExecCreate (&m); X break; X case MSG_CONT: X if (m.m.attach.apid != AttacherPid || !Detached) X break; /* Intruder Alert */ X /*FALLTHROUGH*/ X case MSG_ATTACH: X if (Detached) { X if (kill (m.m.attach.apid, 0) == 0 && X open (m.m.attach.tty, O_RDWR) == 0) { X (void) dup (0); X (void) dup (0); X AttacherPid = m.m.attach.apid; X Detached = 0; X GetTTY (0, &OldMode); X SetMode (&OldMode, &NewMode); X SetTTY (0, &NewMode); X Activate (wtab[CurrNum]); X } X } else { X Kill (m.m.attach.apid, SIGHUP); X Msg (0, "Not detached."); X } X break; X case MSG_ERROR: X Msg (0, "%s", m.m.message); X break; X default: X Msg (0, "Invalid message (type %d).", m.type); X } X} X Xstatic ExecCreate (mp) struct msg *mp; { X char *args[MAXARGS]; X register n; X register char **pp = args, *p = mp->m.create.line; X X#ifdef SYSV X char *xprog; X X xprog = p; X p += strlen(p) + 1; X#endif X for (n = mp->m.create.nargs; n > 0; --n) { X *pp++ = p; X p += strlen (p) + 1; X } X *pp = 0; X#ifdef SYSV X if ((n = MakeWindow (xprog, args, mp->m.create.aflag, 0, X#else X if ((n = MakeWindow (mp->m.create.line, args, mp->m.create.aflag, 0, X#endif X mp->m.create.dir)) != -1) X SwitchWindow (n); X} X Xstatic ReadRc (fn) char *fn; { X FILE *f; X register char *p, **pp, **ap; X register argc, num, c; X char buf[256]; X char *args[MAXARGS]; X int key; X X ap = args; X if (access (fn, R_OK) == -1) X return; X if ((f = fopen (fn, "r")) == NULL) X return; X while (fgets (buf, 256, f) != NULL) { X if (p = rindex (buf, '\n')) X *p = '\0'; X if ((argc = Parse (fn, buf, ap)) == 0) X continue; X if (strcmp (ap[0], "escape") == 0) { X p = ap[1]; X if (argc < 2 || strlen (p) != 2) X Msg (0, "%s: two characters required after escape.", fn); X Esc = *p++; X MetaEsc = *p; X } else if (strcmp (ap[0], "chdir") == 0) { X p = argc < 2 ? home : ap[1]; X if (chdir (p) == -1) X Msg (errno, "%s", p); X } else if (strcmp (ap[0], "mode") == 0) { X if (argc != 2) { X Msg (0, "%s: mode: one argument required.", fn); X } else if (!IsNum (ap[1], 7)) { X Msg (0, "%s: mode: octal number expected.", fn); X } else (void) sscanf (ap[1], "%o", &TtyMode); X } else if (strcmp (ap[0], "bell") == 0) { X if (argc != 2) { X Msg (0, "%s: bell: one argument required.", fn); X } else { X if ((BellString = malloc (strlen (ap[1]) + 1)) == 0) X Msg (0, "Out of memory."); X strcpy (BellString, ap[1]); X } X } else if (strcmp (ap[0], "screen") == 0) { X num = 0; X if (argc > 1 && IsNum (ap[1], 10)) { X num = atoi (ap[1]); X if (num < 0 || num > MAXWIN-1) X Msg (0, "%s: illegal screen number %d.", fn, num); X --argc; ++ap; X } X if (argc < 2) { X ap[1] = ShellProg; argc = 2; X } X ap[argc] = 0; X (void) MakeWindow (ap[1], ap+1, 0, num, (char *)0); X } else if (strcmp (ap[0], "bind") == 0) { X p = ap[1]; X if (argc < 2 || *p == '\0') X Msg (0, "%s: key expected after bind.", fn); X if (p[1] == '\0') { X key = *p; X } else if (p[0] == '^' && p[1] != '\0' && p[2] == '\0') { X c = p[1]; X if (isupper (c)) X p[1] = tolower (c); X key = Ctrl(c); X } else if (IsNum (p, 7)) { X (void) sscanf (p, "%o", &key); X } else { X Msg (0, X "%s: bind: character, ^x, or octal number expected.", fn); X } X if (argc < 3) { X ktab[key].type = 0; X } else { X for (pp = KeyNames; *pp; ++pp) X if (strcmp (ap[2], *pp) == 0) break; X if (*pp) { X ktab[key].type = pp-KeyNames+1; X } else { X ktab[key].type = KEY_CREATE; X ktab[key].args = SaveArgs (argc-2, ap+2); X } X } X } else Msg (0, "%s: unknown keyword \"%s\".", fn, ap[0]); X } X (void) fclose (f); X} X Xstatic Parse (fn, buf, args) char *fn, *buf, **args; { X register char *p = buf, **ap = args; X register delim, argc = 0; X X argc = 0; X for (;;) { X while (*p && (*p == ' ' || *p == '\t')) ++p; X if (*p == '\0' || *p == '#') X return argc; X if (argc > MAXARGS-1) X Msg (0, "%s: too many tokens.", fn); X delim = 0; X if (*p == '"' || *p == '\'') { X delim = *p; *p = '\0'; ++p; X } X ++argc; X *ap = p; ++ap; X while (*p && !(delim ? *p == delim : (*p == ' ' || *p == '\t'))) X ++p; X if (*p == '\0') { X if (delim) X Msg (0, "%s: Missing quote.", fn); X else X return argc; X } X *p++ = '\0'; X } X} X Xstatic char **SaveArgs (argc, argv) register argc; register char **argv; { X register char **ap, **pp; X X if ((pp = ap = (char **)malloc ((argc+1) * sizeof (char **))) == 0) X Msg (0, "Out of memory."); X while (argc--) { X if ((*pp = malloc (strlen (*argv)+1)) == 0) X Msg (0, "Out of memory."); X strcpy (*pp, *argv); X ++pp; ++argv; X } X *pp = 0; X return ap; X} X Xstatic MakeNewEnv () { X register char **op, **np = NewEnv; X static char buf[MAXSTR]; X char envbuf[MAXSTR]; X X if (strlen (SockName) > MAXSTR-5) X SockName = "?"; X sprintf (buf, "STY=%s", SockName); X *np++ = buf; X *np++ = Term; X np += 2; X#ifdef SYSV X sprintf(envbuf, "LINES=%d", rows); X *np++ = strdup(envbuf); X sprintf(envbuf, "COLS=%d", cols); X *np++ = strdup(envbuf); X#endif X for (op = environ; *op; ++op) { X if (np == NewEnv + MAXARGS - 1) X break; X if (!IsSymbol (*op, "TERM") && !IsSymbol (*op, "TERMCAP") X && !IsSymbol (*op, "STY")) X *np++ = *op; X } X *np = 0; X} X Xstatic IsSymbol (e, s) register char *e, *s; { X register char *p; X register n; X X for (p = e; *p && *p != '='; ++p) ; X if (*p) { X *p = '\0'; X n = strcmp (e, s); X *p = '='; X return n == 0; X } X return 0; X} X X/*VARARGS2*/ XMsg (err, fmt, p1, p2, p3, p4, p5, p6) char *fmt; { X char buf[1024]; X register char *p = buf; X X if (Detached) X return; X sprintf (p, fmt, p1, p2, p3, p4, p5, p6); X if (err) { X p += strlen (p); X if (err > 0 && err < sys_nerr) X sprintf (p, ": %s", sys_errlist[err]); X else X sprintf (p, ": Error %d", err); X } X if (HasWindow) { X MakeStatus (buf, curr); X } else { X printf ("%s\r\n", buf); X Kill (AttacherPid, SIGHUP); X#ifdef SYSV X if (chanopen && AttacherPid) X unlink(SockPath); X#endif X exit (1); X } X} X Xbclear (p, n) char *p; { X bcopy (blank, p, n); X} X Xstatic char *Filename (s) char *s; { X register char *p; X X p = s + strlen (s) - 1; X while (p >= s && *p != '/') --p; X return ++p; X} X Xstatic IsNum (s, base) register char *s; register base; { X for (base += '0'; *s; ++s) X if (*s < '0' || *s > base) X return 0; X return 1; X} X Xstatic char *MakeBellMsg (n) { X static char buf[MAXSTR]; X register char *p = buf, *s = BellString; X X for (s = BellString; *s && p < buf+MAXSTR-1; s++) X *p++ = (*s == '%') ? n + '0' : *s; X *p = '\0'; X return buf; X} X Xstatic InitUtmp () { X struct passwd *p; X X#ifdef SYSV X if (setutent() == NULL) X return; X#else X if ((utmpf = open (UtmpName, O_WRONLY)) == -1) { X if (errno != EACCES) X Msg (errno, UtmpName); X return; X } X#endif X if ((LoginName = getlogin ()) == 0 || LoginName[0] == '\0') { X if ((p = getpwuid (getuid ())) == 0) X return; X LoginName = p->pw_name; X } X utmp = 1; X} X Xstatic SetUtmp (name) char *name; { X register char *p; X register struct ttyent *tp; X register slot = 1; X struct utmp u; X X if (!utmp) X return 0; X if (p = rindex (name, '/')) X ++p; X else p = name; X#ifndef SYSV X setttyent (); X while ((tp = getttyent ()) != NULL && strcmp (p, tp->ty_name) != 0) X ++slot; X if (tp == NULL) X return 0; X strncpy (u.ut_line, p, 8); X time (&u.ut_time); X strncpy (u.ut_name, LoginName, 8); X u.ut_host[0] = '\0'; X (void) lseek (utmpf, (long)(slot * sizeof (u)), 0); X (void) write (utmpf, (char *)&u, sizeof (u)); X return slot; X#else X { X int len = strlen(p); X X setutent(); X bzero((char *) &u, sizeof(u)); X strncpy(u.ut_line, p, 8); X u.ut_type = USER_PROCESS; X strncpy (u.ut_name, LoginName, 8); X u.ut_id[0] = 's'; u.ut_id[3] = '\0'; X u.ut_id[1] = p[len - 2]; u.ut_id[2] = p[len - 1]; X slot = *((int *) u.ut_id); X time (&u.ut_time); X pututline(&u); X return slot; X } X#endif X} X Xstatic RemoveUtmp (slot) int slot; { X struct utmp u; X X if (slot) { X#ifdef SYSV X struct utmp *y; X X setutent(); X bzero((char *) &u, sizeof(u)); X *((int *) u.ut_id) = slot; X u.ut_type = USER_PROCESS; X if ((y = getutid(&u)) == 0) X return; X strncpy (u.ut_name, "screen", 8); X strncpy (u.ut_line, y->ut_line, 12); X u.ut_type = DEAD_PROCESS; X time (&u.ut_time); X pututline(&u); X#else X bzero ((char *)&u, sizeof (u)); X (void) lseek (utmpf, (long)(slot * sizeof (u)), 0); X (void) write (utmpf, (char *)&u, sizeof (u)); X#endif X } X} X X#ifndef SYSV X#ifndef GETTTYENT X Xstatic setttyent () { X struct stat s; X register f; X register char *p, *ep; X X if (ttnext) { X ttnext = tt; X return; X } X if ((f = open (ttys, O_RDONLY)) == -1 || fstat (f, &s) == -1) X Msg (errno, ttys); X if ((tt = malloc (s.st_size + 1)) == 0) X Msg (0, "Out of memory."); X if (read (f, tt, s.st_size) != s.st_size) X Msg (errno, ttys); X close (f); X for (p = tt, ep = p + s.st_size; p < ep; ++p) X if (*p == '\n') *p = '\0'; X *p = '\0'; X ttnext = tt; X} X Xstatic struct ttyent *getttyent () { X static struct ttyent t; X X if (*ttnext == '\0') X return NULL; X t.ty_name = ttnext + 2; X ttnext += strlen (ttnext) + 1; X return &t; X} X X#endif X#endif X X#ifdef LOADAV X Xstatic InitKmem () { X if ((kmemf = open (KmemName, O_RDONLY)) == -1) X return; X nl[0].n_name = AvenrunSym; X nlist (UnixName, nl); X if (nl[0].n_type == 0 || nl[0].n_value == 0) X return; X avenrun = 1; X} X Xstatic GetAvenrun () { X if (lseek (kmemf, nl[0].n_value & ~0x80000000, 0) == -1) X return 0; X if (read (kmemf, loadav, sizeof (loadav)) != sizeof (loadav)) X return 0; X return 1; X} X X#endif X X#ifndef USEBCOPY Xbcopy (s1, s2, len) register char *s1, *s2; register len; { X if (s1 < s2 && s2 < s1 + len) { X s1 += len; s2 += len; X while (len-- > 0) { X *--s2 = *--s1; X } X } else { X while (len-- > 0) { X *s2++ = *s1++; X } X } X} X#endif X X#ifdef SYSV Xkillpg(grp, sig) X int grp; X int sig; X{ X return( kill (-grp, sig) ); X} X#endif ________This_Is_The_END________ if test `wc -l < screen.c` -ne 1953; then echo 'shar: screen.c was damaged during transit (should have been 1953 bytes)' fi fi ; : end of overwriting check echo 'x - screen.h' if test -f screen.h; then echo 'shar: not overwriting screen.h'; else sed 's/^X//' << '________This_Is_The_END________' > screen.h X/* Copyright (c) 1987,1988 Oliver Laumann, Technical University of Berlin. X * Not derived from licensed software. X * X * Permission is granted to freely use, copy, modify, and redistribute X * this software, provided that no attempt is made to gain profit from it, X * the author is not construed to be liable for any results of using the X * software, alterations are clearly marked as such, and this notice is X * not modified. X */ X Xenum state_t { X LIT, /* Literal input */ X ESC, /* Start of escape sequence */ X STR, /* Start of control string */ X TERM, /* ESC seen in control string */ X CSI, /* Reading arguments in "CSI Pn ; Pn ; ... ; XXX" */ X PRIN, /* Printer mode */ X PRINESC, /* ESC seen in printer mode */ X PRINCSI, /* CSI seen in printer mode */ X PRIN4 /* CSI 4 seen in printer mode */ X}; X Xenum string_t { X NONE, X DCS, /* Device control string */ X OSC, /* Operating system command */ X APC, /* Application program command */ X PM, /* Privacy message */ X}; X X#define MAXSTR 128 X#define MAXARGS 64 X X#define IOSIZE 80 X Xstruct win { X int wpid; X int ptyfd; X int aflag; X char outbuf[IOSIZE]; X int outlen; X char cmd[MAXSTR]; X char tty[MAXSTR]; X int args[MAXARGS]; X char GotArg[MAXARGS]; X int NumArgs; X int slot; X char **image; X char **attr; X char **font; X int LocalCharset; X int charsets[4]; X int ss; X int active; X int x, y; X char LocalAttr; X int saved; X int Saved_x, Saved_y; X char SavedLocalAttr; X int SavedLocalCharset; X int SavedCharsets[4]; X int top, bot; X int wrap; X int origin; X int insert; X int keypad; X enum state_t state; X enum string_t StringType; X char string[MAXSTR]; X char *stringp; X char *tabs; X int vbwait; X int bell; X}; X X#define MAXLINE 1024 X X#define MSG_CREATE 0 X#define MSG_ERROR 1 X#define MSG_ATTACH 2 X#define MSG_CONT 3 X Xstruct msg { X int type; X union { X struct { X int aflag; X int nargs; X char line[MAXLINE]; X char dir[1024]; X } create; X struct { X int apid; X char tty[1024]; X } attach; X char message[MAXLINE]; X } m; X}; ________This_Is_The_END________ if test `wc -l < screen.h` -ne 98; then echo 'shar: screen.h was damaged during transit (should have been 98 bytes)' fi fi ; : end of overwriting check echo 'x - screen.tic' if test -f screen.tic; then echo 'shar: not overwriting screen.tic'; else sed 's/^X//' << '________This_Is_The_END________' > screen.tic Xscreen, X xon, X cols#80, lines#24, X bel=^G, blink=\E[5m, bold=\E[1m, cbt=\E[Z, X clear=\E[2J\E[H, cr=\r, csr=\E[%i%p1%d;%p2%dr, X cub=\E[%p1%dD, cub1=\b, cud=\E[%p1%dB, cud1=\n, X cuf=\E[%p1%dC, cuf1=\E[C, cup=\E[%i%p1%d;%p2%dH, X cuu=\E[%p1%dA, cuu1=\E[A, dl=\E[%p1%dM, dl1=\E[M, X el=\E[K, ht=\t, hts=\EH, il=\E[%p1%dL, il1=\E[L, X ind=\n, kbs=\b, kcub1=\EOD, kcud1=\EOB, kcuf1=\EOC, X kcuu1=\EOA, kf0=\EOy, kf1=\EOP, kf2=\EOQ, kf3=\EOR, X kf4=\EOS, kf5=\EOt, kf6=\EOu, kf7=\EOv, kf8=\EOl, X kf9=\EOw, rc=\E8, rev=\E[7m, ri=\EM, rmkx=\E>, X rmso=\E[23m, rmul=\E[24m, rs2=\Ec, sc=\E7, sgr0=\E[0m, X smkx=\E=, smso=\E[3m, smul=\E[4m, tbc=\E[3g, ________This_Is_The_END________ if test `wc -l < screen.tic` -ne 15; then echo 'shar: screen.tic was damaged during transit (should have been 15 bytes)' fi fi ; : end of overwriting check exit 0