[net.sources] release #2, shar 4 of 7

toddb@tekcrl.UUCP (Todd Brunhoff) (03/11/86)

#!/bin/sh
#
# RFS, a kernel-resident remote file system.  Shar 4 of 7
#
#
# 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:
#	remote/serverdata.c
#	remote/serverdir.c
#	remote/serverio.c
#	remote/serversyscall.c
#	remote/shells/makemake
#	remote/shells/mkdist
#	remote/shells/mkdist.shar
#	remote/shells/rfs_clean
#	remote/shells/rfs_kerninstall
#	remote/shells/rfs_kernpatch
#	remote/shells/rfs_setup
#	remote/shells/rfs_userpatch
#	remote/usr.include.PYR2.5/syscall.h.diff
#	remote/usr.include.VAX4.2/syscall.h.diff
#	remote/usr.src.lib.libc/Makefile
#	remote/usr.src.lib.libc/gen/pyr.errlst.c.diff
#	remote/usr.src.lib.libc/gen/vax.errlst.c.diff
#
# remote/serverdata.c
#
if [ -f remote/serverdata.c ]; then 
	echo -n 'Hit <return> to overwrite remote/serverdata.c or ^C to quit' 
	read ans 
	rm -f remote/serverdata.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/serverdata.c
X/*
X * Copyright 1985, Todd Brunhoff.
X *
X * This software was written at Tektronix Computer Research Laboratories
X * as partial fulfillment of a Master's degree at the University of Denver.
X * This is not Tektronix proprietary software and should not be
X * confused with any software product sold by Tektronix.  No warranty is
X * expressed or implied on the reliability of this software; the author,
X * the University of Denver, and Tektronix, inc. accept no liability for
X * any damage done directly or indirectly by this software.  This software
X * may be copied, modified or used in any way, without fee, provided this
X * notice remains an unaltered part of the software.
X *
X * $Log:	serverdata.c,v $
X * Revision 2.0  85/12/07  18:22:20  toddb
X * First public release.
X * 
X */
Xstatic char	*rcsid = "$Header: serverdata.c,v 2.0 85/12/07 18:22:20 toddb Rel $";
X#include	"server.h"
X#include	<nlist.h>
X#include	<signal.h>
X#include	<netdb.h>
X#include	<sys/stat.h>
X
X/*
X * system calls.
X */
Xlong	access(), chdir(), chmod(), chown(), close(), dup(), execve(),
X	fchmod(), fchown(), fcntl(), flock(), fork(), fstat(), fsync(),
X	ftruncate(), ioctl(), link(), lseek(), lstat(), mkdir(),
X	mknod(), open(), read(), readlink(), rename(), rmdir(),
X	stat(), symlink(), truncate(), unlink(), utimes(),
X	write(),
X/*
X * ...and our own routines to set up for the system calls.
X */
X	noop(), s_access(), s_dup(), s_execinfo(), s_execread(), s_exit(),
X	s_fcntl(), s_fd1(), s_fd1_plus(), s_fork(), s_ioctl(), s_lseek(),
X	s_open(), s_path1(), s_path1_plus(), s_path2(), s_read(),
X	s_readlink(), s_stat(), s_utimes(), s_write();
X
Xsyscallmap smap[] = {
X	s_fork,		noop,     NEED_ZIP,		/* RSYS_fork */
X	s_read,		read,     NEED_ZIP,		/* RSYS_read */
X	s_write,	write,    NEED_ZIP,		/* RSYS_write */
X	s_open,		open,	  NEED_CWD
X				 |NEED_MYSERVER
X				 |NEED_PERM
X				 |NEED_FD,		/* RSYS_open */
X	s_fd1,		close,    NEED_ZIP,		/* RSYS_close */
X	noop,		noop,	  NEED_CWD
X				 |NEED_PERM
X				 |NEED_FD,		/* RSYS_creat */
X	s_path2,	link,	  NEED_CWD
X				 |NEED_MYSERVER
X				 |NEED_2PATH
X				 |NEED_2REMOTE
X				 |NEED_PERM,		/* RSYS_link */
X	s_path1,	unlink,   NEED_CWD|NEED_PERM,	/* RSYS_unlink */
X	s_path1,	chdir,    NEED_MYSERVER
X				 |NEED_CWD
X				 |NEED_PERM
X				 |NEED_MYSERVER,	/* RSYS_chdir */
X	s_path1_plus,	mknod,    NEED_CWD|NEED_PERM,	/* RSYS_mknod */
X	s_path1_plus,	chmod,    NEED_CWD|NEED_PERM,	/* RSYS_chmod */
X	s_path1_plus,	chown,    NEED_CWD|NEED_PERM,	/* RSYS_chown */
X	s_stat,		stat,     NEED_CWD|NEED_PERM,	/* RSYS_stat */
X	s_lseek,	lseek,    NEED_ZIP,		/* RSYS_lseek */
X	s_access,	access,   NEED_CWD|NEED_PERM,	/* RSYS_access */
X	s_stat,		lstat,    NEED_CWD|NEED_PERM,	/* RSYS_lstat */
X	s_dup,		dup,      NEED_FD,		/* RSYS_dup */
X	s_ioctl,	ioctl,    NEED_ZIP,		/* RSYS_ioctl */
X	s_path2,	symlink,  NEED_CWD
X				 |NEED_2PATH
X				 |NEED_PERM,		/* RSYS_symlink */
X	s_readlink,	readlink, NEED_CWD|NEED_PERM,	/* RSYS_readlink */
X	s_stat,		fstat,    NEED_ZIP,		/* RSYS_fstat */
X	s_dup,		dup,      NEED_FD,		/* RSYS_dup2 */
X	s_fd1_plus,	fcntl,    NEED_ZIP,		/* RSYS_fcntl */
X	s_fd1,		fsync,    NEED_ZIP,		/* RSYS_fsync */
X	noop,		noop,     NEED_ZIP,		/* RSYS_readv */
X	noop,		noop,     NEED_ZIP,		/* RSYS_writev */
X	s_fd1_plus,	fchown,   NEED_PERM,		/* RSYS_fchown */
X	s_fd1_plus,	fchmod,   NEED_PERM,		/* RSYS_fchmod */
X	s_path2,	rename,   NEED_MYSERVER
X				 |NEED_2REMOTE
X				 |NEED_CWD
X				 |NEED_2PATH
X				 |NEED_PERM,		/* RSYS_rename */
X	s_path1_plus,	truncate, NEED_CWD|NEED_PERM,	/* RSYS_truncate */
X	s_fd1_plus,	ftruncate,NEED_ZIP,		/* RSYS_ftruncate */
X	s_fd1_plus,	flock,    NEED_ZIP,		/* RSYS_flock */
X	s_path1_plus,	mkdir,    NEED_CWD|NEED_PERM,	/* RSYS_mkdir */
X	s_path1,	rmdir,    NEED_CWD|NEED_PERM,	/* RSYS_rmdir */
X	s_utimes,	utimes,   NEED_CWD|NEED_PERM,	/* RSYS_utimes */
X	s_exit,		noop,	  NEED_ZIP,		/* RSYS_exit */
X	s_fork,		noop,     NEED_ZIP,		/* RSYS_Vfork */
X	s_execinfo,	noop,	  NEED_MYSERVER
X				 |NEED_CWD
X				 |NEED_PERM,		/* RSYS_execinfo */
X	s_execread,	noop,	  NEED_PERM,		/* RSYS_execread */
X	noop,		noop,	  NEED_ZIP,		/* RSYS_execve */
X	noop,		noop,	  NEED_ZIP,		/* RSYS_nosys */
X	s_lseek,	lseek,    NEED_ZIP,		/* RSYS_qlseek */
X};
X
Xchar	*syscallnames[] = {
X	"fork",
X	"read",
X	"write",
X	"open",
X	"close",
X	"creat",
X	"link",
X	"unlink",
X	"chdir",
X	"mknod",
X	"chmod",
X	"chown",
X	"stat",
X	"lseek",
X	"access",
X	"lstat",
X	"dup",
X	"ioctl",
X	"symlink",
X	"readlink",
X	"fstat",
X	"dup2",
X	"fcntl",
X	"fsync",
X	"readv",
X	"writev",
X	"fchown",
X	"fchmod",
X	"rename",
X	"truncate",
X	"ftruncate",
X	"flock",
X	"mkdir",
X	"rmdir",
X	"utimes",
X	"exit",
X	"vfork",
X	"execinfo",
X	"execread",
X	"execve",
X	"nosys",
X	"quick lseek"
X};
X
Xchar	hostname[ HOSTNAMELEN ];/* our host name */
Xchar	mntpt[ MAXPATHLEN ];	/* mount point for client */
Xchar	*program;		/* name of this program */
Xchar	*last_argaddr;		/* last address that we can scribble on */
Xchar	*service = REMOTE_FS_SERVER; /* name of alternate internet service */
Xchar	*stdlogfile = "/usr/tmp/rfs_log"; /* log file  for server */
Xchar	*logfile;
Xlong	serviceport;		/* port number for service */
Xlong	remote_debug;		/* level of debug output */
Xshort	current_uid;		/* whatever uid we are, right now */
Xshort	current_pid;		/* whatever pid we are, right now */
Xshort	current_ppid;		/* our parent server */
Xshort	current_umask;		/* whatever umask we have, right now */
Xshort	current_server;		/* server that has control right now */
Xshort	gateway_server;		/* pid of our gateway */
Xshort	last_sentry;		/* previous sentry server (if non-zero) */
Xlong	fds_in_use;		/* number of total file descriptors open */
Xlong	to_gateway;		/* file descriptor for messages to gateway */
Xlong	so_listen;		/* socket for listening for connections */
Xlong	from_servers;		/* file descriptor for messages from servers */
Xlong	blocking_servers;	/* number of servers waiting for I/O */
Xhosts	*hostlist;		/* all the hosts we know of */
Xhosts	*host;			/* the current host that we talk to */
Xhosts	*thishost;		/* host pointer for this machine */
Xusers	*userlist;		/* all the users on this host we know of */
Xusers	*default_user;		/* default user to map unknown clients to */
Xprocess *wildcard;		/* wildcard process for easy requests */
Xboolean	i_am_gateway = TRUE;	/* whether we are the gateway server */
Xboolean	i_have_control = TRUE;	/* whether the gateway server has control of */
X				/* the command socket */
Xboolean	i_am_asleep;		/* whether we are sleeping or not */
Xboolean	gateway_needs_control;	/* True if gateway wants control back */
Xboolean	watch_for_lock;		/* True if we need to watch for lock on fd 2 */
Xboolean	route_to_gateway;	/* True if we should route to gateway */
Xboolean	in_root_directory = TRUE;/* whether we are at root directory or not */
Xstruct stat	filetypes[ NOFILE ];	/* file types for open files */
X
Xchar	byteorder[4] = { BYTEORDER };
Xlong	catch(),
X	nameserver(),
X	wakeup_call(),
X	alarmsig();
X
Xstruct sigvec sig_continue = {
X	wakeup_call,
X	1<<(SIGIO -1),
X	0
X};
X
Xstruct sigvec sig_ignore = {
X	(int (*)())SIG_IGN,
X	1<<(SIGHUP -1),
X	0
X};
X
Xstruct sigvec sig_alarm = {
X	alarmsig,
X	1<<(SIGALRM -1),
X	0
X};
X
Xstruct sigvec sig_name = {
X	nameserver,
X	1<<(SIGURG -1),
X	0
X};
X
Xstruct sigvec sig_vec = {
X	catch,
X	 (1<<(SIGINT -1))
X	|(1<<(SIGQUIT-1))
X	|(1<<(SIGBUS-1))
X	|(1<<(SIGILL-1))
X	|(1<<(SIGSEGV-1))
X	|(1<<(SIGPIPE-1))
X	|(1<<(SIGSYS-1))
X	|(1<<(SIGTERM-1))
X	|(1<<(SIGTTIN-1))
X	|(1<<(SIGTTOU-1))
X	|(1<<(SIGXCPU-1))
X	|(1<<(SIGXFSZ-1))
X	|(1<<(SIGVTALRM-1)),
X	0
X};
X
X#ifdef RFSDEBUG
X
Xlong	newdebug();
X
Xstruct sigvec sig_debug = {
X	newdebug,
X	(1<<(SIGTRAP -1)),
X	0
X};
X#endif RFSDEBUG
X
Xstruct stat	root;			/* stat info for root directory */
SHAREOF
chmod 444 remote/serverdata.c
#
# remote/serverdir.c
#
if [ -f remote/serverdir.c ]; then 
	echo -n 'Hit <return> to overwrite remote/serverdir.c or ^C to quit' 
	read ans 
	rm -f remote/serverdir.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/serverdir.c
