[comp.sources.atari.st] v00i003: ::shar - UW sources and man page for BSD 4.{23}

atari-sources-request@imagen.UUCP (04/22/87)

Submitted by: ucbvax!cwruecmp!bammi (Jwahar R. Bammi)
comp.sources.atari.st: Volume 0, Issue 3
Archive-name: uwvax

+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
[Editor's Note]

Here are the sources and man page for the 'host' side of the UW
window connection. I have successfully compiled and used these with
the ST under BSD4.2 and BSD4.3 on the vax. Not being a SVR2 hacker i
have no idea what it would take to make it run under system 5.

{BUGS}
1) if you logout or exit in a window then the program (on the ST)
will bomb out and leave the host side hung in UW. You end up having
to hang up the phone, redial, and start from scratch.

2) (really a corallary of 1) if you run a program using uwtool and
it fails in any way, then the window will collapse and you will bomb
out as in 1)
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=


--
#!/bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #!/bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	uw.1
#	uw.c
#	uw.h
#	uwtool.c
# This archive created: Fri Apr 17 23:35:53 1987
# By:	Jwahar R. Bammi(Case Western Reserve University)
#  Uucp:	 {decvax,cbatt,sun,cbosgd}!cwruecmp!bammi
# Csnet:	 bammi@case.CSNET
#  Arpa:	 bammi%case@csnet-relay.ARPA
#
export PATH; PATH=/bin:$PATH
echo shar: extracting "'uw.1'" '(1732 characters)'
if test -f 'uw.1'
then
	echo shar: over-writing existing file "'uw.1'"
fi
sed 's/^X//' << \SHAR_EOF > 'uw.1'
X.TH UW local "13 November 1985"
X.UC 4
X.SH NAME
Xuw \- unix windowing system for Macintosh
X.SH SYNOPSIS
X.B uw
X.br
X.B uwtool
X[ process ] [ arg1 arg2 ...  ]
X.SH DESCRIPTION
X.I Uw
Xis a server program on unix that works with the program 
X.I uw
Xon the Macintosh.  It creates a pseudo-terminal for each window,
Xgiving the user up to seven `terminals' to work with.  The host
Xprogram multiplexes the output onto one RS\-232 line.
X.PP
X.I Uw
X(on the unix system) with 
X.I uw 
Xon the Macintosh emulate a Lear Siegler ADM-31 terminal (tset adm31), a 
XTektronix 4010, and a DEC VT52.  
XEach window (on the Macintosh) has its own terminal emulation and can be 
Xresized at will; the program
Xkeeps an 80x24 line display in memory for each window, but only shows the 
Xlower left portion possible.
X.PP
X.I Uwtool
Xcan be executed from unix while running 
X.I uw
Xto create a new window/`terminal.'  If no arguments are given, it creates
Xa new `terminal' running csh.  If a process is named, it will create a new
Xwindow with that process running in it, and when that process is terminated
Xthe window will disappear.  (i.e. `uwtool vi foo' will create a new window
Xwith vi, editing the file foo, but the window will go away when vi is exited)  
XAny arguements after the process name are passed as arguements to that process.
X.SH LIMITATIONS
X.I Uw 
Xand 
X.I uwtool 
Xare of no use on unix unless 
X.I uw
Xis being run on the Macintosh.  
X.br
XIf there is a stream of output in one window there will be lag in 
Xrecognizing characters typed in another.
X.SH SEE ALSO
X.I uw
Xdocumentation distributed with the Macintosh program.
X.SH AUTHOR
XProgram written by John Bruner, Lawrence Livermore Laboratories 7/85
X.br
XDocument edited by Chris Borton, UC San Diego 11/13/85
SHAR_EOF
if test 1732 -ne "`wc -c 'uw.1'`"
then
	echo shar: error transmitting "'uw.1'" '(should have been 1732 characters)'
fi
echo shar: extracting "'uw.c'" '(17040 characters)'
if test -f 'uw.c'
then
	echo shar: over-writing existing file "'uw.c'"
