Path: utzoo!mnetor!uunet!ccicpg!felix!dhw68k!macintosh From: jdb@mordor.s1.gov (John Bruner) Newsgroups: comp.sources.mac Subject: UW v4.2 (part 6 of 9) Message-ID: <6602@dhw68k.cts.com> Date: 7 Apr 88 04:55:15 GMT References: <6493@dhw68k.cts.com> <6497@dhw68k.cts.com> <6515@dhw68k.cts.com> <6538@dhw68k.cts.com> <6587@dhw68k.cts.com> Sender: macintosh@dhw68k.cts.com Organization: Lawrence Livermore National Laboratory, S-1 Project Lines: 1489 Approved: bytebug@dhw68k.cts.com (Roger L. Long) [UW v4.2 - part 6 of 9] --- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # server/Makefile_4.2 # server/Makefile_4.3 # server/openpty.c # server/uw_clk.c # server/uw_env.c # server/uw_fd.c # server/uw_main.c # server/uw_ipc.c # This archive created: Mon Apr 4 07:52:04 1988 # By: Roger L. Long (macintosh@dhw68k.cts.com) export PATH; PATH=/bin:$PATH if test ! -d server then echo shar: mkdir server mkdir server fi echo shar: extracting "'server/Makefile_4.2'" '(1203 characters)' if test -f 'server/Makefile_4.2' then echo shar: will not over-write existing file "'server/Makefile_4.2'" else sed 's/^X//' << \SHAR_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 XINCDIR = ../h 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 XSOURCES = `echo $(OBJECTS) | sed -e 's/\\.o/\\.c/g'` X XDEFINES = `cat ../DEFINES` X XCFLAGS = $(DEFINES) -I$(INCDIR) -O XLFLAGS = X Xuw: $(OBJECTS) X $(CC) $(LFLAGS) -o uw $(OBJECTS) $(LIBS) X Xlint: X lint -hbx -I$(INCDIR) $(DEFINES) $(SOURCES) X Xtags: X ctags $(SOURCES) X Xdepend: X grep '^#include' $(SOURCES) | \ 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 *.o X X# DO NOT DELETE THIS LINE (or the following blank line) -- make depend uses it X SHAR_EOF if test 1203 -ne "`wc -c < 'server/Makefile_4.2'`" then echo shar: error transmitting "'server/Makefile_4.2'" '(should have been 1203 characters)' fi fi # end of overwriting check echo shar: extracting "'server/Makefile_4.3'" '(1170 characters)' if test -f 'server/Makefile_4.3' then echo shar: will not over-write existing file "'server/Makefile_4.3'" else sed 's/^X//' << \SHAR_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 XINCDIR = ../h 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 XSOURCES = `echo $(OBJECTS) | sed -e 's/\\.o/\\.c/g'` X XDEFINES = `cat ../DEFINES` X XCFLAGS = $(DEFINES) -I$(INCDIR) -O XLFLAGS = X Xuw: $(OBJECTS) X $(CC) $(LFLAGS) -o uw $(OBJECTS) $(LIBS) X Xlint: X lint -hbx -I$(INCDIR) $(DEFINES) $(SOURCES) X Xtags: X ctags $(SOURCES) X Xdepend: X $(CC) -M -I$(INCDIR) $(DEFINES) $(SOURCES) | \ 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 *.o X X# DO NOT DELETE THIS LINE (or the following blank line) -- make depend uses it X SHAR_EOF if test 1170 -ne "`wc -c < 'server/Makefile_4.3'`" then echo shar: error transmitting "'server/Makefile_4.3'" '(should have been 1170 characters)' fi fi # end of overwriting check echo shar: extracting "'server/openpty.c'" '(3874 characters)' if test -f 'server/openpty.c' then echo shar: will not over-write existing file "'server/openpty.c'" else sed 's/^X//' << \SHAR_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} SHAR_EOF if test 3874 -ne "`wc -c < 'server/openpty.c'`" then echo shar: error transmitting "'server/openpty.c'" '(should have been 3874 characters)' fi fi # end of overwriting check echo shar: extracting "'server/uw_clk.c'" '(1577 characters)' if test -f 'server/uw_clk.c' then echo shar: will not over-write existing file "'server/uw_clk.c'" else sed 's/^X//' << \SHAR_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} SHAR_EOF if test 1577 -ne "`wc -c < 'server/uw_clk.c'`" then echo shar: error transmitting "'server/uw_clk.c'" '(should have been 1577 characters)' fi fi # end of overwriting check echo shar: extracting "'server/uw_env.c'" '(1654 characters)' if test -f 'server/uw_env.c' then echo shar: will not over-write existing file "'server/uw_env.c'" else sed 's/^X//' << \SHAR_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} SHAR_EOF if test 1654 -ne "`wc -c < 'server/uw_env.c'`" then echo shar: error transmitting "'server/uw_env.c'" '(should have been 1654 characters)' fi fi # end of overwriting check echo shar: extracting "'server/uw_fd.c'" '(871 characters)' if test -f 'server/uw_fd.c' then echo shar: will not over-write existing file "'server/uw_fd.c'" else sed 's/^X//' << \SHAR_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} SHAR_EOF if test 871 -ne "`wc -c < 'server/uw_fd.c'`" then echo shar: error transmitting "'server/uw_fd.c'" '(should have been 871 characters)' fi fi # end of overwriting check echo shar: extracting "'server/uw_main.c'" '(8884 characters)' if test -f 'server/uw_main.c' then echo shar: will not over-write existing file "'server/uw_main.c'" else sed 's/^X//' << \SHAR_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} SHAR_EOF if test 8884 -ne "`wc -c < 'server/uw_main.c'`" then echo shar: error transmitting "'server/uw_main.c'" '(should have been 8884 characters)' fi fi # end of overwriting check echo shar: extracting "'server/uw_ipc.c'" '(13438 characters)' if test -f 'server/uw_ipc.c' then echo shar: will not over-write existing file "'server/uw_ipc.c'" else sed 's/^X//' << \SHAR_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 + 1 + 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} SHAR_EOF if test 13438 -ne "`wc -c < 'server/uw_ipc.c'`" then echo shar: error transmitting "'server/uw_ipc.c'" '(should have been 13438 characters)' fi fi # end of overwriting check # End of shell archive exit 0 --- end of part 6 ---