X/*
X * Copyright 1985, Todd Brunhoff.
X *
X * This software was written at Tektronix Computer Research Laboratories
X * as partial fulfillment of a Master's degree at the University of Denver.
X * This is not Tektronix proprietary software and should not be
X * confused with any software product sold by Tektronix.  No warranty is
X * expressed or implied on the reliability of this software; the author,
X * the University of Denver, and Tektronix, inc. accept no liability for
X * any damage done directly or indirectly by this software.  This software
X * may be copied, modified or used in any way, without fee, provided this
X * notice remains an unaltered part of the software.
X *
X * $Log:	serverdir.c,v $
X * Revision 2.0  85/12/07  18:22:28  toddb
X * First public release.
X * 
X */
Xstatic char	*rcsid = "$Header: serverdir.c,v 2.0 85/12/07 18:22:28 toddb Rel $";
X#include	"server.h"
X#include	<sys/dir.h>
X#include	<sys/stat.h>
X#include	<errno.h>
X
Xextern hosts	*host;
Xextern long	errno;
Xextern char	byteorder[];
Xextern struct stat	filetypes[];
X
X/*
X * Check to see type open file type... we may have to massage input
X * it if the user wants to read this file descriptor and it is a directory.
X */
Xcheckfiletype(fd)
X	register int    fd;
X{
X	struct stat	statb, *statp = &statb;
X
X	if (fd < 0)
X		return;
X	fstat(fd, statp);
X	filetypes[ fd ] = statb;
X}
X
X/*
X * If byte-ordering is different between this machine and our client,
X * the directories must be massaged into the right byte order.
X */
Xfixdir(fd, buf, size)
X	register long	size,
X			fd;
X	register char	*buf;
X{
X	register struct direct *dirp;
X	register char	*next, *last;
X	register u_char	*clientorder = host->h_byteorder;
X	short		fixshort();
X
X	if (size < 0)
X		return(errno);
X	if (fd >= NOFILE || (filetypes[fd].st_mode & S_IFDIR) == 0)
X		return(0);
X
X	/*
X	 * we don't know this client's byteorder...  can't do it right
X	 */
X	if (!host->h_mounted)
X		return(EIO);
X	dirp = (struct direct *)buf;
X	last = buf;
X	debug7("nuxi directory entry buf=0%x, size=%d, end @%x\n",
X		buf, size, buf+size);
X	while(last < buf + size && dirp->d_reclen)
X	{
X		dirp = (struct direct *)last;
X		next = last + dirp->d_reclen;
X
X		debug7("dir @0x%x (next+%d @0x%x): %x %x %x %s -->",
X			last, dirp->d_reclen, next,
X			dirp->d_ino,
X			(unsigned)dirp->d_reclen,
X			(unsigned)dirp->d_namlen,
X			dirp->d_name);
X		dirp->d_ino = fixlong(clientorder, &dirp->d_ino);
X		dirp->d_reclen = fixshort(clientorder, &dirp->d_reclen);
X		dirp->d_namlen = fixshort(clientorder, &dirp->d_namlen);
X		debug7(" %x %x %x %s\n",
X			dirp->d_ino,
X			(unsigned)dirp->d_reclen,
X			(unsigned)dirp->d_namlen,
X			dirp->d_name);
X		last = next;
X	}
X	return(0);
X}
X
Xfixlong(clto, from)
X	register char	*clto,	/* clients byte order */
X			*from;	/* data to be fixed */
X{
X	register char	*srvo,	/* server's byte order */
X			*to;
X	long		result;
X
X	to = (char *)&result;
X	srvo = byteorder;
X	to[ clto[0] ] = from[ srvo[0] ];
X	to[ clto[1] ] = from[ srvo[1] ];
X	to[ clto[2] ] = from[ srvo[2] ];
X	to[ clto[3] ] = from[ srvo[3] ];
X	return(result);
X}
X
Xshort fixshort(clto, from)
X	register char	*clto,	/* clients byte order */
X			*from;	/* data to be fixed */
X{
X	register char	*srvo,	/* server's byte order */
X			*to;
X	short		result;
X
X	to = (char *)&result;
X	srvo = byteorder;
X	to[ clto[0]&0x1 ] = from[ srvo[0]&0x1 ];
X	to[ clto[1]&0x1 ] = from[ srvo[1]&0x1 ];
X	return(result);
X}
SHAREOF
chmod 444 remote/serverdir.c
#
# remote/serverio.c
#
if [ -f remote/serverio.c ]; then 
	echo -n 'Hit <return> to overwrite remote/serverio.c or ^C to quit' 
	read ans 
	rm -f remote/serverio.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/serverio.c
