Article View: mod.mac.sources
Article #15UW v3.4 (part 2 of 9)
From: John Bruner
Date: Thu, 23 Oct 1986 19:56
Date: Thu, 23 Oct 1986 19:56
2453 lines
64331 bytes
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, <c);
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, <c);
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!macintoshReferences:
<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)