fi
sed 's/^X//' << \SHAR_EOF > 'uw.c'
X/*
X *	uw - UNIX windows program for the Macintosh (VAX end)
X *
X * Copyright 1985 by John D. Bruner.  All rights reserved.  Permission to
X * copy this program is given provided that the copy is not sold and that
X * this copyright notice is included.
X *
X * Compile: cc -o uw -O uw.c
X */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/socket.h>
X#include <sys/ioctl.h>
X#include <sys/wait.h>
X#include <sys/time.h>
X#include <sys/resource.h>
X#include <sys/uio.h>
X#include <signal.h>
X#include <setjmp.h>
X#include <errno.h>
X#include <fcntl.h>
X#include <stdio.h>
X#include "uw.h"
X
X#define	MAXENV	128			/* maximum environment size */
X
X#define	W_IN	0
X#define	W_OUT	1
X
X#define	NFDS	20			/* max number of file descriptors */
X
X#define	XON	0021			/* ASCII XON */
X#define	XOFF	0023			/* ASCII XOFF */
X#define	RUB	0177			/* ASCII RUBOUT */
X
X#define	META	0200			/* "meta" bit for whatever it's worth */
X
X#define	RCV_OK	(-1)			/* see recvcmd() */
X#define	RCV_META (-2)			/* see recvcmd() */
X
Xtypedef int fildes_t;			/* file descriptor data type */
Xtypedef int nwin_t;			/* window index data type */
X
Xstruct window {
X	fildes_t	w_fd;
X	char		w_tty[32];
X};
X
Xstruct window window[NWINDOW];		/* window data structures */
Xstruct window *fdmap[NFDS];		/* mapping from fd's to windows */
Xstruct window *curwin[2];		/* current input and output windows */
X
Xchar portal[] = "/tmp/uwXXXXXX";	/* UNIX-domain network address */
X
X
X/* The following are added to the environment of all child processes */
X
Xchar env_uwin[64] = "UWIN=";
Xchar *env[] = { 
X	env_uwin,
X	"TERM=adm31",
X	"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:",
X	NULL
X};
X
Xint ctlch[] = { -1, IAC, XON, XOFF, -1, -1, -1, -1 };	/* CTL char mapping */
X
Xstruct selmask {
X	int	sm_rd;
X	int	sm_wt;
X	int	sm_ex;
X} selmask[2];
X
Xextern char *strncpy(), *strncat();
Xextern char *mktemp();
Xextern char *getenv();
Xextern done(), cwait(), onalarm();
Xextern int errno;
X
Xmain(argc, argv)
Xchar **argv;
X{
X	register fildes_t fd, sd;
X	register struct window *w;
X	struct sockaddr sa;
X
X	/*
X	 * Make sure we don't accidentally try to run this inside itself.
X	 */
X	if (getenv("UWIN")) {
X		fprintf(stderr, "%s is already running\n", *argv);
X		exit(1);
X	}
X
X	/*
X	 * Close all file descriptors except 0, 1, and 2.
X	 */
X
X	for (fd=3; fd < NFDS; fd++)
X		(void)close(fd);
X
X	/*
X	 * Mark all windows closed.
X	 */
X
X	for (w=window; w < window+NWINDOW; w++)
X		w->w_fd = -1;
X
X
X	/*
X	 * Create a UNIX-domain network address, and put its name into
X	 * the environment so that descendents can contact us with new
X	 * window requests.
X	 */
X
X	(void)strncat(env_uwin, mktemp(portal), sizeof env_uwin - 1);
X	setenv(env);
X
X	if ((sd=socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
X		perror("socket");
X		exit(1);
X	}
X	sa.sa_family = AF_UNIX;
X	(void)strncpy(sa.sa_data, portal, sizeof sa.sa_data-1);
X	sa.sa_data[sizeof sa.sa_data-1] = '\0';
X	if (bind(sd, &sa, sizeof sa.sa_family + strlen(sa.sa_data)) < 0) {
X		perror("bind");
X		exit(1);
X	}
X	if (fcntl(sd, F_SETFL, FNDELAY))
X		perror("fcntl(sd, F_SETFL, FNDELAY)");
X
X
X	/*
X	 * Ignore interrupts, quits, and terminal stops.  Clean up and exit
X	 * if a hangup or termination is received.  Also catch changes in
X	 * child status (so that we can wait for them).  Set up the terminal
X	 * modes.
X	 */
X
X	(void)signal(SIGHUP, done);
X	(void)signal(SIGINT, SIG_IGN);
X	(void)signal(SIGQUIT, SIG_IGN);
X	(void)signal(SIGTERM, done);
X	(void)signal(SIGTSTP, SIG_IGN);
X	(void)signal(SIGCHLD, cwait);
X
X	tmode(1);
X
X
X	/*
X	 * Tell the Macintosh to initialize.  Initialize the current input
X	 * and output windows to NULL.
X	 */
X
X	xmitcmd(CB_FN_MAINT|CB_MF_ENTRY);
X	curwin[W_IN] = curwin[W_OUT] = NULL;
X
X	
X	/*
X	 * Initialize the "select" masks, create window 1 (to start
X	 * things off) and wait for input.  When input is available,
X	 * process it.
X	 */
X
X	selmask[0].sm_rd = (1<<0)|(1<<sd);
X	selmask[0].sm_wt = 0;
X	selmask[0].sm_ex = selmask[0].sm_rd | 2;
X	if (newwind(window) == 0)
X		xmitcmd(CB_FN_NEWW|1);
X
X	while (1) {
X		selmask[1] = selmask[0];
X		if (select(NFDS, &selmask[1].sm_rd, &selmask[1].sm_wt,
X		    &selmask[1].sm_ex, (struct timeval *)0) < 0) {
X			if (errno == EINTR)
X				continue;
X			perror("select");
X			done(1);	/* for now -- fix this! */
X		}
X		for (fd=0; fd < NFDS; selmask[1].sm_rd >>= 1, fd++) {
X			if (selmask[1].sm_rd&(1<<0)) {
X				if (fd < 2)
X					mrecv();
X				else if (fd == sd)
X					netrecv(sd);
X				else
X					mxmit(fd);
X			}
X		}
X	}
X}
X
Xmrecv()
X{
X	register int len;
X	register char *cp, *cq;
X	auto int nready;
X	char ibuf[512], obuf[512];
X	static int seen_iac, seen_meta;
X
X	/*
X	 * The received bytestream is examined.  Non-command bytes are
X	 * written to the file descriptor corresponding to the current
X	 * "input" window (relative to the Macintosh -- the window the
X	 * user types input to).
X	 */
X
X	if (ioctl(0, (int)FIONREAD, (char *)&nready) < 0) {
X		perror("FIONREAD");
X		return;
X	}
X
X	cq = obuf;
X	while (nready > 0) {
X		if (nready > sizeof ibuf)
X			len = read(0, ibuf, sizeof ibuf);
X		else
X			len = read(0, ibuf, nready);
X		if (len <= 0) {
X			perror("read");
X			return;
X		}
X		for (cp=ibuf; cp < ibuf+len; cp++) {
X			if (seen_iac) {
X				if ((*cp&CB_DIR) == CB_DIR_MTOH) {
X					if (cq > obuf) {
X						(void)write(curwin[W_IN]->w_fd,
X							    obuf, cq-obuf);
X						cq = obuf;
X					}
X					switch (*cq = recvcmd(*cp)) {
X					case RCV_OK:
X						break;
X					case RCV_META:
X						seen_meta = 1;
X						break;
X					default:
X						if (seen_meta) {
X							seen_meta = 0;
X							*cq |= META;
X						}
X						if (curwin[W_IN])
X							cq++;
X						break;
X					}
X				}
X				seen_iac = 0;
X			} else if (*cp == IAC)
X				seen_iac++;
X			else if (curwin[W_IN]) {
X				if (seen_meta) {
X					seen_meta = 0;
X					*cq++ = *cp|META;
X				} else
X					*cq++ = *cp;
X				if (cq >= obuf+sizeof obuf) {
X					(void)write(curwin[W_IN]->w_fd,
X						    obuf, cq-obuf);
X					cq = obuf;
X				}
X			}
X		}
X		nready -= len;
X	}
X	if (cq > obuf)
X		(void)write(curwin[W_IN]->w_fd, obuf, cq-obuf);
X}
X
Xrecvcmd(cmd)
Xchar cmd;
X{
X	register int nwin, fn;
X	register struct window *w;
X
X	/*
X	 * Perform the function the Mac is asking for.  There are three
X	 * broad categories of these functions: RCV_META, which tells
X	 * the caller that the next character is a "meta" character;
X	 * an ASCII data character, which is passed back to the caller
X	 * for proper handling; and RCV_OK, which means that this routine
X	 * has done everything which was required to process the command.
X	 */
X
X	fn = cmd&CB_FN;
X	switch (fn) {
X	case CB_FN_NEWW:
X	case CB_FN_KILLW:
X	case CB_FN_ISELW:
X		nwin = cmd&CB_WINDOW;
X		if (!nwin)
X			break;
X		w = &window[nwin-1];
X
X		switch (fn) {
X		case CB_FN_NEWW:
X			if (w->w_fd < 0 && newwind(w) < 0)
X				xmitcmd(CB_FN_KILLW|nwin);
X			break;
X
X		case CB_FN_KILLW:
X			killwind(w, 0);
X			break;
X
X		case CB_FN_ISELW:
X			if (w->w_fd >= 0)
X				curwin[W_IN] = w;
X			break;
X		}
X		break;
X
X	case CB_FN_META:
X		return(RCV_META);
X
X	case CB_FN_CTLCH:
X		return(ctlch[cmd&CB_CC]);
X
X	case CB_FN_MAINT:
X		if ((cmd&CB_MF) == CB_MF_EXIT)
X			done(0);
X		/*NOTREACHED*/
X	}
X	return(RCV_OK);
X}
X
Xxmitcmd(cmd)
Xchar cmd;
X{
X	static char cmdbuf[2] = { IAC, '\0' };
X
X	/*
X	 * Transmit the command "cmd" to the Macintosh.  The byte is ORed
X	 * with the host-to-Mac direction indicator.
X	 */
X
X	cmdbuf[1] = cmd|CB_DIR_HTOM;
X	(void)write(1, cmdbuf, sizeof cmdbuf);
X}
X
Xnetrecv(sd)
Xregister fildes_t sd;
X{
X	register struct window *w;
X	register int cnt;
X	struct msghdr msg;
X	auto int fd;
X	struct iovec iov;
X	struct stat st1, st2;
X	static int unity = 1;
X	char buf[256];
X
X
X	/*
X	 * main() calls this routine when there is a message waiting on
X	 * the UNIX-domain socket.  The message's access rights are
X	 * expected to contain the file descriptor for the "master" side
X	 * of a pseudo-tty.  The message contains the name of the pty.
X	 * The sender is expected to start up a process on the slave side
X	 * of the pty.  This allows the host end to create windows which
X	 * run something other than the shell.
X	 */
X
X	fd = -1;
X
X	iov.iov_base = (caddr_t)buf;
X	iov.iov_len = sizeof buf - 1;
X
X	msg.msg_name = (caddr_t)0;
X	msg.msg_namelen = 0;
X	msg.msg_iov = &iov;
X	msg.msg_iovlen = 1;
X	msg.msg_accrights = (caddr_t)&fd;
X	msg.msg_accrightslen = sizeof fd;
X
X	if ((cnt=recvmsg(sd, &msg, 0)) < 0)
X		perror("recvmsg");
X
X	if (msg.msg_accrightslen > 0 && fd >= 0) {
X		/*
X		 * We can't trust the process which connected to us, so
X		 * we verify that it really passed us a pseudo-tty's
X		 * file descriptor by checking the device name and its
X		 * inode number.  [Of course, if someone else wants to
X		 * hand us a terminal session running under their uid....]
X		 */
X		buf[cnt] = 0;
X		if (strncmp(buf, "/dev/ptyp", sizeof "/dev/ptyp" - 1) ||
X		    fstat(fd, &st1) < 0 || stat(buf, &st2) < 0 ||
X		    st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) {
X			(void)close(fd);
X			return;
X		}
X		/*
X		 * OK, we believe the sender.  We allocate a window and
X		 * tell the Macintosh to create that window on its end.
X		 */
X		buf[5] = 't';		/* switch to "/dev/ttyp?" */
X		for (w=window; w < window+NWINDOW; w++) {
X			if (w->w_fd < 0) {
X				w->w_fd = fd;
X				fdmap[fd] = w;
X				selmask[0].sm_rd |= (1<<fd);
X				(void)strncpy(w->w_tty, buf, sizeof w->w_tty-1);
X				xmitcmd(CB_FN_NEWW|(w-window+1));
X				break;
X			}
X		}
X		/*
X		 * If we have no free windows, then we close the file
X		 * descriptor (which will terminate the slave process).
X		 */
X		if (w == window+NWINDOW)
X			(void)close(fd);
X		/*
X		 * Set non-blocking I/O on the master side.
X		 */
X		(void)ioctl(fd, FIONBIO, &unity);
X	}
X}
X
Xmxmit(fd)
Xregister fildes_t fd;
X{
X	register char *cp, *cq, i;
X	register int len;
X	char ibuf[16], obuf[16];
X
X	/*
X	 * Copy input from file "fd" to the Macintosh.  Be sure to convert
X	 * any embedded IAC characters.
X	 *
X	 * Note that the input/output buffers should NOT be very large.
X	 * It is undesirable to perform large reads and effectively
X	 * "lock out" all other file descriptors.  The chosen size
X	 * should preserve a reasonable amount of efficiency.
X	 */
X
X	if (fdmap[fd]) {
X		curwin[W_OUT] = fdmap[fd];
X		xmitcmd(CB_FN_OSELW|(fdmap[fd]-window+1));
X		cq = obuf;
X		if ((len = read(fd, ibuf, sizeof ibuf)) < 0 &&
X		    errno != EWOULDBLOCK) {
X			killwind(fdmap[fd], 1);
X			return;
X		}
X		for (cp=ibuf; cp < ibuf+len; cp++) {
X			if (*cp&META) {
X				if (cq > obuf) {
X					(void)write(1, obuf, cq-obuf);
X					cq = obuf;
X				}
X				xmitcmd(CB_FN_META);
X				*cp &= ~META;
X			}
X			i = -1;
X			if (*cp == RUB || *cp < ' ') {
X				i = sizeof ctlch;
X				while (i >= 0 && ctlch[i] != *cp)
X					i--;
X			}
X			if (i >= 0) {
X				if (cq > obuf) {
X					(void)write(1, obuf, cq-obuf);
X					cq = obuf;
X				}
X				xmitcmd(CB_FN_CTLCH|i);
X			} else {
X				*cq++ = *cp;
X				if (cq >= obuf+sizeof obuf) {
X					(void)write(1, obuf, cq-obuf);
X					cq = obuf;
X				}
X			}
X		}
X	} else
X		(void)read(fd, ibuf, sizeof ibuf);
X	if (cq > obuf)
X		(void)write(1, obuf, cq-obuf);
X}
X
Xkillwind(w, notify)
Xregister struct window *w;
X{
X	register int mask;
X
X	/*
X	 * Kill window "w".  Notify the Macintosh that it is gone if
X	 * "notify" is nonzero.
X	 */
X
X	(void)close(w->w_fd);
X	mask = ~(1<<w->w_fd);
X	fdmap[w->w_fd] = NULL;
X	w->w_fd = -1;
X	if (curwin[W_IN] == w)
X		curwin[W_IN] = NULL;
X	if (curwin[W_OUT] == w)
X		curwin[W_OUT] = NULL;
X	selmask[0].sm_rd &= mask;
X	selmask[0].sm_wt &= mask;
X	selmask[0].sm_ex &= mask;
X	if (notify)
X		xmitcmd(CB_FN_KILLW|(w-window+1));
X}
X
Xnewwind(w)
Xregister struct window *w;
X{
X	register char *cp;
X	register fildes_t fd;
X	register int pid;
X	register char *shell;
X	char pty[32], ptysufx[2];
X	static char ptyidx[] = "0123456789abcdefghijklmnopqrstuvwxyz";
X	static int unity = 1;
X	extern char *getenv();
X
X	/*
X	 * Create a new window using the specified component of "window".
X	 * This routine isn't very smart at finding pseudo-ttys.
X	 */
X
X	ptysufx[1] = '\0';
X	for (cp=ptyidx; *cp; cp++) {
X		ptysufx[0] = *cp;
X		(void)strncpy(pty, "/dev/ptyp", sizeof pty-1);
X		(void)strncat(pty, ptysufx, sizeof pty-1);
X		if ((fd = open(pty, 2)) >= 0)
X			break;
X	}
X	if (fd < 0)
X		return(-1);
X	(void)ioctl(fd, FIONBIO, &unity);	/* set non-blocking I/O */
X	fdmap[fd] = w;
X	w->w_fd = fd;
X	selmask[0].sm_rd |= (1<<fd);
X	(void)strncpy(w->w_tty, "/dev/ttyp", sizeof w->w_tty-1);
X	(void)strncat(w->w_tty, ptysufx, sizeof w->w_tty-1);
X
X	while ((pid=fork()) < 0)
X		sleep(5);
X	if (!pid) {
X		(void)signal(SIGHUP, SIG_DFL);
X		(void)signal(SIGINT, SIG_DFL);
X		(void)signal(SIGQUIT, SIG_DFL);
X		(void)signal(SIGTERM, SIG_DFL);
X		(void)signal(SIGTSTP, SIG_IGN);
X		(void)signal(SIGCHLD, SIG_DFL);
X		(void)ioctl(open("/dev/tty", 2), (int)TIOCNOTTY, (char *)0);
X		(void)setuid(getuid());		/* shouldn't need this */
X		if ((fd=open(w->w_tty, 2)) < 0)
X			_exit(1);
X		if (!(shell = getenv("SHELL")))
X			shell = "/bin/sh";
X		(void)dup2(fd, 0);
X		(void)dup2(0, 1);
X		(void)dup2(0, 2);
X		for (fd=3; fd < NFDS; fd++)
X			(void)close(fd);
X		tmode(0);	/* HACK! */
X		execl(shell, shell, (char *)0);
X		_exit(1);
X	}
X
X	return(0);
X}
X
Xtmode(f)
X{
X	static struct sgttyb ostty, nstty;
X	static struct tchars otchars, ntchars;
X	static struct ltchars oltchars, nltchars;
X	static int olmode, nlmode;
X	static saved;
X
X	/*
X	 * This routine either saves the current terminal modes and then
X	 * sets up the terminal line or resets the terminal modes (depending
X	 * upon the value of "f").  The terminal line is used in "cbreak"
X	 * mode with all special characters except XON/XOFF disabled.  The
X	 * hated (by me) LDECCTQ mode is required for the Macintosh to
X	 * handle flow control properly.
X	 */
X
X	if (f == 1) {
X		if (ioctl(0, (int)TIOCGETP, (char *)&ostty) < 0) {
X			perror("ioctl((int)TIOCGETP)");
X			done(1);
X		}
X		if (ioctl(0, (int)TIOCGETC, (char *)&otchars) < 0) {
X			perror("ioctl((int)TIOCGETC)");
X			done(1);
X		}
X		if (ioctl(0, (int)TIOCGLTC, (char *)&oltchars) < 0) {
X			perror("ioctl((int)TIOCGLTC)");
X			done(1);
X		}
X		if (ioctl(0, (int)TIOCLGET, (char *)&olmode) < 0) {
X			perror("ioctl((int)TIOCLGET)");
X			done(1);
X		}
X		nstty = ostty;
X		nstty.sg_erase = nstty.sg_kill = -1;
X		nstty.sg_flags |= CBREAK;
X		nstty.sg_flags &= ~(RAW|CRMOD|ECHO|LCASE|XTABS);
X		ntchars.t_intrc = ntchars.t_quitc = -1;
X		ntchars.t_eofc = ntchars.t_brkc = -1;
X		ntchars.t_startc = XON;
X		ntchars.t_stopc = XOFF;
X		nltchars.t_suspc = nltchars.t_dsuspc = -1;
X		nltchars.t_rprntc = nltchars.t_flushc = -1;
X		nltchars.t_werasc = nltchars.t_lnextc = -1;
X		nlmode = olmode | LDECCTQ;
X		if (ioctl(0, (int)TIOCSETN, (char *)&nstty) < 0) {
X			perror("ioctl((int)TIOCSETN)");
X			done(1);
X		}
X		if (ioctl(0, (int)TIOCSETC, (char *)&ntchars) < 0) {
X			perror("ioctl((int)TIOCSETC");
X			done(1);
X		}
X		if (ioctl(0, (int)TIOCSLTC, (char *)&nltchars) < 0) {
X			perror("ioctl((int)TIOCSLTC");
X			done(1);
X		}
X		if (ioctl(0, (int)TIOCLSET, (char *)&nlmode) < 0) {
X			perror("ioctl((int)TIOCLSET)");
X			done(1);
X		}
X		saved = 1;
X	} else if (saved) {
X		(void)ioctl(0, (int)TIOCSETP, (char *)&ostty);
X		(void)ioctl(0, (int)TIOCSETC, (char *)&otchars);
X		(void)ioctl(0, (int)TIOCSLTC, (char *)&oltchars);
X		(void)ioctl(0, (int)TIOCLSET, (char *)&olmode);
X	}
X}
X
Xdone(s)
X{
X	register struct window *w;
X	register fildes_t fd;
X
X	/*
X	 * Clean up and exit.  It is overkill to close all of the file
X	 * descriptors, but it causes no harm.  After we are sure that
X	 * our UNIX-domain network connection is closed we remove the
X	 * entry that it created (as a side effect) in the filesystem.
X	 *
X	 * We also restore the terminal modes.
X	 */
X	
X	/*xmitcmd(CB_FN_MAINT|CB_MF_EXIT);*/
X	for (fd=3; fd < NFDS; fd++)
X		(void)close(fd);
X	(void)unlink(portal);
X	tmode(0);
X	exit(s);
X}
X
Xcwait()
X{
X	union wait status;
X	struct rusage rusage;
X
X	/*
X	 * Collect dead children.  We don't use the information that
X	 * wait3() returns.  (Someday we might.)
X	 */
X	
X	while (wait3(&status, WNOHANG, &rusage) > 0)
X		;
X}
X
X
Xstatic char *earray[MAXENV+1];
X
Xsetenv(env)
Xchar **env;
X{
X	register char **ep1, **ep2, *cp;
X	char **ep3;
X	extern char **environ;
X
X
X	/*
X	 * Merge the set of environment strings in "env" into the
X	 * environment.
X	 */
X
X	/*
X	 * The first time through, copy the environment from its
X	 * original location to the array "earray".  This makes it a
X	 * little easier to change things.
X	 */
X
X	if (environ != earray){
X		ep1=environ;
X		ep2=earray;
X		while(*ep1 && ep2 <= earray+MAXENV)
X			*ep2++ = *ep1++;
X		*ep2++ = NULL;
X		environ = earray;
X	}
X
X
X	/*
X	 * If "env" is non-NULL, it points to a list of new items to
X	 * be added to the environment.  These replace existing items
X	 * with the same name.
X	 */
X
X	if (env){
X		for(ep1=env; *ep1; ep1++){
X			for(ep2=environ; *ep2; ep2++)
X				if (!envcmp(*ep1, *ep2))
X					break;
X			if (ep2 < earray+MAXENV) {
X				if (!*ep2)
X					ep2[1] = NULL;
X				*ep2 = *ep1;
X			}
X		}
X	}
X
X
X	/* Finally, use an insertion sort to put things in order. */
X
X	for(ep1=environ+1; cp = *ep1; ep1++){
X		for(ep2=environ; ep2 < ep1; ep2++)
X			if (envcmp(*ep1, *ep2) < 0)
X				break;
X		ep3 = ep2;
X		for(ep2=ep1; ep2 > ep3; ep2--)
X			ep2[0] = ep2[-1];
X		*ep2 = cp;
X	}
X}
X
X
Xstatic
Xenvcmp(e1, e2)
Xregister char *e1, *e2;
X{
X	register d;
X
X	do {
X		if (d = *e1 - *e2++)
X			return(d);
X	} while(*e1 && *e1++ != '=');
X	return(0);
X}
SHAR_EOF
if test 17040 -ne "`wc -c 'uw.c'`"
then
	echo shar: error transmitting "'uw.c'" '(should have been 17040 characters)'
fi
echo shar: extracting "'uw.h'" '(2697 characters)'
if test -f 'uw.h'
then
	echo shar: over-writing existing file "'uw.h'"
fi
sed 's/^X//' << \SHAR_EOF > 'uw.h'
X/*
X *	uw command bytes
X *
X * Copyright 1985 by John D. Bruner.  All rights reserved.  Permission to
X * copy this program is given provided that the copy is not sold and that
X * this copyright notice is included.
X *
X *
X * Two types of information are exchanged through the 7-bit serial line:
X * ordinary data and command bytes.  Command bytes are preceeded by
X * an IAC byte.  IAC bytes and literal XON/XOFF characters (those which
X * are not used for flow control) are sent by a CB_FN_CTLCH command.
X * Characters with the eighth bit set (the "meta" bit) are prefixed with
X * a CB_FN_META function.
X *
X * The next most-significant bit in the byte specifies the sender and
X * recipient of the command.  If this bit is clear (0), the command byte
X * was sent from the host computer to the Macintosh; if it is set (1)
X * the command byte was sent from the Macintosh to the host computer.
X * This prevents confusion in the event that the host computer
X * (incorrectly) echos a command back to the Macintosh.
X *
X * The remaining six bits are partitioned into two fields.  The low-order
X * three bits specify a window number from 1-7 (window 0 is reserved for
X * other uses) or another type of command-dependent parameter.  The next
X * three bits specify the operation to be performed by the recipient of
X * the command byte.
X *
X * Note that the choice of command bytes prevents the ASCII XON (021) and
X * XOFF (023) characters from being sent as commands.  CB_FN_ISELW commands
X * are only sent by the Macintosh (and thus are tagged with the CB_DIR_MTOH
X * bit).  Since XON and XOFF data characters are handled via CB_FN_CTLCH,
X * this allows them to be used for flow control purposes.
X */
X 
X#define	IAC		0001		/* interpret as command */
X#define	CB_DIR		0100		/* command direction: */
X#define	CB_DIR_HTOM	0000		/*	from host to Mac */
X#define	CB_DIR_MTOH	0100		/*	from Mac to host */
X#define	CB_FN		0070		/* function code: */
X#define	CB_FN_NEWW	0000		/*	new window */
X#define	CB_FN_KILLW	0010		/*	kill (delete) window */
X#define	CB_FN_ISELW	0020		/*	select window for input */
X#define	CB_FN_OSELW	0030		/*	select window for output */
X#define	CB_FN_META	0050		/*	add meta to next data char */
X#define	CB_FN_CTLCH	0060		/*	low 3 bits specify char */
X#define	CB_FN_MAINT	0070		/*	maintenance functions */
X#define	CB_WINDOW	0007		/* window number mask */
X#define	CB_CC		0007		/* control character specifier: */
X#define	CB_CC_IAC	1		/*	IAC */
X#define	CB_CC_XON	2		/*	XON */
X#define	CB_CC_XOFF	3		/*	XOFF */
X#define	CB_MF		0007		/* maintenance functions: */
X#define	CB_MF_ENTRY	0		/*	beginning execution */
X#define	CB_MF_EXIT	7		/*	execution terminating */
X#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
echo shar: extracting "'uwtool.c'" '(3482 characters)'
if test -f 'uwtool.c'
then
	echo shar: over-writing existing file "'uwtool.c'"
fi
sed 's/^X//' << \SHAR_EOF > 'uwtool.c'
X#
X
X/*
X *	uwtool
X *
X * Copyright 1985 by John D. Bruner.  All rights reserved.  Permission to
X * copy this program is given provided that the copy is not sold and that
X * this copyright notice is included.
X *
X * Compile: cc -o uwtool -O uwtool.c
X */
X
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <sys/ioctl.h>
X#include <sys/wait.h>
X#include <sys/time.h>
X#include <sys/resource.h>
X#include <sys/uio.h>
X#include <signal.h>
X#include <stdio.h>
X
X#define	NFDS	20			/* max number of file descriptors */
X
Xtypedef int fildes_t;
X
Xextern char *strncpy(), *strncat();
Xextern char *getenv();
X
Xmain(argc, argv)
Xchar **argv;
X{
X	register char *cp;
X	register int pid;
X	register fildes_t sd;
X	auto fildes_t fd;
X	char *portal, *shell;
X	char tty[32], pty[32], ptysufx[2];
X	int lmode;
X	struct sgttyb sg;
X	struct tchars tc;
X	struct ltchars ltc;
X	struct iovec iov;
X	struct msghdr msg;
X	static char ptyidx[] = "0123456789abcdefghijklmnopqrstuvwxyz";
X	struct sockaddr sa;
X
X	/*
X	 * Close all file descriptors except 0, 1, and 2.
X	 */
X
X	for (fd=3; fd < NFDS; fd++)
X		(void)close(fd);
X
X	/*
X	 * Get the terminal configuration for this tty.
X	 */
X	(void)ioctl(0, (int)TIOCGETP, (char *)&sg);
X	(void)ioctl(0, (int)TIOCGETC, (char *)&tc);
X	(void)ioctl(0, (int)TIOCGLTC, (char *)&ltc);
X	(void)ioctl(0, (int)TIOCLGET, (char *)&lmode);
X
X	/*
X	 * Create a UNIX-domain socket.
X	 */
X
X	if (!(portal=getenv("UWIN"))) {
X		fprintf(stderr,
X		    "You must run %s under the window manager\n", *argv);
X		exit(1);
X	}
X
X	if ((sd=socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
X		perror("socket");
X		exit(1);
X	}
X	sa.sa_family = AF_UNIX;
X	(void)strncpy(sa.sa_data, portal, sizeof sa.sa_data-1);
X	sa.sa_data[sizeof sa.sa_data-1] = '\0';
X
X
X	/*
X	 * Obtain a pseudo-tty.  This code isn't very smart about finding one.
X	 */
X
X	ptysufx[1] = '\0';
X	for (cp=ptyidx; *cp; cp++) {
X		ptysufx[0] = *cp;
X		(void)strncpy(pty, "/dev/ptyp", sizeof pty-1);
X		(void)strncat(pty, ptysufx, sizeof pty-1);
X		if ((fd = open(pty, 2)) >= 0)
X			break;
X	}
X	if (fd < 0) {
X		fprintf(stderr, "Can't obtain a pseudo-tty for a new window\n");
X		exit(1);
X	}
X	(void)strncpy(tty, "/dev/ttyp", sizeof tty-1);
X	(void)strncat(tty, ptysufx, sizeof tty-1);
X
X
X	/* 
X	 * Fork a child process using this pseudo-tty.  Initialize the
X	 * terminal modes on the pseudo-tty to match those of the parent
X	 * tty.
X	 */
X
X	while ((pid=fork()) < 0)
X		sleep(5);
X	if (!pid) {
X		setuid(getuid());  /* in case it is setuid-root by mistake */
X		(void)signal(SIGTSTP, SIG_IGN);
X		(void)ioctl(open("/dev/tty", 2), (int)TIOCNOTTY, (char *)0);
X		if ((fd=open(tty, 2)) < 0)
X			_exit(1);
X		(void)dup2(fd, 0);
X		(void)dup2(0, 1);
X		(void)dup2(0, 2);
X		for (fd=3; fd < NFDS; fd++)
X			(void)close(fd);
X		(void)ioctl(0, (int)TIOCSETN, (char *)&sg);
X		(void)ioctl(0, (int)TIOCSETC, (char *)&tc);
X		(void)ioctl(0, (int)TIOCSLTC, (char *)&ltc);
X		(void)ioctl(0, (int)TIOCLSET, (char *)&lmode);
X		if (argc == 1) {
X			if (!(shell=getenv("SHELL")))
X				shell = "/bin/sh";
X			execl(shell, shell, (char *)0);
X			perror(shell);
X		} else {
X			execvp(argv[1], argv+1);
X			perror(argv[1]);
X		}
X		_exit(1);
X	}
X
X
X	/*
X	 * Pass the file descriptor to the window server and exit.
X	 */
X
X	iov.iov_base = pty;
X	iov.iov_len = strlen(pty);
X	msg.msg_name = (caddr_t)&sa;
X	msg.msg_namelen = sizeof sa.sa_family + strlen(sa.sa_data);
X	msg.msg_iov = &iov;
X	msg.msg_iovlen = 1;
X	msg.msg_accrights = (caddr_t)&fd;
X	msg.msg_accrightslen = sizeof fd;
X	if (sendmsg(sd, &msg, 0) < 0) {
X		perror("sendmsg");
X		exit(1);
X	}
X
X	exit(0);
X}
SHAR_EOF
if test 3482 -ne "`wc -c 'uwtool.c'`"
then
	echo shar: error transmitting "'uwtool.c'" '(should have been 3482 characters)'
fi
#	End of shell archive
exit 0

--
usenet: {decvax,cbatt,cbosgd,sun}!cwruecmp!bammi	jwahar r. bammi
csnet:       bammi@case
arpa:        bammi%case@csnet-relay
compuServe:  71515,155