Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: 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) : [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 '/ 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 X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include 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 */ 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 , 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 X#include 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 X#include 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 '/ 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 X#include X#include X#include 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 X#include X#include X#include 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 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 X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include 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 X#include X#include X#include X#include X#include X#include X#include X#include X#include X#include 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)