X/*
X * Copyright 1985, Todd Brunhoff.
X *
X * This software was written at Tektronix Computer Research Laboratories
X * as partial fulfillment of a Master's degree at the University of Denver.
X * This is not Tektronix proprietary software and should not be
X * confused with any software product sold by Tektronix.  No warranty is
X * expressed or implied on the reliability of this software; the author,
X * the University of Denver, and Tektronix, inc. accept no liability for
X * any damage done directly or indirectly by this software.  This software
X * may be copied, modified or used in any way, without fee, provided this
X * notice remains an unaltered part of the software.
X *
X * $Log:	serverio.c,v $
X * Revision 2.1  86/01/27  11:30:05  toddb
X * Changed the h_addr component of the hosts structure to be h_iaddr so
X * as not to conflict with the 4.3 define if h_addr in netdb.h.
X * 
X * Revision 2.0  85/12/07  18:22:33  toddb
X * First public release.
X * 
X */
Xstatic char	*rcsid = "$Header: serverio.c,v 2.1 86/01/27 11:30:05 toddb Exp $";
X#include <errno.h>
X#include <stdio.h>
X#include "server.h"
X#include <sys/uio.h>
X#include <sys/file.h>
X#include <netdb.h>
X#include <signal.h>
X
X/*
X * This routine prepares to recieve a connection from another process.  
X * To be any good it must be followed by a call to tcpaccept().
X */
Xextern long	errno;
Xextern short	current_pid;
Xextern char	*sys_errlist[],
X		*service,
X		*logfile,
X		*stdlogfile,
X		*getbuf();
Xextern boolean	i_am_gateway;
Xextern hosts	*host;
Xextern long	serviceport,
X		errno;
Xextern short	last_sentry;
X
Xint	read(),
X	write();
X
X/*
X * Get ready to accept connections.
X */
Xtcppassive()
X{
X	int	f;
X	struct sockaddr_in	sin;
X	struct servent	*servp;
X
X	if ((servp = getservbyname(service, "tcp")) == NULL)
X		log_fatal("%s: unknown service\n", service);
X	serviceport = servp->s_port;
X
X	sin.sin_port = serviceport;
X	sin.sin_addr.s_addr = INADDR_ANY;
X	sin.sin_family = AF_INET;
X
X	f = socket(AF_INET, SOCK_STREAM, 0);
X	setsockopt(f, SOL_SOCKET, SO_KEEPALIVE, 0, 0);
X	setsockopt(f, SOL_SOCKET, SO_REUSEADDR, 0, 0);
X
X	while (bind(f, (caddr_t)&sin, sizeof (sin)) < 0) {
X		if (last_sentry && errno == EADDRINUSE)
X		{
X			log("shutting down old sentry (pid %d)\n",
X				last_sentry);
X			if (! sendsig(last_sentry, SIGTERM))
X				last_sentry = 0;
X			sleep(2);	/* give it time to die */
X			continue;
X		}
X		log("cannot bind %s\n", service);
X		return(-1);
X	}
X
X	listen(f, 5);
X	return(f);
X}
X
X/*
X * Here we passively accept a connection from another process.
X * We return a pointer to the hosts structure.  If there is no
X * corresponding host for a given connection, we make up a new one
X * and return that.
X */
Xhosts *tcpaccept(f)
X	int	f;
X{
X	hosts	*h = NULL;
X	struct sockaddr_in	sin;
X	int	g,
X		i,
X		len = sizeof (struct sockaddr_in);
X
X	for (i = 0, g = -1; g < 0 && i < 10; i++) {
X		g = accept(f, &sin, &len);
X		if (g < 0)
X		{
X			log("accept failed\n");
X			continue;
X		}
X
X		/*
X		 * Ok, we have recieved a connection.  Find out what we
X		 * know about this fella, and save the command file descriptor
X		 * and the port number.
X		 */
X		h = findhostaddr(&sin.sin_addr);
X		h->h_cmdfd = g;
X		h->h_portnum = htons((u_short)sin.sin_port);
X	}
X
X	return(h);
X}
X
X/*
X * Call another host's server.  We assume that he is using the same service
X * as we.
X */
Xtcpconnect(h)
X	register hosts	*h;
X{
X	struct sockaddr_in sin;
X	register long	s;
X
X	bzero((char *)&sin, sizeof (sin));
X	bcopy(&h->h_iaddr, (char *)&sin.sin_addr, sizeof(struct in_addr));
X	sin.sin_family = AF_INET;
X	sin.sin_port = serviceport;
X	s = socket(AF_INET, SOCK_STREAM, 0);
X	if (s < 0)
X	{
X		log("can't get socket to remote server\n");
X		return(-1);
X	}
X
X	/*
X	 * time out on connection rather quickly.
X	 */
X	alarm(5);
X	if (connect(s, (char *)&sin, sizeof (sin)) < 0) {
X		alarm(0);
X		log("can't connect to server\n");
X		close(s);
X		return(-1);
X	}
X	alarm(0);
X	return(s);
X}
X
Xalarmsig()
X{
X	log("timeout\n");
X	errno = EINTR;
X}
X
Xlog(x1, x2, x3, x4, x5, x6, x7, x8, x9)
X{
X	char		buf[ BUFSIZ ];
X	register char	*p = buf;
X	static boolean	printpid = TRUE;
X
X	*p = '\0';
X	if (printpid)
X	{
X		sprintf(p, "(%d)", current_pid);
X		p += strlen(p);
X		if (errno)
X		{
X			sprintf(p, "%s: ", sys_errlist[ errno ]);
X			p += strlen(p);
X			errno = 0;
X		}
X	}
X	sprintf(p, x1, x2, x3, x4, x5, x6, x7, x8, x9);
X	p += strlen(p);
X	if (*(p-1) == '\n')
X		printpid = TRUE;
X	else
X		printpid = FALSE;
X	write(2, buf, p-buf);
X}
X
Xlog_fatal(x1, x2, x3, x4, x5, x6, x7, x8, x9)
X{
X	static boolean		entered = FALSE;
X
X	if (! entered)
X	{
X		entered = TRUE;
X		log ("fileserver: FATAL ERROR: ");
X		log (x1, x2, x3, x4, x5, x6, x7, x8, x9);
X		cleanup();
X	}
X	exit (1);
X}
X
X/*
X * Set up the log file for the current process.  If there is no current
X * host defined, then we are the sentry server and simply use the
X * standard logfile:  this should be done once only.  If 'host' is defined,
X * then set up a logfile for this particular connection.
X *
X * The sentry server always puts his signature at the top of the file
X * (pid number).  So as a side effect, the global variable last_sentry
X * is set to this signature (if there exists one).
X */
Xsetlogfile()
X{
X	char	buf[ BUFSIZ ];
X	register char	*pbuf = buf;
X	register long	newstderr;
X	boolean	sentry = FALSE;
X	FILE	*fd;
X
X	if (logfile)
X		free (logfile);
X	if (host == NULL)
X	{
X		sentry = TRUE;
X		strcpy(pbuf, stdlogfile);
X	}
X	else
X		sprintf(pbuf, "%s.%s.%d",
X			stdlogfile, host->h_names[0], current_pid);
X	logfile = malloc(strlen(pbuf)+1);
X	strcpy(logfile, pbuf);
X
X	/*
X	 * Get the previous signature.
X	 */
X	if (sentry) 
X	{
X		if ((fd = fopen(logfile, "r")) != NULL)
X		{
X			*pbuf = '\0';
X			fgets(pbuf, BUFSIZ, fd);
X			last_sentry = atoi(pbuf+1);
X			fclose(fd);
X		}
X	}
X
X	newstderr = open(logfile, O_RDWR|O_APPEND|O_CREAT|O_TRUNC, 0444);
X	if (newstderr < 0)
X		log_fatal("cannot reopen stderr\n");
X	dup2(newstderr, 2);
X	close(newstderr);
X	log("startup.\n");	/* put down our signature. */
X}
X
Xcleanup()
X{
X	register process	*proc;
X
X	if (i_am_gateway && host)
X		for (proc=host->h_proclist; proc; proc=proc->p_next)
X			if (proc->p_handler != current_pid)
X				sendsig(proc->p_handler, SIGKILL);
X	mourne();
X}
X
Xsndmsg(fd, msg, msglen, data, len)
X	register struct message	*msg;
X	register char	*data;
X	register int	fd, msglen, len;
X{
X	register int	num;
X	struct iovec	iov[2];
X
X
X	showmsg(msg, TRUE);
X	/*
X	 * set up for the write and if there is any data to send, try to send
X	 * a bunch of it.
X	 */
X	if (len > 0 && data)
X	{
X		iov[0].iov_base = (char *)msg;
X		iov[0].iov_len = msglen;
X		iov[1].iov_base = data;
X		iov[1].iov_len = len;
X		if ((num = writev(fd, iov, 2)) == len + msglen)
X		{
X			debug8("wrote data and msg (%d)!!\n", len + msglen);
X			return(TRUE);
X		}
X		debug8("wrote %d of %d msg + data\n", num, len+msglen);
X		if (num < 0)
X			return(FALSE);
X		if (_rmtio(write, fd, data+num, len-num) <= 0)
X			return(FALSE);
X	}
X	else if (_rmtio(write, fd, msg, msglen) <= 0)
X		return(FALSE);
X	return(TRUE);
X}
X
X/*
X * Read the next message.  Its format is null-separated hex-ascii strings.
X * In order, they are:
X *	total_length	length of this request
X *	header_length	length of the message request (minus length of data)
X *	pid		Process id on requesting machine
X *	uid		user id of process on requesting machine
X *	syscall		our internal syscall number
X *	args...		between 0 and ?
X *
X * Followed by actual data (if any).  We grab the first two fields, and
X * use them for making sure we read all that is necessary.  The remainder
X * are returned in a array of character pointers.  It there is any data
X * in this request, then it is pointed to by the last character pointer.
X *
X * The way that we read messages is as follows:
X *
X *	last message length = 0
X *	while no more messages
X *	do
X * 		if last message length > 0
X * 			gobbleup last message length bytes
X *		peek at next message
X *		if this message is for another process
X *		then
X *			wake up the other process
X *			last message length = 0
X *			go to sleep
X *			continue
X *		endif
X *		if data in this message
X *		then
X *			read the message
X *			last message length = 0
X *		else
X *			last message length = length of this message
X *		endif
X *		service request
X *	done
X */
X
Xstruct message *getmsg(fd)
X	register long	fd;
X{
X	register long	cnt,
X			lastcnt = 0,
X			len;
X	register struct message	*msg;
X
X	msg = (struct message *)getbuf(BIGBUF);
X	/*
X	 * Check to see if there is a message still in the queue, that has
X	 * been processed, but not yet read.
X	 */
X	gobble_last_msg(fd, msg);
X	for (;;)
X	{
X		debug8("peek at fd %d... ", fd);
X		cnt = recv(fd, (char *)msg, BIGBUF, MSG_PEEK);
X		if (cnt < R_MINRMSG)
X		{
X			if (cnt < 0 && errno == EINTR)
X				continue;
X			debug8("eof, cnt=%d\n", cnt);
X			return(NULL);
X		}
X		debug8("got %d from peek\n", cnt);
X
X		/*
X		 * Now find out how long the request is (excluding data)
X		 * and make sure that we have at least that amount.
X		 */
X#ifdef magnolia
X		len = msg->m_hdlen;
X#else	 /* magnolias don't need to do this garbage (MC68000) */
X		msg->m_totlen = ntohl(msg->m_totlen);
X		len = msg->m_hdlen = ntohs(msg->m_hdlen);
X		msg->m_pid = ntohs(msg->m_pid);
X		msg->m_uid = ntohs(msg->m_uid);
X		msg->m_syscall = ntohs(msg->m_syscall);
X		msg->m_args[0] = ntohl(msg->m_args[0]);
X		msg->m_args[1] = ntohl(msg->m_args[1]);
X		msg->m_args[2] = ntohl(msg->m_args[2]);
X		msg->m_args[3] = ntohl(msg->m_args[3]);
X#endif
X		if (len > cnt)
X		{
X			if (cnt == lastcnt)
X			{
X				log("most but not all of message is in\n");
X				dumpmsg(msg, cnt);
X				return(NULL);
X			}
X			else
X				debug8("didn't get all of message headder\n");
X			lastcnt = cnt;
X			sleep(5);
X		}
X		else if (len < R_MINRMSG)
X		{
X			log("bad soft msg len=%d, got %d\n", len, cnt);
X			dumpmsg(msg, cnt);
X			if (i_am_gateway)
X				log_fatal("");
X			say_something(S_CORRUPTED, 0);
X			sendsig(current_pid, SIGSTOP);
X		}
X		else
X			break;
X	}
X	showmsg(msg, FALSE);
X	return(msg);
X}
X
X/*
X * Here we format the response to be sent to the client.  Note that
X * the client can never tolerate a message shorter than
X * R_MINRMSG + sizeof(long).  The declaration of x0-xf is for the
X * sake of stupid Pyramid argument conventions.
X */
Xsendreturn(proc, fd, data, cnt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,xa,xb,xc,xd,xe,xf)
X	process		*proc;
X	register long	cnt;
X	register char	*data;
X	long		fd;
X{
X	char	buf[ BUFSIZ ];
X	struct message		msgbuf;
X	register struct message	*msg = &msgbuf;
X	register	*argp = &x0, msglen, i;
X
X	msg->m_errno = htons(proc->p_errno);
X	msg->m_pid = htons(proc->p_pid);
X	msg->m_uid = htons(proc->p_uid);
X	if (proc->p_errno > 0) /* -1 is valid errno: says its a local file */
X	{
X		msglen = R_MINRMSG + sizeof(long);
X		msg->m_totlen = htonl(msglen);
X		proc->p_returnval = -1;
X	}
X	else
X	{
X		msglen = R_MINRMSG + (cnt+1)*sizeof(long);
X		if (data)
X			msg->m_totlen = htonl(msglen + proc->p_returnval);
X		else
X			msg->m_totlen = htonl(msglen);
X#ifdef pyr /* Pyramid */
X		msg->m_args[ R_RETVAL+1 ] = htonl(x0);
X		msg->m_args[ R_RETVAL+2 ] = htonl(x1);
X		msg->m_args[ R_RETVAL+3 ] = htonl(x2);
X		msg->m_args[ R_RETVAL+4 ] = htonl(x3);
X		msg->m_args[ R_RETVAL+5 ] = htonl(x4);
X		msg->m_args[ R_RETVAL+6 ] = htonl(x5);
X		msg->m_args[ R_RETVAL+7 ] = htonl(x6);
X		msg->m_args[ R_RETVAL+8 ] = htonl(x7);
X		msg->m_args[ R_RETVAL+9 ] = htonl(x8);
X		msg->m_args[ R_RETVAL+10 ] = htonl(x9);
X		msg->m_args[ R_RETVAL+11 ] = htonl(xa);
X		msg->m_args[ R_RETVAL+12 ] = htonl(xb);
X		msg->m_args[ R_RETVAL+13 ] = htonl(xc);
X		msg->m_args[ R_RETVAL+14 ] = htonl(xd);
X		msg->m_args[ R_RETVAL+15 ] = htonl(xe);
X		msg->m_args[ R_RETVAL+16 ] = htonl(xf);
X#else pyr
X		for (i=0; i<cnt; i++)
X			msg->m_args[ R_RETVAL+1+i ] = htonl(argp[ i ]);
X#endif
X	}
X	msg->m_args[ R_RETVAL ] = htonl(proc->p_returnval);
X	msg->m_hdlen = htons(msglen);
X	sndmsg(fd, msg, msglen, data, proc->p_returnval);
X	errno = 0;
X}
X
X_shutdown(fd)
X	int	fd;
X{
X	log("shutdown fd %d\n", fd);
X	close(fd);
X}
X
Xchar *getbuf(size)
X{
X	static char	*buf, *calloc(), *realloc();
X	static int	cursize;
X	static int	highwater;
X
X	if (size > highwater)
X	{
X		if (buf == NULL)
X			buf = calloc(cursize = size, sizeof(char));
X		else
X		{
X			buf = realloc(buf, highwater = size);
X			debug8("resize buffer to %d\n", size);
X		}
X		highwater = size;
X		if (buf == NULL)
X			log_fatal("cannot allocate buffer space\n");
X	}
X	return(buf);
X}
X
Xchar *get_data_buf(size)
X{
X	static char	*buf, *malloc(), *realloc();
X	static int	cursize;
X	static int	highwater;
X
X	if (size > highwater)
X	{
X		if (buf == NULL)
X			buf = malloc(cursize = size);
X		else
X		{
X			buf = realloc(buf, highwater = size);
X			debug8("resize data buffer to %d\n", size);
X		}
X		highwater = size;
X		if (buf == NULL)
X			log_fatal("cannot allocate data buffer space\n");
X	}
X	return(buf);
X}
X
Xgobble_last_msg(fd, msg)
X	register long		fd;
X	register struct message	*msg;
X{
X	if (msg->m_totlen)
X	{
X		debug8("gobble up last %d byte message... ", msg->m_totlen);
X		_rmtio(read, fd, msg, msg->m_totlen);
X		msg->m_totlen = 0;
X	}
X}
X
X_rmtio(iofunc, fd, buf, len)
X	register func	iofunc;
X	register int	fd, len;
X	register char	*buf;
X{
X	register int	cnt, need = len;
X
X	debug8("io %d bytes, fd=%d...", len, fd);
X	while(need)
X	{
X		if ((cnt = (*iofunc)(fd, buf+len-need, need)) <= 0)
X		{
X			_shutdown(fd);
X			return(cnt);
X		}
X		need -= cnt;
X	}
X	debug8("did %d.\n", len - need);
X	return(len);
X}
X
X_rmtiov(iofunc, fd, iovec, len)
X	register func	iofunc;
X	register int	fd, len;
X	register struct iovec	*iovec;
X{
X
X	debug8("io %d vectors, fd=%d...", len, fd);
X	if ((len = (*iofunc)(fd, iovec, len)) <= 0)
X		_shutdown(fd);
X	debug8("did %d.\n", len);
X	return(len);
X}
X
X/*
X * Show the message in characters and hex.
X */
Xdumpmsg(msg, len)
X	char	*msg;
X	long	len;
X{
X	char	string[ 100 ], *pstring = string,
X		words[ 100 ], *pwords = words,
X		dwords[ 100 ], *pdwords = dwords,
X		longs[ 100 ], *plongs = longs,
X		*p;
X	long	cnt = 0;
X
X	for(p = msg; cnt<len; cnt++, p++)
X	{
X		/* character */
X		if (*p >= ' ')
X			sprintf(pstring, "%c  ", *p > '~' ? '?' : *p);
X		else
X			sprintf(pstring, "^%c ", *p | 0x40);
X		pstring += 3;
X		if ((cnt & 0x1) == 0)
X		{
X			sprintf(pwords, "%-4.4x  ",
X				*((unsigned short *)p));
X			sprintf(pdwords, "%-5.5d ",
X				*((unsigned short *)p));
X			pwords += 6;
X			pdwords += 6;
X		}
X		if ((cnt & 0x3) == 0)
X		{
X			sprintf(plongs, "%-8.8x    ", *((long *)p));
X			plongs += 12;
X		}
X		if (pstring >= string+72)
X		{	
X			log("%s\n", pstring = string);
X			log("%s\n", pwords = words);
X			log("%s\n", pdwords = dwords);
X			log("%s\n\n", plongs = longs);
X		}
X	}
X	log("%s\n", string);
X	log("%s\n", words);
X	log("%s\n", dwords);
X	log("%s\n", longs);
X}
X
X#ifdef RFSDEBUG
X
Xshowmsg(msg, fromserver)
X	register struct message	*msg;
X	long	fromserver;
X{
X	register long	end, len, pid, uid, totlen;
X
X	if ((remote_debug & 0x100) == 0)
X		return;
X	if (fromserver)
X		len = ntohs(msg->m_hdlen),
X		totlen = ntohl(msg->m_totlen),
X		pid = ntohs(msg->m_pid),
X		uid = ntohs(msg->m_uid);
X	else
X		len = msg->m_hdlen,
X		totlen = msg->m_totlen,
X		pid = msg->m_pid,
X		uid = msg->m_uid;
X	log("%s server: len=%d,tot=%d,pid=%d,uid=%d",
X		fromserver ? "from" : "to", len, totlen, pid, uid);
X
X	/* round up into long words */
X	len = (len - R_MINRMSG + 3) >> 2;
X	if (fromserver)
X	{
X		log(",errno=%d,retval=%d",
X			htons(msg->m_errno), htonl(msg->m_args[ R_RETVAL ]));
X		end = R_RETVAL+1;
X	}
X	else
X	{
X		log(",syscall=%d", msg->m_syscall);
X		end = 0;
X	}
X	for (; end<len; end++)
X		log(",0x%x", ntohl(msg->m_args[ end ]));
X	log("\n");
X}
X
X/*
X * Set new debug levels.
X */
Xnewdebug()
X{
X	register long	fd, cnt;
X	char	*dbfile = "/usr/tmp/rfs_debug",
X		buf[ BUFSIZ ];
X	register char	*p = buf;
X
X	fd = open(dbfile, O_RDONLY);
X	if (fd < 0) {
X		log("can't open %s\n", dbfile);
X		goto out;
X	}
X
X	cnt = read(fd, buf, BUFSIZ);
X	close(fd);
X	if (cnt <= 0) {
X		log("can't read %s\n", dbfile);
X		goto out;
X	}
X
X	while ((*p >= 'a' && *p <= 'f')
X	    || (*p >= 'A' && *p <= 'F')
X	    || (*p >= '0' && *p <= '9'))
X		p++;
X	*p = '\0';
X	remote_debug = atox(buf);
Xout:
X	log("debug=%x\n", remote_debug);
X}
X#endif RFSDEBUG
SHAREOF
chmod 444 remote/serverio.c
#
# remote/serversyscall.c
#
if [ -f remote/serversyscall.c ]; then 
	echo -n 'Hit <return> to overwrite remote/serversyscall.c or ^C to quit' 
	read ans 
	rm -f remote/serversyscall.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/serversyscall.c
