home *** CD-ROM | disk | FTP | other *** search
- Date: Mon, 19 Mar 1990 6:34:35 CST
- From: Werner Uhrig <werner@rascal.ics.utexas.edu>
- Subject: here comes MacLayers_1.0_UNIX-files_shar
-
- # This is a shell archive. Remove anything before this line,
- # then unpack it by saving it in a file and typing "sh file".
- #
- # Wrapped by rascal!werner on Mon Mar 19 04:58:04 CST 1990
- # Contents: README layers.1 layers.c layers.h layersize.c layertitle.c
- # macbput.1 macbput.c makefile protocol.c
-
- echo x - README
- sed 's/^@//' > "README" <<'@//E*O*F README//'
- Layers 1.0 Release
-
- *** CONTENTS ***
-
- The following files are provided with the MacLayers package:
-
- README - this file
- layers.1 - the layers command manual page
- makefile - the layers makefile
- layers.h - Unix source for the layers command
- layers.c - ditto
- protocol.c - ditto
- layersize.c - Unix source for the layersize command
- layertitle.c - Unix source for the layertitle command
- MacLayers.sit.Hqx - the MacLayers Application download file
- MacLayers.doc - the MacLayers User's Manual
- macbput.c - a downloading utility
- macbput.1 - the macbput command manual page
-
- The MacLayers.sit.Hqx file is in hexbin format. After downloading it must be
- processed with a Stuffit compatible utility to produce the MacLayers
- application.
-
- Macbput is a public domain download utility for downloading macbinary files.
- Macbinary files allow downloading to correctly set the Macintosh file creation
- date and file last used date. The version with this package has an important
- bug fixed.
-
-
- *** SUPPORTED SYSTEMS ***
-
- MacLayers has been successfully installed on the following systems:
-
- SunOS 4.0.3
- SunOS 3.2
- Sequent DYNIX 3.0.12 (#DEFINE SEQUENT)
- Sequent DYNIX 3.0.4 (#DEFINE SEQUENT)
-
- MacLayers has failed to install on these systems:
-
- AIX 2.2.1 on IBM RT Unsupported ioctls
-
-
- *** INSTALLATION ***
-
- There are two ways to install the layers system:
-
- make install
-
- or
- make installnopriv
-
- The default is to install the 'layers' command set-uid which allows it to
- update /etc/utmp and perform chown/chmod on its allocated pseudo-ttys.
- This enables commands like 'who' to know about the presence of layers users
- and commands like 'write' and 'talk' to communicate with them. This is not
- a mandatory requirement however and the layers system will otherwise function.
-
- For set-uid installers (especially Sequent users) there are a few customizing
- parameters which may be of interest at the front of layers.c.
-
- *end of document*
- @//E*O*F README//
- chmod u=rw,g=rw,o=rw README
-
- echo x - layers.1
- sed 's/^@//' > "layers.1" <<'@//E*O*F layers.1//'
- @.TH LAYERS l "17 March 1990"
- @.SH NAME
- @.PP
- layers, layertitle \- Protocol for MacLayers Multiwindow Terminal Emulator for Unix
- @.SH SYNOPSIS
- layers - start window protocol
- @.LP
- layers [-l] [command] - create new window
- @.LP
- layertitle string - retitle current layers window
- @.IX "layers" "start layers protocol, create new window"
- @.IX "layertitle" "rename current layers window"
- @.SH DESCRIPTION
- @.PP
- MacLayers provides multi-window capability for a Macintosh (greater than 128K)
- connected to a host UNIX(TM) system with sockets support. Each window may be
- associated with a shell, login to a different host, or an individual
- command. Complete facilities are available for controlling the window
- and the associated host processes attached thereto.
- @.PP
- To use MacLayers, you must have the MacLayers vt-100 terminal emulation
- program on a Macintosh and the layers protocol program installed on your
- Unix host.
- @.SH MACLAYERS OPERATION
- @.PP
- The Maclayers Application on the Mac starts up as a garden variety
- host-to-terminal vt-100 emulator. (As such you can run it with any
- host, not just a Unix machine.) Baud rate and other configurations are set
- by selections in the Control Menu.
- @.PP
- Enter the
- @.I layers
- command to the Unix host using no options or parameters
- to start the layers protocol. The initial terminal window will be closed
- and replaced with a layers protocol window. A shell is run in this
- window, either /bin/sh or the shell indicated by your $SHELL variable.
- @.PP
- You can start a new shell layer by picking "New" on the Layers menu. You can
- also start a new layer window by issuing the
- @.I layers
- command to a
- shell layer window. If you use no operands then the new layer window
- will be a shell. However, you can specify any command you wish by
- simply adding it as a parameter. Examples: "layers vi testfile.c",
- "layers telnet earth."
- @.PP
- If you are specifying a shell then you can also elect to have it be a
- login shell by adding a -l option. This allows broadcast/write/talk
- capabilities for that window. The initial layer window shell defaults
- to a login shell.
- @.PP
- When a layer process group terminates its window is automatically closed.
- MacLayers exits layers mode when the last (or only) layer window is closed.
- You may also use the Layers Menu "Shutdown" to terminate layers mode.
- You cannot quit the MacLayers application while in layers mode but must
- Shutdown the multi-window mode first.
- @.PP
- You can abort host
- @.I layers
- by using the Control Menu "Abort Host Layers"
- item which is always available. This may be necessary if your Mac
- loses contact with the host and you restart the MacLayers application at
- which time the host would still be in multi-window layers mode while
- the application would not. If the MacLayers application terminates due
- to a non-recoverable problem it will always issue an order to terminate
- layers mode on the host before returning to the Finder.
- @.SH XMODEM DOWNLOADING
- @.PP
- MacLayers has a download facility for downloading XMODEM MacTerminal
- ('macput' command) and MacBinary ('macbput' command) files. Straight
- vanilla XMODEM is not supported.
- Only one window can be doing a XMODEM download at any one time.
- Downloading does not effect any other MacLayers operations so you can
- freely use any other windows or applications (with MultiFinder) while
- a download is in progress. Remember though that the topmost window
- receives the highest priority data transfer from the host. So for the
- fastest downloading keep the XMODEM layer window the active window.
- @.SH FILES
- @.PP
- /usr/tmp/layers/<login> Directory created by
- @.I layers
- /usr/tmp/layers/<login>/host.ttySocket Created by
- @.I layers
- @.SH AUTHOR
- Dave Trissel
- @.SH BUGS AND CAVEATS
- @.PP
- *) The shell TERM variable must have the same value in your
- layer shells as it does when you initially start
- @.I layers
- up.
- @.PP
- *) If you set the BSD shell TERMCAP variable then that variable must
- be set in your .login file. It may not be changed to something
- different in .cshrc.
- @.PP
- *) The
- @.I layers
- command will not properly work when being issued from a
- remote login into the same machine which is already running the
- initial
- @.I layers
- startup command.
- @.PP
- *) There is no file upload facility.
- @.PP
- *) MacLayers will access the disk less often if you have RAM Cache
- enabled on the Macintosh.
- @.PP
- *)Layers must be installed as set-uid with owner root in order
- to be able to correctly change the owner of the tty device
- file for each window. Special permission may also be
- required to write the file "/etc/utmp".
- @.SH SEE ALSO
- @.PP
- The MacLayers program is
- completely described in the manual that accompanies it.
- @.PP
- Manual page courtesy of Peter Newton.
- @.PP
- UNIX(TM) is a registered trademark of American Telephone and Telegraph.
- Macintosh is a trademark of McIntosh Laboratories and is licensed to Apple
- Computer.
- @//E*O*F layers.1//
- chmod u=rw,g=rw,o=rw layers.1
-
- echo x - layers.c
- sed 's/^@//' > "layers.c" <<'@//E*O*F layers.c//'
- /******** 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);
- }
- @//E*O*F layers.c//
- chmod u=rw,g=rw,o=rw layers.c
-
- echo x - layers.h
- sed 's/^@//' > "layers.h" <<'@//E*O*F layers.h//'
- /* 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.
- *
- */
-
- #define MAXPCHAN 7 /* maximum layers supported */
-
- #define MAXSTR 200
- #define MAXARGS 64
- #define MAXLINE 1024
- #define IOSIZE 800 /* data gulp handling size */
-
- /* WARNING - packet sizes must be insured to never match the ESCAPE char */
- #define ESCAPE '}' /* datalink escape character */
-
- #define DO if (Dflag) /* for debugging */
-
- /* miscelaneous common data */
- extern int Dflag; /* debug dump indicator flag */
-
- /* Shape structure passed between MacLayers and ourselves */
- struct Shape
- { short worigv; /* verical window bit origin */
- short worigh; /* horizontal window bit origin */
- short wlines; /* window height */
- short wchars; /* window width */
- short wfont; /* window font size */
- short wattr; /* window attributes */
- };
-
- #define Wa_shell 0x01 /* window is a shell */
-
-
- /* The following modules define the complete protocol/server interface */
-
- /* layers.c */
-
- extern void FQuit(/* exitcode */);
- extern void ReceiveQuit();
- extern void ReceiveNew(/* chanid, shape */);
- extern void ReceiveDelete(/* chanid */);
- extern void ReceiveSignal(/* chanid, signal */);
- extern void ReceiveData(/* chanid, buff, cnt */);
- extern void ReceiveReshape(/*chanid, shape */);
- extern void DEBUG(/* format, arg1, arg2, arg3, arg4 */);
-
- /* protocol.c */
-
- extern int InitLink();
- extern int TopChannel();
- extern int SendNew(/* shape */);
- extern void SendTitle(/* chan, buff, cnt */);
- extern void SendDelete(/* chan */);
- extern void SendQuit();
- extern void SendReshape(/* chan, shape */);
- extern void SendData(/* chan, buff, cnt */);
- extern void ProcessStreamin();
- @//E*O*F layers.h//
- chmod u=rw,g=rw,o=rw layers.h
-
- echo x - layersize.c
- sed 's/^@//' > "layersize.c" <<'@//E*O*F layersize.c//'
- /* 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.
- *
- */
- /* All rights reserved. */
-
- /* layersize - update BSD Sun Unix with window size information */
-
- #include <stdio.h>
- #include <errno.h>
- #include <sys/ioctl.h>
-
- extern int sys_nerr;
- extern char *sys_errlist[];
-
- static void gotsyserr(/* char * */);
- static void goterr(/* char * */);
- static int getnumber(/* char * */);
-
-
- /* main() - update BSD window size */
-
- main(ac, av)
- int ac; /* argument count */
- char **av; /* argument vector */
- {
- struct winsize wsize; /* window size structure for ioctl() */
- char *ap; /* argument scan pointer */
- int lines; /* new lines value */
- int cols; /* new columns value */
-
- if (--ac != 2)
- goterr("Missing lines and column options");
-
- /* get window size (actually do this to set xpixel and ypixel values) */
- if (ioctl(0, TIOCGWINSZ, &wsize) == -1)
- gotsyserr("No window support in host"); /* terminate with message */
-
- /* scan looking for -l and -c line and column numeric sizes */
- lines = cols = 0; /* reset values */
- while (ac > 0)
- { ap = *++av; /* point to next argument string */
- if (ac-- > 0 && *ap == '-') /* if option ... */
- switch (ap[1])
- { case 'l': /* lines */
- lines = getnumber(&ap[2]);
- break;
-
- case 'c': /* columns */
- cols = getnumber(&ap[2]);
- break;
-
- default:
- goterr("Usupported option"); /* unsupported option */
- break;
-
- } /* end '-' argument */
- else
- goterr("Unsupported parameter"); /* unsupported parameter */
-
- } /* end while argument vector scan */
-
- /* must have both lines and columns */
- if (lines == 0 || cols == 0)
- goterr("Must specify both lines and columns");
-
- wsize.ws_col = cols; /* set columns */
- wsize.ws_row = lines; /* set lines */
- /* update the kernel */
- if (ioctl(0, TIOCSWINSZ, &wsize) == -1)
- gotsyserr("Failed to update window size"); /* didn't go */
-
- }
-
-
- /* goterr() - issue error and terminate */
-
- static void
- goterr(msg)
- char *msg; /* error message string */
- {
- printf("%s\n", msg); /* send error message to user */
- exit(1); /* terminate with error */
-
- } /* goterr() */
-
-
- /* gotsyserror() - system error return */
-
- static void
- gotsyserr(msg)
- char *msg; /* error string */
- {
- if (errno > 0 && errno < sys_nerr)
- printf("%s: %s\n", msg, sys_errlist[errno]);
- else
- printf("%s: Error %d\n", msg, errno);
-
- exit(1); /* exit with failure */
-
- } /* gotsyserr() */
-
-
- /* getnumber() - parse option number */
-
- static int
- getnumber(str)
- char *str; /* start of option string */
- {
- int n; /* number being built */
-
- if (str == NULL)
- goterr("Invalid numeric in option");
-
- /* skip any leading delimiters */
- while (*str && (*str == ' ' || *str == '\t'))
- str++;
-
- for(n=0; *str && *str >= '0' && *str <= '9'; str++)
- n = n*10 + *str - '0'; /* add next digit in */
-
- /* make sure number terminates legally */
- switch (*str)
- { case '\0':
- case ' ':
- case '\t':
- case '\n':
- if (n <= 0 || n > 200)
- goterr("Number out of range");
- break; /* these are OK */
-
- default:
- goterr("Invalid numeric in option");
-
- } /* end switch */
-
- return ( n ); /* return the number */
-
- } /* getnumber() */
- @//E*O*F layersize.c//
- chmod u=rw,g=rw,o=rw layersize.c
-
- echo x - layertitle.c
- sed 's/^@//' > "layertitle.c" <<'@//E*O*F layertitle.c//'
- /* 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.
- *
- */
- /* All rights reserved. */
-
- /* layertitle - utility to specify window title */
-
- #include <stdio.h>
-
- #define ESC 0x1b
-
- /* main() - send string designating layers window title */
-
- main(ac, av)
- int ac; /* argument count */
- char **av; /* argument vector */
- {
- char *ap; /* argument scan pointer */
-
- if (--ac != 1)
- { printf("usage: layertitle \"new window title\"\n");
- exit(1);
- }
-
- ap = *++av; /* point to argument string */
-
- /* Transmit the title string in the ANSI Private Message format
- ** which is
- ** ESC '^' message ESC '\'
- */
- printf("%c%c%s%c%c", ESC, '^', ap, ESC, '\\');
-
- } /* main() */
- @//E*O*F layertitle.c//
- chmod u=rw,g=rw,o=rw layertitle.c
-
- echo x - macbput.1
- sed 's/^@//' > "macbput.1" <<'@//E*O*F macbput.1//'
- @.TH MACBPUT local "17 Mar 1990"
- @.UC 4
- @.SH NAME
- macbput \- send file to macintosh via macbinary protocol
- @.SH SYNOPSIS
- @.B macbput
- file
- @.br
- @.B macbput
- [
- @.B \-rdu
- ] file
- [
- @.B \-t
- type
- ]
- [
- @.B \-a
- owner
- ]
- [
- @.B \-n
- name
- ]
- @.SH DESCRIPTION
- @.I Macbput
- sends a file to a Macintosh running MacTerminal.
- The File Transfer Protocol settings should specify the "MacBinary"
- transfer method.
- Macbput will also work with other communications programs for the Mac
- (e.g. MacLayers);
- consult the user's manual for your macbinary-compatable communications
- program for more information.
- This manual page will only address the use of macbput with MacTerminal.
- @.PP
- To use this program, log into the unix system using MacTerminal,
- and run macbput specifying the desired options and one file to be sent.
- If MacTerminal is properly configured, it will recognize that a file
- is arriving on the serial line and put up an indicator showing how
- much of the file has been sent.
- Several Control-X's may be used to force macbput
- to give up if the transfer fails.
- @.PP
- If none of the
- @.B \-rdu
- flags are specified,
- @.I macbput
- sends three unix files to the Mac:
- @.IB file .info ,
- @.IB file .data ,
- and
- @.IB file .rsrc .
- These specify the three parts of one Mac file: the .data file
- becomes the data fork, the .rsrc file becomes the resource fork,
- and the .info file specifies the sizes of the two forks, as well
- as the file name, file type, creation date, and other information.
- This is useful for returning files to the Mac which were stored
- using macget or macbget.
- @.PP
- The
- @.B \-r
- flag specifies
- @.I resource
- mode.
- Either
- @.IB file .rsrc
- or
- @.I file
- will be sent to the Mac, along with a forged
- @.B .info
- file and an empty
- @.B .data
- file.
- The file sent becomes the resource fork of the Mac file.
- @.PP
- The
- @.B \-d
- flag specifies
- @.I data
- mode.
- Either
- @.IB file .data
- ,
- @.IB file .text
- or
- @.I file
- will be sent to the Mac, along with a forged
- @.B .info
- file and an empty
- @.B .rsrc
- file.
- The file sent becomes the data fork of the Mac file.
- @.PP
- The
- @.B \-u
- flag requests
- @.I unix
- mode, which is the same as
- @.I data
- mode except unix newline characters are converted
- into carriage returns.
- Human-readable unix text files sent to the Mac using this option
- will be compatible with applications which expect "text only" files.
- @.PP
- The remaining options serve to override the default
- file type, owner, and file name to be used on the Mac.
- The default type and owner for
- @.I resource
- and
- @.I data
- mode defaults are "????", "????", and
- @.I unix
- mode defaults are "TEXT" and "MACA".
- @.SH SEE ALSO
- macput(local), macget(local), xbin(local), macbin(local), mcvert(local)
- @.SH BUGS
- The macbinary protocol may not work over flow controlled communication lines,
- some terminal concentrators, or when using rlogin.
- @.SH FEATURES
- Properly initializes the Creation Date.
- @.SH AUTHOR
- Original base code: Dave Johnson, Brown 7/31/84
- @//E*O*F macbput.1//
- chmod u=rw,g=rw,o=rw macbput.1
-
- echo x - macbput.c
- sed 's/^@//' > "macbput.c" <<'@//E*O*F macbput.c//'
- /*
- * (originally macput) -- send file to Macintosh using MacBinary XMODEM protocol
- * Dave Johnson, Brown University Computer Science
- *
- * (c) 1984 Brown University
- * may be used but not sold without permission
- *
- */
-
- /* To compile:
- cc -O -o macbput macbput.c
- (Sun 4.2 BSD) cc -O -DSUNBSD42 -o macbput macbput.c
- (System V) cc -O -DSYSV -o macbput macbput.c
-
- Latest modifications 10/20/88 by Trissel -
-
- 1. General cleanup by removal of unused definitions and headers.
- 2. Added #ifdefs to support System V and BSD 4.2 Sun compilation.
- 3. Removed ancient Macterminal Beta 0.5X code.
- 4. Fixed bad bug where XMODEM block count was not bumped up
- after the first fork transfer.
-
- Dave Trissel
- Motorola Inc.
- ut-sally!oakhill!davet
-
- This code is fundamentally from two earlier programmers:
-
- Jon Hueras
- Symantec/THINK Technologies
- singer@endor.harvard.edu
-
- who added 2-Byte CRC capability to code from:
-
- Dave Johnson
- ddj%brown@csnet-relay.arpa
- Brown University Computer Science
-
- who did the initial MacTerminal 1.1 transfer protocol.
- */
-
- /* If you have System V define the following: */
- /* #define SYSV */
-
- /* Sun BSD 4.2 systems should define the following: */
- /* #define SUNBSD42 */
-
- #include <stdio.h>
- #include <signal.h>
- #include <setjmp.h>
- #ifdef SYSV
- #include <termio.h>
- #else
- #include <sgtty.h>
- #endif
- #include <sys/types.h>
- #include <sys/stat.h>
-
- #ifdef SUNBSD42
- /* RAW is no longer being found on latest Sun system (??) (Trissel) */
- #define RAW 0x20
- #endif
-
- #define RECORDBYTES 132
- #define DATABYTES 128
- #define NAMEBYTES 63
-
- #define RETRIES 10
- #define ACKTIMO 10
-
- #define MAXRECNO 0xff
- #define BYTEMASK 0xff
-
- #define TMO -1
- #define DUP '\000'
- #define SOH '\001'
- #define EOT '\004'
- #define ACK '\006'
- #define NAK '\025'
- #define CAN '\030'
- #define EEF '\032'
- #define ESC '\033'
-
- #define H_NLENOFF 1
- #define H_NAMEOFF 2
- /* 65 <-> 80 is the FInfo structure */
- #define H_TYPEOFF 65
- #define H_AUTHOFF 69
-
- #define H_LOCKOFF 81
- #define H_DLENOFF 83
- #define H_RLENOFF 87
- #define H_CTIMOFF 91
- #define H_MTIMOFF 95
-
- #define H_OLD_DLENOFF 81
- #define H_OLD_RLENOFF 85
-
- #define TEXT 0
- #define DATA 1
- #define RSRC 2
- #define FULL 3
-
- int mode, txtmode;
-
- struct macheader {
- char m_name[NAMEBYTES+1];
- char m_type[4];
- char m_author[4];
- long m_datalen;
- long m_rsrclen;
- long m_createtime;
- long m_modifytime;
- } mh;
-
- struct filenames {
- char f_info[256];
- char f_data[256];
- char f_rsrc[256];
- } files;
-
- int recno, crc;
- char buf[DATABYTES];
-
- char usage[] =
- "usage: \"macbput [-rdu] [-t type] [-c creator] [-n name] filename\"\n";
-
- main(ac, av)
- char **av;
- {
- int n;
- char *filename;
-
- if (ac == 1) {
- fprintf(stderr, usage);
- exit(1);
- }
-
- mode = FULL;
- ac--; av++;
- while (ac) {
- if (av[0][0] == '-') {
- switch (av[0][1]) {
- case 'r':
- mode = RSRC;
- strncpy(mh.m_type, "????", 4);
- strncpy(mh.m_author, "????", 4);
- break;
- case 'u':
- mode = TEXT;
- strncpy(mh.m_type, "TEXT", 4);
- strncpy(mh.m_author, "MACA", 4);
- break;
- case 'd':
- mode = DATA;
- strncpy(mh.m_type, "????", 4);
- strncpy(mh.m_author, "????", 4);
- break;
- case 'n':
- if (ac > 1) {
- ac--; av++;
- n = strlen(av[0]);
- if (n > NAMEBYTES) n = NAMEBYTES;
- strncpy(mh.m_name, av[0], n);
- mh.m_name[n] = '\0';
- break;
- }
- else goto bad_usage;
- case 't':
- if (ac > 1) {
- ac--; av++;
- strncpy(mh.m_type, av[0], 4);
- break;
- }
- else goto bad_usage;
- case 'c':
- if (ac > 1) {
- ac--; av++;
- strncpy(mh.m_author, av[0], 4);
- break;
- }
- else goto bad_usage;
- default:
- bad_usage:
- fprintf(stderr, usage);
- exit(1);
- }
- }
- else {
- filename = av[0];
- }
- ac--; av++;
- }
-
- setup_tty();
- find_files(filename, mode);
- if (mode != FULL)
- forge_info();
-
- if (send_sync()) {
- recno = 1;
- txtmode = 0;
- send_file(files.f_info, 1);
-
- if (mode != FULL)
- unlink(files.f_info);
-
- if (mode == TEXT) txtmode++;
- send_file(files.f_data, 1);
-
- txtmode = 0;
- send_file(files.f_rsrc, 0);
- }
- reset_tty();
- }
-
- find_files(filename, mode)
- char *filename;
- {
- int n, tdiff;
- struct stat stbuf;
-
- sprintf(files.f_data, "%s.data", filename);
- sprintf(files.f_rsrc, "%s.rsrc", filename);
-
- if (mode == FULL) {
- sprintf(files.f_info, "%s.info", filename);
- if (stat(files.f_info, &stbuf) != 0) {
- perror(files.f_info);
- cleanup(-1);
- }
- return;
- }
- else {
- strcpy(files.f_info, "#machdrXXXXXX");
- mktemp(files.f_info);
- }
-
- if (mode == RSRC) {
- strcpy(files.f_data, "/dev/null");
- if (stat(files.f_rsrc, &stbuf) != 0) {
- strcpy(files.f_rsrc, filename);
- if (stat(files.f_rsrc, &stbuf) != 0) {
- perror(files.f_rsrc);
- cleanup(-1);
- }
- }
- mh.m_datalen = 0;
- mh.m_rsrclen = stbuf.st_size;
- }
- else {
- strcpy(files.f_rsrc, "/dev/null");
- if (stat(files.f_data, &stbuf) != 0) {
- sprintf(files.f_data, "%s.text", filename);
- if (stat(files.f_data, &stbuf) != 0) {
- strcpy(files.f_data, filename);
- if (stat(files.f_data, &stbuf) != 0) {
- perror(files.f_data);
- cleanup(-1);
- }
- }
- }
- mh.m_datalen = stbuf.st_size;
- mh.m_rsrclen = 0;
- }
-
- if (mh.m_name[0] == '\0') {
- n = strlen(filename);
- if (n > NAMEBYTES) n = NAMEBYTES;
- strncpy(mh.m_name, filename, n);
- mh.m_name[n] = '\0';
- }
- }
-
- forge_info()
- {
- int n;
- char *np;
- FILE *fp;
-
- for (np = mh.m_name; *np; np++)
- if (*np == '_') *np = ' ';
-
- buf[H_NLENOFF] = n = np - mh.m_name;
- strncpy(buf + H_NAMEOFF, mh.m_name, n);
- strncpy(buf + H_TYPEOFF, mh.m_type, 4);
- strncpy(buf + H_AUTHOFF, mh.m_author, 4);
- put4(buf + H_DLENOFF, mh.m_datalen);
- put4(buf + H_RLENOFF, mh.m_rsrclen);
- put4(buf + H_CTIMOFF, mh.m_createtime);
- put4(buf + H_MTIMOFF, mh.m_modifytime);
- fp = fopen(files.f_info, "w");
- if (fp == NULL) {
- perror("temp file");
- cleanup(-1);
- }
- fwrite(buf, 1, DATABYTES, fp);
- fclose(fp);
- }
-
- send_sync()
- {
- int c;
-
- tputc(ESC);
- tputc('b');
-
- for (;;) {
-
- if ((c = tgetc(ACKTIMO)) == TMO)
- {
- return(0);
- }
-
- if (c == NAK)
- {
- return(1);
- }
-
- if (c == 'C') {
- crc++;
- return(1);
- }
- }
- }
-
- send_file(fname, more)
- char *fname;
- int more;
- {
- register int status, i, n;
- FILE *inf;
-
- inf = fopen(fname, "r");
- if (inf == NULL) {
- perror(fname);
- cleanup(-1);
- }
- for (;;) {
- n = fread(buf, 1, DATABYTES, inf);
- if (n > 0) {
- for (i = 0; i < RETRIES; i++) {
- send_rec(buf, DATABYTES);
- while ((status = tgetc(ACKTIMO)) != ACK && status != NAK && status != CAN);
- if (status != NAK)
- break;
- }
- if (status != ACK) {
- if (status != CAN)
- while ((status = tgetc(ACKTIMO)) != CAN);
- fclose(inf);
- cleanup(-1);
- /* NOTREACHED */
- }
- }
- if (n < DATABYTES) {
- if (!more) {
- tputc(EOT);
- tgetc(ACKTIMO);
- }
- return;
- }
- recno++;
- recno &= MAXRECNO;
- }
- }
-
- send_rec(buf, recsize)
- char buf[];
- int recsize;
- {
- int i, cksum;
- char *bp;
-
- if (txtmode || !crc) {
- cksum = 0;
- bp = buf;
- for (i = 0; i < recsize; i++, bp++) {
- if (txtmode && *bp == '\n')
- *bp = '\r';
- cksum += *bp;
- }
- }
-
- if (crc)
- cksum = calcrc(buf, recsize);
-
- tputc(SOH);
- tputc((char) recno);
- tputc((char) (MAXRECNO - recno));
- tputrec(buf, recsize);
-
- if (crc) {
- tputc((char) (cksum >> 8));
- tputc((char) cksum);
- } else
- tputc((char) cksum);
- }
-
- static int ttyfd;
- static FILE *ttyf;
- static jmp_buf timobuf;
-
- tgetc(timeout)
- int timeout;
- {
- int c;
-
- if (setjmp(timobuf))
- return TMO;
-
- alarm(timeout);
- c = getc(ttyf);
- alarm(0);
-
- if (c == -1) /* probably hung up or logged off */
- return EOT;
- else
- return c & BYTEMASK;
- }
-
- tputrec(buf, count)
- char *buf;
- int count;
- {
- write(ttyfd, buf, count);
- }
-
- tputc(c)
- char c;
- {
- write(ttyfd, &c, 1);
- }
-
- timedout()
- {
- signal(SIGALRM, timedout); /* for pre-4.2 systems */
- longjmp(timobuf, 1);
- }
-
- #ifdef SYSV
- static struct termio otty, ntty;
- #else
- static struct sgttyb otty, ntty;
- #endif
-
- /* should turn messages off */
-
- setup_tty()
- {
- int cleanup();
- int timedout();
-
- ttyf = stdin;
- ttyfd = fileno(stdout);
- #ifdef SYSV
- ioctl(ttyfd, TCGETA, &otty); /* get termio info */
- #else
- ioctl(ttyfd, TIOCGETP, &otty);
- #endif
- signal(SIGHUP, cleanup);
- signal(SIGINT, cleanup);
- signal(SIGQUIT, cleanup);
- signal(SIGTERM, cleanup);
- signal(SIGALRM, timedout);
- ntty = otty;
- #ifdef SYSV
- ntty.c_iflag = BRKINT; /* only interrupt on break */
- ntty.c_oflag = 0; /* no output processing */
- ntty.c_cflag |= CS8; /* 8 bit characters */
- ntty.c_lflag = 0; /* no echoing */
- ntty.c_cc[VEOF] = 1; /* "MIN" minimum chars before input */
- ntty.c_cc[VEOL] = 1; /* "TIME" maximum .1 secs before feed */
- ioctl(ttyfd, TCSETAF, &ntty); /* set mode and flush input */
- #else
- ntty.sg_flags = RAW;
- ioctl(ttyfd, TIOCSETP, &ntty);
- #endif
- }
-
- reset_tty()
- {
- if (ttyf != NULL) {
- #ifdef SYSV
- ioctl(ttyfd, TCSETAF, &otty); /* reset after output drains */
- #else
- sleep (5); /* wait for output to drain */
- ioctl(ttyfd, TIOCSETP, &otty);
- #endif
- }
- }
-
- cleanup(sig)
- int sig;
- {
- reset_tty();
- exit(sig);
- }
-
- put4(bp, value)
- char *bp;
- long value;
- {
- register int i, c;
-
- for (i = 0; i < 4; i++) {
- c = (value >> 24) & BYTEMASK;
- value <<= 8;
- *bp++ = c;
- }
- }
-
- int calcrc(ptr, count)
- char *ptr;
- int count;
- {
- int crc, i;
-
- crc = 0;
- while (--count >= 0) {
- crc ^= ((int) *ptr++) << 8;
- for (i = 0; i < 8; ++i)
- if (crc & 0x8000)
- crc = crc << 1 ^ 0x1021;
- else
- crc <<= 1;
- }
- return (crc & 0xFFFF);
- }
- @//E*O*F macbput.c//
- chmod u=rw,g=rw,o=rw macbput.c
-
- echo x - makefile
- sed 's/^@//' > "makefile" <<'@//E*O*F makefile//'
- # Makefile for Layers 1.0
-
- BIN = /usr/local
- MANDIR = /usr/local/manl
-
- PGM = layers
- PGM2 = layersize
- PGM3 = layertitle
- PGM4 = macbput
- MS = l
- CFLAGS = -O
- CFILES = layers.c protocol.c
- OFILES = layers.o protocol.o
-
- all: $(PGM) $(PGM2) $(PGM3) $(PGM4)
-
- $(PGM): $(OFILES)
- $(CC) $(CFLAGS) -o $(PGM) $(OFILES)
-
- # $(CC) $(CFLAGS) -o $(PGM) $(OFILES) -ltermcap
-
- layers.o: layers.c layers.h
- $(CC) $(CFLAGS) -c layers.c
-
- protocol.o: protocol.c layers.h
- $(CC) $(CFLAGS) -c protocol.c
-
- $(PGM2): layersize.o
- $(CC) $(CFLAGS) -o $(PGM2) layersize.o
-
- $(PGM3): layertitle.o
- $(CC) $(CFLAGS) -o $(PGM3) layertitle.o
-
- $(PGM4): macbput.o
- $(CC) $(CFLAGS) -o $(PGM4) macbput.o
-
- layersize.o: layersize.c
- $(CC) $(CFLAGS) -c layersize.c
-
- layertitle.o: layertitle.c
- $(CC) $(CFLAGS) -c layertitle.c
-
- macbput.o: macbput.c
- $(CC) $(CFLAGS) -c macbput.c
-
- install: $(PGM) $(PGM2) $(PGM3) $(PGM4)
- rm -f $(BIN)/$(PGM)
- install -c -s -o root -g daemon -m 4711 $(PGM) $(BIN)/$(PGM)
- install -c -s $(PGM2) $(BIN)/$(PGM2)
- install -c -s $(PGM3) $(BIN)/$(PGM3)
- # install -c -s $(PGM4) $(BIN)/$(PGM4)
-
- installnopriv: $(PGM) $(PGM2) $(PGM3) $(PGM4)
- rm -f $(BIN)/$(PGM)
- install -c -s $(PGM) $(BIN)/$(PGM)
- install -c -s $(PGM2) $(BIN)/$(PGM2)
- install -c -s $(PGM3) $(BIN)/$(PGM3)
- # install -c -s $(PGM4) $(BIN)/$(PGM4)
-
- manpage: layers.1
- rm -f $(MANDIR)/$(PGM).$(MS)
- cp layers.1 $(MANDIR)/$(PGM).$(MS)
- chmod 664 $(MANDIR)/$(PGM).$(MS)
-
- clean:
- rm -f a.out core $(PGM) $(PGM2) $(PGM3) $(PGM4) *.o
-
- shar: makefile
- shar README layers.1 makefile layers.h layers.c \
- protocol.c layersize.c layertitle.c MacLayers.sit.Hqx MacLayers.doc \
- macbput.c macbput.1 >layers.shar
- @//E*O*F makefile//
- chmod u=rw,g=rw,o=rw makefile
-
- echo x - protocol.c
- sed 's/^@//' > "protocol.c" <<'@//E*O*F protocol.c//'
- /* 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.
- *
- */
-
- #include <stdio.h>
- #include <signal.h>
- #include <errno.h>
- #include "layers.h"
-
- /* protocol.c - BSD MacLayers protocol driver */
-
- /* This module handles all interaction with the Macintosh MacLayers
- ** program. Services provided are:
- **
- ** InitLink() - initialize link to MacLayers
- **
- ** TopChannel() - return highest prority channel
- **
- ** SendNew() - request new layer channel of MacLayers
- **
- ** SendTitle() - change window title to given string (NOT IMPLENTED YET)
- **
- ** SendDelete()- tell MacLayers indicated layer has died
- **
- ** SendQuit() - order MacLayers to terminate layers mode
- **
- ** SendData() - send output to indicated channel's window
- **
- ** SendReshape() - send Shape structure to MacLayers
- **
- ** ProcessStreamin() - data is ready to be processed from MacLayers
- **
- */
-
- #define DUMPALL
- #undef DUMPALL
-
- /* C library calls */
- unsigned alarm(); /* alarm system call */
-
- static int GetData();
- static void Packet();
- static void Parse();
- static void AwaitInput();
- static void asciishape();
- static void fill4();
- static void fill2();
- static void fill1();
- static int parseshape();
- static unsigned get4();
- static unsigned get2();
- static unsigned get1();
-
- static char inbuff[IOSIZE]; /* input buffer from MacLayers */
- static char *inpos; /* current input position in buffer */
- static int insize = 0; /* characters left to process */
- static int Outstream = -1; /* current output stream channel */
- static int Instream = -1; /* current input stream channel */
-
- static struct Shape SNshape; /* SendNew() shape response */
- static int SNresp = 0; /* SendNew() reponse poll flag */
- static int SNchan = 0; /* SendNew() channel return */
- #define SN_WAITING -1000 /* SendNew() waiting response value */
-
- #define ATTRSIZE 15 /* size of window attribute string */
-
- #define FLUSH fflush(stdout)
-
-
- /* Initlink() - initialize link with MacLayers */
-
- /* Returns:
- ** 0 - linkup failed
- ** 1 - linkup successful, Maclayers now in protocol mode
- */
-
- int
- Initlink()
- {
- int Outstream = -1; /* no default stream yet */
- int Instream = -1; /* no default stream yet */
- int num1, num2, num3; /* scanf item result */
- int err; /* error code */
-
- #define WAITTIME 10 /* second wait response time */
- #define INITTIME 2 /* wait time after succesful startup */
-
- /* we must non-buffer input since all input must be immediate */
- setbuf(stdin, NULL); /* non-buffer all input */
-
- /* send intitial request for terminal type and version number */
- DO DEBUG("write: ESC [ c\n");
- if ((err=printf("\033[c")) < 0)
- {
- DO DEBUG(" printf() error code %d\n", err);
- return ( 0 ); /* problem with stdout */
- }
- FLUSH; /* force output buffer */
-
- /* attempt to read "ESC [ ? 8 ; typedigits ; versiondigits c" */
- num1 = num2 = num3 = -1; /* default to unsupplied values */
- (void) alarm(WAITTIME); /* set timeout */
- DO DEBUG(" doing first scanf\n");
- (void) scanf("\033[?%d;%d;%dc", &num1, &num2, &num3);
- (void) alarm(0); /* cancel alarm */
- DO DEBUG("read ESC [ ? %d ; %d; %d c\n", num1, num2, num3);
- if (num1 != 8 || num2 != 10)
- return ( 0 ); /* not correct response or layers term ID */
-
- /* ask terminal if ENC_ENABLE is to be forced */
- DO DEBUG("write: ESC [ F\n");
- (void) printf("\033[F");
- FLUSH; /* force output buffer */
- (void) alarm(WAITTIME); /* set timeout */
-
- /* attempt to read "ESC [ flag F" (flag indicates ENC_ENABLE status) */
- num1 = -1; /* default to invalid response */
- (void) scanf("\033[%dF", &num1);
- (void) alarm(0); /* cancel alarm */
- DO DEBUG("read ESC [ %d F\n", num1);
- if (num1 != 2 && num1 != 0)
- return ( 0 ); /* something's wrong */
-
- /* now startup packet mode in non ENC_ENABLE processing */
- DO DEBUG("write: ESC [ 2 ; 0 v\n");
- (void) printf("\033[2;0v"); /* "ESC [ 2 ; 0 v" */
- FLUSH; /* force output buffer */
-
- /* we are now in packet mode */
- sleep( INITTIME ); /* let Macintosh keep up with us */
- return ( 1 ); /* return successful startup */
-
- } /* Initlink() */
-
-
- /* TopChannel() - return highest prority channel */
-
- int
- TopChannel()
- {
- return ( Instream );
-
- } /* TopChannel() */
-
-
- /*
- ** WARNING: Most of the following functions may be recursively called
- ** as control commands are processed from the input stream
- */
-
-
- /* ProcessStreamin() - MacLayers has input to process */
-
- void
- ProcessStreamin()
- {
- int c; /* input character being processed */
-
- DO DEBUG("ProcessStreamin()\n");
-
- GetData(0); /* read some and don't timeout */
-
- while (insize > 0) /* while more data to process ... */
- Parse(); /* process next chuck of data */
-
- } /* ProcessStreamin() */
-
-
- /* SendNew() - request new layer channel from MacLayers */
-
- /* This command is unique in that it returns a response from MacLayers.
- ** To do this we continue processing the input stream until we get
- ** our return. (This leads to recursive conditions.) The variables
- ** 'SNresp', 'SNshape' and 'SNchan' are set when our reply is received.
- */
- int
- SendNew(shape)
- struct Shape *shape; /* shape to use for new window */
- {
- int i; /* attribute count variable */
- char astring[ATTRSIZE]; /* copy of attribute string */
-
- DO DEBUG("SendNew() new layer requested: '~%cA'\n", '1'+ATTRSIZE);
-
- /* check for a recursive call */
- if (SNresp == SN_WAITING)
- { DO DEBUG("return 0 - recursive call\n");
- return ( 0 ); /* return failure */
- }
-
- putchar(ESCAPE); /* send start of control packet char */
- putchar('1' + ATTRSIZE); /* send command size */
- putchar('A'); /* send command */
- asciishape(shape, astring); /* convert shape to string */
- for (i=0; i < ATTRSIZE; i++)
- putchar(astring[i]); /* send next attribute digit */
- FLUSH;
-
- /* now stay here and process the input stream until we see our response */
- /**** THIS SHOULD BE ENHANCED TO TIMEOUT WITH GetData() AND REISSUE REQUEST */
- SNresp = SN_WAITING; /* indicate we are waiting a response */
- while (SNresp == SN_WAITING)
- { DO DEBUG(" while (SNresp %d == %d)\n", SNresp, SN_WAITING);
- AwaitInput(); /* wait till input from MacLayers arrives */
- ProcessStreamin(); /* process available input */
- }
-
- if (SNresp == -1) /* if Maclayers rejected request */
- SNchan = 0; /* return failure channel of zero */
- else
- *shape = SNshape; /* else update shape structure */
-
- DO DEBUG("SendNew() returning channel %d\n", SNchan);
-
- return ( SNchan ); /* return the indicated channel */
-
- } /* SendNew() */
-
-
- /* SendReshape() - send to shape to MacLayers */
-
- void
- SendReshape(chan, shape)
- int chan; /* channel shape belongs to */
- struct Shape *shape; /* shape to use for new window */
- {
- int i; /* attribute count variable */
- char astring[ATTRSIZE]; /* copy of attribute string */
-
- DO DEBUG("SendReshape() reshape: '~%cA'\n", '2'+ATTRSIZE);
-
- if (chan <= 0 || chan > MAXPCHAN)
- { DO DEBUG("BAD CHANNEL!!!\n");
- return; /* ignore request */
- }
-
- putchar(ESCAPE); /* send start of control packet char */
- putchar('2' + ATTRSIZE); /* send command size */
- putchar('R'); /* send command */
- putchar(chan + '0'); /* send channel */
- asciishape(shape, astring); /* convert shape to string */
- DO DEBUG("shape: %.*s\n", ATTRSIZE, astring);
- for (i=0; i < ATTRSIZE; i++)
- putchar(astring[i]); /* send next attribute digit */
- FLUSH;
-
- } /* SendReshape() */
-
-
- /* SendTitle() - set layer's window title */
-
- void
- SendTitle(chan, buff, cnt)
- int chan; /* layer window ID */
- char *buff; /* new title string */
- int cnt; /* count of title length */
- {
- int i; /* work variable */
-
- DO DEBUG("SendTitle(chan%d, len %d, '%.*s')\n", chan, cnt, cnt, buff);
-
- if (chan <= 0 || chan > MAXPCHAN)
- { DO DEBUG("BAD CHANNEL!!!\n");
- return; /* ignore request */
- }
-
- if (cnt < 0)
- { DO DEBUG("BAD COUNT!!!\n");
- return; /* ignore request */
- }
-
- /* for now chop title size to 29 chars since that's MacLayer's limit */
- if (cnt > 29)
- cnt = 29; /* due to packet size limit */
-
- /* we must guarantee that the size will not appear to be another ESCAPE */
- if ('2' + cnt == ESCAPE)
- cnt--; /* truncate to avoid ESCAPE ESCAPE */
-
- putchar(ESCAPE); /* send start of control packet char */
- putchar('2' + cnt); /* send size of packet */
- putchar('T'); /* send command */
- putchar(chan + '0'); /* send channel ID */
- for (i=0; i<cnt; i++)
- putchar(buff[i]); /* send out title */
- FLUSH;
-
- } /* SendTitle() */
-
-
- /* SendDelete() - tell Maclayers layer died */
-
- void
- SendDelete(chan)
- int chan; /* dead channel ID */
- {
- DO DEBUG("SendDelete(%d) '~2D%d'\n", chan, chan);
-
- if (chan <= 0 || chan > MAXPCHAN) /* check channel ID */
- { DO DEBUG("BAD CHANNEL!!!\n");
- return; /* ignore request */
- }
-
- putchar(ESCAPE); /* send control packet start char */
- putchar('2'); /* send command size */
- putchar('D'); /* send command character */
- putchar(chan + '0'); /* channel ID in ascii */
- FLUSH;
-
- } /* SendDelete() */
-
-
- /* SendQuit() - order MacLayers to end layers mode */
-
- void
- SendQuit(chan)
- int chan; /* dead channel ID */
- {
- DO DEBUG("SendQuit() '~1E'\n");
-
- putchar(ESCAPE); /* send control packet start char */
- putchar('1'); /* send command size */
- putchar('E'); /* send command */
- FLUSH;
-
- } /* SendQuit() */
-
-
- /* SendData() - send output to layer's window */
-
- void
- SendData(chan, buff, cnt)
- int chan; /* layer window ID */
- unsigned char *buff; /* new title string */
- int cnt; /* count of title length */
- {
- unsigned c; /* output character being sent */
-
- DO
- { int dcnt;
-
- DEBUG("SendData(chan %d, len %d, '", chan, cnt, cnt, buff);
- for (dcnt=0; dcnt<cnt; dcnt++)
- DEBUG("%c", buff[dcnt]); /* dump each char so null doesn't stop */
- DEBUG("')\n");
- }
-
- if (chan <= 0 || chan > MAXPCHAN)
- { DO DEBUG("BAD CHANNEL!!!\n");
- return; /* ignore request */
- }
-
- /* if new output channel stream then prefix redirect command */
- if (chan != Outstream)
- { DO DEBUG("Redirecting output to %d '~2O%d'\n", chan, chan);
- putchar(ESCAPE); /* start of command sequence */
- putchar('2'); /* send command size */
- putchar('O'); /* send command */
- putchar(chan + '0'); /* put out channel in ASCII */
- Outstream = chan; /* new output stream set */
- }
-
- /* transmit the buffer converting the ESCAPE sequence to double ESCAPE */
- while (cnt--)
- { c = *buff++; /* get next output character */
- #ifdef DUMPALL
- DO DEBUG("outchar %c 0x%x\n", c, c);
- #endif
- if (c == ESCAPE || c == (ESCAPE + 0x80))
- { putchar(c); /* put it out twice */
- #ifdef DUMPALL
- DO DEBUG(" Doubled Escape!\n");
- #endif
- }
- putchar(c); /* write character out */
- }
-
- FLUSH; /* force out queued output characters */
-
- } /* SendData() */
-
-
- /* Parse() - process next chunk of input stream */
-
- static void
- Parse()
- {
- #define ST_NULL 0 /* not primed for next state yet */
- #define ST_STREAM 1 /* processing default stream input */
- #define ST_PKT 2 /* processing packet data */
-
- int c; /* input character being processed */
-
- static int state = ST_NULL; /* current input state */
- static int psize = 0; /* packet size */
- static int rempsize = 0; /* remembered packet size */
- static char pdata[MAXSTR]; /* area for packet data */
- static char *ppos; /* packet read insert position */
- static int escapemode = 0; /* processing escape character */
- static int escapechar; /* escape character being processed */
- static pchan = -1; /* packet input stream channel */
-
- while (insize-- > 0) /* while more data */
- { c = *inpos++; /* get next character */
- switch (state) /* process according to state */
- { case ST_NULL: /* prepare for new packet */
- DO DEBUG("ST_NULL\n");
- psize = 0; /* clear packet size */
- ppos = pdata; /* start fill at data position */
- pchan = Instream; /* packet channel is current input stream */
- state = ST_STREAM; /* default is stream processing */
-
- case ST_STREAM:
- /* stream keyboard input for layer */
- /* check for escape char with possible high bit on */
- #ifdef DUMPALL
- DO DEBUG("ST_STREAM %x/%x esc %d insz %d\n",
- c, c & 0x7f, escapemode, insize);
- #endif
- if (c == ESCAPE || c == (ESCAPE | 0x80))
- { if (escapemode && c == escapechar) /* previous was ESCAPE */
- /* this is really a single ESCAPE character */
- escapemode = 0; /* back out of ESCAPE mode */
- else
- /* what do we do with back to back esc esc+0x80 ? */
- { /* flag in escape mode */
- escapemode++;
- escapechar = c; /* remember character used for escape */
- continue; /* and continue scan */
- }
- }
- else
- if (escapemode)
- { /* this is the start of a control packet */
- if (psize) /* if we have previous data packet */
- Packet(pchan, psize, pdata); /* finish up previous pkt */
- /* process packet size */
- psize = (c & 0x7f) - '0'; /* save size byte */
- if (psize <= 0 || psize > MAXSTR)
- { /* bad size */
- DO DEBUG("Bad pkt size %d\n", psize);
- break; /* trash this packet */
- }
- rempsize = psize; /* remember this size for later */
- #if 0
- ptimo = rtimo; /* start receive timeout */
- #endif
- escapemode = 0; /* escape mode now off */
- ppos = pdata; /* initialize data store pointer */
- state = ST_PKT; /* expect packet data next */
- continue; /* continue scan */
- }
-
- /* process standard data output character for current stream */
-
- *ppos++ = c; /* save next data character */
-
- if (++psize >= MAXSTR) /* if packet full ... */
- { Packet(pchan, psize, pdata); /* process this packet */
- break; /* end packet processing */
- }
- continue; /* continue scan */
-
- case ST_PKT:
- /* process next paket data byte */
- *ppos++ = c & 0x7f; /* store next data byte */
- #ifdef DUMPALL
- DO DEBUG("ST_PKT: %x sz %d\n", c & 0x7f, psize);
- #endif
- if (--psize != 0)
- continue;
- #if 0
- if (crc((unsigned char *) &rpkt, rpkt.pkt.HEADER_DSIZE+2))
- STATS(Scrcerr); /* communications error */
- else
- #endif
- Packet(0, rempsize, pdata); /* process it */
-
- } /* end build packet switch */
-
- #if 0
- ptimo = 0; /* no more receive timeout */
- #endif
- state = ST_NULL; /* no more receive packet in progress */
-
- } /* end while (insize) */
-
- if (state == ST_STREAM && psize ) /* if we have some data ... */
- { Packet(Instream, psize, pdata); /* process this data */
- #if 0
- ptimo = 0; /* no more receive timeout */
- #endif
- state = ST_NULL; /* no more receive packet in progress */
- }
-
- } /* Parse() */
-
-
- /* Packet() - prcess next input data string or control packet */
- static void
- Packet(chan, size, buff)
- int chan; /* channel (0 if control packet) */
- int size; /* amount of data */
- char *buff; /* pointer to packet data */
- {
- static struct Shape shape; /* Shape structure */
-
- DO DEBUG("Packet(chan %d, size %d, '%.*s')\n", chan, size, size, buff);
-
- /* verify channel */
- if (chan < 0 || chan > MAXPCHAN)
- { DO DEBUG("BAD CHANNEL!!\n");
- return; /* ignore bad channel */
- }
-
- /* if data packet (chan>0) feed data to server */
- if (chan > 0)
- { ReceiveData(chan, buff, size);
- return; /* we are through */
- }
-
- /* control packet (channel 0) */
- chan = buff[1] - '0'; /* assume channel specified */
- if (chan < 0 || chan > MAXPCHAN) /* if invalid ... */
- chan = 0; /* set to zero */
-
- switch (buff[0])
- { case 'I': /* redirect stream */
- DO DEBUG("CMD 'I' redirect stream to %c\n", buff[1]);
- if (size != 2) /* verify size */
- break; /* break if bad */
- if (chan == 0) /* verify channel */
- break; /* break if bad */
- Instream = chan; /* new instream channel */
- return; /* we are through */
-
- case 'A': /* returned A_NEWLAYER packet */
- DO DEBUG("CMD 'A' A_NEWLAYER response %c newchan %c SNresp %d\n",
- buff[2], buff[1], SNresp);
- if (size != 3 + ATTRSIZE)
- break; /* break if bad */
-
- /* if SendNew() not waiting for a response this is invalid */
- if (SNresp != SN_WAITING)
- break; /* break if bad */
-
- if (buff[2] == '1') /* if response is "failed" ... */
- SNresp = -1; /* show -1 response */
- else
- if (buff[2] == '0') /* if response is "success" ... */
- { if (chan == 0) /* if invalid channel */
- break; /* break if bad */
- /* build shape structure for SendNew() */
- if (parseshape(&SNshape, &buff[3]) == -1)
- break; /* if invalid data then bad packet */
- SNresp = 0; /* show good response */
- SNchan = chan; /* indicate channel returned */
- }
- else
- break; /* break if bad */
-
- DO DEBUG("SNresp = %d, SNchan = %d\n", SNresp, SNchan);
- return; /* we are through */
-
- case 'N': /* new layer creation */
- DO DEBUG("CMD 'N' new layer creation newchan %c\n", buff[1]);
- if (size != 2 + ATTRSIZE) /* verify size */
- break; /* break if bad */
- if (chan == 0) /* verify channel */
- break; /* break if bad */
- /* build shape structure */
- if (parseshape(&shape, &buff[2]) == -1)
- break; /* if invalid data then bad packet */
- ReceiveNew(chan, &shape); /* pass to server */
- return; /* packet is done */
-
- case 'D': /* deleted layer */
- DO DEBUG("CMD 'D' deleted layer %c\n", buff[1]);
- if (size != 2) /* verify size */
- break; /* break if bad */
- if (chan == 0) /* verify channel */
- break; /* break if bad */
- ReceiveDelete(chan); /* pass on to server */
- return; /* packet is done */
-
- case 'E': /* exit - awaiting shutdown */
- DO DEBUG("CMD 'E' exit MacLayers awaiting shutdown msg\n");
- if (size != 1) /* verify size */
- break; /* break if bad */
- ReceiveQuit(); /* pass to server */
- /* NOT REACHED*/
- return; /* ?? should never reach here */
-
- case 'R': /* reshaped */
- DO DEBUG("CMD 'R' reshape chan %c\n", buff[1]);
-
- if (size != 2 + ATTRSIZE) /* verify size */
- break; /* break if bad */
-
- if (chan == 0) /* verify channel */
- break; /* break if bad */
-
- /* build shape structure */
- if (parseshape(&shape, &buff[2]) == -1)
- break; /* if invalid data then bad packet */
-
- ReceiveReshape(chan, &shape); /* tell server about shape */
- return; /* packet processed */
-
- case 'S': /* signal */
- DO DEBUG("CMD 'S' SIGNAL chan %c sig %c\n", buff[1], buff[2]);
- if (size != 3) /* verify size */
- break; /* break if bad */
- if (chan == 0)
- break; /* break if bad */
-
- if (buff[2] == '0') /* if SIGINT */
- size = SIGINT; /* yes */
- else
- if (buff[2] == '1') /* if SIGHUP */
- size = SIGHUP; /* yes */
- else
- break; /* invalid signal */
-
- ReceiveSignal(chan, size); /* pass to server */
- return; /* packet processed */
-
- default:
- DO DEBUG("ILLEGAL CONTROL PACKET!!!\n");
- return; /* ignore bad packet */
-
- } /* end command packet switch */
-
- /* switch falls out if bad size or channel for given command */
- DO DEBUG("Invalid size or channel!!!\n"); /* dump error */
- return; /* ignore packet */
-
- } /* Packet() */
-
-
- /* GetData() - read next input from MacLayers stream */
-
- /* An input timout parameter can indicate that we return if nothing
- ** is read within a certain amount of seconds. The return code is:
- **
- ** 0 - timeout occured and no data was read
- **
- ** 1 - no timeout occured, data read
- */
- static int
- GetData(timeout)
- int timeout; /* timeout in seconds (or zero) */
- {
- int result; /* return from read() */
-
- DO DEBUG("GetData(timout %d)\n", timeout);
-
- /* if buffer still has data simply return (SHOULD NOT OCCUR?) */
- if (insize > 0)
- return ( 1 ); /* act as through data read */
- inpos = inbuff; /* next get will start at beginning */
- insize = 0; /* default insize back to zero */
-
- /* set timeout if we are to do so */
- if (timeout)
- (void) alarm(timeout); /* set timeout in seconds */
-
- /* do the read from stdin */
- result = read(0, inbuff, IOSIZE);
-
- /* if alarm was set cancel it now */
- if (timeout)
- (void) alarm(0); /* cancel alarm */
-
- /* check for timeout or error */
- /* EWOULDBLOCK for no data avail -(but we should not see this) */
- /* EINTR if signal stopped the read -(rare but could happen) */
- if (result <= 0)
- return ( 0 ); /* return nothing read */
-
- /* return with fresh buffer data */
- insize = result;
- DO DEBUG("read %d bytes\n", insize);
- return ( 1 ); /* return OK code */
-
- } /* GetData() */
-
-
- /* AwaitInput() - wait for more input from MacLayers */
-
- static void
- AwaitInput()
- {
- int r; /* read descriptor bits */
-
- DO DEBUG("AwaitInput()\n");
-
- do
- { r = 1<<0; /* wait for read from input device */
- if (select(32, &r, NULL, NULL, NULL) == -1) /* if problem waiting ... */
- { if (errno != EINTR) /* if not simply signal taken ... */
- { /* SHOULD NOT OCCUR - shutdown layers */
- DO DEBUG("AwaitInput: select error %d\n", errno);
- printf("layers: AwaitInput: bad select %d\n", errno);
- FQuit(); /* shutdown layers */
- /* NOT REACHED */
- }
- }
- } while ((r & 1<<0) == 0);
-
- } /* AwaitInput() */
-
- /* asciishape() - convert Shape structure to ASCII */
- static void
- asciishape(shape, loc)
- struct Shape *shape; /* Shape structure for channel */
- char *loc; /* location to start filling result */
- {
- char *origloc; /* (for debuggin) */
-
- origloc = loc; /* remember start of string */
- fill4(&loc, shape->worigh); /* origin h */
- fill4(&loc, shape->worigv); /* origin v */
- fill2(&loc, shape->wlines); /* lines high */
- fill2(&loc, shape->wchars); /* chars wide */
- fill1(&loc, shape->wfont); /* font size */
- fill2(&loc, shape->wattr); /* attributes */
-
- DO DEBUG("asciishape(): %.*s\n", ATTRSIZE, origloc);
-
- } /* asciishape() */
-
-
- /* fill4() - convert parameter to ASCII */
-
- static void
- fill4(loc, valu)
- char **loc; /* pointer to fill area pointer */
- unsigned valu; /* value to use */
- {
- fill2(loc, valu>>8); /* fill high half word */
- fill2(loc, valu & 0xff); /* fill low half word */
-
- } /* fill4() */
-
-
- /* fill2() - convert parameter to ASCII */
-
- static void
- fill2(loc, valu)
- char **loc; /* pointer to fill area pointer */
- unsigned valu; /* value to use */
- {
- fill1(loc, valu>>4); /* fill high byte */
- fill1(loc, valu & 0xf); /* fill low byte */
-
- } /* fill2() */
-
-
- /* fill1() - convert parameter to ASCII */
-
- static void
- fill1(loc, valu)
- char **loc; /* pointer to fill area pointer */
- unsigned valu; /* value to use */
- {
- *(*loc)++ = "0123456789ABCDEF"[valu & 0xf]; /* return hex value */
-
- } /* fill1() */
-
-
- /* parseshape() - convert ASCII image to Shape structure */
-
- static int Badconvert; /* indicates bad conversion */
-
- static int
- parseshape(shape, loc)
- struct Shape *shape; /* Shape structure for channel */
- char *loc; /* location to start parsing */
- {
- Badconvert = 0; /* clear bad characters indicator */
- shape->worigh = get4(&loc); /* origin h */
- shape->worigv = get4(&loc); /* origin v */
- shape->wlines = get2(&loc); /* lines high */
- shape->wchars = get2(&loc); /* chars wide */
- shape->wfont = get1(&loc); /* font size */
- shape->wattr = get2(&loc); /* attributes */
-
- DO DEBUG("ParseShape(): origv %d, origh %d, lines %d, chars %d\n",
- shape->worigv, shape->worigh, shape->wlines, shape->wchars);
- DO DEBUG(" font %d, attr 0x%x, badconv %d\n",
- shape->wfont, shape->wattr, Badconvert);
-
- return ( Badconvert ? -1 : 0 ); /* return conversion code */
-
- } /* parseshape() */
-
-
- /* get4() - convert ASCII to parameter */
-
- static unsigned
- get4(loc)
- char **loc; /* pointer to fill area pointer */
- {
- unsigned hi; /* high portion */
- unsigned low; /* low portion */
-
- hi = get2(loc); /* get high byte */
- low = get2(loc); /* get low byte */
-
- return ( (hi<<8) + low ); /* return word value */
-
- } /* get4() */
-
-
- /* get2() - convert ASCII to parameter */
-
- static unsigned
- get2(loc)
- char **loc; /* pointer to fill area pointer */
- {
- unsigned hi; /* high portion */
- unsigned low; /* low portion */
-
- hi = get1(loc); /* get high half */
- low = get1(loc); /* get low half */
-
- return ( (hi<<4) + low ); /* return byte value */
-
- } /* get2() */
-
-
- /* get1() - convert ASCII to parameter */
-
- /* This function sets 'Badconvert' if an invalid character is detected */
-
- static unsigned
- get1(loc)
- char **loc; /* pointer to fill area pointer */
- {
- int c; /* character to convert */
-
- c = *(*loc)++; /* fetch character */
-
- if (c >= '0' && c <= '9')
- /* zero through nine */
- return ( c - '0' ); /* return it's binary value */
-
- if (c >= 'a' && c <= 'f')
- /* lower case hex */
- return ( c - 'a' + 10); /* return it's binary value */
-
- if (c >= 'A' && c <= 'F')
- /* upper case hex */
- return ( c - 'A' + 10); /* return it's binary value */
-
- /* invalid digit! */
- Badconvert++; /* set bad character flag */
- return ( 0 ); /* return a zero */
-
- } /* get1() */
- @//E*O*F protocol.c//
- chmod u=rw,g=rw,o=rw protocol.c
-
- echo Inspecting for damage in transit...
- temp=/tmp/shar$$; dtemp=/tmp/.shar$$
- trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
- cat > $temp <<\!!!
- 62 290 2241 README
- 123 795 4858 layers.1
- 2213 8497 56819 layers.c
- 64 311 2049 layers.h
- 146 589 3586 layersize.c
- 41 176 1242 layertitle.c
- 122 506 2849 macbput.1
- 529 1341 9383 macbput.c
- 71 212 1674 makefile
- 869 4181 25546 protocol.c
- 4240 16898 110247 total
- !!!
- wc README layers.1 layers.c layers.h layersize.c layertitle.c macbput.1 macbput.c makefile protocol.c | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
- if [ -s $dtemp ]
- then echo "Ouch [diff of wc output]:" ; cat $dtemp
- else echo "No problems found."
- fi
- exit 0
-
-