🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: mod.mac.sources
Article #15

UW v3.4 (part 2 of 9)

#15
From: John Bruner
Date: Thu, 23 Oct 1986 19:56
2453 lines
64331 bytes
: [UW v3.4 - part 2 of 9]
:
: This is a shar archive.  Extract with sh, not csh.
echo mkdir server
mkdir server
echo mkdir utility
mkdir utility
echo x - utility/Makefile_4.2
sed -e 's/^X//' > utility/Makefile_4.2 << '!EOF!utility/Makefile_4.2!'
X#! /bin/make -f
X#
X#	uw utility makefile (4.2BSD)
X#
X#	INCDIR should be set to the directory containing header files.
X#
X#	LIBUW should be set to the name of the library file (or, if it is
X#	installed in a system directory, "-luw").
X#
X#	Note: in order for "uwterm" to work on remote machines it is
X#	necessary for it to be installed in a directly where "rsh"
X#	will find it.  The #defined symbol UWTERM in the source can
X#	be set to the desired absolute pathname, if necessary.
X#
X
XINCDIR	=	../h
X
XLIBUW	=	../lib/libuw.a
X
XCFLAGS	=	-O -I$(INCDIR)
XLFLAGS	=
X
XUWTOOL_OBJS =	uwtool.o
XUWTITLE_OBJS =	uwtitle.o
XUWTERM_OBJS =	uwterm.o
X
XOBJECTS	=	$(UWTOOL_OBJS) $(UWTITLE_OBJS) $(UWTERM_OBJS)
X
Xall:		uwtool uwtitle uwterm
X
Xuwtool:		$(UWTOOL_OBJS)
X	$(CC) -o $@ $(LFLAGS) $(UWTOOL_OBJS) $(LIBUW)
X
Xuwtitle:	$(UWTITLE_OBJS)
X	$(CC) -o $@ $(LFLAGS) $(UWTITLE_OBJS) $(LIBUW)
X
Xuwterm:		$(UWTERM_OBJS)
X	$(CC) -o $@ $(LFLAGS) $(UWTERM_OBJS) $(LIBUW)
X
Xlint:
X	lint -hubx -I$(INCDIR) `echo $(OBJECTS) | sed -e 's/\\.o/\\.c/g'`
X
Xtags:
X	ctags `echo $(OBJECTS) | sed -e 's/\\.o/\\.c/g'`
X
Xdepend: 
X	grep '^#include' `echo $(OBJECTS) | sed -e 's/\\.o/\\.c/g'` | \
X	sed -e '/</d' \
X	    -e 's/:[^"]*"\([^"]*\)".*/: ..\/h\/\1/' \
X	    -e 's,^../[a-zA-Z0-9]*/\([^\.]*\)\.[cs],\1.o \1.L,' | \
X	awk ' { if ($$1 != prev) { print rec; rec = $$0; prev = $$1; } \
X		else { if (length(rec $$3) > 78) { print rec; rec = $$0; } \
X		       else rec = rec " " $$3 } } \
X	      END { print rec } ' > makedep
X	echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep
X	echo '$$r makedep' >>eddep
X	echo 'w' >>eddep
X	cp Makefile Makefile.bak
X	ex - Makefile < eddep
X	rm eddep makedep
X
Xclean:
X	rm -f *.o
X
X# DO NOT DELETE THIS LINE (or the following blank line) -- make depend uses it
X
!EOF!utility/Makefile_4.2!
echo x - utility/Makefile_4.3
sed -e 's/^X//' > utility/Makefile_4.3 << '!EOF!utility/Makefile_4.3!'
X#! /bin/make -f
X#
X#	uw utility makefile (4.3BSD)
X#
X#	INCDIR should be set to the directory containing header files.
X#
X#	LIBUW should be set to the name of the library file (or, if it is
X#	installed in a system directory, "-luw").
X#
X#	Note: in order for "uwterm" to work on remote machines it is
X#	necessary for it to be installed in a directly where "rsh"
X#	will find it.  The #defined symbol UWTERM in the source can
X#	be set to the desired absolute pathname, if necessary.
X#
X
XINCDIR	=	../h
X
XLIBUW	=	../lib/libuw.a
X
XCFLAGS	=	-O -I$(INCDIR)
XLFLAGS	=
X
XUWTOOL_OBJS =	uwtool.o
XUWTITLE_OBJS =	uwtitle.o
XUWTERM_OBJS =	uwterm.o
X
XOBJECTS	=	$(UWTOOL_OBJS) $(UWTITLE_OBJS) $(UWTERM_OBJS)
X
Xall:		uwtool uwtitle uwterm
X
Xuwtool:		$(UWTOOL_OBJS)
X	$(CC) -o $@ $(LFLAGS) $(UWTOOL_OBJS) $(LIBUW)
X
Xuwtitle:	$(UWTITLE_OBJS)
X	$(CC) -o $@ $(LFLAGS) $(UWTITLE_OBJS) $(LIBUW)
X
Xuwterm:		$(UWTERM_OBJS)
X	$(CC) -o $@ $(LFLAGS) $(UWTERM_OBJS) $(LIBUW)
X
Xlint:
X	lint -hubx -I$(INCDIR) `echo $(OBJECTS) | sed -e 's/\\.o/\\.c/g'`
X
Xtags:
X	ctags `echo $(OBJECTS) | sed -e 's/\\.o/\\.c/g'`
X
Xdepend: 
X	$(CC) -M -I$(INCDIR) `echo $(OBJECTS) | sed -e 's/\\.o/\\.c/g'` | \
X	sed -e ':loop' \
X	    -e 's/\.\.\/[^ /]*\/\.\./../' \
X	    -e 't loop' | \
X	awk ' { if ($$1 != prev) { print rec; rec = $$0; prev = $$1; } \
X		else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \
X		       else rec = rec " " $$2 } } \
X	      END { print rec } ' >> makedep
X	echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep
X	echo '$$r makedep' >>eddep
X	echo 'w' >>eddep
X	cp Makefile Makefile.bak
X	ex - Makefile < eddep
X	rm eddep makedep
X
Xclean:
X	rm -f *.o
X
X# DO NOT DELETE THIS LINE (or the following blank line) -- make depend uses it
X
!EOF!utility/Makefile_4.3!
echo x - utility/uwterm.c
sed -e 's/^X//' > utility/uwterm.c << '!EOF!utility/uwterm.c!'
X/*
X *	uwterm
X *
X * Copyright 1986 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#include <sys/types.h>
X#include <sys/file.h>
X#include <sys/ioctl.h>
X#include <sys/socket.h>
X#include <sys/time.h>
X#include <sys/resource.h>
X#include <sys/wait.h>
X#include <netinet/in.h>
X#include <signal.h>
X#include <strings.h>
X#include <ctype.h>
X#include <errno.h>
X#include <stdio.h>
X
X#include "openpty.h"
X#include "uwlib.h"
X
X#ifndef UWTERM
X#define	UWTERM	"uwterm"
X#endif
X
X#define	CTL(c)		((c)&037)
X
X#ifndef FD_SET
X/* 4.2 retrofit: better definitions for these are in 4.3BSD's <sys/types.h> */
X#define	FD_SET(n,p)	((p)->fds_bits[0] |= (1 << (n)))
X#define	FD_CLR(n,p)	((p)->fds_bits[0] &= ~(1 << (n)))
X#define	FD_ISSET(n,p)	((p)->fds_bits[0] & (1 << (n)))
X#define	FD_ZERO(p)	((p)->fds_bits[0] = 0)
X#define	FD_SETSIZE	(NBBY*sizeof(long))
X#endif
X
Xextern int optind;
Xextern char *optarg;
Xextern char *getenv();
Xextern char *malloc();
Xextern deadkid();
Xextern int errno;
X
X#ifndef htons
X/* These should have been defined in <netinet/in.h>, but weren't (in 4.2BSD) */
Xextern unsigned short htons(), ntohs();
Xextern unsigned long htonl(), ntohl();
X#endif
X
Xchar *argv0;
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X	register char *cp;
X	register int c;
X	int wflag;
X	uwtype_t wtype;
X	char *term, *title, *server, *login;
X	struct sockaddr_in sa, *sin;
X	char hostname[32];
X
X	/*
X	 * If called with no arguments, create a new window using the
X	 * current shell according to the SHELL environment variable
X	 * (or "/bin/sh" if that doesn't exist).
X	 *
X	 * Options which are recognized directly are:
X	 *
X	 *	-ninet	connect to server at address "inet"
X	 *	-wtype	create window with emulation "type"
X	 *	-ttitle	label window with "title"
X	 *	-llogin	use login name "login" on remote machine
X	 *
X	 * If no explicit title is specified, the command name is used.
X	 */
X	argv0 = argv[0];
X	sin = (struct sockaddr_in *)0;
X	server = (char *)0;
X	login = (char *)0;
X	title = (char *)0;
X	wflag = 0;
X	term = (char *)0;
X	while ((c = getopt(argc, argv, "l:n:t:w:")) != EOF) {
X		switch (c) {
X		case 'l':
X			if (optarg[0] == '\0') {
X				fprintf(stderr,
X				    "%s: \"-l\" requires user name\n", argv0);
X			} else
X				login = optarg;
X			break;
X		case 'n':
X			server = optarg;
X			sa.sin_family = AF_INET;
X			sa.sin_addr.s_addr = 0;
X			sa.sin_port = 0;
X			bzero(sa.sin_zero, sizeof sa.sin_zero);
X			for (cp=optarg; isxdigit(c = *cp); cp++) {
X				/* Pyramid compiler botch */
X				/* sa.sin_addr.s_addr *= 16; */
X				sa.sin_addr.s_addr <<= 4;
X				if (isdigit(c))
X					sa.sin_addr.s_addr += c - '0';
X				else if (islower(c))
X					sa.sin_addr.s_addr += c-'a' + 10;
X				else
X					sa.sin_addr.s_addr += c-'A' + 10;
X			}
X			if (c == '.')
X				for (cp++; isdigit(c = *cp); cp++)
X					sa.sin_port = sa.sin_port*10 + c-'0';
X			if (sa.sin_addr.s_addr == 0 || sa.sin_port == 0) {
X				fprintf(stderr,
X				    "%s: bad Internet address: %s\n",
X				    argv0, optarg);
X				return(1);
X			}
X			sa.sin_addr.s_addr = htonl(sa.sin_addr.s_addr);
X			sa.sin_port = htons(sa.sin_port);
X			sin = &sa;
X			break;
X		case 'w':
X			wflag++;
X			term = optarg;
X			wtype = uw_ttype(optarg);
X			break;
X		case 't':
X			title = optarg;
X			break;
X		}
X	}
X
X	gethostname(hostname, sizeof hostname);
X	if (title == (char *)0) {
X		/*
X		 * If there was no "-t" argument, then "title" will still
X		 * be NULL.  In this case we use the host name.
X		 */
X		if (optind == argc)
X			title = hostname;
X		else
X			title = argv[optind];
X	}
X	
X	if (!term) {
X		/*
X		 * If there was no "-w" argument, fetch the window
X		 * type from the environment.  If that fails, use
X		 * a default.
X		 */
X		if ((term=getenv("TERM")) != (char *)0)
X			wtype = uw_ttype(term);
X		else
X			wtype = UWT_ADM31;
X	}
X
X	if (optind == argc-1) {
X		/*
X		 * The remaining argument is the host name.  Fork an "rsh"
X		 * to execute this on the remote machine.
X		 */
X		return(doremote(argv[optind], server, title, term, login));
X	} else if (optind == argc) {
X		/*
X		 * There are no other arguments.  Set up the connection
X		 * to this machine.
X		 */
X		return(dolocal(sin, title, wtype, term));
X	} else {
X		fprintf(stderr,
X		    "Usage: \"%s [-ttitle] [-wtype] [-naddr] [-llogin] host\"\n",
X		    argv0);
X		return(1);
X	}
X}
X
Xdoremote(host, server, title, term, login)
Xchar *host;
Xchar *server;
Xchar *title;
Xchar *term;
Xchar *login;
X{
X	register int fd, i, pid;
X	register char *cp;
X	char *av[16];
X
X	/*
X	 * Invoke a remote "uwterm" via "rsh".
X	 */
X	i = 0;
X	av[i++] = "rsh";
X	av[i++] = host;
X	av[i++] = "-n";
X	if (login != NULL) {
X		av[i++] = "-l";
X		av[i++] = login;
X	}
X	av[i++] = UWTERM;
X	if (server == (char *)0) {
X		if ((server = getenv("UW_INET")) == (char *)0) {
X			fprintf(stderr,"%s: Can't find window server\n",argv0);
X			return(1);
X		}
X	}
X	if ((cp = malloc(3+strlen(server))) == (char *)0) {
X		fprintf(stderr, "%s: out of memory\n", argv0);
X		return(1);
X	}
X	(void)strcat(strcpy(cp, "-n"), server);
X	av[i++] = cp;
X
X	if (title != (char *)0) {
X		if ((cp = malloc(3+strlen(title))) == (char *)0) {
X			fprintf(stderr, "%s: out of memory\n", argv0);
X			return(1);
X		}
X		(void)strcat(strcpy(cp, "-t"), title);
X		av[i++] = cp;
X	}
X
X	if (term != (char *)0) {
X		if ((cp = malloc(3+strlen(term))) == (char *)0) {
X			fprintf(stderr, "%s: out of memory\n", argv0);
X			return(1);
X		}
X		(void)strcat(strcpy(cp, "-w"), term);
X		av[i++] = cp;
X	}
X
X	av[i] = (char *)0;
X
X	for (fd=getdtablesize()-1; fd > 2; fd--)
X		(void)fcntl(fd, F_SETFD, 1);
X	(void)execvp(av[0], av);
X	(void)execv("/usr/ucb/rsh", av);	/* last-ditch try */
X	perror(av[0]);
X	return(1);
X}
X
X			
Xdolocal(sin, title, wtype, term)
Xstruct sockaddr_in *sin;
Xchar *title;
Xuwtype_t wtype;
Xchar *term;
X{
X	register UWIN uwin;
X	register int fd;
X	register int s;
X	struct ptydesc pt;
X
X	/*
X	 * Create and initialize a pseudo-terminal.
X	 */
X	if (openpty(&pt) < 0) {
X		fprintf(stderr, "No pseudo-terminals are available\n");
X		return(1);
X	}
X	ttyinit(pt.pt_tfd);
X
X
X	/*
X	 * Make fd's 0 and 1 be "/dev/null".  We'd like to force a known
X	 * definition for fd 2 at this point, but we may need it for
X	 * uw_perror() if uw_new() fails.
X	 */
X	if ((fd = open("/dev/null", O_RDWR)) >= 0) {	/* should be zero */
X		if (fd != 0 && pt.pt_tfd != 0 && pt.pt_pfd != 0)
X			dup2(fd, 0);
X		if (fd != 1 && pt.pt_tfd != 1 && pt.pt_pfd != 1)
X			dup2(fd, 1);
X		if (fd > 2)
X			(void)close(fd);
X	}
X
X	/*
X	 * Create and title the window.  Make it visible.
X	 */
X	if ((uwin = uw_new(wtype, sin)) == (UWIN)0) {
X		uw_perror(argv0, uwerrno, errno);
X		return(1);
X	}
X	(void)uw_stitle(uwin, title);
X	(void)uw_svis(uwin, 1);
X
X	/*
X	 * We no longer have use for fd 2, so make it "/dev/null" (the
X	 * same as fd 0.
X	 */
X	(void)dup2(0, 2);
X
X	/*
X	 * Adjust the environment to contain the correct values of TERM,
X	 * UW_ID, and UW_INET.  These will be inherited by the child
X	 * we will create next.
X	 */
X	adjenv(term, sin, UW_ID(uwin));
X
X	/*
X	 * Create a process to execute the command connected to the pty.
X	 */
X	runcmd(pt.pt_tfd, pt.pt_tname);
X
X	/*
X	 * Ignore signals that might cause us trouble.  We do NOT ignore
X	 * SIGTSTP so that the user can move us from the foreground into
X	 * the background if desired.
X	 */
X	signal(SIGINT, SIG_IGN);
X	signal(SIGQUIT, SIG_IGN);
X	signal(SIGCHLD, deadkid);
X
X#if defined(TIOCSWINSZ) || defined(TIOCSSIZE)
X	/*
X	 * Install an option handling routine to catch window size
X	 * changes from the Mac and make the appropriate changes to
X	 * the pseudo-terminal.
X	 */
X	setresize(uwin, pt.pt_pfd);
X#endif
X
X	/*
X	 * Close the slave side of the pty.  Copy data between the pty
X	 * and the window.  The return value from copy() is the exit
X	 * status.
X	 */
X	(void)close(pt.pt_tfd);
X	s = copy(pt.pt_pfd, UW_DATAFD(uwin));
X	uw_kill(uwin);
X	return(s);
X}
X
Xttyinit(ptyfd)
Xregister int ptyfd;
X{
X	register int ttyfd;
X	struct sgttyb sg;
X	struct tchars tc;
X	struct ltchars ltc;
X	int ldisc;
X	int lmode;
X
X	/*
X	 * Initialize the modes of the terminal whose file descriptor
X	 * is "ptyfd" to the same modes as the current terminal.  If there
X	 * isn't a "current terminal" handy, then use hardcoded defaults.
X	 */
X	for (ttyfd=0; ttyfd < 3 && ioctl(ttyfd, TIOCGETD, &ldisc) < 0; ttyfd++)
X		;
X	if (ttyfd < 3) {
X		(void)ioctl(ttyfd, TIOCGETP, &sg);
X		(void)ioctl(ttyfd, TIOCGETC, &tc);
X		(void)ioctl(ttyfd, TIOCGLTC, &ltc);
X		(void)ioctl(ttyfd, TIOCLGET, &lmode);
X	} else {
X		ldisc = NTTYDISC;
X
X		sg.sg_ispeed = sg.sg_ospeed = 13; /* doesn't really matter */
X		sg.sg_erase = 0177;	/* ugh */
X		sg.sg_kill = CTL('u');	/* ugh */
X		sg.sg_flags = ECHO|CRMOD|ANYP;
X
X		tc.t_intrc = CTL('c');	/* yuck, should be 0177 */
X		tc.t_quitc = CTL('\\');
X		tc.t_startc = CTL('q');
X		tc.t_stopc = CTL('s');
X		tc.t_eofc = CTL('d');
X		tc.t_brkc = -1;
X
X		ltc.t_suspc = CTL('z');
X		ltc.t_dsuspc = CTL('y');
X		ltc.t_rprntc = CTL('r');
X		ltc.t_flushc = CTL('o');
X		ltc.t_werasc = CTL('w');
X		ltc.t_lnextc = CTL('v');
X
X		lmode = LCRTBS|LCRTERA|LCRTKIL|LCTLECH;
X	}
X	(void)ioctl(ptyfd, TIOCSETD, &ldisc);
X	(void)ioctl(ptyfd, TIOCSETP, &sg);
X	(void)ioctl(ptyfd, TIOCSETC, &tc);
X	(void)ioctl(ptyfd, TIOCSLTC, &ltc);
X	(void)ioctl(ptyfd, TIOCLSET, &lmode);
X}
X
Xadjenv(term, sin, wid)
Xchar *term;
Xstruct sockaddr_in *sin;
Xuwid_t wid;
X{
X	char *env[4];
X	static char ttype[sizeof "TERM=" + 16];
X	static char inet[sizeof INET_ENV + 16];
X	static char idstr[sizeof "UW_ID=" + 20];
X
X	/*
X	 * Redefine the environment variable UW_ID.  Redefine UW_INET
X	 * if "sin" is non-NULL.  Redefine TERM.
X	 */
X	(void)sprintf(ttype, "TERM=%.15s", term);
X	env[0] = ttype;
X	
X	(void)sprintf(idstr, "UW_ID=%ld", wid);
X	env[1] = idstr;
X
X	if (sin != NULL) {
X		(void)sprintf(inet, "%s=%08lx.%d", INET_ENV,
X		    ntohl(sin->sin_addr.s_addr), ntohs(sin->sin_port));
X		env[2] = inet;
X		env[3] = (char *)0;
X	}  else
X		env[2] = (char *)0;
X	env_set(env);
X}
X
Xruncmd(fd, tname)
Xint fd;
Xchar *tname;
X{
X	register int pid;
X	register char *shell;
X
X	/*
X	 * Figure out the name of the user's shell.  If unknown,
X	 * use a default.
X	 */
X	if ((shell = getenv("SHELL")) == (char *)0)
X		shell = "/bin/sh";
X
X	/*
X	 * Fork a new process and attach "fd" to fd's 0, 1, and 2 of
X	 * that new process.  Disassociate the current controlling
X	 * terminal and attach the new one (whose name is "tname").
X	 */
X	while ((pid = fork()) < 0)
X		sleep(5);
X	if (pid == 0) {
X		if (fd != 0)
X			dup2(fd, 0);
X		if (fd != 1)
X			dup2(fd, 1);
X		if (fd != 2)
X			dup2(fd, 2);
X		if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
X			(void)ioctl(fd, TIOCNOTTY, (char *)0);
X			(void)close(fd);
X		} else
X			setpgrp(0, 0);
X		(void)open(tname, O_RDWR);
X		for (fd=getdtablesize()-1; fd > 2; fd--)
X			(void)fcntl(fd, F_SETFD, 1);
X		execlp(shell, "-", (char *)0);
X		execl(shell, "-", (char *)0);
X		_exit(1);
X	}
X}
X
Xcopy(fd1, fd2)
Xint fd1, fd2;
X{
X	struct fdinfo {
X		int	fi_fd;		/* associated file descriptor */
X		int	fi_size;	/* amount of data in buffer */
X		char	*fi_ptr;	/* pointer to data in fi_buf */
X		char	fi_buf[1024];
X	};
X	register struct fdinfo *fi, *fo;
X	register int n, nfds, len;
X	struct fdinfo fdinfo[2];
X	struct fd_set rdmask[2], wtmask[2], exmask[2];
X	struct timeval tv;
X
X	/*
X	 * Copy data between file descriptors fd1 and fd2.  Return when an
X	 * EOF is read or an I/O error (other than an interrupted system
X	 * call or non-blocking I/O message) is encountered.
X	 */
X	FD_ZERO(&rdmask[1]);
X	FD_ZERO(&wtmask[1]);
X	FD_ZERO(&exmask[1]);
X
X	fdinfo[0].fi_fd = fd1;
X	fdinfo[0].fi_size = 0;
X	fdinfo[1].fi_fd = fd2;
X	fdinfo[1].fi_size = 0;
X
X	FD_SET(fd1, &rdmask[1]);
X	FD_SET(fd2, &rdmask[1]);
X
X	(void)fcntl(fd1, F_SETFL, FNDELAY);
X	(void)fcntl(fd2, F_SETFL, FNDELAY);
X
X	nfds = ((fd1 > fd2) ? fd1 : fd2) + 1;
X
X	while (1) {
X		rdmask[0] = rdmask[1];
X		wtmask[0] = wtmask[1];
X		exmask[0] = exmask[1];
X		errno = 0;
X		if (fdinfo[0].fi_size != 0 || fdinfo[1].fi_size != 0) {
X			/*
X			 * Select does not work correctly for writes on
X			 * some machines, so we must fake it.  If a write
X			 * is pending, we time out after 1/50 second and
X			 * pretend that select told us that writes could
X			 * now be performed.  The code below will do the
X			 * correct thing if the write would still block.
X			 */
X			tv.tv_sec = 0;
X			tv.tv_usec = 1000000 / 50;
X			n = select(nfds, rdmask, wtmask, exmask, &tv);
X			wtmask[0] = wtmask[1];
X		} else
X			n = select(nfds, rdmask, wtmask, exmask, (struct timeval *)0);
X		if (n < 0 && errno == EINTR) {
X			continue;
X		} else if (n <= 0) {
X			perror("select");
X			return(1);
X		}
X		for (fi=fdinfo; fi < fdinfo+2; fi++) {
X			fo = fdinfo + !(fi - fdinfo);
X			if (FD_ISSET(fi->fi_fd, rdmask)) {
X				/* data available for reading */
X				len = read(fi->fi_fd, fi->fi_buf,
X				    sizeof fi->fi_buf);
X				if (len > 0) {
X					fi->fi_size = len;
X					fi->fi_ptr = fi->fi_buf;
X					FD_CLR(fi->fi_fd, &rdmask[1]);
X					FD_SET(fo->fi_fd, &wtmask[1]);
X					FD_SET(fo->fi_fd, &wtmask[0]);
X				} else if (len == 0) {
X					/* EOF, exit */
X					return(0);
X				} else if (errno != EWOULDBLOCK &&
X				    errno != EINTR) {
X					/* error, exit */
X					return(1);
X				}
X			}
X			if (FD_ISSET(fo->fi_fd, wtmask)) {
X				/* data ready for writing */
X				errno = 0;
X				len = write(fo->fi_fd, fi->fi_ptr, fi->fi_size);
X				if (len > 0) {
X					fi->fi_ptr += len;
X					fi->fi_size -= len;
X					if (fi->fi_size == 0) {
X						FD_SET(fi->fi_fd, &rdmask[1]);
X						FD_CLR(fo->fi_fd, &wtmask[1]);
X					}
X				} else if (errno != EWOULDBLOCK &&
X				    errno != EINTR) {
X					/* error, exit */
X					return(1);
X				}
X			}
X		}
X	}
X}
X
Xdeadkid()
X{
X	register int pid;
X
X	/*
X	 * Collect dead children.  Don't bother with their exit status
X	 * or resource usage.
X	 */
X	while ((pid = wait3((union wait *)0, WNOHANG, (struct rusage *)0)) > 0)
X		;
X}
X
X#if defined(TIOCSWINSZ) || defined(TIOCSSIZE)
Xstatic int ptyfd;
X
X#ifdef TIOCSWINSZ
Xstatic struct winsize winsz;
X
Xvoid
Xdoresize(uwin, optnum, optcmd, uwoptval)
XUWIN uwin;
Xuwopt_t optnum;
Xuwoptcmd_t optcmd;
Xunion uwoptval *uwoptval;
X{
X	uwtype_t wtype;
X
X	/*
X	 * 4.3BSD-style window resizing
X	 */
X	if (uw_gtype(uwin, &wtype) < 0)
X		wtype = UWT_ADM31;	/* probably wrong to do this here */
X	if (optcmd == UWOC_SET) {
X		switch (optnum) {
X		case UWOP_WSIZE:
X			winsz.ws_ypixel = uwoptval->uwov_point.v;
X			winsz.ws_xpixel = uwoptval->uwov_point.h;
X			break;
X		case UWOP_TSIZE:
X			if (wtype <= UWT_ANSI) {
X				winsz.ws_row = uwoptval->uwov_point.v;
X				winsz.ws_col = uwoptval->uwov_point.h;
X			}
X			break;
X		}
X		if (wtype <= UWT_ANSI &&
X		    (optnum == UWOP_WSIZE || optnum == UWOP_TSIZE))
X			(void)ioctl(ptyfd, TIOCSWINSZ, &winsz);
X	}
X}
X
Xsetresize(uwin, fd)
XUWIN uwin;
Xint fd;
X{
X	struct uwpoint pt;
X	uwtype_t wtype;
X
X	/*
X	 * Set up the option-handling routine "doresize".
X	 */
X	ptyfd = fd;
X	uw_optfn(uwin, UWOP_TSIZE, doresize);
X	uw_optfn(uwin, UWOP_WSIZE, doresize);
X	winsz.ws_row = 24;	/* default to standard terminal size */
X	winsz.ws_col = 80;
X	if (uw_gwsize(uwin, &pt) == 0) {
X		winsz.ws_ypixel = pt.uwp_v;
X		winsz.ws_xpixel = pt.uwp_h;
X	} else {
X		/* make up something plausible */
X		winsz.ws_ypixel = 8 * winsz.ws_row;
X		winsz.ws_xpixel = 8 * winsz.ws_col;
X	}
X
X	if (uw_gtype(uwin, &wtype) == 0 && wtype <= UWT_ANSI)
X		(void)uw_optcmd(uwin, UWOP_TSIZE, UWOC_DO, (union uwoptval *)0);
X}
X
X#else
X#ifdef TIOCSSIZE
Xvoid
Xdoresize(uwin, optnum, optcmd, uwoptval)
XUWIN uwin;
Xuwopt_t optnum;
Xuwoptcmd_t optcmd;
Xunion uwoptval *uwoptval;
X{
X	struct ttysize ts;
X	uwtype_t wtype;
X
X	/*
X	 * Sun-style window resizing
X	 */
X	if (uw_gtype(uwin, &wtype) < 0)
X		wtype = UWT_ADM31;	/* probably wrong to do this here */
X	if (wtype <= UWT_ANSI && optnum == UWOP_TSIZE && optcmd == UWOC_SET) {
X		ts.ts_lines = uwoptval->uwov_point.v;
X		ts.ts_cols = uwoptval->uwov_point.h;
X		(void)ioctl(ptyfd, TIOCSSIZE, &ts);
X	}
X}
X
Xsetresize(uwin, fd)
XUWIN uwin;
Xint fd;
X{
X	uwtype_t wtype;
X
X	/*
X	 * Set up the option-handling routine "doresize".
X	 */
X	ptyfd = fd;
X	uw_optfn(uwin, UWOP_TSIZE, doresize);
X
X	if (uw_gtype(uwin, &wtype) == 0 && wtype <= UWT_ANSI)
X		(void)uw_optcmd(uwin, UWOP_TSIZE, UWOC_DO, (union uwoptval *)0);
X}
X#endif
X#endif
X#endif
!EOF!utility/uwterm.c!
echo x - utility/uwtitle.c
sed -e 's/^X//' > utility/uwtitle.c << '!EOF!utility/uwtitle.c!'
X/*
X *	uwtitle
X *
X * Copyright 1986 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#include <strings.h>
X#include <stdio.h>
X
X#include "uwlib.h"
X
Xextern char *optarg;
Xextern int optind;
Xextern int errno;
X
Xextern char *getenv();
Xextern long atol();
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X	register int c;
X	register char *cp, *cq, **av;
X	register uwid_t uwid;
X	char *argv0;
X	char *cqlimit;
X	union uwoptval uwoptval;
X
X	/*
X	 * If called with no arguments, print a syntax message.  Otherwise,
X	 * set the title of the current window to argv[1..argc-1].  The
X	 * window ID is obtained from the environment or the "-i" argument.
X	 */
X	argv0 = argv[0];
X	uwid = 0;
X	while ((c = getopt(argc, argv, "i:")) != EOF) {
X		switch (c) {
X		case 'i':
X			if ((uwid = atol(optarg)) == 0) {
X				fprintf(stderr,
X				    "%s: malformed \"-i\" argument\n", argv0);
X				return(1);
X			}
X			break;
X		}
X	}
X	if (optind >= argc) {
X		fprintf(stderr, "Syntax: \"%s [-iID] title ...\"\n", *argv);
X		return(1);
X	}
X
X	if (uwid == 0) {
X		if ((cp = getenv("UW_ID")) == NULL) {
X			fprintf(stderr,
X			    "%s: can't determine window ID\n", argv0);
X			return(1);
X		}
X
X		if ((uwid = (uwid_t)atol(cp)) == 0) {
X			fprintf(stderr,
X			    "%s: garbaged window ID in environment: %s",
X			    argv0, cp);
X			return(1);
X		}
X	}
X
X	/*
X	 * Copy the argv list into "uwoptval" and change the title.
X	 */
X	av = argv + optind - 1;
X	cq = uwoptval.uwov_string;
X	cqlimit = uwoptval.uwov_string + sizeof uwoptval.uwov_string;
X	while ((cp = *++av) != NULL && cq < cqlimit) {
X		while (cq < cqlimit && (*cq++ = *cp++) != '\0')
X			;
X		cq[-1] = ' ';
X	}
X	cq[-1] = '\0';
X
X	if (uw_rsetopt(uwid, UWOP_TITLE, &uwoptval) < 0) {
X		uw_perror("uw_rsetopt", uwerrno, errno);
X		return(1);
X	} else
X		return(0);
X}
!EOF!utility/uwtitle.c!
echo x - utility/uwtool.c
sed -e 's/^X//' > utility/uwtool.c << '!EOF!utility/uwtool.c!'
X/*
X *	uwtool
X *
X * Copyright 1986 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#include <strings.h>
X#include <stdio.h>
X
X#include "uwlib.h"
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X	register uwid_t uwid;
X	register char *fname, *term;
X	register int c;
X	register uwtype_t wtype;
X	char *argv0;
X	char *av[2];
X	int vflag;
X	int wflag;
X	char *title;
X	union uwoptval uwoptval;
X	extern int errno;
X	extern int optind;
X	extern char *optarg;
X	extern char *getenv();
X
X	/*
X	 * If called with no arguments, create a new window using the
X	 * current shell according to the SHELL environment variable
X	 * (or "/bin/sh" if that doesn't exist).  If called with
X	 * arguments, argv[optind] through argv[argc-1] are the arguments
X	 * to the command.
X	 *
X	 * Options which are recognized directly are:
X	 *
X	 *	-v	(verbose) print new window ID on stdout
X	 *	-wtype	create window with emulation "type"
X	 *	-ttitle	label window with "title"
X	 *
X	 * If no explicit title is specified, the command name is used.
X	 */
X	argv0 = argv[0];
X	wflag = 0;
X	vflag = 0;
X	title = (char *)0;
X	while ((c = getopt(argc, argv, "vw:t:")) != EOF) {
X		switch (c) {
X		case 'v':
X			vflag++;
X			break;
X		case 'w':
X			wflag++;
X			wtype = uw_ttype(optarg);
X			break;
X		case 't':
X			title = optarg;
X			break;
X		}
X	}
X			
X	if (optind < argc) {
X		/*
X		 * Adjust the "argv" pointer according to the number of
X		 * arguments we've processed.
X		 */
X		argv += optind;
X		fname = *argv;
X	} else {
X		/*
X		 * No (non-option) arguments -- use SHELL
X		 */
X		if ((fname = getenv("SHELL")) == (char *)0)
X			fname = "/bin/sh";
X		av[0] = fname;
X		av[1] = (char *)0;
X		argv = av;
X	}
X
X	if (title == (char *)0) {
X		/*
X		 * If there was no "-t" argument, then "title" will still
X		 * be NULL.  In this case we use the command name as
X		 * the title.
X		 */
X		title = fname;
X	}
X	
X	if (!wflag) {
X		/*
X		 * If there was no "-w" argument, fetch the window
X		 * type from the environment.  If that fails, use
X		 * a default.
X		 */
X		if ((term=getenv("TERM")) != (char *)0)
X			wtype = uw_ttype(term);
X		else
X			wtype = UWT_ADM31;
X	}
X	
X	if ((uwid = uw_cmd(wtype, fname, argv)) > 0) {
X		(void)strncpy(uwoptval.uwov_string, title,
X		    sizeof uwoptval.uwov_string);
X		(void)uw_rsetopt(uwid, UWOP_TITLE, &uwoptval);
X		if (vflag)
X			printf("%d\n", uwid);
X		return(0);
X	} else {
X		if (uwerrno != UWE_NXSERV)
X			uw_perror(fname, uwerrno, errno);
X		else
X			uw_perror(argv0, uwerrno, errno);
X		return(1);
X	}
X}
!EOF!utility/uwtool.c!
echo x - server/Makefile_4.2
sed -e 's/^X//' > server/Makefile_4.2 << '!EOF!server/Makefile_4.2!'
X#! /bin/make -f
X#
X#	uw makefile (4.2BSD)
X#
X# INCDIR names the directory where the header files are located.
X#
X# OBJECTS names all of the object files required for the server.
X#
X# OPTIONS is a list of the site-dependent compile-time options:
X# 	-DUTMP		attempt to update "/etc/utmp" (who) file
X# 	-DV7TTYS	V7-format "/etc/ttys" (pre-4.3BSD)
X#
X# V7TTYS should be used for V7-derived systems that do not have 4.3BSD's
X# "/etc/ttys" file.  This includes 4.2BSD and Sun UNIX.  There is no
X# support for USG's "/etc/inittab".
X#
X
XINCDIR	=	../h
X
XOPTIONS	=	-DUTMP -DV7TTYS
X
XOBJECTS	=	uw_clk.o uw_env.o uw_fd.o uw_ipc.o uw_main.o uw_opt.o \
X		uw_pcl.o uw_tty.o uw_utmp.o uw_win.o openpty.o
X
XCFLAGS	=	$(OPTIONS) -I$(INCDIR) -O
XLFLAGS	=
X
Xuw:		$(OBJECTS)
X	$(CC) $(LFLAGS) -o uw $(OBJECTS) $(LIBS)
X
Xlint:
X	lint -hbx -I$(INCDIR) $(OPTIONS) `echo $(OBJECTS) | sed -e 's/\\.o/\\.c/g'`
X
Xtags:
X	ctags `echo $(OBJECTS) | sed -e 's/\\.o/\\.c/g'`
X
Xdepend: 
X	grep '^#include' `echo $(OBJECTS) | sed -e 's/\\.o/\\.c/g'` | \
X	sed -e '/</d' \
X	    -e 's/:[^"]*"\([^"]*\)".*/: ..\/h\/\1/' \
X	    -e 's,^../[a-zA-Z0-9]*/\([^\.]*\)\.[cs],\1.o \1.L,' | \
X	awk ' { if ($$1 != prev) { print rec; rec = $$0; prev = $$1; } \
X		else { if (length(rec $$3) > 78) { print rec; rec = $$0; } \
X		       else rec = rec " " $$3 } } \
X	      END { print rec } ' > makedep
X	echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep
X	echo '$$r makedep' >>eddep
X	echo 'w' >>eddep
X	cp Makefile Makefile.bak
X	ex - Makefile < eddep
X	rm eddep makedep
X
Xclean:
X	rm -f *.o
X
X# DO NOT DELETE THIS LINE (or the following blank line) -- make depend uses it
X
!EOF!server/Makefile_4.2!
echo x - server/Makefile_4.3
sed -e 's/^X//' > server/Makefile_4.3 << '!EOF!server/Makefile_4.3!'
X#! /bin/make -f
X#
X#	uw makefile (4.3BSD)
X#
X# INCDIR names the directory where the header files are located.
X#
X# OBJECTS names all of the object files required for the server.
X#
X# OPTIONS is a list of the site-dependent compile-time options:
X# 	-DUTMP		attempt to update "/etc/utmp" (who) file
X# 	-DV7TTYS	V7-format "/etc/ttys" (pre-4.3BSD)
X#
X# V7TTYS should be used for V7-derived systems that do not have 4.3BSD's
X# "/etc/ttys" file.  This includes 4.2BSD and Sun UNIX.  There is no
X# support for USG's "/etc/inittab".
X#
X
XINCDIR	=	../h
X
XOPTIONS	=	-DUTMP
X
XOBJECTS	=	uw_clk.o uw_env.o uw_fd.o uw_ipc.o uw_main.o uw_opt.o \
X		uw_pcl.o uw_tty.o uw_utmp.o uw_win.o openpty.o
X
XCFLAGS	=	$(OPTIONS) -I$(INCDIR) -O
XLFLAGS	=
X
Xuw:		$(OBJECTS)
X	$(CC) $(LFLAGS) -o uw $(OBJECTS) $(LIBS)
X
Xlint:
X	lint -hbx -I$(INCDIR) $(OPTIONS) `echo $(OBJECTS) | sed -e 's/\\.o/\\.c/g'`
X
Xtags:
X	ctags `echo $(OBJECTS) | sed -e 's/\\.o/\\.c/g'`
X
Xdepend: 
X	$(CC) -M -I$(INCDIR) $(OPTIONS) `echo $(OBJECTS) | sed -e 's/\\.o/\\.c/g'` | \
X	sed -e ':loop' \
X	    -e 's/\.\.\/[^ /]*\/\.\./../' \
X	    -e 't loop' | \
X	awk ' { if ($$1 != prev) { print rec; rec = $$0; prev = $$1; } \
X		else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \
X		       else rec = rec " " $$2 } } \
X	      END { print rec } ' >> makedep
X	echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep
X	echo '$$r makedep' >>eddep
X	echo 'w' >>eddep
X	cp Makefile Makefile.bak
X	ex - Makefile < eddep
X	rm eddep makedep
X
Xclean:
X	rm -f *.o
X
X# DO NOT DELETE THIS LINE (or the following blank line) -- make depend uses it
X
!EOF!server/Makefile_4.3!
echo x - server/openpty.c
sed -e 's/^X//' > server/openpty.c << '!EOF!server/openpty.c!'
X/*
X *	openpty - open a pseudo-terminal
X *
X * The first time that the routine is called, the device directory is
X * searched and a list of all candidate pseudo-terminals is compiled.
X * Candidates are defined to be those entries in "/dev" whose names
X * (1) are the same length as PTY_PROTO and (2) start with the
X * initial string PTY_PREFIX.  Further, the master and slave sides
X * must both exist.
X *
X * openpty() attempts to find an unused pseudo-terminal from the list
X * of candidates.  If one is found, the master and slave sides are
X * opened and the file descriptors and names of these two devices are
X * returned in a "ptydesc" structure.  (The address of this structure
X * is supplied by the caller.  Zero is returned if openpty() was
X * successful, -1 is returned if no pty could be found.
X */
X
X#include <sys/types.h>
X#include <sys/dir.h>
X#include <fcntl.h>
X#include <strings.h>
X#include "openpty.h"
X
X#define	DEV_DIR		"/dev"		/* directory where devices live */
X#define	PT_INDEX	(sizeof DEV_DIR)	/* location of 'p' in "pty" */
X
X#define	PTY_PROTO	"ptyp0"		/* prototype for pty names */
X#define	PTY_PREFIX	"pty"		/* prefix required for name of pty */
X
Xstruct ptyinfo {
X	struct ptyinfo	*pi_next;
X	char		*pi_pty;
X	char		*pi_tty;
X};
X
Xstatic struct ptyinfo *ptylist;
X
Xextern char *malloc();
X
Xstatic
Xchar *
Xdevname(name)
Xchar *name;
X{
X	register char *fullname;
X
X	/*
X	 * Construct the full name of a device in DEV_DIR.  Returns
X	 * NULL if it failed (because malloc() failed).
X	 */
X
X	fullname = malloc((unsigned)(sizeof DEV_DIR + 1 + strlen(name)));
X	if (fullname != NULL) {
X		(void)strcpy(fullname, DEV_DIR);
X		(void)strcat(fullname, "/");
X		(void)strcat(fullname, name);
X	}
X	return(fullname);
X}
X
Xstatic
Xisapty(dp)
Xstruct direct *dp;
X{
X	static struct ptyinfo *pi;
X
X	/*
X	 * We don't care about the gory details of the directory entry.
X	 * Instead, what we really want is an array of pointers to
X	 * device names (with DEV_DIR prepended).  Therefore, we create
X	 * this array ourselves and tell scandir() to ignore every
X	 * directory entry.
X	 *
X	 * If malloc() fails, the current directory entry is ignored.
X	 */
X	if (pi == NULL) {
X		pi = (struct ptyinfo *)malloc((unsigned)sizeof *pi);
X		if (pi == NULL)
X			return(0);
X	}
X
X	if (strlen(dp->d_name) == sizeof PTY_PROTO - 1 &&
X	    strncmp(dp->d_name, PTY_PREFIX, sizeof PTY_PREFIX - 1) == 0) {
X		pi->pi_pty = devname(dp->d_name);
X		if (pi->pi_pty == NULL)
X			return(0);
X		pi->pi_tty = malloc((unsigned)(strlen(pi->pi_pty) + 1));
X		if (pi->pi_tty == NULL) {
X			free(pi->pi_pty);
X			return(0);
X		}
X		(void)strcpy(pi->pi_tty, pi->pi_pty);
X		pi->pi_tty[PT_INDEX] = 't';
X		if (access(pi->pi_pty, 0) == 0 && access(pi->pi_tty, 0) == 0) {
X			pi->pi_next = ptylist;
X			ptylist = pi;
X			pi = NULL;
X		} else {
X			free(pi->pi_pty);
X			free(pi->pi_tty);
X		}
X	}
X	return(0);
X}
X
Xopenpty(pt)
Xstruct ptydesc *pt;
X{
X	register struct ptyinfo *pi;
X	static int fail;
X	auto struct direct **dirlist;
X	extern char *re_comp();
X	extern int alphasort();
X
X	/*
X	 * If scandir() fails or no possible pty's are found, then "fail"
X	 * is set non-zero.  If "fail" is non-zero then the routine bombs
X	 * out immediately.  Otherwise, the list of candidates is examined
X	 * starting with the entry following the last one chosen.
X	 */
X	if (fail)
X		return(-1);
X
X	if (!ptylist) {		/* first time */
X		if (scandir(DEV_DIR, &dirlist, isapty, alphasort) < 0 ||
X		    ptylist == NULL) {
X			fail = 1;
X			return(-1);
X		}
X		for (pi=ptylist; pi->pi_next; pi=pi->pi_next)
X			;
X		pi->pi_next = ptylist;	/* make the list circular */
X	}
X
X	pi = ptylist;
X	do {
X		if ((pt->pt_pfd = open(pi->pi_pty, O_RDWR)) >= 0) {
X			if ((pt->pt_tfd = open(pi->pi_tty, O_RDWR)) >= 0) {
X				ptylist = pi->pi_next;
X				pt->pt_pname = pi->pi_pty;
X				pt->pt_tname = pi->pi_tty;
X				return(0);
X			} else
X				(void)close(pt->pt_pfd);
X		}
X		pi = pi->pi_next;
X	} while (pi != ptylist);
X	return(-1);
X}
!EOF!server/openpty.c!
echo x - server/uw_clk.c
sed -e 's/^X//' > server/uw_clk.c << '!EOF!server/uw_clk.c!'
X/*
X *	uw_clk - timer support for UW
X *
X * Copyright 1986 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#include <sys/types.h>
X#include <sys/time.h>
X#include <sys/signal.h>
X#include <sys/resource.h>
X
X#include "uw_param.h"
X#include "uw_clk.h"
X
Xstatic struct timeout *pending;
Xstatic struct timeout *freelist;
X
Xint timer_rdy;			/* nonzero when some timeout is ready to run */
X
Xclk_timeout(secs, fn, arg)
Xint secs;
Xvoid (*fn)();
Xtoarg_t arg;
X{
X	register struct timeout *to, **tol;
X	register time_t curtime;
X	extern time_t time();
X
X	to = freelist;
X	if (!to) {
X		if (!(to = (struct timeout *)malloc(sizeof *to)))
X			return(-1);
X	} else
X		freelist = to->to_next;
X	to->to_fn = fn;
X	to->to_arg = arg;
X
X	if (secs < 0)
X		secs = 0;
X	curtime = time((time_t *)0);
X	to->to_when = curtime + secs;
X
X	tol = &pending;
X	while (*tol && to->to_when > (*tol)->to_when)
X		tol = &(*tol)->to_next;
X	to->to_next = *tol;
X	*tol = to;
X
X	clk_service();
X	return(0);
X}
X
Xclk_service()
X{
X	register struct timeout *to;
X	register time_t curtime;
X
X	curtime = time((time_t *)0);
X	while ((to=pending) && to->to_when <= curtime) {
X		pending = to->to_next;
X		if (to->to_fn) {
X			(*to->to_fn)(to->to_arg);
X			to->to_next = freelist;
X			freelist = to;
X		}
X	}
X
X	timer_rdy = 0;
X	if (pending)
X		(void)alarm((unsigned)(pending->to_when - curtime));
X}
X
Xvoid
Xclk_alarm()
X{
X	/*
X	 * A SIGALRM has been received.
X	 */
X	timer_rdy = 1;
X}
X
Xclk_init()
X{
X	timer_rdy = 0;
X	(void)signal(SIGALRM, clk_alarm);
X}
!EOF!server/uw_clk.c!
echo x - server/uw_env.c
sed -e 's/^X//' > server/uw_env.c << '!EOF!server/uw_env.c!'
X/*
X *	uw_env - environment manipulation
X *
X * Copyright 1985,1986 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#define	MAXENV	128	/* maximum number of arguments in environment */
X
Xstatic char *earray[MAXENV+1];
X
Xenv_set(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++ = (char *)0;
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 (!env_cmp(*ep1, *ep2))
X					break;
X			if (ep2 < earray+MAXENV) {
X				if (!*ep2)
X					ep2[1] = (char *)0;
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 (env_cmp(*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
Xenv_cmp(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}
!EOF!server/uw_env.c!
echo x - server/uw_fd.c
sed -e 's/^X//' > server/uw_fd.c << '!EOF!server/uw_fd.c!'
X/*
X *	uw_fd - file-descriptor/select data
X *
X * Copyright 1986 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#include <sys/types.h>
X
X#include "uw_param.h"
X#include "uw_fd.h"
X
Xstruct selmask selmask[2];
Xstruct fdmap fdmap[FD_SETSIZE];
Xfildes_t nfds;				/* number of file descriptors */
X
Xfd_init()
X{
X	register fildes_t fd;
X
X	nfds = getdtablesize();
X	if (nfds > FD_SETSIZE)
X		nfds = FD_SETSIZE;
X	fdmap[0].f_type = FDT_MAC;
X	fdmap[1].f_type = FDT_MAC;
X	fdmap[2].f_type = FDT_DEBUG;
X	for (fd=3; fd < FD_SETSIZE; fd++) {
X		fdmap[fd].f_type = FDT_NONE;
X		(void)close(fd);
X	}
X	FD_ZERO(&selmask[0].sm_rd);
X	FD_ZERO(&selmask[0].sm_wt);
X	FD_ZERO(&selmask[0].sm_ex);
X}
X
Xfd_exit()
X{
X	register fildes_t fd;
X
X	for (fd=3; fd < nfds; fd++)
X		(void)close(fd);
X}
!EOF!server/uw_fd.c!
echo x - server/uw_ipc.c
sed -e 's/^X//' > server/uw_ipc.c << '!EOF!server/uw_ipc.c!'
X/*
X *	uw IPC
X *
X * Copyright 1986 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#include <sys/types.h>
X#include <sys/file.h>
X#include <sys/stat.h>
X#include <sys/socket.h>
X#include <sys/un.h>
X#include <sys/ioctl.h>
X#include <sys/uio.h>
X#include <netinet/in.h>
X#include <strings.h>
X#include <netdb.h>
X#include <errno.h>
X#include <stdio.h>
X
X#include "uw_param.h"
X#include "uw_err.h"
X#include "uw_opt.h"
X#include "uw_win.h"
X#include "uw_fd.h"
X#include "uw_pcl.h"
X#include "uw_ipc.h"
X
X#ifndef ntohs
X/* declaring these as one-element arrays or as NULL pointers is a HACK */
Xextern unsigned long ntohl(), htonl();
Xextern unsigned short ntohs(), htons();
Xstatic struct netadj na_ntoh[1] = {
X	(short (*)())ntohs, (long (*)())ntohl, ntohs, ntohl
X};
Xstatic struct netadj na_hton[1] = {
X	(short (*)())htons, (long (*)())htonl, htons, htonl
X};
X#else
Xstatic struct netadj *na_ntoh = NULL;
Xstatic struct netadj *na_hton = NULL;
X#endif
X
Xstatic int have_udport;
Xstatic char uipc_port[] = "/tmp/uwXXXXXX";
X
Xstatic int inet_sd;
Xstatic struct ipcmsg {
X	int		im_len;
X	struct uwipc	im_msg;
X} *inet_buf;
X
Xextern int errno;
X
Xipc_init(use_uipc)
X{
X	ipc_isinit();
X	if (use_uipc)
X		ipc_udinit();
X}
X
X
X/*
X * UNIX-domain
X */
X
Xstatic
Xipc_udinit()
X{
X	register int len;
X	register char *cp;
X	register fildes_t sd;
X	auto struct sockaddr_un sa;
X	auto char *env[2];
X	extern char *mktemp();
X
X	len = strlen(UIPC_ENV) + sizeof uipc_port + 1;
X	if ((cp = malloc(len)) != NULL) {
X		(void)sprintf(cp, "%s=%s", UIPC_ENV, mktemp(uipc_port));
X		env[0] = cp;
X		env[1] = (char *)0;
X		env_set(env);
X
X		sa.sun_family = AF_UNIX;
X		(void)strncpy(sa.sun_path, uipc_port, sizeof sa.sun_path-1);
X		sa.sun_path[sizeof sa.sun_path-1] = '\0';
X		if ((sd = socket(AF_UNIX, SOCK_DGRAM, 0)) >= 0 &&
X		    bind(sd,&sa,sizeof sa.sun_family+strlen(sa.sun_path)) >= 0){
X			have_udport = 1;
X			(void)chmod(uipc_port, S_IREAD|S_IWRITE);
X			(void)fcntl(sd, F_SETFL, FNDELAY);
X			fdmap[sd].f_type = FDT_UDSOCK;
X			FD_SET(sd, &selmask[0].sm_rd);
X		}
X	}
X}
X
Xipc_exit()
X{
X	if (have_udport)
X		(void)unlink(uipc_port);
X}
X
Xipc_udrecv(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	union {
X		struct uwipc uwip;
X		char data[1024];
X	} buf;
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	fd = -1;
X
X	iov.iov_base = (caddr_t)buf.data;
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 || cnt != buf.uwip.uwip_len)
X		return;
X	switch (buf.uwip.uwip_cmd) {
X	case UWC_NEWT:
X		if (msg.msg_accrightslen > 0 && fd >= 0) {
X			/*
X			 * We can't trust the process which connected to us,
X			 * so 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
X			 * uid....]
X			 */
X			if (cnt == sizeof buf)
X				cnt--;
X			buf.data[cnt] = '\0';
X			if (strncmp(buf.uwip.uwip_newt.uwnt_pty,
X			    "/dev/pty", sizeof "/dev/pty"-1) ||
X			    fstat(fd, &st1) < 0 ||
X			    stat(buf.uwip.uwip_newt.uwnt_pty, &st2) < 0 ||
X			    st1.st_dev != st2.st_dev ||
X			    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			 * If we have no free windows, then we close the file
X			 * descriptor (which will terminate the slave process).
X			 */
X			w = PCL_NEWW(0, WC_INTERNAL,
X			      buf.uwip.uwip_newt.uwnt_type,
X			      (nwin_t)0, buf.uwip.uwip_newt.uwnt_id,
X			      fd, (fildes_t)-1);
X			if (w != NULL) {
X				(void)strncpy(w->w_tty,
X				    buf.uwip.uwip_newt.uwnt_pty,
X				    sizeof w->w_tty-1);
X				w->w_tty[5] = 't'; /* switch to "/dev/ttyp?" */
X				utmp_add(w->w_tty);
X			} else
X				(void)close(fd);
X		}
X		break;
X	case UWC_OPTION:
X		w = win_search(buf.uwip.uwip_option.uwop_id,
X		    protocol->p_maxwin);
X		if (w != NULL) {
X			opt_extopt((caddr_t)w, &w->w_optdefn,
X			    (woptcmd_t)buf.uwip.uwip_option.uwop_cmd,
X			    (woption_t)buf.uwip.uwip_option.uwop_opt,
X			    (char *)&buf.uwip.uwip_option.uwop_val,
X			    (struct netadj *)0);
X		}
X		break;
X	}
X}
X
X
X/*
X * Internet domain
X */
X
Xstatic
Xipc_isinit()
X{
X	register fildes_t sd;
X	register char *cp;
X	struct hostent *h;
X	struct sockaddr_in sin;
X	auto int sinlen;
X	char hostname[32];
X	char *env[2];
X
X	/*
X	 * Allocate enough buffers for each file descriptor to have one.
X	 * This is overkill.
X	 */
X	inet_buf = (struct ipcmsg *)malloc(nfds * sizeof(struct ipcmsg));
X	if (inet_buf == NULL)
X		return;
X
X	/*
X	 * Determine our host name and get an Internet stream socket.
X	 * We really should specify the protocol here (rather than 0)
X	 * but we "know" that it defaults to TCP.
X	 */
X	if ((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
X		return;
X	sin.sin_family = AF_INET;
X	sin.sin_port = 0;
X	bzero(sin.sin_zero, sizeof sin.sin_zero);
X	if (gethostname(hostname, sizeof hostname) < 0 || hostname[0] == '\0')
X		(void)strcpy(hostname, "localhost");
X	if ((h = gethostbyname(hostname)) != NULL)
X		bcopy(h->h_addr, (char *)&sin.sin_addr, h->h_length);
X	else
X		sin.sin_addr.s_addr = htonl(0x7f000001L); /* 128.0.0.1 (lo0) */
X	if (bind(sd, &sin, sizeof sin) < 0) {
X		/*
X		 * Unable to bind to unspecified port -- try once more with
X		 * loopback device.  If we already were using the loopback
X		 * device we just suffer the inefficiency of doing this twice.
X		 */
X		sin.sin_addr.s_addr = htonl(0x7f000001L);
X		if (bind(sd, &sin, sizeof sin) < 0) {
X			(void)close(sd);
X			return;
X		}
X	}
X
X	/*
X	 * Listen for incoming connections
X	 */
X	if (listen(sd, NWINDOW) < 0) {
X		(void)close(sd);
X		return;
X	}
X
X	/*
X	 * Determine our port number and put our address in the environment.
X	 */
X	sinlen = sizeof sin;
X	if (getsockname(sd, (char *)&sin, &sinlen) < 0) {
X		/* huh?  Oh well, give up */
X		(void)close(sd);
X		return;
X	}
X	if ((cp = malloc(sizeof INET_ENV + 8 + 1 + 5)) == NULL) {
X		/* no memory, give up */
X		(void)close(sd);
X		return;
X	}
X	sprintf(cp, "%s=%08lx.%05u", INET_ENV,
X	    ntohl(sin.sin_addr.s_addr), ntohs(sin.sin_port));
X	env[0] = cp;
X	env[1] = (char *)0;
X	env_set(env);
X
X	inet_sd = sd;
X	fdmap[sd].f_type = FDT_ISSOCK;
X	FD_SET(sd, &selmask[0].sm_rd);
X}
X
Xipc_isrecv(sd)
Xregister fildes_t sd;
X{
X	register fildes_t fd;
X	register struct uwipc *uwip;
X	register struct window *w;
X	register uwerr_t uwerr;
X	register int len;
X	struct sockaddr sin;
X	struct uwipc reply;
X	auto int sinlen;
X
X	/*
X	 * This routine is called when one of two conditions occur.  It is
X	 * called when an outside process tries to establish a steam
X	 * Internet connection.
X	 *
X	 * Later, as soon as data is available, this routine will be
X	 * called again to handle the external message (which must be
X	 * a "new window" command).
X	 */
X	if (sd == inet_sd) {
X		sinlen = sizeof sin;
X		if ((fd = accept(sd, &sin, &sinlen)) >= 0) {
X			(void)fcntl(fd, F_SETFL, FNDELAY);
X			fdmap[fd].f_type = FDT_ISSOCK;
X			fdmap[fd].f_win = (struct window *)0;
X			FD_SET(fd, &selmask[0].sm_rd);
X			inet_buf[fd].im_len = 0;
X		}
X	} else {
X		switch (ipc_getmsg(sd, inet_buf + sd)) {
X		case -1:
X			(void)close(sd);
X			fdmap[sd].f_type = FDT_NONE;
X			FD_CLR(sd, &selmask[0].sm_rd);
X			FD_CLR(sd, &selmask[0].sm_wt);
X			FD_CLR(sd, &selmask[0].sm_ex);
X			break;
X		case 1:
X			uwip = &inet_buf[sd].im_msg;
X			uwerr = UWE_NONE;
X			if ((uwip->uwip_len < sizeof(struct uwneww) + 
X			    ((char *)&uwip->uwip_neww - (char *)uwip)) ||
X			    uwip->uwip_cmd != UWC_NEWW) {
X				uwerr = UWE_NXTYPE;
X			} else {
X				fd = ipc_ctlopen(sd,
X				    (unsigned)uwip->uwip_neww.uwnw_ctlport);
X				w = PCL_NEWW(0, WC_EXTERNAL,
X				      ntohs(uwip->uwip_neww.uwnw_type),
X				      (nwin_t)0, ntohl(uwip->uwip_neww.uwnw_id),
X				      sd, fd);
X				if (w == (struct window *)0)
X					uwerr = UWE_NXTYPE;	/* for now */
X				else
X					uwerr = UWE_NONE;
X			}
X			len = sizeof(struct uwstatus) +
X			    ((char *)&reply.uwip_status - (char *)&reply);
X			reply.uwip_len = htons(len);
X			reply.uwip_cmd = htons(UWC_STATUS);
X			reply.uwip_status.uwst_err = htons(uwerr);
X			reply.uwip_status.uwst_errno = htons(errno);
X			if (uwerr == UWE_NONE)
X				reply.uwip_status.uwst_id = htonl(w->w_id);
X			else
X				reply.uwip_status.uwst_id = 0;
X			(void)write(sd, (char *)&reply, len);
X			if (uwerr != UWE_NONE) {
X				(void)close(sd);
X				fdmap[sd].f_type = FDT_NONE;
X				FD_CLR(sd, &selmask[0].sm_rd);
X				FD_CLR(sd, &selmask[0].sm_wt);
X				FD_CLR(sd, &selmask[0].sm_ex);
X			}
X			inet_buf[sd].im_len = 0;
X		}
X	}
X}
X
Xipc_ctlopen(sd, port)
Xfildes_t sd;
Xunsigned port;
X{
X	register int fd;
X	auto struct sockaddr_in sin;
X	auto int sinlen;
X
X	/*
X	 * Create a control socket and connect it to the same host as
X	 * "sd" on the specified port.
X	 */
X	sinlen = sizeof sin;
X	if (port == 0 ||
X	    getpeername(sd, (struct sockaddr *)&sin, &sinlen) < 0 ||
X	    (fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
X		return(-1);
X	} else {
X		sin.sin_port = port;
X		(void)fcntl(fd, F_SETFL, FNDELAY);
X		if (connect(fd, &sin, sinlen) < 0 && errno != EINPROGRESS) {
X			(void)close(fd);
X			return(-1);
X		} else
X			return(fd);
X	}
X}
X
Xvoid
Xipc_optmsg(win, optcmd, optnum, data, datalen)
Xcaddr_t win;
Xwoptcmd_t optcmd;
Xwoption_t optnum;
Xchar *data;
Xunsigned datalen;
X{
X	register struct window *w;
X	register int len;
X	struct uwipc uwip;
X
X	/*
X	 * Propagate a window option message (WILL, WONT, SET) from the Mac
X	 * to the remote process (external windows only).
X	 */
X	if ((w = (struct window *)win) != NULL && w->w_alloc &&
X	    w->w_class == WC_EXTERNAL && w->w_ctlfd >= 0 &&
X	    optnum <= WONUM_MAX && (optcmd == WOC_WILL || optcmd == WOC_WONT ||
X	     (optcmd == WOC_SET && data != NULL))) {
X		len = datalen +
X		    ((char *)&uwip.uwip_option.uwop_val - (char *)&uwip);
X		uwip.uwip_len = htons(len);
X		uwip.uwip_cmd = htons(UWC_OPTION);
X		uwip.uwip_option.uwop_id = htonl(w->w_id);
X		uwip.uwip_option.uwop_opt = htons(optnum);
X		uwip.uwip_option.uwop_cmd = htons(optcmd);
X		if (optcmd == WOC_SET) {
X			bcopy(data, (char *)&uwip.uwip_option.uwop_val,
X			    (int)datalen);
X			opt_netadj(w->w_optdefn.wod_optlst[optnum].wol_argdefn,
X			    (char *)&uwip.uwip_option.uwop_val, na_hton);
X		}
X		(void)write(w->w_ctlfd, (char *)&uwip, len);
X	}
X}
X
Xipc_ctlrecv(mfd, sd, win)
Xfildes_t mfd;
Xregister fildes_t sd;
Xregister struct window *win;
X{
X	register struct window *w;
X	register struct uwipc *uwip;
X
X	switch (ipc_getmsg(sd, inet_buf + sd)) {
X	case -1:
X		(void)close(sd);
X		fdmap[sd].f_type = FDT_NONE;
X		FD_CLR(sd, &selmask[0].sm_rd);
X		FD_CLR(sd, &selmask[0].sm_wt);
X		FD_CLR(sd, &selmask[0].sm_ex);
X		break;
X	case 1:
X		uwip = &inet_buf[sd].im_msg;
X		switch (uwip->uwip_cmd) {
X		case UWC_KILLW:
X			if ((uwip->uwip_len == sizeof(struct uwkillw) + 
X			    ((char *)&uwip->uwip_killw - (char *)uwip))) {
X				w = win_search(ntohl(uwip->uwip_killw.uwkw_id),
X				    protocol->p_maxwin);
X				if (w == win)
X					PCL_KILLW(mfd, w);
X			}
X			break;
X		case UWC_OPTION:
X			/* hope the message is long enough... sigh */
X			if (uwip->uwip_len > 
X			 ((char *)&uwip->uwip_option.uwop_val - (char *)uwip)) {
X				w = win_search(ntohl(uwip->uwip_option.uwop_id),
X				    protocol->p_maxwin);
X				if (w == win) {
X					opt_extopt((caddr_t)w, &w->w_optdefn,
X					    (woptcmd_t)ntohs(uwip->uwip_option.uwop_cmd),
X					    (woption_t)ntohs(uwip->uwip_option.uwop_opt),
X					    (char *)&uwip->uwip_option.uwop_val,
X					    na_ntoh);
X				}
X			}
X			break;
X		}
X		inet_buf[sd].im_len = 0;
X	}
X}
X
Xipc_getmsg(sd, im)
Xregister fildes_t sd;
Xregister struct ipcmsg *im;
X{
X	register int len;
X	register char *cp;
X
X	/*
X	 * Read some more bytes from socket "sd" into the message buffer
X	 * contained in "im".  Return 1 if the message is now complete,
X	 * -1 if an EOF was reached, or 0 otherwise.  Before returning 1,
X	 * the byte order of the common parameters (command, length) is
X	 * changed from network to host order.
X	 *
X	 * This routine expects the socket to use non-blocking I/O (which
X	 * is enabled by ipc_isrecv() when the connection is accepted).
X	 */
X	cp = (char *)&im->im_msg + im->im_len;
X	if (im->im_len < sizeof(im->im_msg.uwip_len)) {
X		len = read(sd, cp, sizeof im->im_msg.uwip_len - im->im_len);
X		if (len == 0 || (len < 0 && errno != EWOULDBLOCK))
X			return(-1);
X		if ((im->im_len += len) < sizeof im->im_msg.uwip_len)
X			return(0);
X		im->im_msg.uwip_len = ntohs(im->im_msg.uwip_len);
X		if (im->im_msg.uwip_len == sizeof im->im_msg.uwip_len)
X			return(1);
X		cp += len;
X	}
X	if (im->im_msg.uwip_len > sizeof(struct ipcmsg))
X		im->im_msg.uwip_len = sizeof(struct ipcmsg);
X	len = read(sd, cp, im->im_msg.uwip_len - im->im_len);
X	if (len == 0)
X		return(-1);
X	if (len < 0)
X		return((errno==EWOULDBLOCK) ? 0 : -1);
X	if ((im->im_len += len) == im->im_msg.uwip_len) {
X		im->im_msg.uwip_cmd = ntohs(im->im_msg.uwip_cmd);
X		return(1);
X	} else
X		return(0);
X}
!EOF!server/uw_ipc.c!
echo x - server/uw_main.c
sed -e 's/^X//' > server/uw_main.c << '!EOF!server/uw_main.c!'
X/*
X *	uw - UNIX windows program for the Macintosh (host end)
X *
X * Copyright 1985,1986 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#include <sys/types.h>
X#include <sys/file.h>
X#include <sys/wait.h>
X#include <sys/time.h>
X#include <sys/resource.h>
X#include <sys/ioctl.h>
X#include <pwd.h>
X#include <signal.h>
X#include <errno.h>
X#include <strings.h>
X#include <stdio.h>
X
X#include "uw_param.h"
X#include "uw_clk.h"
X#include "uw_opt.h"
X#include "uw_win.h"
X#include "uw_fd.h"
X#include "uw_pcl.h"
X#include "uw_ipc.h"
X#include "openpty.h"
X
Xint nflag;			/* no startup file */
Xint sflag;			/* "secure" (hee hee) -- no network requests */
Xint errflag;			/* argument error */
Xchar *rcfile;			/* ".uwrc" file name */
X
Xextern void rc_kludge();	/* horrible hack (see rc_kludge()) */
X
Xmain(argc, argv)
Xchar **argv;
X{
X	register int c;
X	register fildes_t fd;
X	extern int calloptscan;
X	extern int errno;
X	extern int optind;
X	extern char *optarg;
X
X	/*
X	 * Make sure we don't accidentally try to run this inside itself.
X	 */
X	if (getenv(UIPC_ENV)) {
X		fprintf(stderr, "%s is already running\n", *argv);
X		exit(1);
X	}
X
X	/*
X	 * Process command-line arguments.
X	 */
X	while ((c=getopt(argc, argv, "f:ns")) != EOF) {
X		switch (c) {
X		case 'f':
X			if (nflag) {
X				fprintf(stderr,
X				    "Cannot specify both \"-f\" and \"-n\"\n");
X				nflag = 0;
X			}
X			rcfile = optarg;
X			break;
X		case 'n':
X			if (rcfile != (char *)0) {
X				fprintf(stderr,
X				    "Cannot specify both \"-f\" and \"-n\"\n");
X				rcfile = (char *)0;
X			}
X			nflag = 1;
X			break;
X		case 's':
X			sflag = 1;
X			break;
X		case '?':
X		default:
X			errflag = 1;
X			break;
X		}
X	}
X	if (errflag) {
X		fprintf(stderr, "Usage: \"%s [-f file] [-n] [-s]\"\n", *argv);
X		exit(1);
X	}
X
X	/*
X	 * Initialize the file descriptor table.
X	 */
X	fd_init();
X	FD_SET(0, &selmask[0].sm_rd);
X
X	/*
X	 * If we can open the "/etc/utmp" for write, do so.
X	 * Immediately afterwards, we lose any magic powers that
X	 * might have allowed us to do this.
X	 */
X#ifdef UTMP
X	fd = open("/etc/utmp", O_WRONLY);
X	(void)setgid(getgid());
X	(void)setuid(getuid());
X	if (fd >= 0)
X		fdmap[fd].f_type = FDT_OTHER;
X	utmp_init(fd);
X#endif
X
X	/*
X	 * Initialize the window structures.
X	 */
X	win_init();
X
X	/*
X	 * Initialize timeouts.
X	 */
X	clk_init();
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.  If we want to be "secure", we don't allow
X	 * any UNIX-domain messages to come in.
X	 */
X	ipc_init(!sflag);
X	if (!sflag)
X		clk_timeout(5, rc_kludge, (toarg_t)0);
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	(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	tty_mode(1);
X
X
X	/*
X	 * Tell the Macintosh to initialize.
X	 */
X	pcl_entry(0);
X
X	
X	/*
X	 * Create window 1 (to start things off) and wait for input.
X	 * When input is available, process it.
X	 */
X	if (!nflag)
X		finduwrc();
X
X	while (1) {
X		CLK_CHECK();
X		if (calloptscan && protocol->p_chkopt) {
X			calloptscan = 0;
X			(*protocol->p_chkopt)(0);
X		}
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; fd++) {
X			if (FD_ISSET(fd, &selmask[1].sm_rd)) {
X				switch (fdmap[fd].f_type) {
X				case FDT_MAC:
X					PCL_RECV(0, (char *)0, 0);
X					break;
X				case FDT_UDSOCK:
X					ipc_udrecv(fd);
X					break;
X				case FDT_ISSOCK:
X					ipc_isrecv(fd);
X					break;
X				case FDT_DATA:
X					PCL_XMIT(0, fdmap[fd].f_win);
X					break;
X				case FDT_CTL:
X					ipc_ctlrecv(0, fd, fdmap[fd].f_win);
X					break;
X				default:
X					/* "can't happen" */
X					FD_CLR(fd, &selmask[0].sm_rd);
X					break;
X				}
X			}
X			if (FD_ISSET(fd, &selmask[1].sm_wt)) {
X				/* "can't happen" */
X				FD_CLR(fd, &selmask[0].sm_wt);
X				break;
X			}
X			if (FD_ISSET(fd, &selmask[1].sm_ex)) {
X				/* "can't happen" */
X				FD_CLR(fd, &selmask[0].sm_ex);
X				break;
X			}
X		}
X	}
X}
X
Xfinduwrc()
X{
X	register struct passwd *pw;
X	register char *homedir;
X
X	/*
X	 * If the global variable "rcfile" is non-NULL, then it specifies
X	 * the name of the startup file.  Otherwise, the name of the startup
X	 * file is "$HOME/.uwrc".  If $HOME is undefined or null, the password
X	 * file is consulted.  The ".uwrc" file is an executable program or
X	 * "/bin/sh" command file.  (For "csh" (ugh) use "#! /bin/csh".)
X	 *
X	 * Returns 0 if the ".uwrc" file doesn't exist, 1 if it does.  As
X	 * a side-effect, this routine sets the global variable "rcfile"
X	 * to the name of the ".uwrc" file.
X	 */
X	if (rcfile == (char *)0) {
X		if ((homedir=getenv("HOME")) == NULL || !*homedir) {
X			if ((pw = getpwuid(getuid())) != NULL)
X				homedir = pw->pw_dir;
X			else
X				return;
X		}
X		rcfile = malloc((unsigned)(strlen(homedir) + sizeof "/.uwrc"));
X		if (rcfile == (char *)0)
X			return;
X		(void)strcpy(rcfile, homedir);
X		(void)strcat(rcfile, "/.uwrc");
X	}
X	if (access(rcfile, F_OK) < 0)
X		rcfile = (char *)0;
X}
X
Xrunuwrc()
X{
X	register int pid;
X	register fildes_t fd;
X	struct ptydesc pt;
X
X	/*
X	 * We use a real fork (rather than a vfork()) because the parent
X	 * doesn't wait for the child.  The caller knows that the file
X	 * exists; however, it cannot determine whether or not it is
X	 * successfully executed.
X	 *
X	 * We acquire a pseudo-terminal for rather convoluted reasons.
X	 * Programs such as "uwtool" expect to be able to inherit tty
X	 * modes from their controlling terminal.  By the time that we
X	 * reach this point, we've already changed our controlling
X	 * terminal to use cbreak mode with no special characters except
X	 * XON/XOFF.  Therefore, we obtain a pseudo-terminal and
X	 * restore our original modes onto it.  We double-fork (sigh,
X	 * another miserable kludge) so that the server does not have
X	 * to wait for the completion of the ".uwrc" file.  (The child
X	 * waits for the grandchild so that the master side of the pty
X	 * remains open until the grandchild is finished.)
X	 */
X	if (openpty(&pt) < 0)
X		return;
X	while ((pid = fork()) < 0)
X		sleep(5);
X	if (pid > 0) {
X		(void)close(pt.pt_pfd);
X		(void)close(pt.pt_tfd);
X	} else {
X		/* child */
X		while ((pid = fork()) < 0)
X			sleep(5);
X		if (pid > 0) {
X			while (wait((int *)0) < 0 && errno == EINTR)
X				;
X			_exit(1);
X			/*NOTREACHED*/
X		} else {
X			/* grandchild */
X			(void)setgid(getgid());
X			(void)setuid(getuid());
X			(void)close(pt.pt_pfd);
X			if (pt.pt_tfd != 0)
X				(void)dup2(pt.pt_tfd, 0);
X			if (pt.pt_tfd != 1);
X				(void)dup2(pt.pt_tfd, 1);
X			if (pt.pt_tfd != 2)
X				(void)dup2(pt.pt_tfd, 2);
X			win_envinit(defwtype, (long)0);
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",O_RDWR),
X			    (int)TIOCNOTTY, (char *)0);
X			(void)open(pt.pt_tname, O_RDONLY);
X			for (fd=3; fd < nfds; fd++)
X				(void)close(fd);
X			tty_mode(0);
X			(void)execlp(rcfile, rcfile, (char *)0);
X			(void)execl("/bin/sh", "sh", rcfile, (char *)0);
X			_exit(1);
X			/*NOTREACHED*/
X		}
X	}
X}
X
Xvoid
Xrc_kludge()
X{
X	static int firsttime = 1;
X
X	/*
X	 * A problem which occurs with ".uwrc" file handling is that
X	 * the "rc" file is interpreted immediately after the server
X	 * begins, i.e. before it and the Macintosh have (possibly)
X	 * changed from the default protocol to an extended one.
X	 *
X	 * To get around this problem, if a ".uwrc" file exists, it
X	 * is not executed immediately.  Instead, it will be executed
X	 * when this routine is called, either directly by pcl_newpcl()
X	 * when the protocol changes, or after an initial timeout.
X	 *
X	 * It is most unfortunate that "pcl_newpcl" must call "upwards"
X	 * into this source file.
X	 */
X	if (firsttime) {
X		firsttime = 0;
X		if (rcfile != (char *)0)
X			runuwrc();
X		else
X			(void)PCL_NEWW(0, WC_INTERNAL, defwtype, (nwin_t)1, 0L,
X			    (fildes_t)-1, (fildes_t)-1);
X	}
X}
X
Xvoid
Xdone(s)
X{
X	/*
X	 * Clean up and exit.  It is overkill to close all of the file
X	 * descriptors, but it causes no harm.
X	 */
X	pcl_exit(0);
X	utmp_exit();
X	fd_exit();
X	ipc_exit();
X	tty_mode(0);
X	exit(s);
X}
X
Xvoid
Xcwait()
X{
X	register int pid;
X	union wait status;
X	struct rusage rusage;
X
X	/*
X	 * Collect dead children.  Restart any children that have stopped.
X	 */
X	while ((pid=wait3(&status, WNOHANG|WUNTRACED, &rusage)) > 0)
X		if (WIFSTOPPED(status))
X			(void)kill(pid, SIGCONT);
X}
!EOF!server/uw_main.c!
exit 0
: end of shell archive (part 2 of 9)
Technical Details
Message-ID: <1688@felix.UUCP>
Path: arc1-ca.pugleaf.net!utzoo!decvax!ucbvax!dual!unisoft!lll-lcc!lll-crg!mordor!sri-spam!sri-unix!hplabs!felix!macintosh
References: <1687@felix.UUCP>

Show Full Headers
Complete Article Headers
Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: arc1-ca.pugleaf.net!utzoo!decvax!ucbvax!dual!unisoft!lll-lcc!lll-crg!mordor!sri-spam!sri-unix!hplabs!felix!macintosh
From: jdb@mordor.ARPA (John Bruner)
Newsgroups: mod.mac.sources
Subject: UW v3.4 (part 2 of 9)
Message-ID: <1688@felix.UUCP>
Date: Thu, 23-Oct-86 15:56:38 EDT
Article-I.D.: felix.1688
Posted: Thu Oct 23 15:56:38 1986
Date-Received: Fri, 24-Oct-86 21:39:27 EDT
References: <1687@felix.UUCP>
Sender: macintosh@felix.UUCP
Reply-To: macintosh@felix.UUCP (The Moderator)
Organization: FileNet Corp., Costa Mesa, CA
Lines: 2453
Approved: bytebug@felix.UUCP (Roger L. Long)