X/*
X * Copyright 1985, Todd Brunhoff.
X *
X * This software was written at Tektronix Computer Research Laboratories
X * as partial fulfillment of a Master's degree at the University of Denver.
X * This is not Tektronix proprietary software and should not be
X * confused with any software product sold by Tektronix.  No warranty is
X * expressed or implied on the reliability of this software; the author,
X * the University of Denver, and Tektronix, inc. accept no liability for
X * any damage done directly or indirectly by this software.  This software
X * may be copied, modified or used in any way, without fee, provided this
X * notice remains an unaltered part of the software.
X *
X * $Log:	serversyscall.c,v $
X * Revision 2.1  86/01/27  10:47:30  toddb
X * s_execinfo() was returning the wrong error if the access permission
X * was wrong: ENOEXEC.  It now returns EACCESS.  Thanks to Joe Othemer@vax135.
X * 
X * Revision 2.0  85/12/07  18:22:44  toddb
X * First public release.
X * 
X */
Xstatic char	*rcsid = "$Header: serversyscall.c,v 2.1 86/01/27 10:47:30 toddb Exp $";
X#include	"server.h"
X#include	<sys/stat.h>
X#include	<sys/dir.h>
X#include	<sys/file.h>
X#include	<sys/user.h>
X#include	<errno.h>
X
Xextern char	*syscallnames[];
Xextern short	current_pid;
Xextern short	gateway_server;
Xextern boolean	i_am_gateway;
Xextern boolean	in_root_directory;
Xextern syscallmap	smap[];
Xextern struct stat	filetypes[];
Xextern hosts	*host;
Xextern long	errno;
X
Xs_fork(msg, proc)
X	register struct message	*msg;
X	register process	*proc;
X{
X	register process	*newproc;
X	register long	newpid = msg->m_args[ 0 ],
X				i, fd;
X	register short	syscall = msg->m_syscall;
X	boolean needtofork = FALSE;
X
X	if (newproc = findprocess(newpid, msg->m_uid))
X		debug1("%d = %sfork(%d), redundant\n",
X			newpid, syscall == RSYS_vfork ? "v" : "",
X			msg->m_args[ 1 ]);
X	else
X	{
X		debug1("%d = %sfork(%d)\n",
X			newpid, syscall == RSYS_vfork ? "v" : "",
X			proc->p_pid);
X		newproc = add_new_process(msg->m_uid, newpid);
X		for (i=0; i<NOFILE; i++)
X			if ((fd = proc->p_fds[ i ]) >= 0)
X				newproc->p_fds[ i ] = fd, needtofork = TRUE;
X
X		if (needtofork)
X			become_server(msg);
X		else if (! i_am_gateway)
X			say_something(S_NEWPROCESS, newpid);
X	}
X	/*
X	 * No return message is sent!
X	 */
X}
X
Xs_read(msg, proc)
X	register struct message  *msg;
X	register process	*proc;
X{
X	register long	clientfd = msg->m_args[0],
X			fd,
X			size = msg->m_args[1];
X	register char	*buf = get_data_buf(size);
X
X	fd = MAPFD(clientfd, proc);
X	proc->p_returnval = read(fd, buf, size);
X	proc->p_errno = fixdir(fd, buf, proc->p_returnval);
X	debug1("%d = read(%d->%d, 0x%x, %d);\n",
X		proc->p_returnval, clientfd, fd, buf, size);
X	sendreturn(proc, host->h_cmdfd, buf, 0);
X}
X
Xs_write(msg, proc)
X	register struct message  *msg;
X	register process	*proc;
X{
X	register long	clientfd = msg->m_args[0],
X			fd,
X			size = msg->m_args[1],
X			totlen = msg->m_totlen;
X	register char	*buf;
X
X	if (totlen > BIGBUF)
X		msg = (struct message *)getbuf(totlen);
X	buf = (char *)&msg->m_args[R_DATA];
X	gobble_last_msg(host->h_cmdfd, msg);
X	fd = MAPFD(clientfd, proc);
X	proc->p_returnval = write(fd, buf, size);
X	proc->p_errno = errno;
X	debug1("%d = write(%d->%d, 0x%x, %d);\n",
X		proc->p_returnval, clientfd, fd, buf, size);
X	sendreturn(proc, host->h_cmdfd, NULL, 0);
X}
X
X/*
X * Open a file.  Also interface for creat().  Note that we pass back
X * the current file offset.
X */
Xs_open(msg, proc)
X	struct message  	*msg;
X	register process	*proc;
X{
X#define mask		args[ 3 ]
X#define	clientfd	args[ 2 ]
X#define	mode		args[ 1 ]
X#define	flags		args[ 0 ]
X
X	register long	ourfd,
X			*args = msg->m_args;
X	register char	*path = path1addr(msg);
X
X	change_to_umask(mask);
X	ourfd = open(path, flags, mode);
X	proc->p_errno = errno;
X	proc->p_returnval =  allocate_fd(ourfd, proc, clientfd);
X	debug1("%d = open(\"%s\", 0%o, %d)\n",
X		proc->p_returnval, path, flags, mode);
X	sendreturn(proc, host->h_cmdfd, NULL, 1, lseek(ourfd, 0, L_INCR));
X
X#undef	mask
X#undef	clientfd
X#undef	mode
X#undef	flags
X}
X
Xs_fd1(msg, proc)
X	register struct message  *msg;
X	register process	*proc;
X{
X	register long	clientfd = msg->m_args[0],
X			fd,
X			syscall = msg->m_syscall;
X
X	fd = MAPFD(clientfd, proc);
X	/*
X	 * No return sent for close or fsync!
X	 */
X	if (syscall == RSYS_close || syscall == RSYS_fsync)
X		proc->p_returnval = deallocate_fd(proc, msg->m_args[0]);
X	else
X	{
X		proc->p_returnval = (*smap[ syscall ].s_syscall)(fd);
X		proc->p_errno = errno;
X		if (syscall != RSYS_fsync)
X			sendreturn(proc, host->h_cmdfd, NULL, 0);
X	}
X	debug1("%d = %s(%d->%d)\n",
X		proc->p_returnval, syscallnames[ syscall ], clientfd, fd);
X}
X
Xs_fd1_plus(msg, proc)
X	register struct message  *msg;
X	register process	*proc;
X{
X#define	arg1		msg->m_args[1]
X#define	arg2		msg->m_args[2]
X	register long	clientfd = msg->m_args[0],
X			fd;
X
X	fd = MAPFD(clientfd, proc);
X	proc->p_returnval = (*smap[ msg->m_syscall ].s_syscall)(fd, arg1, arg2);
X	proc->p_errno = errno;
X	debug1("%d = %s(%d->%d, %d(0%o), %d(0%o))\n",
X		proc->p_returnval, syscallnames[ msg->m_syscall ],
X		clientfd, fd, arg1, arg1, arg2, arg2);
X	sendreturn(proc, host->h_cmdfd, NULL, 0);
X#undef	arg1
X#undef	arg2
X}
X
X/*
X * link, symlink and rename
X */
Xs_path2(msg, proc)
X	register struct message  *msg;
X	register process	*proc;
X{
X#define	mask	msg->m_args[0]
X	register char	*path1, *path2;
X	register short	syscall = msg->m_syscall;
X
X	change_to_umask(mask);
X	path2 = twopath2addr(msg);
X	path1 = twopath1addr(msg);
X	proc->p_returnval = (*smap[ syscall ].s_syscall)(path1, path2);
X	proc->p_errno = errno;
X	debug1("%d = %s(\"%s\", \"%s\")\n", syscallnames[ syscall ],
X		proc->p_returnval, path1, path2);
X	sendreturn(proc, host->h_cmdfd, NULL, 0);
X#undef	mask
X}
X
Xs_path1(msg, proc)
X	register struct message  *msg;
X	register process	*proc;
X{
X	register char	*path;
X	register short	syscall = msg->m_syscall;
X	register long	mask = msg->m_args[0];
X	struct stat	statb;
X	extern struct stat	root;
X	register struct	stat *statp = &statb;
X
X	change_to_umask(mask);
X	path = path1addr(msg);
X	proc->p_returnval = (*smap[ syscall ].s_syscall)(path);
X	proc->p_errno = errno;
X	debug1("%d = %s(\"%s\")\n",
X		proc->p_returnval, syscallnames[ syscall ], path);
X	if (syscall == RSYS_chdir)
X		if (proc->p_returnval == -1)
X			debug1("can't chdir to %s\n", path);
X		else
X		{
X			if (stat(".", statp) == 0 && isroot(statp))
X				in_root_directory = TRUE;
X			else
X				in_root_directory = FALSE;
X			debug10("Now I'm %sin root\n",
X				!in_root_directory ? "not " : "");
X		}
X	sendreturn(proc, host->h_cmdfd, NULL, 0);
X}
X
Xs_access(msg, proc)
X	register struct message  *msg;
X	register process	*proc;
X{
X	register char	*path;
X	register long	perm = msg->m_args[0];
X
X	path = path1addr(msg);
X	
X	/*
X	 * The kernel access is strange:  it first sets the effective uid
X	 * and gid to be the real uid/gid and THEN it does the access.
X	 * Well, our real uid is always 0 (so we can change our effective
X	 * uid at will), so the effect is different than a normal user
X	 * would expect.  i.e. access always succeeds no matter what
X	 * the arguments.  This is clearly not what we want, so we apply
X	 * an awful kludge here; change our real uid to be the user we
X	 * are pretending to be, and then call access.
X	 */
X	change_to_uid(0);
X	setreuid(proc->p_ruser->r_user->u_local_uid, 0);
X	proc->p_returnval = access(path, perm);
X	proc->p_errno = errno;
X	debug1("%d = access(\"%s\", 0%o\n", proc->p_returnval, path, perm);
X	setreuid(0, 0);
X	sendreturn(proc, host->h_cmdfd, NULL, 0);
X}
X
Xs_path1_plus(msg, proc)
X	register struct message  *msg;
X	register process	*proc;
X{
X	register char	*path;
X	register long	syscall = msg->m_syscall,
X			arg1 = msg->m_args[0],
X			arg2 = msg->m_args[1],
X			mask = msg->m_args[2];
X
X	path = path1addr(msg);
X	change_to_umask(mask);
X	
X	proc->p_returnval = (*smap[ syscall ].s_syscall)(path, arg1, arg2);
X	proc->p_errno = errno;
X	debug1("%d = %s(\"%s\", %d(0%o), %d(%o))\n",
X		proc->p_returnval,
X		syscallnames[ syscall ], path, arg1, arg1, arg2, arg2);
X	sendreturn(proc, host->h_cmdfd, NULL, 0);
X}
X
Xs_stat(msg, proc)
X	register struct message  *msg;
X	register process	*proc;
X{
X	union a {
X		char	*path;
X		long	fd;
X	} arg;
X	register short	syscall = msg->m_syscall;
X	register long	clientfd = msg->m_args[0];
X	struct stat		statbuf;
X	register struct stat	*statp = &statbuf;
X
X	if (syscall == RSYS_fstat)
X		arg.fd = MAPFD(clientfd, proc);
X	else
X		arg.path = path1addr(msg);
X	proc->p_returnval = (*smap[ syscall ].s_syscall)(arg.path, statp);
X	proc->p_errno = errno;
X#ifdef RFSDEBUG
X	if (syscall == RSYS_fstat)
X		debug1("%d = fstat(%d->%d, 0x%x)\n",
X			proc->p_returnval, clientfd, arg.fd, &statbuf);
X	else
X		debug1("%d = %s(\"%s\", 0x%x)\n", proc->p_returnval,
X			syscallnames[ syscall ], arg.path, &statbuf);
X#endif RFSDEBUG
X	if (proc->p_returnval == -1)
X		sendreturn(proc, host->h_cmdfd, NULL, 0);
X	else
X		sendreturn(proc, host->h_cmdfd, NULL, 14,
X			statp->st_dev,
X			statp->st_ino,
X			statp->st_mode,
X			statp->st_nlink,
X			statp->st_uid,
X			statp->st_gid,
X			statp->st_rdev,
X			statp->st_size,
X			statp->st_atime,
X			statp->st_mtime,
X			statp->st_ctime,
X			statp->st_blksize,
X			statp->st_blocks,
X			isroot(statp));
X}
X
Xs_lseek(msg, proc)
X	register struct message  *msg;
X	register process	*proc;
X{
X	register long	clientfd = msg->m_args[0], fd;
X
X	fd = MAPFD(clientfd, proc);
X	proc->p_returnval = lseek(fd, msg->m_args[1], msg->m_args[2]);
X	proc->p_errno = errno;
X	debug1("%d = lseek(%d->%d, %d, %d)\n", proc->p_returnval,
X		clientfd, fd, msg->m_args[1], msg->m_args[2]);
X	if (msg->m_syscall == RSYS_lseek)
X		sendreturn(proc, host->h_cmdfd, NULL, 0);
X}
X
Xs_dup(msg, proc)
X	register struct message  *msg;
X	register process	*proc;
X{
X	register long	clientfd = msg->m_args[0], fd,
X			newclientfd = msg->m_args[1],
X			ourfd,
X			newfd;
X
X	fd = MAPFD(clientfd, proc);
X	if (msg->m_syscall == RSYS_dup2)
X	{
X		newfd = MAPFD(newclientfd, proc);
X		if (newfd >= 0)
X		{
X			proc->p_returnval = deallocate_fd(proc, newclientfd, 0);
X			debug1("%d = (dup2)close(%d->%d)... ",
X				proc->p_returnval, newclientfd, newfd);
X		}
X	}
X	if (fd >= 0)
X	{
X		ourfd = dup(fd);
X		proc->p_returnval =  allocate_fd(ourfd, proc, newclientfd);
X		proc->p_errno = errno;
X	}
X	else if (msg->m_syscall == RSYS_dup2 && newfd >= 0)
X		proc->p_returnval = newclientfd;
X	else
X	{
X		proc->p_returnval = -1;
X		proc->p_errno = EINVAL;
X	}
X	debug1("%d = dup(%d->%d)\n", proc->p_returnval, clientfd, fd);
X	sendreturn(proc, host->h_cmdfd, NULL, 0);
X}
X
Xs_ioctl(msg, proc)
X	struct message  *msg;
X	process	*proc;
X{
X	long	fd = msg->m_args[0];
X}
X
Xs_readlink(msg, proc)
X	register struct message  *msg;
X	register process	*proc;
X{
X	register long	size = msg->m_args[0];
X	register char	*buf = get_data_buf(size),
X			*path = path1addr(msg);
X
X	proc->p_returnval = readlink(path, buf, size);
X	proc->p_errno = errno;
X	debug1("%d = readlink(\"%s\", 0x%x, %d);\n",
X		proc->p_returnval, path, buf, size);
X	sendreturn(proc, host->h_cmdfd, buf, 0);
X}
X
X/*
X * Send exec information the remote host.
X */
Xs_execinfo(msg, proc)
X	register struct message  *msg;
X	register process	*proc;
X{
X	register long	hdrsize = msg->m_args[ 0 ],
X			red,
X			err = 0,
X			msglen = R_MINRMSG + sizeof(long)*R_EXECDATA;
X	register char	*path = path1addr(msg),
X			*p;
X	struct stat	st;
X	struct message	msgbuf;
X
X	errno = 0;
X	if (hdrsize > (R_MAXARGS - R_EXECDATA)*sizeof(long))
X	{
X		log("exec: hdrsize = %d!!\n", hdrsize);
X		err = EINVAL;
X		goto done;
X	}
X	/*
X	 * Start building the outgoing message... get header,
X	 * check permissions and open file.
X	 */
X	msg = &msgbuf;
X	if ((proc->p_execfd = open(path, O_RDONLY)) == -1)
X		goto done;
X	fstat(proc->p_execfd, &st);
X	if ((st.st_mode & S_IFMT) != S_IFREG
X	|| ! myaccess(&st, proc->p_ruser->r_user, X_OK))
X	{
X		err = EACCES;
X		debug12("%s mode=0%o %sreg file, %sexecutable\n",
X			path, st.st_mode,
X			(st.st_mode & S_IFMT) != S_IFREG ? "not " : "",
X			myaccess(&st, proc->p_ruser->r_user, X_OK) ?
X			"" : "not ");
X		goto done;
X	}
X	msg->m_args[ R_EXECREADONLY ] =
X		(myaccess(&st, proc->p_ruser->r_user, W_OK) == FALSE);
X	msg->m_args[R_EXECDATA] = 0; /* for zero-length files */
X	red = read(proc->p_execfd, msg->m_args + R_EXECDATA, hdrsize);
X	if (red <= 0)
X	{
X		debug12("read on exec fd %d=%d\n", proc->p_execfd, red);
X		err = EINVAL;
X		goto done;
X	}
X	msglen += red;
X
X
X	/*
X	 * Check setuid/setgid info
X	 */
X	if (st.st_mode & S_ISUID)
X		msg->m_args[ R_EXECUID ] = htonl(st.st_uid);
X	else
X		msg->m_args[ R_EXECUID ] = htonl(-1);
X	if (st.st_mode & S_ISGID)
X		msg->m_args[ R_EXECGID ] = htonl(st.st_gid);
X	else
X		msg->m_args[ R_EXECGID ] = htonl(-1);
X
Xdone:
X	proc->p_execstarted = FALSE;
X	msg->m_hdlen = htons(msglen);
X	msg->m_totlen = htonl(msglen);
X	if (errno)
X		err = errno;
X	if (err)
X	{
X		debug12("execinfo: err=%d\n", err);
X		close(proc->p_execfd);
X		proc->p_execfd = -1;
X	}
X	debug1("%d = execve(\"%s\");\n", proc->p_returnval, path);
X	if (msg->m_errno = htons(err))
X		msg->m_args[ R_RETVAL ] = htonl(-1);
X	else
X		msg->m_args[ R_RETVAL ] = htonl(st.st_size);
X	msg->m_pid = htons(proc->p_pid);
X	msg->m_uid = htons(proc->p_uid);
X	sndmsg(host->h_cmdfd, msg, msglen, 0, 0);
X}
X
X/*
X * Send exec text and data to remote host.
X */
Xs_execread(msg, proc)
X	struct message  *msg;
X	process	*proc;
X{
X	register long	fd = proc->p_execfd,
X			hdrsize = msg->m_args[0],
X			size = msg->m_args[1],
X			red;
X	register char	*buf = get_data_buf(size);
X
X	if (!proc->p_execstarted)
X	{
X		if (lseek(fd, hdrsize, 0) != hdrsize)
X		{
X			log("can't seek to %d on fd %d for exec\n",
X				hdrsize, fd);
X			proc->p_errno = EINVAL;
X		}
X		proc->p_execstarted = TRUE;
X	}
X	if (size)
X	{
X		proc->p_returnval = read(fd, buf, size);
X		proc->p_errno = errno;
X		debug1("%d = execread(%d)\n", proc->p_returnval, size);
X	}
X	else /* all done; send no return */
X	{
X		proc->p_returnval = close(proc->p_execfd);
X		proc->p_execfd = -1;
X		debug1("%d = execread(%d)\n", proc->p_returnval, size);
X		return;
X	}
X
X	sendreturn(proc, host->h_cmdfd, buf, 0);
X}
X
Xs_utimes(msg, proc)
X	struct message  *msg;
X	process	*proc;
X{
X	char	*path;
X	struct timeval	tv[2];
X
X	path = path1addr(msg);
X	tv[0].tv_sec  = msg->m_args[0];
X	tv[0].tv_usec = msg->m_args[1];
X	tv[1].tv_sec  = msg->m_args[2];
X	tv[1].tv_usec = msg->m_args[3];
X	
X	
X	proc->p_returnval = utimes(path, tv);
X	proc->p_errno = errno;
X	debug1("%d = utimes(\"%s\", 0x%x\n", proc->p_returnval, path, tv);
X	sendreturn(proc, host->h_cmdfd, NULL, 0);
X}
X
X/*
X * Let a process exit.
X */
Xs_exit(msg, proc)
X	struct message  *msg;
X	process	*proc;
X{
X	long	otherprocs = 0;
X	process	*p2;
X
X	/*
X	 * No return message sent!
X	 */
X	debug1("exit()\n");
X	deletelist(&host->h_proclist, proc);
X	freeproc(proc);
X	if (! i_am_gateway)
X	{
X		for (proc=host->h_proclist; proc; proc=proc->p_next)
X			if (proc->p_handler == current_pid)
X				otherprocs++;
X		if (otherprocs == 0)
X		{
X			gobble_last_msg(host->h_cmdfd, msg);
X			say_something(S_ALLDONE, 0);
X			mourne();
X			exit(0);
X		}
X		else
X			say_something(S_PROCEXIT, msg->m_pid);
X	}
X}
X
Xnoop(msg, proc)
X	struct message  *msg;
X	process	*proc;
X{
X	extern long	errno;
X
X	log("*** FUNCTION IGNORED ***\n", proc->p_pid);
X	proc->p_returnval = -1;
X	proc->p_errno = EINVAL;
X	sendreturn(proc, host->h_cmdfd, NULL, 0);
X}
SHAREOF
chmod 444 remote/serversyscall.c
#
# remote/shells/makemake
#
if [ -f remote/shells/makemake ]; then 
	echo -n 'Hit <return> to overwrite remote/shells/makemake or ^C to quit' 
	read ans 
	rm -f remote/shells/makemake 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/shells/makemake
