Article View: comp.sources.mac
Article #39UW v4.2 (part 6 of 9)
From: John Bruner
Date: Thu, 07 Apr 1988 04:55
Date: Thu, 07 Apr 1988 04:55
1489 lines
39879 bytes
39879 bytes
[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 '/</d' \
X -e 's/:[^"]*"\([^"]*\)".*/: ..\/h\/\1/' \
X -e 's,^../[a-zA-Z0-9]*/\([^\.]*\)\.[cs],\1.o \1.L,' | \
X awk ' { if ($$1 != prev) { print rec; rec = $$0; prev = $$1; } \
X else { if (length(rec $$3) > 78) { print rec; rec = $$0; } \
X else rec = rec " " $$3 } } \
X END { print rec } ' > makedep
X echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep
X echo '$$r makedep' >>eddep
X echo 'w' >>eddep
X cp Makefile Makefile.bak
X ex - Makefile < eddep
X rm eddep makedep
X
Xclean:
X rm *.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 <sys/types.h>
X#include <sys/dir.h>
X#include <fcntl.h>
X#include <strings.h>
X#include "openpty.h"
X
X#define DEV_DIR "/dev" /* directory where devices live */
X#define PT_INDEX (sizeof DEV_DIR) /* location of 'p' in "pty" */
X
X#define PTY_PROTO "ptyp0" /* prototype for pty names */
X#define PTY_PREFIX "pty" /* prefix required for name of pty */
X
Xstruct ptyinfo {
X struct ptyinfo *pi_next;
X char *pi_pty;
X char *pi_tty;
X};
X
Xstatic struct ptyinfo *ptylist;
X
Xextern char *malloc();
X
Xstatic
Xchar *
Xdevname(name)
Xchar *name;
X{
X register char *fullname;
X
X /*
X * Construct the full name of a device in DEV_DIR. Returns
X * NULL if it failed (because malloc() failed).
X */
X
X fullname = malloc((unsigned)(sizeof DEV_DIR + 1 + strlen(name)));
X if (fullname != NULL) {
X (void)strcpy(fullname, DEV_DIR);
X (void)strcat(fullname, "/");
X (void)strcat(fullname, name);
X }
X return(fullname);
X}
X
Xstatic
Xisapty(dp)
Xstruct direct *dp;
X{
X static struct ptyinfo *pi;
X
X /*
X * We don't care about the gory details of the directory entry.
X * Instead, what we really want is an array of pointers to
X * device names (with DEV_DIR prepended). Therefore, we create
X * this array ourselves and tell scandir() to ignore every
X * directory entry.
X *
X * If malloc() fails, the current directory entry is ignored.
X */
X if (pi == NULL) {
X pi = (struct ptyinfo *)malloc((unsigned)sizeof *pi);
X if (pi == NULL)
X return(0);
X }
X
X if (strlen(dp->d_name) == sizeof PTY_PROTO - 1 &&
X strncmp(dp->d_name, PTY_PREFIX, sizeof PTY_PREFIX - 1) == 0) {
X pi->pi_pty = devname(dp->d_name);
X if (pi->pi_pty == NULL)
X return(0);
X pi->pi_tty = malloc((unsigned)(strlen(pi->pi_pty) + 1));
X if (pi->pi_tty == NULL) {
X free(pi->pi_pty);
X return(0);
X }
X (void)strcpy(pi->pi_tty, pi->pi_pty);
X pi->pi_tty[PT_INDEX] = 't';
X if (access(pi->pi_pty, 0) == 0 && access(pi->pi_tty, 0) == 0) {
X pi->pi_next = ptylist;
X ptylist = pi;
X pi = NULL;
X } else {
X free(pi->pi_pty);
X free(pi->pi_tty);
X }
X }
X return(0);
X}
X
Xopenpty(pt)
Xstruct ptydesc *pt;
X{
X register struct ptyinfo *pi;
X static int fail;
X auto struct direct **dirlist;
X extern char *re_comp();
X extern int alphasort();
X
X /*
X * If scandir() fails or no possible pty's are found, then "fail"
X * is set non-zero. If "fail" is non-zero then the routine bombs
X * out immediately. Otherwise, the list of candidates is examined
X * starting with the entry following the last one chosen.
X */
X if (fail)
X return(-1);
X
X if (!ptylist) { /* first time */
X if (scandir(DEV_DIR, &dirlist, isapty, alphasort) < 0 ||
X ptylist == NULL) {
X fail = 1;
X return(-1);
X }
X for (pi=ptylist; pi->pi_next; pi=pi->pi_next)
X ;
X pi->pi_next = ptylist; /* make the list circular */
X }
X
X pi = ptylist;
X do {
X if ((pt->pt_pfd = open(pi->pi_pty, O_RDWR)) >= 0) {
X if ((pt->pt_tfd = open(pi->pi_tty, O_RDWR)) >= 0) {
X ptylist = pi->pi_next;
X pt->pt_pname = pi->pi_pty;
X pt->pt_tname = pi->pi_tty;
X return(0);
X } else
X (void)close(pt->pt_pfd);
X }
X pi = pi->pi_next;
X } while (pi != ptylist);
X return(-1);
X}
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 <sys/types.h>
X#include <sys/time.h>
X#include <sys/signal.h>
X#include <sys/resource.h>
X
X#include "uw_param.h"
X#include "uw_clk.h"
X
Xstatic struct timeout *pending;
Xstatic struct timeout *freelist;
X
Xint timer_rdy; /* nonzero when some timeout is ready to run */
X
Xclk_timeout(secs, fn, arg)
Xint secs;
Xvoid (*fn)();
Xtoarg_t arg;
X{
X register struct timeout *to, **tol;
X register time_t curtime;
X extern time_t time();
X
X to = freelist;
X if (!to) {
X if (!(to = (struct timeout *)malloc(sizeof *to)))
X return(-1);
X } else
X freelist = to->to_next;
X to->to_fn = fn;
X to->to_arg = arg;
X
X if (secs < 0)
X secs = 0;
X curtime = time((time_t *)0);
X to->to_when = curtime + secs;
X
X tol = &pending;
X while (*tol && to->to_when > (*tol)->to_when)
X tol = &(*tol)->to_next;
X to->to_next = *tol;
X *tol = to;
X
X clk_service();
X return(0);
X}
X
Xclk_service()
X{
X register struct timeout *to;
X register time_t curtime;
X
X curtime = time((time_t *)0);
X while ((to=pending) && to->to_when <= curtime) {
X pending = to->to_next;
X if (to->to_fn) {
X (*to->to_fn)(to->to_arg);
X to->to_next = freelist;
X freelist = to;
X }
X }
X
X timer_rdy = 0;
X if (pending)
X (void)alarm((unsigned)(pending->to_when - curtime));
X}
X
Xvoid
Xclk_alarm()
X{
X /*
X * A SIGALRM has been received.
X */
X timer_rdy = 1;
X}
X
Xclk_init()
X{
X timer_rdy = 0;
X (void)signal(SIGALRM, clk_alarm);
X}
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 <sys/types.h>
X
X#include "uw_param.h"
X#include "uw_fd.h"
X
Xstruct selmask selmask[2];
Xstruct fdmap fdmap[FD_SETSIZE];
Xfildes_t nfds; /* number of file descriptors */
X
Xfd_init()
X{
X register fildes_t fd;
X
X nfds = getdtablesize();
X if (nfds > FD_SETSIZE)
X nfds = FD_SETSIZE;
X fdmap[0].f_type = FDT_MAC;
X fdmap[1].f_type = FDT_MAC;
X fdmap[2].f_type = FDT_DEBUG;
X for (fd=3; fd < FD_SETSIZE; fd++) {
X fdmap[fd].f_type = FDT_NONE;
X (void)close(fd);
X }
X FD_ZERO(&selmask[0].sm_rd);
X FD_ZERO(&selmask[0].sm_wt);
X FD_ZERO(&selmask[0].sm_ex);
X}
X
Xfd_exit()
X{
X register fildes_t fd;
X
X for (fd=3; fd < nfds; fd++)
X (void)close(fd);
X}
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 <sys/types.h>
X#include <sys/file.h>
X#include <sys/wait.h>
X#include <sys/time.h>
X#include <sys/resource.h>
X#include <sys/ioctl.h>
X#include <pwd.h>
X#include <signal.h>
X#include <errno.h>
X#include <strings.h>
X#include <stdio.h>
X
X#include "uw_param.h"
X#include "uw_clk.h"
X#include "uw_opt.h"
X#include "uw_win.h"
X#include "uw_fd.h"
X#include "uw_pcl.h"
X#include "uw_ipc.h"
X#include "openpty.h"
X
Xint nflag; /* no startup file */
Xint sflag; /* "secure" (hee hee) -- no network requests */
Xint errflag; /* argument error */
Xchar *rcfile; /* ".uwrc" file name */
X
Xextern void rc_kludge(); /* horrible hack (see rc_kludge()) */
X
Xmain(argc, argv)
Xchar **argv;
X{
X register int c;
X register fildes_t fd;
X extern int calloptscan;
X extern int errno;
X extern int optind;
X extern char *optarg;
X
X /*
X * Make sure we don't accidentally try to run this inside itself.
X */
X if (getenv(UIPC_ENV)) {
X fprintf(stderr, "%s is already running\n", *argv);
X exit(1);
X }
X
X /*
X * Process command-line arguments.
X */
X while ((c=getopt(argc, argv, "f:ns")) != EOF) {
X switch (c) {
X case 'f':
X if (nflag) {
X fprintf(stderr,
X "Cannot specify both \"-f\" and \"-n\"\n");
X nflag = 0;
X }
X rcfile = optarg;
X break;
X case 'n':
X if (rcfile != (char *)0) {
X fprintf(stderr,
X "Cannot specify both \"-f\" and \"-n\"\n");
X rcfile = (char *)0;
X }
X nflag = 1;
X break;
X case 's':
X sflag = 1;
X break;
X case '?':
X default:
X errflag = 1;
X break;
X }
X }
X if (errflag) {
X fprintf(stderr, "Usage: \"%s [-f file] [-n] [-s]\"\n", *argv);
X exit(1);
X }
X
X /*
X * Initialize the file descriptor table.
X */
X fd_init();
X FD_SET(0, &selmask[0].sm_rd);
X
X /*
X * If we can open the "/etc/utmp" for write, do so.
X * Immediately afterwards, we lose any magic powers that
X * might have allowed us to do this.
X */
X#ifdef UTMP
X fd = open("/etc/utmp", O_WRONLY);
X (void)setgid(getgid());
X (void)setuid(getuid());
X if (fd >= 0)
X fdmap[fd].f_type = FDT_OTHER;
X utmp_init(fd);
X#endif
X
X /*
X * Initialize the window structures.
X */
X win_init();
X
X /*
X * Initialize timeouts.
X */
X clk_init();
X
X
X /*
X * Create a UNIX-domain network address, and put its name into
X * the environment so that descendents can contact us with new
X * window requests. If we want to be "secure", we don't allow
X * any UNIX-domain messages to come in.
X */
X ipc_init(!sflag);
X if (!sflag)
X clk_timeout(5, rc_kludge, (toarg_t)0);
X
X
X /*
X * Ignore interrupts, quits, and terminal stops. Clean up and exit
X * if a hangup or termination is received. Also catch changes in
X * child status (so that we can wait for them). Set up the terminal
X * modes.
X */
X (void)signal(SIGHUP, done);
X (void)signal(SIGINT, SIG_IGN);
X (void)signal(SIGQUIT, SIG_IGN);
X (void)signal(SIGTERM, done);
X (void)signal(SIGTSTP, SIG_IGN);
X (void)signal(SIGCHLD, cwait);
X
X tty_mode(1);
X
X
X /*
X * Tell the Macintosh to initialize.
X */
X pcl_entry(0);
X
X
X /*
X * Create window 1 (to start things off) and wait for input.
X * When input is available, process it.
X */
X if (!nflag)
X finduwrc();
X
X while (1) {
X CLK_CHECK();
X if (calloptscan && protocol->p_chkopt) {
X calloptscan = 0;
X (*protocol->p_chkopt)(0);
X }
X selmask[1] = selmask[0];
X if (select(nfds, &selmask[1].sm_rd, &selmask[1].sm_wt,
X &selmask[1].sm_ex, (struct timeval *)0) < 0) {
X if (errno == EINTR)
X continue;
X perror("select");
X done(1); /* for now -- fix this! */
X }
X for (fd=0; fd < nfds; fd++) {
X if (FD_ISSET(fd, &selmask[1].sm_rd)) {
X switch (fdmap[fd].f_type) {
X case FDT_MAC:
X PCL_RECV(0, (char *)0, 0);
X break;
X case FDT_UDSOCK:
X ipc_udrecv(fd);
X break;
X case FDT_ISSOCK:
X ipc_isrecv(fd);
X break;
X case FDT_DATA:
X PCL_XMIT(0, fdmap[fd].f_win);
X break;
X case FDT_CTL:
X ipc_ctlrecv(0, fd, fdmap[fd].f_win);
X break;
X default:
X /* "can't happen" */
X FD_CLR(fd, &selmask[0].sm_rd);
X break;
X }
X }
X if (FD_ISSET(fd, &selmask[1].sm_wt)) {
X /* "can't happen" */
X FD_CLR(fd, &selmask[0].sm_wt);
X break;
X }
X if (FD_ISSET(fd, &selmask[1].sm_ex)) {
X /* "can't happen" */
X FD_CLR(fd, &selmask[0].sm_ex);
X break;
X }
X }
X }
X}
X
Xfinduwrc()
X{
X register struct passwd *pw;
X register char *homedir;
X
X /*
X * If the global variable "rcfile" is non-NULL, then it specifies
X * the name of the startup file. Otherwise, the name of the startup
X * file is "$HOME/.uwrc". If $HOME is undefined or null, the password
X * file is consulted. The ".uwrc" file is an executable program or
X * "/bin/sh" command file. (For "csh" (ugh) use "#! /bin/csh".)
X *
X * Returns 0 if the ".uwrc" file doesn't exist, 1 if it does. As
X * a side-effect, this routine sets the global variable "rcfile"
X * to the name of the ".uwrc" file.
X */
X if (rcfile == (char *)0) {
X if ((homedir=getenv("HOME")) == NULL || !*homedir) {
X if ((pw = getpwuid(getuid())) != NULL)
X homedir = pw->pw_dir;
X else
X return;
X }
X rcfile = malloc((unsigned)(strlen(homedir) + sizeof "/.uwrc"));
X if (rcfile == (char *)0)
X return;
X (void)strcpy(rcfile, homedir);
X (void)strcat(rcfile, "/.uwrc");
X }
X if (access(rcfile, F_OK) < 0)
X rcfile = (char *)0;
X}
X
Xrunuwrc()
X{
X register int pid;
X register fildes_t fd;
X struct ptydesc pt;
X
X /*
X * We use a real fork (rather than a vfork()) because the parent
X * doesn't wait for the child. The caller knows that the file
X * exists; however, it cannot determine whether or not it is
X * successfully executed.
X *
X * We acquire a pseudo-terminal for rather convoluted reasons.
X * Programs such as "uwtool" expect to be able to inherit tty
X * modes from their controlling terminal. By the time that we
X * reach this point, we've already changed our controlling
X * terminal to use cbreak mode with no special characters except
X * XON/XOFF. Therefore, we obtain a pseudo-terminal and
X * restore our original modes onto it. We double-fork (sigh,
X * another miserable kludge) so that the server does not have
X * to wait for the completion of the ".uwrc" file. (The child
X * waits for the grandchild so that the master side of the pty
X * remains open until the grandchild is finished.)
X */
X if (openpty(&pt) < 0)
X return;
X while ((pid = fork()) < 0)
X sleep(5);
X if (pid > 0) {
X (void)close(pt.pt_pfd);
X (void)close(pt.pt_tfd);
X } else {
X /* child */
X while ((pid = fork()) < 0)
X sleep(5);
X if (pid > 0) {
X while (wait((int *)0) < 0 && errno == EINTR)
X ;
X _exit(1);
X /*NOTREACHED*/
X } else {
X /* grandchild */
X (void)setgid(getgid());
X (void)setuid(getuid());
X (void)close(pt.pt_pfd);
X if (pt.pt_tfd != 0)
X (void)dup2(pt.pt_tfd, 0);
X if (pt.pt_tfd != 1);
X (void)dup2(pt.pt_tfd, 1);
X if (pt.pt_tfd != 2)
X (void)dup2(pt.pt_tfd, 2);
X win_envinit(defwtype, (long)0);
X (void)signal(SIGHUP, SIG_DFL);
X (void)signal(SIGINT, SIG_DFL);
X (void)signal(SIGQUIT, SIG_DFL);
X (void)signal(SIGTERM, SIG_DFL);
X (void)signal(SIGTSTP, SIG_IGN);
X (void)signal(SIGCHLD, SIG_DFL);
X (void)ioctl(open("/dev/tty",O_RDWR),
X (int)TIOCNOTTY, (char *)0);
X (void)open(pt.pt_tname, O_RDONLY);
X for (fd=3; fd < nfds; fd++)
X (void)close(fd);
X tty_mode(0);
X (void)execlp(rcfile, rcfile, (char *)0);
X (void)execl("/bin/sh", "sh", rcfile, (char *)0);
X _exit(1);
X /*NOTREACHED*/
X }
X }
X}
X
Xvoid
Xrc_kludge()
X{
X static int firsttime = 1;
X
X /*
X * A problem which occurs with ".uwrc" file handling is that
X * the "rc" file is interpreted immediately after the server
X * begins, i.e. before it and the Macintosh have (possibly)
X * changed from the default protocol to an extended one.
X *
X * To get around this problem, if a ".uwrc" file exists, it
X * is not executed immediately. Instead, it will be executed
X * when this routine is called, either directly by pcl_newpcl()
X * when the protocol changes, or after an initial timeout.
X *
X * It is most unfortunate that "pcl_newpcl" must call "upwards"
X * into this source file.
X */
X if (firsttime) {
X firsttime = 0;
X if (rcfile != (char *)0)
X runuwrc();
X else
X (void)PCL_NEWW(0, WC_INTERNAL, defwtype, (nwin_t)1, 0L,
X (fildes_t)-1, (fildes_t)-1);
X }
X}
X
Xvoid
Xdone(s)
X{
X /*
X * Clean up and exit. It is overkill to close all of the file
X * descriptors, but it causes no harm.
X */
X pcl_exit(0);
X utmp_exit();
X fd_exit();
X ipc_exit();
X tty_mode(0);
X exit(s);
X}
X
Xvoid
Xcwait()
X{
X register int pid;
X union wait status;
X struct rusage rusage;
X
X /*
X * Collect dead children. Restart any children that have stopped.
X */
X while ((pid=wait3(&status, WNOHANG|WUNTRACED, &rusage)) > 0)
X if (WIFSTOPPED(status))
X (void)kill(pid, SIGCONT);
X}
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 <sys/types.h>
X#include <sys/file.h>
X#include <sys/stat.h>
X#include <sys/socket.h>
X#include <sys/un.h>
X#include <sys/ioctl.h>
X#include <sys/uio.h>
X#include <netinet/in.h>
X#include <strings.h>
X#include <netdb.h>
X#include <errno.h>
X#include <stdio.h>
X
X#include "uw_param.h"
X#include "uw_err.h"
X#include "uw_opt.h"
X#include "uw_win.h"
X#include "uw_fd.h"
X#include "uw_pcl.h"
X#include "uw_ipc.h"
X
X#ifndef ntohs
X/* declaring these as one-element arrays or as NULL pointers is a HACK */
Xextern unsigned long ntohl(), htonl();
Xextern unsigned short ntohs(), htons();
Xstatic struct netadj na_ntoh[1] = {
X (short (*)())ntohs, (long (*)())ntohl, ntohs, ntohl
X};
Xstatic struct netadj na_hton[1] = {
X (short (*)())htons, (long (*)())htonl, htons, htonl
X};
X#else
Xstatic struct netadj *na_ntoh = NULL;
Xstatic struct netadj *na_hton = NULL;
X#endif
X
Xstatic int have_udport;
Xstatic char uipc_port[] = "/tmp/uwXXXXXX";
X
Xstatic int inet_sd;
Xstatic struct ipcmsg {
X int im_len;
X struct uwipc im_msg;
X} *inet_buf;
X
Xextern int errno;
X
Xipc_init(use_uipc)
X{
X ipc_isinit();
X if (use_uipc)
X ipc_udinit();
X}
X
X
X/*
X * UNIX-domain
X */
X
Xstatic
Xipc_udinit()
X{
X register int len;
X register char *cp;
X register fildes_t sd;
X auto struct sockaddr_un sa;
X auto char *env[2];
X extern char *mktemp();
X
X len = strlen(UIPC_ENV) + sizeof uipc_port + 1;
X if ((cp = malloc(len)) != NULL) {
X (void)sprintf(cp, "%s=%s", UIPC_ENV, mktemp(uipc_port));
X env[0] = cp;
X env[1] = (char *)0;
X env_set(env);
X
X sa.sun_family = AF_UNIX;
X (void)strncpy(sa.sun_path, uipc_port, sizeof sa.sun_path-1);
X sa.sun_path[sizeof sa.sun_path-1] = '\0';
X if ((sd = socket(AF_UNIX, SOCK_DGRAM, 0)) >= 0 &&
X bind(sd,&sa,sizeof sa.sun_family+strlen(sa.sun_path)) >= 0){
X have_udport = 1;
X (void)chmod(uipc_port, S_IREAD|S_IWRITE);
X (void)fcntl(sd, F_SETFL, FNDELAY);
X fdmap[sd].f_type = FDT_UDSOCK;
X FD_SET(sd, &selmask[0].sm_rd);
X }
X }
X}
X
Xipc_exit()
X{
X if (have_udport)
X (void)unlink(uipc_port);
X}
X
Xipc_udrecv(sd)
Xregister fildes_t sd;
X{
X register struct window *w;
X register int cnt;
X struct msghdr msg;
X auto int fd;
X struct iovec iov;
X struct stat st1, st2;
X union {
X struct uwipc uwip;
X char data[1024];
X } buf;
X
X
X /*
X * main() calls this routine when there is a message waiting on
X * the UNIX-domain socket. The message's access rights are
X * expected to contain the file descriptor for the "master" side
X * of a pseudo-tty. The message contains the name of the pty.
X * The sender is expected to start up a process on the slave side
X * of the pty. This allows the host end to create windows which
X * run something other than the shell.
X */
X fd = -1;
X
X iov.iov_base = (caddr_t)buf.data;
X iov.iov_len = sizeof buf - 1;
X
X msg.msg_name = (caddr_t)0;
X msg.msg_namelen = 0;
X msg.msg_iov = &iov;
X msg.msg_iovlen = 1;
X msg.msg_accrights = (caddr_t)&fd;
X msg.msg_accrightslen = sizeof fd;
X
X if ((cnt=recvmsg(sd, &msg, 0)) < 0 || cnt != buf.uwip.uwip_len)
X return;
X switch (buf.uwip.uwip_cmd) {
X case UWC_NEWT:
X if (msg.msg_accrightslen > 0 && fd >= 0) {
X /*
X * We can't trust the process which connected to us,
X * so we verify that it really passed us a pseudo-tty's
X * file descriptor by checking the device name and its
X * inode number. [Of course, if someone else wants to
X * hand us a terminal session running under their
X * uid....]
X */
X if (cnt == sizeof buf)
X cnt--;
X buf.data[cnt] = '\0';
X if (strncmp(buf.uwip.uwip_newt.uwnt_pty,
X "/dev/pty", sizeof "/dev/pty"-1) ||
X fstat(fd, &st1) < 0 ||
X stat(buf.uwip.uwip_newt.uwnt_pty, &st2) < 0 ||
X st1.st_dev != st2.st_dev ||
X st1.st_ino != st2.st_ino) {
X (void)close(fd);
X return;
X }
X /*
X * OK, we believe the sender. We allocate a window and
X * tell the Macintosh to create that window on its end.
X * If we have no free windows, then we close the file
X * descriptor (which will terminate the slave process).
X */
X w = PCL_NEWW(0, WC_INTERNAL,
X buf.uwip.uwip_newt.uwnt_type,
X (nwin_t)0, buf.uwip.uwip_newt.uwnt_id,
X fd, (fildes_t)-1);
X if (w != NULL) {
X (void)strncpy(w->w_tty,
X buf.uwip.uwip_newt.uwnt_pty,
X sizeof w->w_tty-1);
X w->w_tty[5] = 't'; /* switch to "/dev/ttyp?" */
X utmp_add(w->w_tty);
X } else
X (void)close(fd);
X }
X break;
X case UWC_OPTION:
X w = win_search(buf.uwip.uwip_option.uwop_id,
X protocol->p_maxwin);
X if (w != NULL) {
X opt_extopt((caddr_t)w, &w->w_optdefn,
X (woptcmd_t)buf.uwip.uwip_option.uwop_cmd,
X (woption_t)buf.uwip.uwip_option.uwop_opt,
X (char *)&buf.uwip.uwip_option.uwop_val,
X (struct netadj *)0);
X }
X break;
X }
X}
X
X
X/*
X * Internet domain
X */
X
Xstatic
Xipc_isinit()
X{
X register fildes_t sd;
X register char *cp;
X struct hostent *h;
X struct sockaddr_in sin;
X auto int sinlen;
X char hostname[32];
X char *env[2];
X
X /*
X * Allocate enough buffers for each file descriptor to have one.
X * This is overkill.
X */
X inet_buf = (struct ipcmsg *)malloc(nfds * sizeof(struct ipcmsg));
X if (inet_buf == NULL)
X return;
X
X /*
X * Determine our host name and get an Internet stream socket.
X * We really should specify the protocol here (rather than 0)
X * but we "know" that it defaults to TCP.
X */
X if ((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
X return;
X sin.sin_family = AF_INET;
X sin.sin_port = 0;
X bzero(sin.sin_zero, sizeof sin.sin_zero);
X if (gethostname(hostname, sizeof hostname) < 0 || hostname[0] == '\0')
X (void)strcpy(hostname, "localhost");
X if ((h = gethostbyname(hostname)) != NULL)
X bcopy(h->h_addr, (char *)&sin.sin_addr, h->h_length);
X else
X sin.sin_addr.s_addr = htonl(0x7f000001L); /* 128.0.0.1 (lo0) */
X if (bind(sd, &sin, sizeof sin) < 0) {
X /*
X * Unable to bind to unspecified port -- try once more with
X * loopback device. If we already were using the loopback
X * device we just suffer the inefficiency of doing this twice.
X */
X sin.sin_addr.s_addr = htonl(0x7f000001L);
X if (bind(sd, &sin, sizeof sin) < 0) {
X (void)close(sd);
X return;
X }
X }
X
X /*
X * Listen for incoming connections
X */
X if (listen(sd, NWINDOW) < 0) {
X (void)close(sd);
X return;
X }
X
X /*
X * Determine our port number and put our address in the environment.
X */
X sinlen = sizeof sin;
X if (getsockname(sd, (char *)&sin, &sinlen) < 0) {
X /* huh? Oh well, give up */
X (void)close(sd);
X return;
X }
X if ((cp = malloc(sizeof INET_ENV + 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 ---
Technical Details
Message-ID:
<6602@dhw68k.cts.com>Path:
arc1-ca.pugleaf.net!utzoo!mnetor!uunet!ccicpg!felix!dhw68k!macintoshReferences:
<6493@dhw68k.cts.com> <6497@dhw68k.cts.com> <6515@dhw68k.cts.com> <6538@dhw68k.cts.com> <6587@dhw68k.cts.com>Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!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)