home *** CD-ROM | disk | FTP | other *** search
Text File | 1988-06-23 | 33.3 KB | 1,315 lines |
- # Then run the rest of the file through sh.
- #----cut here-----cut here-----cut here-----cut here----#
- #!/bin/sh
- # shar: Shell Archiver
- # Run the following text with /bin/sh to create:
- # README
- # Makefile
- # openpty.c
- # uw.c
- # uwtool.c
- # openpty.h
- # uw.h
- # This archive created: Mon Jan 25 09:35:02 1988
- # By: Patrick White (PUCC Land, USA)
- echo shar: extracting README '(4555 characters)'
- cat << \SHAR_EOF > README
- The program "uw" is a multiple-window terminal emulator for the
- Macintosh(tm) computer. It is designed for use with a 4.2BSD
- UNIX(tm) system. Up to seven independent windows may be created,
- each of which is connected to a pseudo-terminal on the UNIX machine.
- A server program which runs on the UNIX host multiplexes the input
- and output for these terminal sessions onto a single RS-232 serial
- line.
-
- UW requires the following:
-
- a Macintosh
- a 4.2BSD UNIX host
- the "uw" program for the Macintosh
- the "uw" server for the UNIX host
- the "uwtool" program for the UNIX host (optional)
- the RAM serial driver (resource SERD, ID=1) (optional)
-
- At the present time, UW emulates a Lear Siegler ADM-31 terminal,
- a DEC VT52, and a Tektronix 4010.
-
- All portions of UW are copyrighted 1985 by John D. Bruner.
- Permission to copy is given provided that the copy is not sold
- and the copyright notices are included.
-
- UW was designed to use the RAM serial driver from the Apple software
- supplement. Since this driver is proprietary Apple software, it is
- not distributed with UW. For this reason, UW will use the ROM
- serial driver if the RAM serial driver is not present, and it will
- attempt to provide flow control itself. The flow control provided
- in this fashion is not as effective as that which the RAM serial
- driver provides, so use of the RAM driver is recommended if it is
- available.
-
- The distribution includes:
-
- README - this file
- Makefile - to be used to compile the 4.2BSD programs
- uw.h - include file (describes the simple serial protocol)
- uw.c - source for the 4.2BSD server program
- uwtool.c - source for a 4.2BSD "tool" program
- openpty.c - source for a utility routine to find and open pty's
- openpty.h - include file (describes a structure used by openpty())
- macmouse.ml - mlisp functions for use with (Unipress) Emacs
- uw.hqx - Binhex 4.0 binary for the Macintosh
- uw.doc.hqx - Binhex 4.0 MacWrite documentation
-
-
- Changes to UW
- -------------
-
- This is UW version 2.10. The last distributed version was 1.6.
-
- A number of changes have been made to the Macintosh portion of UW.
- Some of the more significant ones are
-
- 1) Configuration files: A number of parameters such as the
- baud rate, parity, number of stop bits, keyboard mapping,
- etc. can be saved to and reloaded from a configuration
- file.
-
- 2) Terminal emulations: In addition to an ADM31 emulation,
- UW also can emulate the VT52 and Tektronix 4010. (The
- VT52 emulation is provisional and may be replaced by a
- VT100 emulation in a future version of UW.) The terminal
- emulation is selectable on a per-window basis.
-
- 3) Clipboard: Desk accessories may use all of the standard
- clipboard functions. Text may be copied from a UW window
- onto the clipboard, and text in the clipboard may be
- pasted into a window.
-
- 4) Mouse clicks: As an alternative to the clipboard, mouse
- (up/down) events within a window may be translated into an
- escape sequence and transmitted as input data to the host.
- This provides a rudimentary facility for (e.g.) EMACS to
- use mouse input. The use of mouse-to-host or clipboard
- copying is selectable on a per-window basis.
-
- 5) Multiple fonts: In addition to the standard 9-point Monaco
- font, UW will also use a 7-point font. The font size is
- selectable on a per-window basis.
-
- 6) Inverse video: Inverse video was not implemented in the
- previous version of UW. It is now supported for the ADM31.
-
- 7) Window renaming: Window titles may be changed (on the
- Macintosh).
-
- In conjunction with (4) above, Chris Kent at Purdue (cak@purdue)
- has written mlisp code for Goslings Emacs which interprets the
- mouse-event encoding that UW can optionally provide. He has
- given his permission for his file "macmouse.ml" to be included
- in this distribution.
-
- There are no changes in the Mac-host interface (although some plans
- are being made in this area). Thus, one of the most-requested
- features, file transfer, is not implemented (yet).
-
- Of course, bugs in the previous version have been fixed (most notably
- some that dealt with scrolling). Almost certainly new bugs have been
- introduced to take the place of those which were expunged.
-
- Since some of the changes are rather significant (and a couple,
- like the method of selecting text to copy to the clipboard, are
- slightly non-standard), the updated documentation is recommended
- reading for all UW users.
-
- UW is much larger than it was before. Extensive use of the
- Tektronix 4010 emulation will almost certainly exhaust memory
- on a 128K Macintosh.
- SHAR_EOF
- if test 4555 -ne "`wc -c README`"
- then
- echo shar: error transmitting README '(should have been 4555 characters)'
- fi
- echo shar: extracting Makefile '(156 characters)'
- cat << \SHAR_EOF > Makefile
- CC = /bin/cc
- CFLAGS = -O
-
- all: uw uwtool
-
- uw: uw.o openpty.o
- $(CC) -o uw uw.o openpty.o
-
- uwtool: uwtool.o openpty.o
- $(CC) -o uwtool uwtool.o openpty.o
- SHAR_EOF
- if test 156 -ne "`wc -c Makefile`"
- then
- echo shar: error transmitting Makefile '(should have been 156 characters)'
- fi
- echo shar: extracting openpty.c '(3914 characters)'
- cat << \SHAR_EOF > openpty.c
- /*
- * openpty - open a pseudo-terminal
- *
- * The first time that the routine is called, the device directory is
- * searched and a list of all candidate pseudo-terminals is compiled.
- * Candidates are defined to be those entries in "/dev" whose names
- * (1) are the same length as PTY_PROTO and (2) start with the
- * initial string PTY_PREFIX. Further, the master and slave sides
- * must both exist.
- *
- * openpty() attempts to find an unused pseudo-terminal from the list
- * of candidates. If one is found, the master and slave sides are
- * opened and the file descriptors and names of these two devices are
- * returned in a "ptydesc" structure. (The address of this structure
- * is supplied by the caller. Zero is returned if openpty() was
- * successful, -1 is returned if no pty could be found.
- */
-
- #include <sys/types.h>
- #include <sys/dir.h>
- #include <fcntl.h>
- #include <strings.h>
- #include "openpty.h"
-
- #define DEV_DIR "/dev" /* directory where devices live */
- #define PT_INDEX (sizeof DEV_DIR) /* location of 'p' in "pty" */
-
- #define PTY_PROTO "ptyp0" /* prototype for pty names */
- #define PTY_PREFIX "pty" /* prefix required for name of pty */
-
- struct ptyinfo {
- struct ptyinfo *pi_next;
- char *pi_pty;
- char *pi_tty;
- };
-
- static struct ptyinfo *ptylist;
-
- extern char *malloc();
-
- static
- char *
- devname(name)
- char *name;
- {
- register char *fullname;
-
- /*
- * Construct the full name of a device in DEV_DIR. Returns
- * NULL if it failed (because malloc() failed).
- */
-
- fullname = malloc((unsigned)(sizeof DEV_DIR + 1 + strlen(name)));
- if (fullname != NULL) {
- (void)strcpy(fullname, DEV_DIR);
- (void)strcat(fullname, "/");
- (void)strcat(fullname, name);
- }
- return(fullname);
- }
-
- static
- isapty(dp)
- struct direct *dp;
- {
- static struct ptyinfo *pi;
-
- /*
- * We don't care about the gory details of the directory entry.
- * Instead, what we really want is an array of pointers to
- * device names (with DEV_DIR prepended). Therefore, we create
- * this array ourselves and tell scandir() to ignore every
- * directory entry.
- *
- * If malloc() fails, the current directory entry is ignored.
- */
-
- if (pi == NULL &&
- (pi = (struct ptyinfo *)malloc((unsigned)sizeof *pi)) == NULL)
- return(0);
-
- if (strlen(dp->d_name) == sizeof PTY_PROTO - 1 &&
- strncmp(dp->d_name, PTY_PREFIX, sizeof PTY_PREFIX - 1) == 0) {
- pi->pi_pty = devname(dp->d_name);
- if (pi->pi_pty == NULL)
- return(0);
- pi->pi_tty = malloc((unsigned)(strlen(pi->pi_pty) + 1));
- if (pi->pi_tty == NULL) {
- free(pi->pi_pty);
- return(0);
- }
- (void)strcpy(pi->pi_tty, pi->pi_pty);
- pi->pi_tty[PT_INDEX] = 't';
- if (access(pi->pi_pty, 0) == 0 && access(pi->pi_tty, 0) == 0) {
- pi->pi_next = ptylist;
- ptylist = pi;
- pi = NULL;
- } else {
- free(pi->pi_pty);
- free(pi->pi_tty);
- }
- }
- return(0);
- }
-
- openpty(pt)
- struct ptydesc *pt;
- {
- register struct ptyinfo *pi;
- static int fail;
- auto struct direct **dirlist;
- extern char *re_comp();
- extern int alphasort();
-
- /*
- * If the regular expression PTY_PROTO is bad, scandir() fails, or
- * no possible pty's are found, then "fail" is set non-zero. If
- * "fail" is non-zero then the routine bombs out immediately.
- * Otherwise, the list of candidates is examined starting with the
- * entry following the last one chosen.
- */
-
- if (fail)
- return(-1);
-
- if (!ptylist) { /* first time */
- if (scandir(DEV_DIR, &dirlist, isapty, alphasort) < 0 ||
- ptylist == NULL) {
- fail = 1;
- return(-1);
- }
- for (pi=ptylist; pi->pi_next; pi=pi->pi_next)
- ;
- pi->pi_next = ptylist; /* make the list circular */
- }
-
- pi = ptylist;
- do {
- if ((pt->pt_pfd = open(pi->pi_pty, O_RDWR)) >= 0) {
- if ((pt->pt_tfd = open(pi->pi_tty, O_RDWR)) >= 0) {
- ptylist = pi->pi_next;
- pt->pt_pname = pi->pi_pty;
- pt->pt_tname = pi->pi_tty;
- return(0);
- } else
- (void)close(pt->pt_pfd);
- }
- pi = pi->pi_next;
- } while (pi != ptylist);
- return(-1);
- }
- SHAR_EOF
- if test 3914 -ne "`wc -c openpty.c`"
- then
- echo shar: error transmitting openpty.c '(should have been 3914 characters)'
- fi
- echo shar: extracting uw.c '(17598 characters)'
- cat << \SHAR_EOF > uw.c
- #
-
- /*
- * uw - UNIX windows program for the Macintosh (VAX end)
- *
- * Copyright 1985 by John D. Bruner. All rights reserved. Permission to
- * copy this program is given provided that the copy is not sold and that
- * this copyright notice is included.
- */
-
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/socket.h>
- #include <sys/ioctl.h>
- #include <sys/wait.h>
- #include <sys/time.h>
- #include <sys/resource.h>
- #include <sys/uio.h>
- #include <signal.h>
- #include <setjmp.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <strings.h>
- #include <stdio.h>
- #include "uw.h"
- #include "openpty.h"
-
- #define MAXENV 128 /* maximum environment size */
-
- #define W_IN 0
- #define W_OUT 1
-
- #define XON 0021 /* ASCII XON */
- #define XOFF 0023 /* ASCII XOFF */
- #define RUB 0177 /* ASCII RUBOUT */
-
- #define META 0200 /* "meta" bit for whatever it's worth */
-
- #define RCV_OK (-1) /* see recvcmd() */
- #define RCV_META (-2) /* see recvcmd() */
-
- #ifndef FD_SET
- #define FD_SET(n,p) ((p)->fds_bits[0] |= (1 << (n)))
- #define FD_CLR(n,p) ((p)->fds_bits[0] &= ~(1 << (n)))
- #define FD_ISSET(n,p) ((p)->fds_bits[0] & (1 << (n)))
- #define FD_ZERO(p) ((p)->fds_bits[0] = 0)
- #endif
-
- typedef int fildes_t; /* file descriptor data type */
- typedef int nwin_t; /* window index data type */
-
- struct window {
- fildes_t w_fd;
- char w_tty[32];
- };
-
- struct window window[NWINDOW]; /* window data structures */
- struct window **fdmap; /* mapping from fd's to windows */
- struct window *curwin[2]; /* current input and output windows */
- fildes_t nfds; /* number of file descriptors */
-
- char portal[] = "/tmp/uwXXXXXX"; /* UNIX-domain network address */
-
-
- /* The following are added to the environment of all child processes */
-
- char env_uwin[64] = "UWIN=";
- char *env[] = {
- env_uwin,
- "TERM=adm31",
- "TERMCAP=adm31:cr=^M:do=^J:nl=^J:al=\\EE:am:le=^H:bs:ce=\\ET:cm=\\E=%+ %+ :cl=^Z:cd=\\EY:co#80:dc=\\EW:dl=\\ER:ei=\\Er:ho=^^:im=\\Eq:li#24:mi:nd=^L:up=^K:MT:km:so=\\EG1:se=\\EG0:",
- NULL
- };
-
- int ctlch[] = { -1, IAC, XON, XOFF, -1, -1, -1, -1 }; /* CTL char mapping */
-
- struct selmask {
- struct fd_set sm_rd;
- struct fd_set sm_wt;
- struct fd_set sm_ex;
- } selmask[2];
-
- extern char *mktemp();
- extern char *getenv();
- extern char *malloc();
- extern done(), cwait();
- extern int errno;
-
- main(argc, argv)
- char **argv;
- {
- register fildes_t fd, sd;
- register struct window *w;
- struct sockaddr sa;
-
- /*
- * Make sure we don't accidentally try to run this inside itself.
- */
- if (getenv("UWIN")) {
- fprintf(stderr, "%s is already running\n", *argv);
- exit(1);
- }
-
- /*
- * Close all file descriptors except 0, 1, and 2.
- */
- nfds = getdtablesize();
- for (fd=3; fd < nfds; fd++)
- (void)close(fd);
-
- /*
- * Allocate "fdmap". We can't do this at compile time because
- * we get the number of file descriptors from getdtablesize().
- */
- if (!(fdmap=(struct window **)malloc(nfds*sizeof(struct window *)))) {
- fprintf(stderr, "cannot allocate 'fdmap' array\n");
- exit(1);
- }
-
- /*
- * Mark all windows closed.
- */
-
- for (w=window; w < window+NWINDOW; w++)
- w->w_fd = -1;
-
-
- /*
- * Create a UNIX-domain network address, and put its name into
- * the environment so that descendents can contact us with new
- * window requests.
- */
-
- (void)strncat(env_uwin, mktemp(portal), sizeof env_uwin - 1);
- setenv(env);
-
- if ((sd=socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
- perror("socket");
- exit(1);
- }
- sa.sa_family = AF_UNIX;
- (void)strncpy(sa.sa_data, portal, sizeof sa.sa_data-1);
- sa.sa_data[sizeof sa.sa_data-1] = '\0';
- if (bind(sd, &sa, sizeof sa.sa_family + strlen(sa.sa_data)) < 0) {
- perror("bind");
- exit(1);
- }
- if (fcntl(sd, F_SETFL, FNDELAY))
- perror("fcntl(sd, F_SETFL, FNDELAY)");
-
-
- /*
- * Ignore interrupts, quits, and terminal stops. Clean up and exit
- * if a hangup or termination is received. Also catch changes in
- * child status (so that we can wait for them). Set up the terminal
- * modes.
- */
-
- (void)signal(SIGHUP, done);
- (void)signal(SIGINT, SIG_IGN);
- (void)signal(SIGQUIT, SIG_IGN);
- (void)signal(SIGTERM, done);
- (void)signal(SIGTSTP, SIG_IGN);
- (void)signal(SIGCHLD, cwait);
-
- tmode(1);
-
-
- /*
- * Tell the Macintosh to initialize. Initialize the current input
- * and output windows to NULL.
- */
-
- xmitcmd(CB_FN_MAINT|CB_MF_ENTRY);
- curwin[W_IN] = curwin[W_OUT] = NULL;
-
-
- /*
- * Initialize the "select" masks, create window 1 (to start
- * things off) and wait for input. When input is available,
- * process it.
- */
-
- FD_ZERO(&selmask[0].sm_rd);
- FD_ZERO(&selmask[0].sm_wt);
- FD_ZERO(&selmask[0].sm_ex);
-
- FD_SET(0, &selmask[0].sm_rd);
- FD_SET(sd, &selmask[0].sm_rd);
-
- if (newwind(window) == 0)
- xmitcmd(CB_FN_NEWW|1);
-
- while (1) {
- selmask[1] = selmask[0];
- if (select(nfds, &selmask[1].sm_rd, &selmask[1].sm_wt,
- &selmask[1].sm_ex, (struct timeval *)0) < 0) {
- if (errno == EINTR)
- continue;
- perror("select");
- done(1); /* for now -- fix this! */
- }
- for (fd=0; fd < nfds; fd++) {
- if (FD_ISSET(fd, &selmask[1].sm_rd)) {
- if (fd < 2)
- mrecv();
- else if (fd == sd)
- netrecv(sd);
- else
- mxmit(fd);
- }
- }
- }
- }
-
- mrecv()
- {
- register int len;
- register char *cp, *cq;
- auto int nready;
- char ibuf[512], obuf[512];
- static int seen_iac, seen_meta;
-
- /*
- * The received bytestream is examined. Non-command bytes are
- * written to the file descriptor corresponding to the current
- * "input" window (relative to the Macintosh -- the window the
- * user types input to).
- */
-
- if (ioctl(0, (int)FIONREAD, (char *)&nready) < 0) {
- perror("FIONREAD");
- return;
- }
-
- cq = obuf;
- while (nready > 0) {
- if (nready > sizeof ibuf)
- len = read(0, ibuf, sizeof ibuf);
- else
- len = read(0, ibuf, nready);
- if (len <= 0) {
- perror("read");
- return;
- }
- for (cp=ibuf; cp < ibuf+len; cp++) {
- if (seen_iac) {
- if ((*cp&CB_DIR) == CB_DIR_MTOH) {
- if (cq > obuf) {
- (void)write(curwin[W_IN]->w_fd,
- obuf, cq-obuf);
- cq = obuf;
- }
- switch (*cq = recvcmd(*cp)) {
- case RCV_OK:
- break;
- case RCV_META:
- seen_meta = 1;
- break;
- default:
- if (seen_meta) {
- seen_meta = 0;
- *cq |= META;
- }
- if (curwin[W_IN])
- cq++;
- break;
- }
- }
- seen_iac = 0;
- } else if (*cp == IAC)
- seen_iac++;
- else if (curwin[W_IN]) {
- if (seen_meta) {
- seen_meta = 0;
- *cq++ = *cp|META;
- } else
- *cq++ = *cp;
- if (cq >= obuf+sizeof obuf) {
- (void)write(curwin[W_IN]->w_fd,
- obuf, cq-obuf);
- cq = obuf;
- }
- }
- }
- nready -= len;
- }
- if (cq > obuf)
- (void)write(curwin[W_IN]->w_fd, obuf, cq-obuf);
- }
-
- recvcmd(cmd)
- char cmd;
- {
- register int nwin, fn;
- register struct window *w;
-
- /*
- * Perform the function the Mac is asking for. There are three
- * broad categories of these functions: RCV_META, which tells
- * the caller that the next character is a "meta" character;
- * an ASCII data character, which is passed back to the caller
- * for proper handling; and RCV_OK, which means that this routine
- * has done everything which was required to process the command.
- */
-
- fn = cmd&CB_FN;
- switch (fn) {
- case CB_FN_NEWW:
- case CB_FN_KILLW:
- case CB_FN_ISELW:
- nwin = cmd&CB_WINDOW;
- if (!nwin)
- break;
- w = &window[nwin-1];
-
- switch (fn) {
- case CB_FN_NEWW:
- if (w->w_fd < 0 && newwind(w) < 0)
- xmitcmd(CB_FN_KILLW|nwin);
- break;
-
- case CB_FN_KILLW:
- killwind(w, 0);
- break;
-
- case CB_FN_ISELW:
- if (w->w_fd >= 0)
- curwin[W_IN] = w;
- break;
- }
- break;
-
- case CB_FN_META:
- return(RCV_META);
-
- case CB_FN_CTLCH:
- return(ctlch[cmd&CB_CC]);
-
- case CB_FN_MAINT:
- if ((cmd&CB_MF) == CB_MF_EXIT)
- done(0);
- /*NOTREACHED*/
- }
- return(RCV_OK);
- }
-
- xmitcmd(cmd)
- char cmd;
- {
- static char cmdbuf[2] = { IAC, '\0' };
-
- /*
- * Transmit the command "cmd" to the Macintosh. The byte is ORed
- * with the host-to-Mac direction indicator.
- */
-
- cmdbuf[1] = cmd|CB_DIR_HTOM;
- (void)write(1, cmdbuf, sizeof cmdbuf);
- }
-
- netrecv(sd)
- register fildes_t sd;
- {
- register struct window *w;
- register int cnt;
- struct msghdr msg;
- auto int fd;
- struct iovec iov;
- struct stat st1, st2;
- static int unity = 1;
- char buf[256];
-
-
- /*
- * main() calls this routine when there is a message waiting on
- * the UNIX-domain socket. The message's access rights are
- * expected to contain the file descriptor for the "master" side
- * of a pseudo-tty. The message contains the name of the pty.
- * The sender is expected to start up a process on the slave side
- * of the pty. This allows the host end to create windows which
- * run something other than the shell.
- */
-
- fd = -1;
-
- iov.iov_base = (caddr_t)buf;
- iov.iov_len = sizeof buf - 1;
-
- msg.msg_name = (caddr_t)0;
- msg.msg_namelen = 0;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_accrights = (caddr_t)&fd;
- msg.msg_accrightslen = sizeof fd;
-
- if ((cnt=recvmsg(sd, &msg, 0)) < 0)
- perror("recvmsg");
-
- if (msg.msg_accrightslen > 0 && fd >= 0) {
- /*
- * We can't trust the process which connected to us, so
- * we verify that it really passed us a pseudo-tty's
- * file descriptor by checking the device name and its
- * inode number. [Of course, if someone else wants to
- * hand us a terminal session running under their uid....]
- */
- buf[cnt] = 0;
- if (strncmp(buf, "/dev/pty", sizeof "/dev/pty" - 1) ||
- fstat(fd, &st1) < 0 || stat(buf, &st2) < 0 ||
- st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) {
- (void)close(fd);
- return;
- }
- /*
- * OK, we believe the sender. We allocate a window and
- * tell the Macintosh to create that window on its end.
- */
- buf[5] = 't'; /* switch to "/dev/ttyp?" */
- for (w=window; w < window+NWINDOW; w++) {
- if (w->w_fd < 0) {
- w->w_fd = fd;
- fdmap[fd] = w;
- FD_SET(fd, &selmask[0].sm_rd);
- (void)strncpy(w->w_tty, buf, sizeof w->w_tty-1);
- xmitcmd(CB_FN_NEWW|(w-window+1));
- break;
- }
- }
- /*
- * If we have no free windows, then we close the file
- * descriptor (which will terminate the slave process).
- */
- if (w == window+NWINDOW)
- (void)close(fd);
- /*
- * Set non-blocking I/O on the master side.
- */
- (void)ioctl(fd, (int)FIONBIO, (char *)&unity);
- }
- }
-
- mxmit(fd)
- register fildes_t fd;
- {
- register char *cp, *cq, i;
- register int len;
- char ibuf[32], obuf[32];
-
- /*
- * Copy input from file "fd" to the Macintosh. Be sure to convert
- * any embedded IAC characters.
- *
- * Note that the input/output buffers should NOT be very large.
- * It is undesirable to perform large reads and effectively
- * "lock out" all other file descriptors. The chosen size
- * should preserve a reasonable amount of efficiency.
- */
-
- if (fdmap[fd]) {
- curwin[W_OUT] = fdmap[fd];
- xmitcmd(CB_FN_OSELW|(fdmap[fd]-window+1));
- cq = obuf;
- if ((len = read(fd, ibuf, sizeof ibuf)) < 0 &&
- errno != EWOULDBLOCK) {
- killwind(fdmap[fd], 1);
- return;
- }
- for (cp=ibuf; cp < ibuf+len; cp++) {
- if (*cp&META) {
- if (cq > obuf) {
- (void)write(1, obuf, cq-obuf);
- cq = obuf;
- }
- xmitcmd(CB_FN_META);
- *cp &= ~META;
- }
- i = -1;
- if (*cp == RUB || *cp < ' ') {
- i = sizeof ctlch;
- while (i >= 0 && ctlch[i] != *cp)
- i--;
- }
- if (i >= 0) {
- if (cq > obuf) {
- (void)write(1, obuf, cq-obuf);
- cq = obuf;
- }
- xmitcmd(CB_FN_CTLCH|i);
- } else {
- *cq++ = *cp;
- if (cq >= obuf+sizeof obuf) {
- (void)write(1, obuf, cq-obuf);
- cq = obuf;
- }
- }
- }
- } else
- (void)read(fd, ibuf, sizeof ibuf);
- if (cq > obuf)
- (void)write(1, obuf, cq-obuf);
- }
-
- killwind(w, notify)
- register struct window *w;
- {
- /*
- * Kill window "w". Notify the Macintosh that it is gone if
- * "notify" is nonzero.
- */
-
- FD_CLR(w->w_fd, &selmask[0].sm_rd);
- FD_CLR(w->w_fd, &selmask[0].sm_wt);
- FD_CLR(w->w_fd, &selmask[0].sm_ex);
- (void)close(w->w_fd);
- fdmap[w->w_fd] = NULL;
- w->w_fd = -1;
- if (curwin[W_IN] == w)
- curwin[W_IN] = NULL;
- if (curwin[W_OUT] == w)
- curwin[W_OUT] = NULL;
- if (notify)
- xmitcmd(CB_FN_KILLW|(w-window+1));
- }
-
- newwind(w)
- register struct window *w;
- {
- register int pid;
- register char *shell;
- register int fd;
- auto struct ptydesc pt;
- static int unity = 1;
- extern char *getenv();
-
- /*
- * Create a new window using "w".
- */
-
- if (openpty(&pt) < 0)
- return(-1); /* better recovery is needed */
-
- (void)ioctl(pt.pt_pfd, (int)FIONBIO, (char *)&unity);
- fdmap[pt.pt_pfd] = w;
- w->w_fd = pt.pt_pfd;
- FD_SET(pt.pt_pfd, &selmask[0].sm_rd);
- (void)strncpy(w->w_tty, pt.pt_tname, sizeof w->w_tty);
-
- /*
- * We must spawn a new process with fork(), not vfork(), because
- * some implementations (e.g. Sun UNIX) manipulate static
- * variables within the signal() subroutine. If we vfork()
- * the parent will die when the first SIGCHLD arrives. The
- * data+bss size is fairly small, so this isn't too expensive.
- */
- while ((pid=fork()) < 0)
- sleep(5);
- if (!pid) {
- (void)signal(SIGHUP, SIG_DFL);
- (void)signal(SIGINT, SIG_DFL);
- (void)signal(SIGQUIT, SIG_DFL);
- (void)signal(SIGTERM, SIG_DFL);
- (void)signal(SIGTSTP, SIG_IGN);
- (void)signal(SIGCHLD, SIG_DFL);
- (void)ioctl(open("/dev/tty",O_RDWR), (int)TIOCNOTTY, (char *)0);
- (void)close(open(pt.pt_tname, O_RDONLY)); /* set new ctrl tty */
- (void)setuid(getuid()); /* shouldn't need this */
- if (!(shell = getenv("SHELL")))
- shell = "/bin/sh";
- (void)dup2(pt.pt_tfd, 0);
- (void)dup2(0, 1);
- (void)dup2(0, 2);
- for (fd=3; fd < nfds; fd++)
- (void)close(fd);
- tmode(0); /* HACK! */
- execl(shell, shell, (char *)0);
- _exit(1);
- }
-
- (void)close(pt.pt_tfd);
- return(0);
- }
-
- tmode(f)
- {
- static struct sgttyb ostty, nstty;
- static struct tchars otchars, ntchars;
- static struct ltchars oltchars, nltchars;
- static int olmode, nlmode;
- static saved;
-
- /*
- * This routine either saves the current terminal modes and then
- * sets up the terminal line or resets the terminal modes (depending
- * upon the value of "f"). The terminal line is used in "cbreak"
- * mode with all special characters except XON/XOFF disabled. The
- * hated (by me) LDECCTQ mode is required for the Macintosh to
- * handle flow control properly.
- */
-
- if (f == 1) {
- if (ioctl(0, (int)TIOCGETP, (char *)&ostty) < 0) {
- perror("ioctl((int)TIOCGETP)");
- done(1);
- }
- if (ioctl(0, (int)TIOCGETC, (char *)&otchars) < 0) {
- perror("ioctl((int)TIOCGETC)");
- done(1);
- }
- if (ioctl(0, (int)TIOCGLTC, (char *)&oltchars) < 0) {
- perror("ioctl((int)TIOCGLTC)");
- done(1);
- }
- if (ioctl(0, (int)TIOCLGET, (char *)&olmode) < 0) {
- perror("ioctl((int)TIOCLGET)");
- done(1);
- }
- nstty = ostty;
- nstty.sg_erase = nstty.sg_kill = -1;
- nstty.sg_flags |= CBREAK|TANDEM;
- nstty.sg_flags &= ~(RAW|CRMOD|ECHO|LCASE|XTABS);
- ntchars.t_intrc = ntchars.t_quitc = -1;
- ntchars.t_eofc = ntchars.t_brkc = -1;
- ntchars.t_startc = XON;
- ntchars.t_stopc = XOFF;
- nltchars.t_suspc = nltchars.t_dsuspc = -1;
- nltchars.t_rprntc = nltchars.t_flushc = -1;
- nltchars.t_werasc = nltchars.t_lnextc = -1;
- nlmode = olmode | LDECCTQ;
- if (ioctl(0, (int)TIOCSETN, (char *)&nstty) < 0) {
- perror("ioctl((int)TIOCSETN)");
- done(1);
- }
- if (ioctl(0, (int)TIOCSETC, (char *)&ntchars) < 0) {
- perror("ioctl((int)TIOCSETC");
- done(1);
- }
- if (ioctl(0, (int)TIOCSLTC, (char *)&nltchars) < 0) {
- perror("ioctl((int)TIOCSLTC");
- done(1);
- }
- if (ioctl(0, (int)TIOCLSET, (char *)&nlmode) < 0) {
- perror("ioctl((int)TIOCLSET)");
- done(1);
- }
- saved = 1;
- } else if (saved) {
- (void)ioctl(0, (int)TIOCSETP, (char *)&ostty);
- (void)ioctl(0, (int)TIOCSETC, (char *)&otchars);
- (void)ioctl(0, (int)TIOCSLTC, (char *)&oltchars);
- (void)ioctl(0, (int)TIOCLSET, (char *)&olmode);
- }
- }
-
- done(s)
- {
- register fildes_t fd;
-
- /*
- * Clean up and exit. It is overkill to close all of the file
- * descriptors, but it causes no harm. After we are sure that
- * our UNIX-domain network connection is closed we remove the
- * entry that it created (as a side effect) in the filesystem.
- *
- * We also restore the terminal modes.
- */
-
- /*xmitcmd(CB_FN_MAINT|CB_MF_EXIT);*/
- for (fd=3; fd < nfds; fd++)
- (void)close(fd);
- (void)unlink(portal);
- tmode(0);
- exit(s);
- }
-
- cwait()
- {
- union wait status;
- struct rusage rusage;
-
- /*
- * Collect dead children. We don't use the information that
- * wait3() returns. (Someday we might.)
- */
-
- while (wait3(&status, WNOHANG, &rusage) > 0)
- ;
- }
-
-
- static char *earray[MAXENV+1];
-
- setenv(env)
- char **env;
- {
- register char **ep1, **ep2, *cp;
- char **ep3;
- extern char **environ;
-
-
- /*
- * Merge the set of environment strings in "env" into the
- * environment.
- */
-
- /*
- * The first time through, copy the environment from its
- * original location to the array "earray". This makes it a
- * little easier to change things.
- */
-
- if (environ != earray){
- ep1=environ;
- ep2=earray;
- while(*ep1 && ep2 <= earray+MAXENV)
- *ep2++ = *ep1++;
- *ep2++ = NULL;
- environ = earray;
- }
-
-
- /*
- * If "env" is non-NULL, it points to a list of new items to
- * be added to the environment. These replace existing items
- * with the same name.
- */
-
- if (env){
- for(ep1=env; *ep1; ep1++){
- for(ep2=environ; *ep2; ep2++)
- if (!envcmp(*ep1, *ep2))
- break;
- if (ep2 < earray+MAXENV) {
- if (!*ep2)
- ep2[1] = NULL;
- *ep2 = *ep1;
- }
- }
- }
-
-
- /* Finally, use an insertion sort to put things in order. */
-
- for(ep1=environ+1; cp = *ep1; ep1++){
- for(ep2=environ; ep2 < ep1; ep2++)
- if (envcmp(*ep1, *ep2) < 0)
- break;
- ep3 = ep2;
- for(ep2=ep1; ep2 > ep3; ep2--)
- ep2[0] = ep2[-1];
- *ep2 = cp;
- }
- }
-
-
- static
- envcmp(e1, e2)
- register char *e1, *e2;
- {
- register d;
-
- do {
- if (d = *e1 - *e2++)
- return(d);
- } while(*e1 && *e1++ != '=');
- return(0);
- }
- SHAR_EOF
- if test 17598 -ne "`wc -c uw.c`"
- then
- echo shar: error transmitting uw.c '(should have been 17598 characters)'
- fi
- echo shar: extracting uwtool.c '(3073 characters)'
- cat << \SHAR_EOF > uwtool.c
- #
-
- /*
- * uwtool
- *
- * Copyright 1985 by John D. Bruner. All rights reserved. Permission to
- * copy this program is given provided that the copy is not sold and that
- * this copyright notice is included.
- */
-
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/ioctl.h>
- #include <sys/wait.h>
- #include <sys/time.h>
- #include <sys/resource.h>
- #include <sys/uio.h>
- #include <strings.h>
- #include <signal.h>
- #include <stdio.h>
- #include "openpty.h"
-
- #define NFDS 20 /* max number of file descriptors */
-
- typedef int fildes_t;
-
- extern char *getenv();
-
- main(argc, argv)
- char **argv;
- {
- register int pid;
- register fildes_t sd;
- auto fildes_t fd;
- char *portal, *shell;
- int lmode;
- struct sgttyb sg;
- struct tchars tc;
- struct ltchars ltc;
- struct iovec iov;
- struct msghdr msg;
- struct sockaddr sa;
- auto struct ptydesc pt;
-
- /*
- * Close all file descriptors except 0, 1, and 2.
- */
-
- for (fd=3; fd < NFDS; fd++)
- (void)close(fd);
-
- /*
- * Get the terminal configuration for this tty.
- */
- (void)ioctl(0, (int)TIOCGETP, (char *)&sg);
- (void)ioctl(0, (int)TIOCGETC, (char *)&tc);
- (void)ioctl(0, (int)TIOCGLTC, (char *)<c);
- (void)ioctl(0, (int)TIOCLGET, (char *)&lmode);
-
- /*
- * Create a UNIX-domain socket.
- */
-
- if (!(portal=getenv("UWIN"))) {
- fprintf(stderr,
- "You must run %s under the window manager\n", *argv);
- exit(1);
- }
-
- if ((sd=socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
- perror("socket");
- exit(1);
- }
- sa.sa_family = AF_UNIX;
- (void)strncpy(sa.sa_data, portal, sizeof sa.sa_data-1);
- sa.sa_data[sizeof sa.sa_data-1] = '\0';
-
-
- /*
- * Obtain a pseudo-tty.
- */
-
- if (openpty(&pt) < 0) {
- fprintf(stderr, "Can't obtain a pseudo-tty for a new window\n");
- exit(1);
- }
-
-
- /*
- * Fork a child process using this pseudo-tty. Initialize the
- * terminal modes on the pseudo-tty to match those of the parent
- * tty.
- */
-
- while ((pid=vfork()) < 0)
- sleep(5);
- if (!pid) {
- (void)setuid(getuid());/* in case it's setuid-root by mistake */
- (void)signal(SIGTSTP, SIG_IGN);
- (void)ioctl(open("/dev/tty", 2), (int)TIOCNOTTY, (char *)0);
- (void)close(open(pt.pt_tname, 0)); /*set new ctrl tty */
- (void)dup2(pt.pt_tfd, 0);
- (void)dup2(0, 1);
- (void)dup2(0, 2);
- for (fd=3; fd < NFDS; fd++)
- (void)close(fd);
- (void)ioctl(0, (int)TIOCSETN, (char *)&sg);
- (void)ioctl(0, (int)TIOCSETC, (char *)&tc);
- (void)ioctl(0, (int)TIOCSLTC, (char *)<c);
- (void)ioctl(0, (int)TIOCLSET, (char *)&lmode);
- if (argc == 1) {
- if (!(shell=getenv("SHELL")))
- shell = "/bin/sh";
- execl(shell, shell, (char *)0);
- perror(shell);
- } else {
- execvp(argv[1], argv+1);
- perror(argv[1]);
- }
- _exit(1);
- }
-
-
- /*
- * Pass the file descriptor to the window server and exit.
- */
-
- iov.iov_base = pt.pt_pname;
- iov.iov_len = strlen(pt.pt_pname);
- msg.msg_name = (caddr_t)&sa;
- msg.msg_namelen = sizeof sa.sa_family + strlen(sa.sa_data);
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_accrights = (caddr_t)&pt.pt_pfd;
- msg.msg_accrightslen = sizeof pt.pt_pfd;
- if (sendmsg(sd, &msg, 0) < 0) {
- perror("sendmsg");
- exit(1);
- }
-
- exit(0);
- }
- SHAR_EOF
- if test 3073 -ne "`wc -c uwtool.c`"
- then
- echo shar: error transmitting uwtool.c '(should have been 3073 characters)'
- fi
- echo shar: extracting openpty.h '(308 characters)'
- cat << \SHAR_EOF > openpty.h
- /*
- * This file defines the "ptydesc" structure which is returned
- * by the routine "openpty".
- */
-
- struct ptydesc {
- int pt_pfd; /* file descriptor of master side */
- int pt_tfd; /* file descriptor of slave side */
- char *pt_pname; /* master device name */
- char *pt_tname; /* slave device name */
- };
- SHAR_EOF
- if test 308 -ne "`wc -c openpty.h`"
- then
- echo shar: error transmitting openpty.h '(should have been 308 characters)'
- fi
- echo shar: extracting uw.h '(2697 characters)'
- cat << \SHAR_EOF > uw.h
- /*
- * uw command bytes
- *
- * Copyright 1985 by John D. Bruner. All rights reserved. Permission to
- * copy this program is given provided that the copy is not sold and that
- * this copyright notice is included.
- *
- *
- * Two types of information are exchanged through the 7-bit serial line:
- * ordinary data and command bytes. Command bytes are preceeded by
- * an IAC byte. IAC bytes and literal XON/XOFF characters (those which
- * are not used for flow control) are sent by a CB_FN_CTLCH command.
- * Characters with the eighth bit set (the "meta" bit) are prefixed with
- * a CB_FN_META function.
- *
- * The next most-significant bit in the byte specifies the sender and
- * recipient of the command. If this bit is clear (0), the command byte
- * was sent from the host computer to the Macintosh; if it is set (1)
- * the command byte was sent from the Macintosh to the host computer.
- * This prevents confusion in the event that the host computer
- * (incorrectly) echos a command back to the Macintosh.
- *
- * The remaining six bits are partitioned into two fields. The low-order
- * three bits specify a window number from 1-7 (window 0 is reserved for
- * other uses) or another type of command-dependent parameter. The next
- * three bits specify the operation to be performed by the recipient of
- * the command byte.
- *
- * Note that the choice of command bytes prevents the ASCII XON (021) and
- * XOFF (023) characters from being sent as commands. CB_FN_ISELW commands
- * are only sent by the Macintosh (and thus are tagged with the CB_DIR_MTOH
- * bit). Since XON and XOFF data characters are handled via CB_FN_CTLCH,
- * this allows them to be used for flow control purposes.
- */
-
- #define IAC 0001 /* interpret as command */
- #define CB_DIR 0100 /* command direction: */
- #define CB_DIR_HTOM 0000 /* from host to Mac */
- #define CB_DIR_MTOH 0100 /* from Mac to host */
- #define CB_FN 0070 /* function code: */
- #define CB_FN_NEWW 0000 /* new window */
- #define CB_FN_KILLW 0010 /* kill (delete) window */
- #define CB_FN_ISELW 0020 /* select window for input */
- #define CB_FN_OSELW 0030 /* select window for output */
- #define CB_FN_META 0050 /* add meta to next data char */
- #define CB_FN_CTLCH 0060 /* low 3 bits specify char */
- #define CB_FN_MAINT 0070 /* maintenance functions */
- #define CB_WINDOW 0007 /* window number mask */
- #define CB_CC 0007 /* control character specifier: */
- #define CB_CC_IAC 1 /* IAC */
- #define CB_CC_XON 2 /* XON */
- #define CB_CC_XOFF 3 /* XOFF */
- #define CB_MF 0007 /* maintenance functions: */
- #define CB_MF_ENTRY 0 /* beginning execution */
- #define CB_MF_EXIT 7 /* execution terminating */
- #define NWINDOW 7 /* maximum number of windows */
- SHAR_EOF
- if test 2697 -ne "`wc -c uw.h`"
- then
- echo shar: error transmitting uw.h '(should have been 2697 characters)'
- fi
- # End of shell archive
- exit 0
-
-
-