X#!/bin/sh
XMAKEFILE=Makefile
X
Xcase "$1" in
X"")
X	echo "Usage: $0 <machinetype>"
X	exit 1
X	;;
XM68)
X	MAKEFILE=M68
X	;;
Xesac
X
Xif [ ! -f make.base.$1 ]
Xthen
X	echo No machine type $1 supported.
X	exit 1
Xfi
X
Xcat make.base.$1 make.base > $MAKEFILE
SHAREOF
chmod 755 remote/shells/makemake
#
# remote/shells/mkdist
#
if [ -f remote/shells/mkdist ]; then 
	echo -n 'Hit <return> to overwrite remote/shells/mkdist or ^C to quit' 
	read ans 
	rm -f remote/shells/mkdist 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/shells/mkdist
X#!/bin/sh
X
XFILES='
X	remote/README
X	remote/*.[ch]
X	remote/doc
X	remote/make.*
X	remote/shells
X	remote/usr.*'
X
XFILES=`echo $FILES`
Xcd ..
Xtar cvhf - $FILES > remote/remotefs.tar
SHAREOF
chmod 755 remote/shells/mkdist
#
# remote/shells/mkdist.shar
#
if [ -f remote/shells/mkdist.shar ]; then 
	echo -n 'Hit <return> to overwrite remote/shells/mkdist.shar or ^C to quit' 
	read ans 
	rm -f remote/shells/mkdist.shar 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/shells/mkdist.shar
X#!/bin/sh
X
XFILES='
X	remote/README
X	remote/*.[ch]
X	remote/doc
X	remote/make.*
X	remote/shells
X	remote/usr.*'
X
Xset -x
Xcd ..
Xshar $FILES
Xmv shar.? remote
X
X#
X# put in the count
X#
XCOUNT=`ls remote/shar.? | grep -c .`
Xcnt=1
Xwhile [ $cnt -le $COUNT ]
Xdo
X
Xed remote/shar.$cnt << EOF
X1a
X#
X# RFS, a kernel-resident remote file system.  Shar $cnt of $COUNT
X#
X.
Xw
Xq
XEOF
X	cnt=`expr $cnt + 1`
Xdone
X
X#
X# add in the intro
X#
Xed remote/shar.1 << \EOF
X1i
XThese seven shar files contain the software and documentation for
Xinstallation, maintenance and adjustment of RFS, a public domain,
Xkernel-resident distributed file system, written at Tektronix Computer
XResearch Laboratories* by me for partial fulfillment of the master's
Xdegree program at the University of Denver.  It was designed to provide
Xcomplete transparency with respect to file access and protections for
Xall programs whether they use local or remote files and directories.
XIt has been installed on VAX BSD 4.2 and 4.3 UNIX, Pyramid 4.2/5.0
XUNIX, version 2.5, and on a Tektronix internal proprietary workstation,
Xcalled Magnolia.  The instructions are designed in a way that keeps all
Xchanges separate from your standard sources, in hope that it will
Xencourage sites to try the installation.
X
X			Todd Brunhoff
X			toddb%crl@tektronix.csnet
X			decvax!tektronix!crl!toddb
X
X* RFS should not be confused with another completely different (but
X  excellent) implementation from Tektronix available on the 6000 series
X  workstation, called DFS, and done by a separate product group.  The
X  work on RFS was designed and written strictly by the author of this
X  paper at about the same time as DFS, and draws none of its
X  implementation details from DFS.  RFS is public domain, while DFS is
X  proprietary.
X
X.
Xw
Xq
XEOF
SHAREOF
chmod 755 remote/shells/mkdist.shar
#
# remote/shells/rfs_clean
#
if [ -f remote/shells/rfs_clean ]; then 
	echo -n 'Hit <return> to overwrite remote/shells/rfs_clean or ^C to quit' 
	read ans 
	rm -f remote/shells/rfs_clean 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/shells/rfs_clean
X#!/bin/sh
X
Xcd /usr/tmp
Xfor file in rfs_log.*.*
Xdo
X	pid=`expr "$file" : '.*\.\(.*\)'`
X	result=`kill -19 $pid 2>&1`
X	case "$result" in
X	*"No such process")	(set -x; rm -f $file);;
X	esac
Xdone
SHAREOF
chmod 755 remote/shells/rfs_clean
#
# remote/shells/rfs_kerninstall
#
if [ -f remote/shells/rfs_kerninstall ]; then 
	echo -n 'Hit <return> to overwrite remote/shells/rfs_kerninstall or ^C to quit' 
	read ans 
	rm -f remote/shells/rfs_kerninstall 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/shells/rfs_kerninstall
X#!/bin/sh
X
X#
X# Install script for added RFS kernel sources.
X#
X          NL='
X'
X	 SRC=$1
X	DEST=$2
X	 VER=$3
X      USAGE="${NL}Usage: $0 src-dir dest-dir VAX4.3|VAX4.2|PYR2.5"
XRemove_start=
X  Remove_end=
X      Delete=
X
X#
X# Figure out what software we are running...
X#
Xcase "$VER" in
XVAX4.3)	Remove_start='^#else[ 	]BSD4_3'
X	  Remove_end='^#endif[ 	]BSD4_3'
X	      Delete='^#ifdef[ 	]BSD4_3'
X	;;
XVAX4.2)	Remove_start='^#ifdef[ 	]BSD4_3'
X	  Remove_end='^#else[ 	]BSD4_3'
X	      Delete='^#endif[ 	]BSD4_3'
X	;;
XPYR2.5)	Remove_start='^#ifdef[ 	]BSD4_3'
X	  Remove_end='^#else[ 	]BSD4_3'
X	      Delete='^#endif[ 	]BSD4_3'
X	;;
X*)	echo "$0: Unknown type = $VER" \
X		"$USAGE"
X	exit 1
X	;;
Xesac
Xif [	"$SRC" = "" -o ! -d "$SRC" \
X	-o "$DEST" = "" -o ! -d "$DEST" ]
Xthen
X	echo "Either \"$SRC\" or \"$DEST\" is not a directory!" \
X		"$USAGE"
X	exit 1
Xfi
X
Xfor file in `ls $SRC`
Xdo
X	echo -n "${NL}$file  "
X	sed	-e "/$Remove_start/,/$Remove_end/d" \
X		-e "/$Delete/d" \
X		< $SRC/$file > $DEST/$file
Xdone
Xchmod 0755 $DEST/remote_mkdata
Xecho
SHAREOF
chmod 755 remote/shells/rfs_kerninstall
#
# remote/shells/rfs_kernpatch
#
if [ -f remote/shells/rfs_kernpatch ]; then 
	echo -n 'Hit <return> to overwrite remote/shells/rfs_kernpatch or ^C to quit' 
	read ans 
	rm -f remote/shells/rfs_kernpatch 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/shells/rfs_kernpatch
X#!/bin/sh
X#
X# Kernel level setup for compiling RFS.
X#
XCHANGELIST='	h/errno.h
X		h/param.h
X		h/user.h
X		sys/init_sysent.c
X		sys/kern_exec.c
X		sys/kern_exit.c
X		sys/ufs_syscalls.c'
XCHANGE_42='	sys/sys_inode.c
X		sys/ufs_nami.c
X		sys/uipc_socket.c
X		machine/trap.c
X		conf/files'
XCHANGE_43='	sys/ufs_namei.c
X		machine/trap.c
X		conf/files'
XCHANGE_PYR='	sys/kern_trap.c'
X   PATCHES=$1
X       SRC=$2
X      DEST=$3
X       VER=$4
X     USAGE="Usage: $0 patch-dir src-dir dest-dir VAX4.3|VAX4.2|PYR2.5"
X	NL='
X'
X
Xif [ ! -d "$PATCHES" -o ! -d "$SRC" -o ! -d "$DEST" ]
Xthen
X	echo "One of \"$PATCHES\", \"$SRC\" or \"$DEST\" is not a directory" \
X		"$NL$USAGE"
X	exit 1
Xfi
X
Xcase "$VER" in
XVAX4.3) CHANGELIST="$CHANGELIST $CHANGE_43"
X	if [ -f $SRC/conf/Makefile.vax ]
X	then
X		CHANGELIST="$CHANGELIST conf/Makefile.vax"
X	else
X		CHANGELIST="$CHANGELIST conf/makefile.vax"
X	fi
X	;;
XVAX4.2) CHANGELIST="$CHANGELIST $CHANGE_42 conf/makefile.vax" ;;
XPYR2.5) CHANGELIST="$CHANGELIST $CHANGE_PYR conf/makefromsource" ;;
X*)	echo "Invalid version = \"$VER\"$NL$USAGE"
X	exit 1
X	;;
Xesac
X
X#
X# copy the target files for the patches.
X#
Xcase "$DEST" in
X
X$SRC)	;; # no need to copy
X
X*)	echo "Copy in files that must be changed..."
X	(cd $DEST; rm -f $CHANGELIST)
X	for file in $CHANGELIST
X	do
X		(set -x; cp $SRC/$file $DEST/$file)
X	done
X	;;
Xesac
X(cd $DEST; chmod 0644 $CHANGELIST)
X
X#
X# do the patches
X#
Xfor file in $CHANGELIST
Xdo
X	while :
X	do
X		echo -n "${NL}${NL}Hit <return> to patch" \
X			"$file or 'n' to skip: "
X		read prompt
X		case "$prompt" in
X		"")	(set -x; patch $DEST/$file $PATCHES/$file.diff)
X			;;	
X		n)	;;
X		*)	echo "Enter <return> or the letter 'n' only!"
X			continue
X			;;
X		esac
X		break
X	done
Xdone
SHAREOF
chmod 755 remote/shells/rfs_kernpatch
#
# remote/shells/rfs_setup
#
if [ -f remote/shells/rfs_setup ]; then 
	echo -n 'Hit <return> to overwrite remote/shells/rfs_setup or ^C to quit' 
	read ans 
	rm -f remote/shells/rfs_setup 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/shells/rfs_setup
X#!/bin/sh
X#
X# Setup for compiling RFS.
X#
XPWD=`pwd`
XKERNELDIRS='	conf
X		h
X		net
X		netimp
X		netinet
X		remote
X		sys'
XKDIRS_42='	vax
X		vaxif
X		vaxmba
X		vaxuba
X		netpup'
XKDIRS_43='	vax
X		vaxif
X		vaxmba
X		vaxuba
X		bbnnet
X		netns'
XKDIRS_PYR='	ether
X		io
X		kernel
X		kernel_m
X		ml
X		netpup
X		vls'
XINCLUDEFILE=syscall.h
X         NL='
X'
XEXECDIR=`expr $0 : '\(.*\)\/.*'`
X
X#
X# Figure out what software they are running...
X#
Xwhile :
Xdo
X	echo -n "Are you running" \
X		"${NL}	1. VAX 4.3 BSD" \
X		"${NL}	2. VAX 4.2 BSD" \
X		"${NL}	3. Pyramid 2.5 (4.2/5.0)" \
X		"${NL}enter 1, 2 or 3: "
X	read ans
X	case "$ans" in
X	1)	         VER=VAX4.3
X			MACH=vax
X		  KERNELDIRS="$KERNELDIRS $KDIRS_43"
X		;;
X	2)	         VER=VAX4.2
X			MACH=vax
X		  KERNELDIRS="$KERNELDIRS $KDIRS_42"
X		;;
X	3)	         VER=PYR2.5
X			MACH=pyr
X		  KERNELDIRS="$KERNELDIRS $KDIRS_PYR"
X		;;
X	*)	echo "only 1, 2 and 3 are supported..."
X		continue
X		;;
X	esac
X	break;
Xdone
X
X#
X# Find out the sys directory
X#
XSYSDIR=
Xwhile :
Xdo
X	echo -n "${NL}${NL}What is the top-level path of your kernel source" \
X		"${NL}directory (normally it is /usr/sys)? "
X	read ans
X	if [ "$ans" = "" -o ! -d "$ans" ]
X	then
X		echo "...but \"$ans\" is not a directory!"
X		continue
X	fi
X
X	#
X	# Ensure that the path begins with /
X	#
X	case "$ans" in
X	/*)	;;
X	*)	echo "\"$ans\" must begin with '/'"
X		continue
X		;;
X	esac
X
X	SYSDIR=$ans
X	break
Xdone
X
X#
X# ask if the changes are to be permanent
X#
Xwhile :
Xdo
X	echo -n "${NL}${NL}Do you want these changes" \
X	"$NL	1. installed in $SYSDIR and in /usr/include" \
X	"$NL	2. installed in this directory (reccomended 1st pass)" \
X	"${NL}enter 1 or 2: "
X	read ans
X	case "$ans" in
X	1)	DEST=$SYSDIR
X		INCLUDEDIR=/usr/include
X		;;
X	2)	DEST=$PWD/sys
X		INCLUDEDIR=usr.include
X		;;
X	*)	echo "only 1 or 2 allowed."
X		continue
X		;;
X	esac
X	break
Xdone
X
X
Xumask 022
Xcase "$DEST" in
X
X"$SYSDIR")	# don't need to make local directories, 'cept one.
X	mkdir $SYSDIR/remote
X	;;
X
X*)	#
X	# make directories
X	#
X	echo "${NL}${NL}Make kernel source directories in `pwd` ..."
X	ERR=
X	mkdir sys
X	for dir in $KERNELDIRS
X	do
X		mkdir	sys/$dir
X
X		case "$dir" in
X		remote)	continue;;	# don't check its existence...
X		esac
X
X		if [ ! -d $SYSDIR/$dir ]
X		then
X			echo "Kernel sources not in $SYSDIR/$dir ???"
X			ERR=true
X		fi
X	done
X	case "$ERR" in
X	"")	;;
X	*)	exit 1;;
X	esac
X
X	case "$VER" in
X	VAX4.2|VAX4.3) (cd sys; ln -s vax machine);;
X	esac
X
X	#
X	# make the symbolic links
X	#
X	for dir in $KERNELDIRS
X	do
X		case "$dir" in
X		remote)	continue;;
X		esac
X
X		echo "Make symbolic links from $DEST/$dir/*" \
X			"${NL}to $SYSDIR/$dir/*..."
X		(cd $DEST/$dir; ln -s $SYSDIR/$dir/* .)
X	done
X	;;
Xesac
X
X#
X# move the remote kernel stuff into place...
X#
Xecho "${NL}${NL}Copy $PWD/remote/usr.sys.remote/* files" \
X	"${NL}to $DEST/remote (and remove" \
X	"${NL}#ifdef BSD4_3 at the same time)..."
X$EXECDIR/rfs_kerninstall $PWD/remote/usr.sys.remote $DEST/remote $VER
X	
X#
X# Now run patch on each files to install
X# the changes necessary.
X#
Xcat <<EOF
X
X
XI will now install all the kernel changes for you in
X$DEST with the 'patch' utility, so you must have that
Xprogram to continue.  You will be given an opportunity to either suspend
Xthis program or kill it before each file is patched so that you may
Xmake adjustments as you think of them.  You may also skip the patches
Xif you know that they are already installed (Better be sure, though).
X
XFor the C-source files with the exception of two bug fixes, all changes
Xwill be installed between the control statements:
X
X#ifdef REMOTEFS
X#endif REMOTEFS
X
XEOF
X
X$EXECDIR/rfs_kernpatch remote/usr.sys.$VER $SYSDIR $DEST $VER
X$EXECDIR/rfs_userpatch remote/usr.include.$VER $INCLUDEDIR $DEST
X
Xcat <<EOF
X
X
XRfs software is set up and ready for compilation.  See the installation
Xmanual.
X
XEOF
SHAREOF
chmod 755 remote/shells/rfs_setup
#
# remote/shells/rfs_userpatch
#
if [ -f remote/shells/rfs_userpatch ]; then 
	echo -n 'Hit <return> to overwrite remote/shells/rfs_userpatch or ^C to quit' 
	read ans 
	rm -f remote/shells/rfs_userpatch 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/shells/rfs_userpatch
X#!/bin/sh
X#
X# User-level software setup for compiling RFS.
X#
Xumask 02
X   PATCHES=$1
XINCLUDEDIR=$2
X       SYS=$3
X	NL='
X'
X
Xecho "$NL"
X
Xif [ ! -d $PATCHES -o ! -d $SYS ]
Xthen
X	echo "Either \"$PATCHES\" or \"$SYS\" is not a directory"
X	exit 1
Xfi
X
X#
X# Make the proper include directories if they don't already exist.
X# link in remotefs.h and param.h
X#
Xif [ ! -d $INCLUDEDIR ]
Xthen
X	mkdir $INCLUDEDIR
Xfi
Xif [ ! -d $INCLUDEDIR/remote ]
Xthen
X	mkdir $INCLUDEDIR/remote
Xfi
Xif [ ! -d $INCLUDEDIR/sys ]
Xthen
X	mkdir $INCLUDEDIR/sys
Xfi
X
Xrm -f $INCLUDEDIR/remote/remotefs.h $INCLUDEDIR/sys/param.h
X
Xln -s $SYS/remote/remotefs.h $INCLUDEDIR/remote/remotefs.h
Xln -s $SYS/h/param.h $INCLUDEDIR/sys/param.h
X
X#
X# Finally make the change to syscall.h.  If the changes go in usr.include,
X# then assume that we must copy it there first.  Otherwise, we make the
X# changes in place.
X#
Xcase "$INCLUDEDIR" in
X
X/usr/include)	;;
X
X*)	rm -f $INCLUDEDIR/syscall.h
X	cat /usr/include/syscall.h > $INCLUDEDIR/syscall.h
X	;;
Xesac
X
Xwhile :
Xdo
X	echo -n "${NL}${NL}Hit <return> to patch" \
X		"$INCLUDEDIR/syscall.h or 'n' to skip: "
X	read prompt
X	case "$prompt" in
X	"")	(set -x; patch $INCLUDEDIR/syscall.h $PATCHES/syscall.h.diff)
X		;;	
X	n)	;;
X	*)	echo "Enter <return> or the letter 'n' only!"
X		continue
X		;;
X	esac
X	break
Xdone
SHAREOF
chmod 755 remote/shells/rfs_userpatch
#
# remote/usr.include.PYR2.5/syscall.h.diff
#
if [ -f remote/usr.include.PYR2.5/syscall.h.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.include.PYR2.5/syscall.h.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.include.PYR2.5/syscall.h.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.include.PYR2.5/syscall.h.diff
XIf the changes to sys/init_sysent.c succeeded, then this should be fine.
XIf not, you should check that the system call numbers added coincide with
Xthose in sys/init_sysent.c.
X***************
X*** 154,159
X  /* 152 thru 165 reserved */
X  #define SYS_setprocesshost 166
X  #define SYS_getprocesshost 167
X  
X  /*
X   * BTL system call header table.
X
X--- 154,162 -----
X  /* 152 thru 165 reserved */
X  #define SYS_setprocesshost 166
X  #define SYS_getprocesshost 167
X+ #define SYS_remoteon	168
X+ #define SYS_remoteoff	169
X+ #define SYS_remotename	170
X  
X  /*
X   * BTL system call header table.
SHAREOF
chmod 664 remote/usr.include.PYR2.5/syscall.h.diff
#
# remote/usr.include.VAX4.2/syscall.h.diff
#
if [ -f remote/usr.include.VAX4.2/syscall.h.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.include.VAX4.2/syscall.h.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.include.VAX4.2/syscall.h.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.include.VAX4.2/syscall.h.diff
XIf the changes to sys/init_sysent.c succeeded, then this should be fine.
XIf not, you should check that the system call numbers added coincide with
Xthose in sys/init_sysent.c.
X***************
X*** 150,152
X  #define	SYS_setquota	148
X  #define	SYS_quota	149
X  #define	SYS_getsockname	150
X
X--- 150,155 -----
X  #define	SYS_setquota	148
X  #define	SYS_quota	149
X  #define	SYS_getsockname	150
X+ #define	SYS_remoteon	151
X+ #define	SYS_remoteoff	152
X+ #define	SYS_remotename	153
SHAREOF
chmod 664 remote/usr.include.VAX4.2/syscall.h.diff
#
# remote/usr.src.lib.libc/Makefile
#
if [ -f remote/usr.src.lib.libc/Makefile ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.src.lib.libc/Makefile or ^C to quit' 
	read ans 
	rm -f remote/usr.src.lib.libc/Makefile 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.src.lib.libc/Makefile
X#
X# This makefile is present only to build a temporary libc... until
X# you decide that the files compiled here should be installed in the
X# source directory.  This makefile should not be installed anywhere.
X#
XOBJS=	remotename.o remoteon.o remoteoff.o errlst.o
XSRC=/usr/src
XLIBSRC=${SRC}/lib/libc
XUSR_INCLUDE=../../usr.include
XLIBDIR=/lib
X
Xnothing:
X	echo "Nothing made!"
X	echo "You must type 'make vax' or 'make pyr'"
X
Xvax: /tmp
X	make	INCLUDE="-I${LIBSRC}/vax/sys -I${USR_INCLUDE}" \
X		MACHTYPE=vax \
X		SUFFIX=c \
X		LIBDIR=${LIBDIR} \
X		SRC=${SRC} \
X		install
X
Xpyr: /tmp
X	make	INCLUDE="-I${USR_INCLUDE}" \
X		MACHTYPE=pyr \
X		SUFFIX=s \
X		LIBDIR=${LIBDIR} \
X		SRC=${SRC} \
X		install
X
Xnewlibc.a: ${OBJS} libc.a
X	cp libc.a newlibc.a
X	ar cru newlibc.a ${OBJS}
X
Xinstall: newlibc.a libc.a
X	-cp ${LIBDIR}/libc.a ${LIBDIR}/libc.a.bak
X	cp newlibc.a ${LIBDIR}/libc.a
X	ranlib ${LIBDIR}/libc.a
X
Xlibc.a:	/lib/libc.a
X	cp /lib/libc.a .
X
Xerrlst.o: errlst.c
Xremotename.o remoteon.o remoteoff.o:
Xremotename.o: ${MACHTYPE}/sys/remotename.${SUFFIX}
X	/lib/cpp ${INCLUDE} -E $? | ${AS} -o $@
X	-ld -x -r $@
X	mv a.out $@
Xremoteon.o: ${MACHTYPE}/sys/remoteon.${SUFFIX}
X	/lib/cpp ${INCLUDE} -E $? | ${AS} -o $@
X	-ld -x -r $@
X	mv a.out $@
Xremoteoff.o: ${MACHTYPE}/sys/remoteoff.${SUFFIX}
X	/lib/cpp ${INCLUDE} -E $? | ${AS} -o $@
X	-ld -x -r $@
X	mv a.out $@
X
Xerrlst.c: ${LIBSRC}/gen/errlst.c
X	cp ${LIBSRC}/gen/errlst.c nerrlst.c
X	patch nerrlst.c gen/${MACHTYPE}.errlst.c.diff
X	mv nerrlst.c errlst.c
SHAREOF
chmod 664 remote/usr.src.lib.libc/Makefile
#
# remote/usr.src.lib.libc/gen/pyr.errlst.c.diff
#
if [ -f remote/usr.src.lib.libc/gen/pyr.errlst.c.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.src.lib.libc/gen/pyr.errlst.c.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.src.lib.libc/gen/pyr.errlst.c.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.src.lib.libc/gen/pyr.errlst.c.diff
XThese changes being installed should be just fine if you were able to make
Xthe earlier changes to h/errno.h.  Otherwise, you must install these changes
Xby hand.
X***************
X*** 82,88
X  	"Too many processes",			/* 67 - EPROCLIM */
X  	"Too many users",			/* 68 - EUSERS */
X  	"Disc quota exceeded",			/* 69 - EDQUOT */
X! 	"","","","","","","","","","",          /* 70-79 - spare */
X  	"","","","","","","","","","",          /* 80-89 - spare */
X  	"","","","","","","","","","",          /* 90-99 - spare */
X  
X
X--- 82,91 -----
X  	"Too many processes",			/* 67 - EPROCLIM */
X  	"Too many users",			/* 68 - EUSERS */
X  	"Disc quota exceeded",			/* 69 - EDQUOT */
X! 	"File is on remote host",		/* 70 - EISREMOTE */
X! 	"Too many remote hosts defined",	/* 71 - ETOOMANYREMOTE */
X! 	"No remote file system",		/* 72 - ENOREMOTEFS */
X! 	"","","","","","","",                   /* 73-79 - spare */
X  	"","","","","","","","","","",          /* 80-89 - spare */
X  	"","","","","","","","","","",          /* 90-99 - spare */
X  
SHAREOF
chmod 664 remote/usr.src.lib.libc/gen/pyr.errlst.c.diff
#
# remote/usr.src.lib.libc/gen/vax.errlst.c.diff
#
if [ -f remote/usr.src.lib.libc/gen/vax.errlst.c.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.src.lib.libc/gen/vax.errlst.c.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.src.lib.libc/gen/vax.errlst.c.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.src.lib.libc/gen/vax.errlst.c.diff
XThese changes being installed should be just fine if you were able to make
Xthe earlier changes to h/errno.h.  Otherwise, you must install these changes
Xby hand.
X***************
X*** 81,85
X  	"Too many processes",			/* 67 - EPROCLIM */
X  	"Too many users",			/* 68 - EUSERS */
X  	"Disc quota exceeded",			/* 69 - EDQUOT */
X  };
X  int	sys_nerr = { sizeof sys_errlist/sizeof sys_errlist[0] };
X
X--- 81,88 -----
X  	"Too many processes",			/* 67 - EPROCLIM */
X  	"Too many users",			/* 68 - EUSERS */
X  	"Disc quota exceeded",			/* 69 - EDQUOT */
X+ 	"File is on remote host",		/* 70 - EISREMOTE */
X+ 	"Too many remote hosts defined",	/* 71 - ETOOMANYREMOTE */
X+ 	"No remote file system",		/* 72 - ENOREMOTEFS */
X  };
X  int	sys_nerr = { sizeof sys_errlist/sizeof sys_errlist[0] };
SHAREOF
chmod 664 remote/usr.src.lib.libc/gen/vax.errlst.c.diff