[mod.sources] RFS: remote file system

sources-request@panda.UUCP (01/08/86)

Mod.sources:  Volume 3, Issue 77
Submitted by: genrad!masscomp!tektronix!tekcrl!toddb
Subject: RFS: a Kernel-resident remote file system

RFS release 2.0+ (plus more fixes, easy installation w/ patch, etc.)

These seven shar files contain the software and documentation for
installation, maintenance and adjustment of RFS, a public domain,
kernel-resident distributed file system, written at Tektronix Computer
Research Laboratories* by me for partial fulfillment of the master's
degree program at the University of Denver.  It was designed to provide
complete transparency with respect to file access and protections for
all programs whether they use local or remote files and directories.
It has been installed on VAX BSD 4.2 and 4.3 UNIX, Pyramid 4.2/5.0
UNIX, version 2.5, and on a Tektronix internal proprietary workstation,
called Magnolia.  The instructions are designed in a way that keeps all
changes separate from your standard sources, in hope that it will
encourage sites to try the installation.

			Todd Brunhoff
			toddb%crl@tektronix.csnet
			decvax!tektronix!crl!toddb

* RFS should not be confused with another completely different (but
  excellent) implementation from Tektronix available on the 6000 series
  workstation, called DFS, and done by a separate product group.  The
  work on RFS was designed and written strictly by the author of this
  paper at about the same time as DFS, and draws none of its
  implementation details from DFS.  RFS is public domain, while DFS is
  proprietary.

#!/bin/sh
#
# RFS, a kernel-resident remote file system.  Shar 1 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/README
#	remote/byteorder.c
#	remote/change.c
#	remote/debug.c
#	remote/doc
#	remote/doc/install.ms
#	remote/doc/paper
#	remote/doc/paper/Makefile
#	remote/doc/paper/appendixB
#	remote/doc/paper/fig1
#	remote/doc/paper/fig1.mag
#	remote/doc/paper/fig4
#	remote/doc/paper/fig5
#	remote/doc/paper/fig6

mkdir remote

#
# remote/README
#
if [ -f remote/README ]; then 
	echo -n 'Hit <return> to overwrite remote/README or ^C to quit' 
	read ans 
	rm -f remote/README 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/README
XStart with running off the following documents in the doc directory:
X
X	install.ms	(standard Berkeley ms macros)
X	remotename.2	\
X	remoteon.2	 \ (standard Berkeley man macros)
X	rfs_server.8	 /
X	rmtmnt.8	/
X
XThe directory doc/paper, contains a paper that contains most of the early
Xdesign considerations for RFS, but is written using some TEK-internal
Xms macros.
X
XRead the install.ms document first.
SHAREOF
chmod 664 remote/README
#
# remote/byteorder.c
#
if [ -f remote/byteorder.c ]; then 
	echo -n 'Hit <return> to overwrite remote/byteorder.c or ^C to quit' 
	read ans 
	rm -f remote/byteorder.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/byteorder.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:	byteorder.c,v $
X * Revision 2.0  85/12/07  18:20:50  toddb
X * First public release.
X * 
X */
Xstatic char	*rcsid = "$Header: byteorder.c,v 2.0 85/12/07 18:20:50 toddb Rel $";
Xlong	data = 0x03020100;
X
Xmain()
X{
X	char	*p = (char *)&data;
X
X	printf("bytes order=%d,%d,%d,%d\n", p[0],p[1],p[2],p[3]);
X}
SHAREOF
chmod 444 remote/byteorder.c
#
# remote/change.c
#
if [ -f remote/change.c ]; then 
	echo -n 'Hit <return> to overwrite remote/change.c or ^C to quit' 
	read ans 
	rm -f remote/change.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/change.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:	change.c,v $
X * Revision 2.0  85/12/07  18:20:57  toddb
X * First public release.
X * 
X */
Xstatic char	*rcsid = "$Header: change.c,v 2.0 85/12/07 18:20:57 toddb Rel $";
X#include	"server.h"
X#include	<stdio.h>
X#include	<sys/time.h>
X
Xextern short	current_uid;
Xextern short	current_pid;
Xextern short	current_umask;
Xextern short	current_server;
Xextern short	gateway_server;
Xextern long	fds_in_use;
Xextern long	to_gateway;
Xextern long	from_servers;
Xextern boolean	i_am_gateway;
Xextern boolean	i_have_control;
Xextern process	*wildcard;
Xextern syscallmap	smap[];
Xextern hosts	*host;
X
X/*
X * Given the user id # and the process id # in the message, we look up the
X * process (or allocate a new one).  If there are things to be accomplished
X * before the system call is performed, do them here.
X */
Xprocess *change_to_proc(msg)
X	register struct message	*msg;
X{
X	register rusers	*ruser;
X	register process	*proc = NULL;
X	register char	*p;
X	register long	syscall = msg->m_syscall,
X			syscalltype = smap[ syscall ].s_type;
X
X	/*
X	 * First, we check to see that the file is not really a local file
X	 * for the client.  A simple example of this is a pathname of '..'
X	 * while sitting in our root directory.  If it is local, islocal()
X	 * will compose a message and send it.  We simply return.
X	 *
X	 * Even if this is handled by another server, we may be able to serve
X	 * the request;  but only if:
X	 *	1. it is a system call using a path (NEED_CWD).
X	 *	2. The path is starts with a '/'.
X	 *	3. The system call does not generate a new file descriptor
X	 *	   (like open).
X	 *	4. This is not chdir().
X	 * The system calls that fall in this category, are stat, lstat,
X	 * rename, unlink, symlink, readlink, etc.
X	 * If the system call does not match these criterion, then we must
X	 * reroute it.
X	 */
X
X	proc = findprocess(msg->m_pid, msg->m_uid);
X	if (syscalltype & NEED_CWD) {
X		if (proc
X		&& proc->p_handler == current_pid
X		&& islocal(msg, syscalltype))
X			return(NULL);
X		if ((syscalltype & NEED_MYSERVER) == 0)
X		{
X			if (syscalltype & NEED_2PATH)
X				p = twopath2addr(msg);
X			else
X				p = path1addr(msg);
X			if (*p == '/')
X			{
X				setup_proc(proc = wildcard,
X					msg->m_uid, msg->m_pid);
X				debug0("using wildcard proc... ");
X			}
X		}
X	}
X
X	/*
X	 * A fork() (but not vfork()) generates two messages, one
X	 * from parent, one from the child.  If we know about it (no
X	 * matter if we are the server for the parent, the child or if
X	 * we are the gateway), then we already have received the
X	 * first notification.  Don't do a reroute for that, just
X	 * handle it locally (its redundant info).  If we don't know
X	 * about it, then this is the first anyone has heard of it,
X	 * so we use args[1] which is the parent pid of
X	 * the fork (in both messages).
X	 */
X	if (proc == NULL && (syscall == RSYS_fork || syscall == RSYS_vfork))
X		proc = findprocess(msg->m_args[ 1 ], msg->m_uid);
X
X	if (proc == NULL)
X	{
X		/*
X		 * If we are the gateway, and don't know about this process,
X		 * and it is an exit() call, then just ignore it; cause if we
X		 * don't know this guy, nobody does.  Otherwise,
X		 * allocate a new slot for it.
X		 */
X		if (i_am_gateway)
X		{
X			if (syscall == RSYS_exit)
X			{
X				debug0("discard exit call for pid %d\n",
X					msg->m_pid);
X				return(NULL);
X			}
X			else
X				proc = add_new_process(msg->m_uid, msg->m_pid);
X		}
X		/*
X		 * If we are'nt the gateway, then hand this request back to
X		 * the gateway.  Maybe he will know where to send the request.
X		 */
X		else
X		{
X			reroute(gateway_server, msg);
X			return(NULL);
X		}
X	}
X	/*
X	 * And if we just happen to know about this process (whether we
X	 * are the gateway or not), then just reroute it.
X	 */
X	else if (proc->p_handler != current_pid)
X	{
X		reroute(proc->p_handler, msg);
X		if (syscall == RSYS_exit && !i_am_gateway)
X		{
X			deletelist(&host->h_proclist, proc);
X			freeproc(proc);
X		}
X		return(NULL);
X	}
X
X	/*
X	 * At this point, the request is for us, and there is definitely
X	 * no mistake.
X	 */
X	if ((syscalltype & NEED_FD) || syscall == RSYS_chdir)
X	{
X		debug3("%d current file descriptors\n", fds_in_use);
X		/*
X		 * Here is where we reroute the opening of a file
X		 * or a chdir() to another server.
X		 */
X		if (need_to_fork())
X			if (! become_server(msg))
X				return(NULL);
X	}
X
X	if (syscalltype & NEED_PERM)
X		change_to_user( proc->p_ruser->r_user );
X
X	debug1("pid %d: ", proc->p_pid);
X	return(proc);
X}
X
X/*
X * change the current user id to 'uid'.
X * This is done with simply a setreuid
X */
Xchange_to_user(user)
X	register users	*user;
X{
X#ifdef RFSDEBUG
X	long	gids[ NGROUPS ], ngids, i;
X#endif RFSDEBUG
X
X	if (current_uid != user->u_local_uid)
X	{
X		debug2("set uid to %s(%d)\n",
X			user->u_name, user->u_local_uid);
X		change_to_uid(0);
X		if (setgroups(user->u_numgroups, user->u_local_groups) < 0)
X		{
X			register long	i;
X
X			log("cannot set gids\n");
X			for (i=1; i<user->u_numgroups; i++)
X				log(",%d", user->u_local_groups[i]);
X			return(FALSE);
X		}
X		change_to_uid(user->u_local_uid);
X	}
X	else
X		debug2("already at uid %d (uid=%d/%d)\n",
X			current_uid, getuid(), geteuid());
X#ifdef RFSDEBUG
X	if (remote_debug & 0x4)
X	{
X		log("%d gids should be", user->u_numgroups);
X		for (i=0; i<user->u_numgroups; i++)
X			log(" %d", user->u_local_groups[i]);
X		ngids = getgroups(NGROUPS, gids);
X		log("\n%d gids are=", ngids);
X		for (i=0; i<ngids; i++)
X			log(" %d", gids[i]);
X		log("\n");
X	}
X#endif RFSDEBUG
X	return (TRUE);
X}
X
X/*
X * Change to uid 'uid'.
X */
Xchange_to_uid(uid)
X	register long	uid;
X{
X	if (current_uid != uid)
X		if (setreuid(0, uid) < 0)
X			log("cannot set uid to %d\n", uid);
X		else
X		{
X			current_uid = uid;
X			debug2("uid now %d/%d\n", getuid(), geteuid());
X		}
X}
X
X/*
X * Change to umask 'mask'.
X */
Xchange_to_umask(mask)
X	register long	mask;
X{
X	register long	oldmask;
X
X	if (mask != current_umask)
X	{
X		oldmask = umask(current_umask = mask);
X		debug2("umask now 0%o, was 0%o\n", current_umask, oldmask);
X	}
X}
X
X/*
X * check to see if we need to fork.  We do this for two reasons:
X *	1. we are the gateway server.
X *	2. we are currently handling other processes (a chdir might mess
X *	   them up).
X * Note that we only have to ask ourselves "do we need to fork" when we are
X * opening a new file, accepting a new process (the client is doing a fork()
X * or vfork()), or changing directory.
X */
Xneed_to_fork()
X{
X	register char	*fds;
X	register process	*proc;
X	register long	myprocs = 0;
X
X	if (i_am_gateway)
X		return(TRUE);
X	for (proc = host->h_proclist; proc; proc = proc->p_next)
X		if(proc->p_handler == current_pid)
X			myprocs++;
X	return(myprocs > 1);
X}
SHAREOF
chmod 444 remote/change.c
#
# remote/debug.c
#
if [ -f remote/debug.c ]; then 
	echo -n 'Hit <return> to overwrite remote/debug.c or ^C to quit' 
	read ans 
	rm -f remote/debug.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/debug.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:	debug.c,v $
X * Revision 2.0  85/12/07  18:21:07  toddb
X * First public release.
X * 
X */
Xstatic char	*rcsid = "$Header: debug.c,v 2.0 85/12/07 18:21:07 toddb Rel $";
X#include	"server.h"
X
Xmain(argc, argv)
X	char	**argv;
X	int	argc;
X{
X	int	dbg;
X
X	dbg = atox(argv[1]);
X	printf("set debug to %x\n", dbg);
X	printf("remotename()=%d\n", remotename(NM_DEBUG, dbg));
X	perror("debug");
X}
X
X/*
X * ascii to hex
X */
Xatox(buf)
X	char    *buf;
X{
X	register char   *p;
X	register unsigned       num, nibble;
X
X	/*
X	 * now, take it out checking to make sure that the number is
X	 * valid.
X	 */
X	if (! buf)
X		return(0);
X	for(num=0, p = buf; *p; p++)
X	{
X		nibble = *p;
X		if (nibble >= 'A' && nibble <= 'F')
X			nibble -= 'A' - 10;
X		else if (nibble >= 'a' && nibble <= 'f')
X			nibble -= 'a' - 10;
X		else if (nibble >= '0' && nibble <= '9')
X			nibble -= '0';
X		else
X			return(0);
X		num = (num << 4) | nibble;
X	}
X	return(num);
X}
SHAREOF
chmod 444 remote/debug.c
#
# remote/doc
#
mkdir remote/doc
chmod 775 remote/doc
#
# remote/doc/install.ms
#
if [ -f remote/doc/install.ms ]; then 
	echo -n 'Hit <return> to overwrite remote/doc/install.ms or ^C to quit' 
	read ans 
	rm -f remote/doc/install.ms 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/doc/install.ms
X.ds Fi \\u\\s-4\\n+*\\s+4\\d
X.TL
XInstalling and Operating RFS
X.AU
XT. Brunhoff
Xtoddb%crl@tektronix.csnet
Xdecvax!tektronix!crl!toddb
X.AI
XUniversity of Denver
X.AB
XThis document describes
Xthe installation, maintenance and adjustment
Xof RFS, a public domain, kernel\-resident distributed file system,
Xwritten at
XTektronix Computer Research Laboratories* for partial
Xfulfillment of the master's degree program at the University of Denver.
XIt was designed to provide complete transparency with
Xrespect to file access and protections for all programs
Xwhether they use local or remote files and directories.
XIt has been installed on VAX BSD 4.2 and 4.3 UNIX,
XPyramid 4.2/5.0 UNIX, version 2.5,
Xand on a Tektronix internal proprietary workstation,
Xcalled Magnolia.
XThe instructions are designed in a way that keeps all changes
Xseparate from your standard sources, in hope that
Xit will encourage sites to try the installation.
X.AE
X.nr * 0 1
X.FS *
XRFS should not be confused with another completely different (but excellent)
Ximplementation
Xfrom Tektronix available on the 6000 series workstation, called DFS,
Xand done by a separate product group.
XThe work on RFS was designed and written
Xstrictly by the author of this paper at about the same
Xtime as DFS, and draws none of its implementation details from DFS.
XRFS is public domain, while DFS is proprietary.
X.FE
X.NH 1
XInstalling and Compiling
X.PP
XThese instructions assume that you are familiar with
Xthe C compiler, the commands \fImake(1)\fP, \fIvi\fP,
Xthe structure of the kernel source files,
Xhow to build a new kernel[1],
Xthe structure of \fI/etc/passwd, /etc/hosts, /etc/services, /etc/rc.local\fP.
XInstalling and compiling the software should take about two to four hours
Xwithout interruption and on a lightly loaded 11/750.
X.PP
XThe best way to install this at first, is to make everything in someone's
Xlogin directory, keeping all changes from being anywhere near permanent.
XIn this way
Xyou can gain confidence comfortably that the software really
Xworks.
XAll compiles can be done by an unprivilaged user that has read access
Xto the kernel source.
X.PP
XTo do this,
Xyou need the \fIremote\fP directory
X(this document came from \fIremote/doc/install.ms\fP)
Xwith all of its original contents.
XLet us say that you have allocated this project to a user named \fIrfs\fP,
Xand that he will be installing everything beneath his login directory,
X\fI~rfs\fP.
XIf you are reading this document,
Xthen you probably now have the following directories
Xunder \fI~rfs\fP:
X.DS
Xremote
Xremote/RCS
Xremote/doc
Xremote/doc/paper
Xremote/usr.include.{VAX4.2,VAX4.3,PYR2.5}
Xremote/usr.src.lib.libc
Xremote/usr.src.lib.libc/gen
Xremote/usr.src.lib.libc/{vax,pyr}
Xremote/usr.src.lib.libc/{vax,pyr}/sys
Xremote/usr.sys.VAX4.2/{conf,h,machine,sys}
Xremote/usr.sys.VAX4.3/{conf,h,machine,sys}
Xremote/usr.sys.PYR2.5/{conf,h,sys}
Xremote/usr.sys.remote
X.DE
X.PP
XIf not,
Xthey are easily obtained by mounting the tape (if that is the medium of this
Xrelease) or by placing the \fIshar\fP file in, say,
X\fI/tmp/rfs.shar\fP.
XTo extract them, you would type, respectively,
X.DS
X% cd ~rfs; tar x
X	or
X% cd ~rfs; sh < /tmp/rfs.shar
X.DE
X.NH 2
XBuilding the Kernel
X.PP
XA new kernel must be installed on the machine that is to have the
Xdistributed file system capability.
XThe machines that will be accessed through RFS
Xdo not need to have a new kernel if they are running
XBSD 4.3;
Xhowever, BSD 4.2 sites have a serious bug in sys_socket.c that
Xcauses infinite loops if there is any activity on a socket being
Xread using the \fIrecv(2)\fP system call.
XThe server uses this system call.
X.PP
XFirst,
Xyou must set up a local copy of the kernel sources
Xin \fI~rfs/sys\fP
Xusing symbolic links for most,
Xand copying and changing others (note that \fI~rfs/sys\fP does not
Xexist yet, so be patient).
XThe files new to the kernel are:
X.DS
X~rfs/sys/remote/remotefs.h
X~rfs/sys/remote/rmt_data_template	(used to build rmt_data.c)
X~rfs/sys/remote/remote_mkdata	(used to build rmt_data.c)
X~rfs/sys/remote/rmt_exec.c
X~rfs/sys/remote/rmt_final.c
X~rfs/sys/remote/rmt_general.c
X~rfs/sys/remote/rmt_generic.c
X~rfs/sys/remote/rmt_io.c
X~rfs/sys/remote/rmt_subr.c
X~rfs/sys/remote/rmt_syscall1.c
X~rfs/sys/remote/rmt_syscall2.c
X~rfs/sys/remote/rmt_syscall3.c
X.DE
XThe files that must be changed in the kernel are:
X.DS
X~rfs/sys/h/errno.h
X~rfs/sys/h/param.h
X~rfs/sys/h/user.h
X~rfs/sys/machine/trap.c
X~rfs/sys/sys/init_sysent.c
X~rfs/sys/sys/kern_exec.c
X~rfs/sys/sys/kern_exit.c
X~rfs/sys/sys/sys_inode.c		(a semantic bug; fixed in 4.3)
X~rfs/sys/sys/ufs_nami.c		(ufs_namei.c in 4.3)
X~rfs/sys/sys/ufs_syscalls.c
X~rfs/sys/sys/uipc_socket.c	(the \fIrecv(2)\fP bug; fixed in 4.3)
X.DE
XFor configuration, there are a few files which must be changed
Xslightly:
X.DS
X~rfs/sys/conf/files
X~rfs/sys/conf/makefile.vax	(Makefile.vax in 4.3)
X.DE
XFinally,
Xthe source files for building the new system calls (see 
X\fBBuilding the User Programs\fP)
Xmust know about the new system call numbers.
XThis requires a
X(local) change to a file normally found in \fI/usr/include\fP:
X.DS
X~rfs/usr.include/syscalls.h
X.DE
X.NH 3
XEditing in the Changes (about 15 minutes)
X.PP
XAll of these files, or the changes that need to be made to them
Xare found in files of the same name (plus a \fI.diff\fP for the
Xpatch files) under \fI~rfs/remote/usr.*\fP.
XA shell program named \fI~rfs/remote/shells/rfs_setup\fP
Xhas been provided for setting up the symbolic links,
Xcopying files,
Xand patching in all the changes to the kernel using the \fBpatch\fP
Xutility which has been posted publicly to newsgroups such as \fInet.sources\fP
Xby Larry Wall\*(Fi.
XSome of the added kernel
Xsoftware contains \fIifdef\fPs for 4.3 BSD differences
Xwhich only clutter the code and cause problems
Xwhen you run \fImake depend\fP on BSD 4.2.
X\fI~Rfs_setup\fP will remove these.
X.FS
XIf you have never heard of the \fBpatch\fP program, I don't know how you ever
Xfound out about RFS.
XSend me a note and I will mail the source to you.
X.FE
XRunning \fIremote/shells/rfs_setup\fP will work for 4.2 and 4.3 BSD Vax systems,
Xand for Pyramid 90x systems running 2.5,
Xbut for other systems, you must examine the shell
Xscript to infer what it accomplishes.
XLet me emphasize again that you are not (and should not be)
Xediting the standard kernel sources.
X.DS
X% cd ~rfs
X% ./remote/shells/rfs_setup	# several questions will be asked
X.DE
X.NH 3
XEnsuring that RFS Software Does Not Interfere with the Kernel
X.PP
XThere are four variables defined in \fI~rfs/sys/remote/remotefs.h\fP
Xwhich must be examined to be sure that they fit in correctly with
Xthe rest of the kernel.
XTheir values in the distributed software have been chosen
Xso as not to conflict
Xwith VAX BSD 4.2 or 4.3, and Pyramid 2.5 software.
XIt will have to be changed for other Unix versions.
X.IP FREMOTE
Xis a flag that must not conflict with any other flags associated
Xwith the kernel \fIfile\fP structure.
XCheck in \fI/usr/sys/h/file.h\fP.
X.IP DTYPE_REMOTE
Xshould not conflict with DTYPE_INODE or DTYPE_SOCKET in
X\fI/usr/sys/h/file.h\fP.
XThis new file descriptor type means the
Xfix to \fIino_close()\fP in \fI~rfs/sys/sys/sys_inode.c\fP must be installed.
X.IP SREMOTE
Xmarks a process as having used a remote file system at some time.
XIt must be a unique bit for the \fIproc\fP structure element \fIp_flag\fP
Xas defined in \fI/usr/sys/h/proc.h\fP.
X.IP SNOREMOTE
Xmust also be a unique bit for the \fIproc\fP structure element \fIp_flag\fP.
XThis flag bit prevents any processes having it from using any remote
Xfile system.
XIt is used primarily by \fIrfs_server\fP to prevent ``hopping''
Xacross more than one machine with the remote file system.
X.NH 3
XSetting up VAX\*(Fi Configuration (about 10 minutes)
X.PP
X.FS
XPyramid software does not have a configuration file.
Xconfiguration is done with command\-line shell script arguments.
X.FE
XThe configuration file for VAX machines should now be in \fI~/rfs/sys/conf\fP,
Xbut it is a symbolic link to the real one in \fI/usr/sys/conf\fP,
Xlet us say, FOOVAX.
XYou should remove the link and copy it to this directory so
Xthat you can add three lines to it\*(Fi:
X.FS
XThe RFSDEBUG option gives you the ability to 
Xenable selective portions of the RFS kernel to give out
Xinformation about activity and problems.
XSee the section on debugging.
XCompiling it in has a negligible performance impact (<< %1)
Xif it is not used.
XYou can compile it out later by removing \fIrmt*.o\fP,
Xremoving the RFSDEBUG option line from the config file,
Xrunning config again, and recompiling.
X.FE
X.DS
Xoptions		REMOTEFS	# to compile in REMOTEFS changes
Xoptions		RFSDEBUG	# to compile in debug software (optional)
Xpseudo-device	remotefs		# to include the rfs software in the makefile
X
X	so
X
X% cd ~rfs/sys/conf
X% rm FOOVAX
X% cp /usr/sys/conf/FOOVAX .
X% vi FOOVAX
X< add in the three new lines >
X% mkdir ../FOOVAX			# for the config directory
X% config FOOVAX
X.DE
X.NH 3
XCompiling the RFS Kernel (about 90-120 minutes)
X.PP
XIf you have installed everything correctly
Xand if I have told you all that I should,
Xthen you should now be able to compile the kernel.
XNote that compilation is different for VAX and Pyramid.
X.DS
X	VAX
X% cd ~rfs/sys/FOOVAX
X% make depend
X% make
X
X	PYRAMID
X% mkdir ~rfs/sys/FOOVAX	# not made yet
X% cd ~rfs/sys/FOOVAX
X% cp ../conf/* .		# copy in configuration scripts and makefiles
X% makesys 64 VER=01 N	# you better check with your pyramid rep.
X.DE
XYou should boot the kernel to assure yourself that
Xit won't crash and to prepare for the remaining software.
X.NH 2
XBuilding the User Programs
X.PP
X\fIRmtmnt\fP is to a remote file system what \fI/etc/mount\fP is
Xto a disk file system.
XIn addition,
Xit provides statistics on currently active remote file systems.
X\fIRfs_server\fP
Xprovides name translation to the kernel for pathnames
Xbelow a generic mount point, e.g. \fI/net/foovax/etc/passwd\fP,
Xand it is the system call server which a client talks to.
X.PP
XThere are three new system calls added to the kernel,
Xand there are three new error numbers defined in \fI<errno.h>\fP.
XThe system calls
X\fIremoteon(2)\fP and \fIremoteoff(2)\fP turn on and
Xoff the remote file system,
Xand \fIremotename(2)\fP allows the
Xserver and kernel to talk to each other.
XHence, you must first make a new libc,
Xso that \fIrfs_server\fP and \fIrmtmnt\fP compile and link
Xwithout any undefined symbols,
Xand any new programs that get relinked will be able to print
Xa reasonable message using the standard library call, \fIperror(3)\fP.
X.NH 3
XBuilding a new \fIlibc.a\fP (about 10 minutes)
X.PP
XThe new system calls and the new error messages for \fI/lib/libc.a\fP are:
X.DS
X~rfs/remote/usr.src.lib.libc/gen/errlst.c.diff
X~rfs/remote/usr.src.lib.libc/{vax,pyr}/sys/remoteon.c
X~rfs/remote/usr.src.lib.libc/{vax,pyr}/sys/remoteoff.c
X~rfs/remote/usr.src.lib.libc/{vax,pyr}/sys/remotename.c
X.DE
XThe contents of \fIerrlst.c.diff\fP is a patch file for
X\fI/usr/src/lib/libc/gen/errlst.c\fP\*(Fi.
X.FS
XThe \fIMakefile\fP assumes that general source is in \fI/usr/src\fP.
XThis can be overridden with an assignment on the command line:
X.sp 1
X	# make vax SRC=/usr/othersrcdir
X.sp 1
X.FE
XThe file \fI~rfs/remote/usr.src.lib.libc/Makefile\fP
Xknows how to build a C\-library from the sources and patch files provided.
XBy default, the \fIMakefile\fP will install the new libc in
X\fI/lib/libc.a\fP\*(Fi so you must be root.
X.FS
XYou can install it in \fI~rfs/remote\fP
Xby changing the \fIMakefile\fP variable LIBDIR,
Xor by assigning it on the command line
X.sp 1
X	# make vax LIBDIR=..
X.sp 1
Xbut then you must remember to change the \fIMakefile\fP
Xin ~rfs/remote
Xafter it is generated by \fI~rfs/remote/shells/makemake\fP.
X.FE
X.DS
X% su root
XPassword:
X# cd ~rfs/remote/usr.src.lib.libc
X# make vax	# for VAX BSD 4.2 or 4.3
X	or
X# make pyr	# for Pyramid 2.5
X.DE
X.NH 3
XBuilding a Makefile for \fIRfs_server\fP, and \fIRmtmnt\fP (about 5 minutes)
X.PP
XThere are a variety of makefiles for building the server, \fIrfs_server\fP,
Xand each is built with a command called \fIshells/makemake\fP.
XCurrently there is support for a makefile
Xon a Vax that will run the RFS kernel, for
Xa Pyramid that will run the RFS kernel and
Xfor a Vax that will only be a server (running an ordinary kernel).
XEach is created\*(Fi
X.FS
XThe last command run will leave that kind of makefile in \fI./remote\fP.
X.FE
Xwith one of the following commands\*(Fi:
X.FS
XIf none of these fit your needs,
Xyou must design your own from the files \fImake.base*\fP.
XAn important part of the makefile is the byte\-ordering
Xfor the machine on which the server will run.
XIf your architecture is neither Vax nor Pyramid,
Xyou should compile the program \fI~rfs/remote/byteorder.c\fP
Xand run it to get its opinion.
X.FE
X.DS
X% cd ~rfs/remote
X% shells/makemake vax		# Vax with RFS kernel
X	or
X% shells/makemake vaxnorfs	# Vax without RFS kernel
X	or
X% shells/makemake pyramid	# Pyramid with RFS kernel
X.DE
X.NH 3
XCompiling \fIRmtmnt\fP and \fIRfs_server\fP (about 30 minutes)
X.PP
XNow, compile the server and \fIrmtmnt\fP program\*(Fi,
Xinstalling the binaries as root:
X.FS
XIf you put the new libc.a in ~rfs/remote, instead
Xof following the reccomended procedure,
Xyou should edit the makefile at this point.
X.FE
X.DS
X% cd ~rfs/remote
X% make
X% su root
XPassword:
X# make install
X.DE
X.NH 2
XOther Chores
X.PP
XAt this point,
Xyou should have an RFS kernel running on one or more machines,
Xcall them \fIclient\fPs, and the
Xpotential to run the RFS server on one or more machines,
Xcall them \fIserver\fPs\*(Fi.
X.FS
XAny machine can be both client and server,
Xeven with respect to itself.
X.FE
XBefore starting up any connections,
Xthere are a few extra items that should be tended to.
X.IP \(bu .125i
XAdd the service \fIremotefs\fP to \fI/etc/services\fP,
Xon all server and client machines.
XIt should be a privileged port number, i.e. less than 1024,
Xbecause the server runs as root and does a \fIseteuid(2)\fP
Xto whatever user it thinks it should be.
XI have used port 556 on the machines where I installed RFS.
X.IP \(bu .125i
XAdd the user \fIguest\fP to \fI/etc/passwd\fP on
Xeach server machine.
XThe default permissions for any access to a server machine
Xare mapped to guest (so it shouldn't have wide access).
XThe server process will refuse to run without this user id installed.
X.IP \(bu .125i
XIf you are on a Pyramid,
Xthere is no easy way to turn on the debugging software in the kernel,
Xso there is a program provided;
Xyou should compile it now hand have it ready.
XMore on debugging later.
X.DS
X% cd ~rfs/remote
X% make debug
X.DE
X.NH 2
XStarting up the software
X.PP
XThe server should be started as root.
XFor now, you start it by hand,
Xand then arrange for it to be started automatically.
XThis should be done on all machines that will be servers or
Xclients.
XRemember that \fI/etc/rfs_server\fP is slightly different for
Xa machine running the RFS kernel; see section \fB1.2.2\fP.
X.DS
X% su root
XPassword:
X# /etc/rfs_server
X# vi /etc/rc.local
X< insert at an appropriate place, the lines... >
X	if [ -f /etc/rfs_server ]; then
X		/etc/rfs_server & echo -n ' rfs_server'	>/dev/console
X	fi
X.DE
X.PP
XNext we should set up for loop\-back RFS access just to make
Xsure that everything works.
XNote that the mount point is a file,
Xnot a directory.
XThis is very important.
XThe design decisions are discussed in a separate paper
Xunder \fI~rfs/remote/doc/paper\fP.
XIn a nutshell,
Xusing a file for a mount point
Xallows the natural syntax for file access
X.DS
X% cp /foovax/etc/passwd /feevax/tmp/x
X.DE
Xbut prevents programs like
X.DS
X% find / -print
X.DE
Xfrom finding every file on every remote host.
X.PP
XIf your host name is foovax, then create the file /foovax and
Xmount your host.
XThe use of the file /foovax is not required,
Xbut only suggested as a convention\*(Fi.
XFoovax must be defined in \fI/etc/hosts\fP and \fIrfs_server\fP
Xshould be running.
X.FS
XIt has been pointed out to me that this convention
Xis slightly restrictive for machines whose owners choose
Xinteresting names such as bin and tmp.
X.FE
X.DS
X% touch /foovax
X% /etc/rmtmnt foovax /foovax
X.DE
XIn all likelyhood,
Xyou should not have crashed by this time,
Xbut if there are any problems with the way you installed the software,
Xthey will be encountered now.
XTry the commands
X.DS
X% ls -ld /foovax/
X% ls -ld /foovax/etc
X% ls -l /foovax/etc
X% cd /foovax/etc
X% pwd
X% ls
X.DE
XIf the machine crashes
Xor the result is not what you expected,
Xyou should pull out the stops and start debugging.
XSee the section on debugging.
XIf all goes well,
Xthen try mounting another host, say foo2vax:
X.DS
X% touch /foo2vax
X% /etc/rmtmnt foo2vax /foo2vax
X% ls -l /foo2vax/etc
X% ....
X.DE
XTry a generic mount point:
X.DS
X% touch /net
X% /etc/rmtmnt -g /net
X% more /net/anotherhost/etc/passwd
X.DE
X.PP
XFinally,
Xwhen you are satisfied that everything is working,
Xyou should install the mount commands in \fI/etc/rc.local\fP.
XNote that you don't really need the generic mount point
Xunless you have many workstations that you don't want to explicitly
Xmount.
X.DS
X% su root
XPassword:
X# /etc/rfs_server
X# vi /etc/rc.local
X< insert at an appropriate place, the lines... >
X	if [ -f /foovax ]; then
X		/etc/rmtmnt foovax /foovax
X	fi
X	if [ -f /foo2vax ]; then
X		/etc/rmtmnt foovax /foovax
X	fi
X	if [ -f /net ]; then
X		/etc/rmtmnt -v /net
X	fi
X.DE
X.NH 1
XGeneral Portability
X.PP
XI consider RFS to be ``installable'', not necessarily portable.
X.PP
XRFS's server, \fIrfs_server\fP,
Xdepends very heavily on the BSD signal mechanism,
Xinheirited file descriptors (sockets to the client),
Xand the \fIrecv(2)\fP system call using the MSG_PEEK flag.
X.PP
XThe RFS kernel depends very heavily on mbuf structures, and the BSD
Xsocket paradigm.
X.NH 1
XAccess Permissions over RFS
X.PP
XFor a greater understanding of this discussion,
Xand the terms ``sentry server'', ``gateway server'',
XI suggest that the reader familiarize himself
Xwith the \fIrfs_server(8)\fP man page.
XThe terms ``client'' and ``server'' are described in section \fI1.3\fP.
X.PP
XA permission map is compiled by \fIrfs_server\fP
Xwhen it starts up
Xbased on \fI/etc/hosts\fP, \fI/etc/passwd\fP and \fI.rhosts\fP files
Xunder every user's login directory.
XIn addition,
Xwhenever a client does a \fIrmtmnt\fP command,
Xthat command sends its \fI/etc/passwd\fP file to the sentry server.
XSimilarly,
Xif a server receives a call from a client,
Xbut has not received an \fI/etc/passwd\fP file,
Xthe server calls the client's server,
Xand asks for it\*(Fi.
X.FS
XIf this fails,
Xthen the server will return EIO
Xon all \fIread(2)\fP calls where the file descriptor
Xis to a directory,
Xbecause it doesn't know the client architecture's byte order.
X.FE
X.PP
XWhen a server receives a message from a client process
Xwhose uid number is \fIn\fP,
Xit consults the client's \fI/etc/passwd\fP file.
XIf it finds a matching uid number,
Xthen it checks\*(Fi to see if
Xthat uid name is allowed login privileges in some
Xuser's \fI.rhosts\fP file on the server.
XIf a user allows it,
Xthen the server for that process sets
Xthe effective user id
Xto that user's uid number (with \fIseteuid(2)\fP)
Xand sets the groups associated with that
Xuser (with \fIsetgroups(2)\fP).
X.FS
XMost of this checking is done when \fIrfs_server\fP first starts up,
Xand is kept in LRU lists for fast access.
XMappings from client uid to server uid are already done
Xby the time a client makes a connection.
X.FE
X.PP
XIf more than one user on the server host
Xallows login access to that client's user,
Xthen the last user in the server's \fI/etc/passwd\fP takes precedence.
XHowever,
Xif the one of the users on the server hosts has the same uid name
Xas that on the client,
Xthat mapping takes precedence over all other mappings.
XNote that this means the user \fIx\fP on may have remote
Xlogin privileges for users \fIy\fP and \fIz\fP,
Xbut his access permissions over RFS will be for one or the other,
Xnever both.
X.PP
XIf a user changes his \fI.rhosts\fP file on a server,
Xthat change is not noticed until the server is restarted.
XFortunately,
Xrestarting the server is simple:
Xjust run \fIrfs_server\fP again.
XAs long as the primary log \fI/usr/tmp/rfs_log\fP
Xstill exists which contains the process id number of the running server,
Xit is intelligent enough to shutdown the old server.
X.PP
XIf the server host on which the user wanted to change his \fI.rhosts\fP file
Xis currently connected to the client,
Xthat connection must be severed and a new one started.
XThis can be done by killing all processes
Xhaving the SREMOTE bit set\(*Fi on the client machine.
XThe \fI/etc/rmtmnt\fP command with no arguments will tell
Xyou how many processes are connected to each server.
X.FS
XThe command \fIps axl\fP will show all commands and their per\-process
Xflag bits.
Xsimply examine the left\-most field of the \fIps\fP output
Xlooking for the SREMOTE bit.
XUnfortunately,
Xmultiple remote systems may be open,
Xand \fIps\fP output does not show which process is using which remote hosts
Xor even if it is using multiple hosts.
X.FE
X.PP
XSimilarly,
Xif a new user is added to a client's \fI/etc/passwd\fP file,
Xor an existing user's uid number changes on a client,
Xthe \fIrfs_server\fP must be started again on each of the server machines,
Xor the remote file systems can be unmounted and mounted again using
X\fI/etc/rmtmnt\fP.
XAgain, however,
Xif the client host where the change was made is currently connected
Xto a server,
Xthen that connection must be severed and a new one started
Xas described above.
X.NH 1
XDebugging
X.PP
XAll kernel debugging is accomplished by setting the
Xglobal variable \fIremote_debug\fP.
XThe bit definitions are briefly explained in the
Xfile \fI~rfs/sys/remote/remotefs.h\fP.
X.PP
XDebugging on the server is explained briefly in the
Xman page for \fIrfs_server(8)\fP.
X.NH 2
XPlaces to Look if RFS Does Not Work
X.PP
XIf the kernel gets hung in startup or does not seem to do
Xsome of the system calls correctly
Xcheck the code inserted into \fI~rfs/sys/machine/trap.c\fP for
Xone of the following problems:
X.IP \(bu .125i
XOn the Vax,
Xthe declarations at the top of the routine are very position
Xdependent.
XRFS has some register declarations that must appear last
Xor the register allocation that the code depends on will be
Xmessed up.
X.IP \(bu .125i
XOn the Pyramid,
Xsystem calls are made by passing the arguments as arguments
X(the Vax copies them to an array).
XCheck to make sure that the code inserted is doing this right,
Xbecause I only tested it for a week.
X.PP
XOn the Pyramid,
Xdeclarations of variables inside of local blocks
Xsometimes causes the value of other local variables in outer blocks to
Xbe corrupted.
XFor example:
X.DS
X	routinex(arg1, ...)
X	{
X		register long	a, b, c, ...;	/* lots of variables */
X		...
X		x = y;
X
X		{ /* start a local block */
X			register long	z;
X
X			z = 1;
X		}
X	}
X.DE
XThe declaration and use of z
Xwill probably clobber one of the earlier variables \fIa, b, c, ...\fP.
XThis is a pretty bad compiler bug, but I think they are aware of it.
XThis kind of code was completely removed at one time from the
XRFS source code, but may have crept back in;
Xbe sure that you don't add any.
X.PP
XIf you \fIcd\fP to a remote directory,
Xbut it always appears as if you are still in the root directory for
Xthat machine,
Xit almost certainly has to do with \fIfork(2)\fP or \fIvfork(2)\fP
Xsystem calls not being sent to the server.
XCheck the generated table at the end of 
X\fI~rfs/sys/remote/rmt_data.c\fP to ensure that there is a \fIRFS_\fP
Xentry for both \fIfork(2)\fP and \fIvfork(2)\fP.
XIf there isn't, change it by hand or try to fix the shell file
Xthat generates it in \fI~rfs/sys/remote/remote_mkdata\fP.
X.NH 1
XMaking the Software Permanent
X.PP
XFirst,
Xread in the distribution tape again, this
Xtime putting it in \fI/usr/src/etc\fP;
Xthis will be the proper resting place for the software that
Xlives in the directory immediately below the first\-level directory,
X\fIremote\fP,
Xbecause the two commands \fI/etc/rfs_server\fP and \fI/etc/rmtmnt\fP
Xreside there.
X.PP
XSecond,
Xrerun the installation procedure,
Xthis time instructing \fIrfs_setup\fP to make the installation permanent,
Xinstead of in the current directory.
XThe only exception is that the software in \fI~rfs/remote/usr.src.lib.libc\fP
Xmust be copied by hand to /usr/src/lib/libc and placed in
Xthe proper directories there, modifying the \fImakefile\fP accordingly.
X.NH 1
XCurrent Bugs and Needed Extensions
X.PP
XThe bugs listed have only proved irritating for our environment,
Xbut worthy of note, none the less.
X.IP \(bu .125i
XWhen a client fails to connect to a server,
Xthe internal count of how many processes there are sometimes
Xgoes awry,
Xand the kernel (as seen by \fIrmtmnt\fP)
Xwill insist that it is still closing
Xwaiting for processes to die that aren't there.
XThe bug is almost certainly in \fIremote_getconnection()\fP.
X.IP \(bu .125i
XWhenever a connection goes down,
Xthere may be processes still up ``using'' that connection.
XHowever,
Xif there are no open files or remote \fIchdir(2)\fP's,
Xthe kernel could just as well restart the connection
Xwithout waiting for those processes to die.
XThis fix would go into \fIremote_getconnection()\fP.
X.IP \(bu .125i
XThe server has the beginnings of capability to
Xdo an asynchronous system call (like reading 10k of data),
Xbut it has not been fully implemented.
XA much better solution would be to implement an
Xatomic \fIwrite(2)\fP system call where
Xthe writer is guarenteed that no one else
Xwill be able to write on the same file descriptor (socket,
Xin this case)
Xuntil he is done.
XThis would allow servers to perform system calls
Xat their own pace sending the results back at any time.
X.IP \(bu .125i
XAlong the same lines,
Ximplementing an atomic message reader system call
Xthat would allow all servers to be blocked on a read
Xof the single socket connected to the client.
XThe reading server would provide a list of process id's
Xthat he is handling as input arguments along with
Xfile descriptor, buffer and size.
XThe kernel would slice up all the messages, handing
Xeach out to the server that is serving that process.
XThe only reason it wasn't implemented so far, was to keep the
Xserver standard.
X.IP \(bu .125i
XThe server maps two user id names with the same
Xnumber on a client to one user id on a server.
XThe reason is that only the uid number is sent in the messages
Xto the server.
XThere is no real fix for this.
X.IP \(bu .125i
XThe sentry server has the information about every host in
Xits memory and hands all this information off to each \fIgateway\fP
Xserver and its children even though it is never used.
XIf this was freed when each \fIgateway\fP
Xserver starts up, the servers would consume fewer memory
Xand swap resources.
X.IP \(bu .125i
XThe server currently does not handle \fI.rhosts\fP
Xfiles that have entries uttering only a host name.
XIt also ignores \fI/etc/hosts.equiv\fP.
X.IP \(bu .125i
XThis implementation ignores the possibility that the kernel COMPAT
Xoption may have been used.
XOld system calls should just fail.
X.IP \(bu .125i
XThe \fIpwd\fP command (and library call) does not work
Xwhile your current directory is under \fI/net/host/somedirectory\fP.
XBasically, the \fIpwd\fP command discovers that its current directory
Xis \fI/net/somedirectory\fP
Xbecause the \fIhost\fP is really only a virtual pathname component.
XBut when it tries to do
Xa \fIchdir(2)\fP back to it, it fails.
XThis is an irritating problem,
Xbut the only easy solution is for a change in the implementation,
Xsuch that \fI/net\fP becomes a directory, and the nameserver
Xcreates files and
Xdoes an explicit mount for any hosts that the kernel asks about.
XSo far I have resisted this because it requires another change
Xto the kernel routine \fInamei()\fP,
Xand because \fIpwd\fP works just fine if a host explicitly mounted.
X.IP \(bu .125i
XI think that RFS may be responsible for dropping an mbuf when a connection
Xfails, but this is apparently infrequent.
X.IP \(bu .125i
X\fIChroot(2)\fP system call is only partially implemented.
Xand should not be used with a remote directory as an argument.
X.IP \(bu .125i
XThe \fIselect(2)\fP and \fIioctl(2)\fP system calls are not yet implemented.
XThe latter means that the \fItip\fP command won't work with remote
Xpointers to tty dialers.
X.IP \(bu .125i
XThe server allows any unknown user on a client to see
Xits file system through the guest
Xaccount.
XThis is a good default.
XBut an appropriate extension
Xwould be a table describing a restricted domain of access,
Xso that if machines \fIx\fP and \fIy\fP appear in the table,
Xthey are allowed access through the normal permission scheme
Xdescribed above.
XHowever, any machine not in the table would be denied access in general,
Xso that only users on the client that have been allowed remote logins
Xvia \fI.rhosts\fP files can have access.
X.IP \(bu .125i
XNo fixes have been provided for \fImv(1)\fP or \fIcp(1)\fP
Xto distinguish the triple device/inode/host for uniqueness.
XThe information is available:
Xfor a local file,
Xthe \fIstat(2)\fP, \fIfstat(2)\fP and \fIlstat(2)\fP
Xsystem calls return a stat structure whose
X\fIst_spare1\fP element is 0.
XIf the file is remote,
Xthe \fIst_spare1\fP element contains the value \fIn\fP+1
Xwhere \fIn\fP is the number of the remote host mount point,
Xas shown by \fI/etc/rmtmnt\fP.
X.IP \(bu .125i
XThe server, \fIrfs_server\fP, does not correctly handle situations where
Xa host has more than one internet address.
XWhat happens is that all of the user access privileges
X(distilled from all the .rhosts files)
Xgets attached to one address, and when a call is made using the
Xother address, everyone only has the access of the \fIguest\fP user.
X.IP \(bu .125i
XSome user commands,
Xlike \fIchgrp(1)\fP and \fIrn(1)\fP
Xtry to guess ahead of time whether the kernel will allow you write
Xpermission on a file.
XHence, they will fail sometimes where they should not.
XFor example,
Xif your user id number on one host is 5 and on
Xanother host it is 6,
X\fIchgrp(1)\fP on one host
Xwill tell you that you cannot change the group of a file that resides on
Xanother host, even though RFS would allow it.
X.NH 1
XConclusions and Plans for the Future
X.PP
XRFS is not production quality,
Xbut is very useful,
Xproviding reasonably fast file access:
XI consider rcp unreasonable.
XI have made this software publicly available in hopes that other
Xinterested parties might contribute some of the fixes to it.
XI have other responsibilities and cannot afford to spend the
Xmany hours necessary to get that last 5 or 10% of quality,
Xbut perhaps you can help.
X.PP
XThe only hope for this software is that it is free and easy
Xto install and debug.
XI am more than willing to accept bug reports and fixes for it
Xuntil this or something else becomes part of the Berkeley Software
XDistribution.
SHAREOF
chmod 664 remote/doc/install.ms
#
# remote/doc/paper
#
mkdir remote/doc/paper
chmod 775 remote/doc/paper
#
# remote/doc/paper/Makefile
#
if [ -f remote/doc/paper/Makefile ]; then 
	echo -n 'Hit <return> to overwrite remote/doc/paper/Makefile or ^C to quit' 
	read ans 
	rm -f remote/doc/paper/Makefile 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/doc/paper/Makefile
XRFS = remotefs fig1.mag fig2.mag fig3.mag fig4.mag fig5.mag fig6.mag \
X	appendixB.out
X
Xrfs: $(RFS)
X	troff $(ONLY) -Tmag -mstek remotefs > image
X	@sh -c "echo -n Waiting... ; read x"
X	dmag -w$(WIND) < image
Xlgp: $(RFS)
X	ltroff -mstek $(ONLY) remotefs
X
X#
X# run off figure 1 or 2 or 3
X#
Xf1: fig1.mag
X	troff -Tmag -mstek fig1.mag > image
X	@sh -c "echo -n Waiting... ; read x"
X	dmag -w$(WIND) < image
Xf2: fig2.mag
X	troff -Tmag -mstek fig2.mag > image
X	@sh -c "echo -n Waiting... ; read x"
X	dmag -w$(WIND) < image
Xf3: fig3.mag
X	troff -Tmag -mstek fig3.mag > image
X	@sh -c "echo -n Waiting... ; read x"
X	dmag -w$(WIND) < image
Xf4: fig4.mag
X	troff -Tmag -mstek fig4.mag > image
X	@sh -c "echo -n Waiting... ; read x"
X	dmag -w$(WIND) < image
Xf5: fig5.mag
X	troff -Tmag -mstek fig5.mag > image
X	@sh -c "echo -n Waiting... ; read x"
X	dmag -w$(WIND) < image
Xf5: fig5.mag
X	troff -Tmag -mstek fig5.mag > image
X	@sh -c "echo -n Waiting... ; read x"
X	dmag -w$(WIND) < image
Xf6: fig6.mag
X	troff -Tmag -mstek fig6.mag > image
X	@sh -c "echo -n Waiting... ; read x"
X	dmag -w$(WIND) < image
XA: appendixA.out
X	troff -Tmag -mstek appendixA.out > image
X	@sh -c "echo -n Waiting... ; read x"
X	dmag -w$(WIND) < image
XB: appendixB.out
X	troff -Tmag -mstek appendixB.out > image
X	@sh -c "echo -n Waiting... ; read x"
X	dmag -w$(WIND) < image
X
X#
X# generate figure 1
X#
Xfig1.mag: fig1
X	/lib/cpp -Dfigure1 fig1 | sed -e '/^#/d' | pic -T100 > fig1.mag
Xfig1.lgp: fig1
X	/lib/cpp -Dfigure1 fig1 | sed -e '/^#/d' | pic > fig1.lgp
X
X#
X# generate figure 2
X#
Xfig2.mag: fig1
X	/lib/cpp -Dfigure2 fig1 | sed -e '/^#/d' | pic -T100 > fig2.mag
Xfig2.lgp: fig1
X	/lib/cpp -Dfigure2 fig1 | sed -e '/^#/d' | pic > fig2.lgp
X
X#
X# generate figure 3
X#
Xfig3.mag: fig1
X	/lib/cpp -Dfigure3 fig1 | sed -e '/^#/d' | pic -T100 > fig3.mag
Xfig3.lgp: fig1
X	/lib/cpp -Dfigure3 fig1 | sed -e '/^#/d' | pic > fig3.lgp
X
X#
X# generate figure 4
X#
Xfig4.mag: fig4
X	pic -T100 fig4 > fig4.mag
Xfig4.lgp: fig4
X	pic fig4 > fig4.lgp
X
X#
X# generate figure 5
X#
Xfig5.mag: fig5
X	pic -T100 fig5 > fig5.mag
Xfig5.lgp: fig5
X	pic fig5 > fig5.lgp
X
X#
X# generate figure 6
X#
Xfig6.mag: fig6
X	pic -T100 fig6 > fig6.mag
Xfig6.lgp: fig6
X	pic fig6 > fig6.lgp
X
X#
X# generate appendix A
X#
XappendixA.out: appendixA
X	tbl appendixA > appendixA.out
X
X#
X# generate appendix B
X#
XappendixB.out: appendixB
X	tbl appendixB > appendixB.out
SHAREOF
chmod 664 remote/doc/paper/Makefile
#
# remote/doc/paper/appendixB
#
if [ -f remote/doc/paper/appendixB ]; then 
	echo -n 'Hit <return> to overwrite remote/doc/paper/appendixB or ^C to quit' 
	read ans 
	rm -f remote/doc/paper/appendixB 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/doc/paper/appendixB
X.if "\*(.T"mag" \{\
X.	nr PS 12
X.	nr VS 14
X.	ps \n(PS
X.	vs \n(VS
X.	pl 9.5i
X.\}
X.ds LH \fBAppendix B\fP
X.BP
X.NH 1
XAppendix B
X.PP
XThese two tables contain the functions that must be ``changed'' for a remote
Xor distributed file system to work.
XThe column headings have the same meaning for both tables,
Xbut since some system calls have no before and after necessities (column 4),
Xit is clearer to put them by themselves in \fITable 1\fP.
X\fITable 2\fP has the rest of the system calls.
XThe first column, \fBSystem Call\fP, is the name of the system call
Xas found in section 2 of the UNIX User's Manual.
X.PP
XThe second column,
X\fBInteresting Arguments\fP,
Xlists the arguments that we are particularly interested in.
XFor example, \fIaccess()\fP, has two arguments, one a flag and one is
Xa path.
XThe path is noteworthy because we must find out what portion of the path
Xis on a remote host, and what remote host it is on.
XOther interesting arguments are those with two path names and those
Xhaving file descriptors.
XSome may not have any arguments worth considering,
Xbut are included because of important side effects.
X.PP
X\fBFollow Symlinks\fP shows whether \fInamei()\fP must follow
Xsymbolic links when determining ``remoteness'' (and is not applicable
Xto system calls that do not deal with path names).
XThis is an important point,
Xbut only for an implementation like \fBRemotefs\fP.
X\fBRemotefs\fP uses another system call, \fIisremote()\fP,
Xwhen determining what remote host a file is on and what portion
Xof the path is on that host.
XNow, the authors of 4.2
Xdecided when \fInamei()\fP may or may not follow a symbolic link,
Xand \fIisremote()\fP must do the same for whatever system call is
Xin operation.
X.PP
XThe last column, \fBSpecial Considerations Before & After the Syscall\fP,
Xshows what preparation
Xthe local host must do before
Xsending the system call to a remote host,
Xsuch as doing a local open to allocate a file descriptor
Xfor a \fIdup()\fP system call.
XThe fourth column shows the followup steps that should be taken
Xafter a successful remote system call.
X.PP
XThese descriptions assume that the system call has already been identified
Xas one that needs to be sent to a remote host.
XThat is,
Xat least one of the path names (for those system calls that deal with paths)
Xis remote,
Xor that the file descriptor passed as an argument to a system call is
Xto a remote file,
Xor even that there has been one or more remote system call requests
Xof some kind
X(\fIfork()\fP, \fIvfork()\fP, \fIumask()\fP, \fIexit()\fP).
X.BP
X.TS
Xtab(+) center box;
Xc | c | c
Xc | c | c
Xl | l | c.
X\fBSystem+Interesting+Follow\fR
X\fBCall+Arguments+Symlinks\fR
X=
X\fIaccess()\fP+One Path Name+yes+
X\fIstat()\fP+\^+\^
X\fIutimes()\fP+\^+\^
X\fItruncate()\fP+\^+\^
X_
X\fIchmod()\fP+One Path Name+no
X\fIchown()\fP+\^+\^
X\fIlstat()\fP+\^+\^
X\fImkdir()\fP+\^+\^
X\fImknod()\fP+\^+\^
X\fIrmdir()\fP+\^+\^
X\fIunlink()\fP+\^+\^
X_
X\fIfchmod()\fP+File Descriptor+n/a+
X\fIfchown()\fP+\^+\^
X\fIfcntl()\fP+\^+\^
X\fIflock()\fP+\^+\^
X\fIfstat()\fP+\^+\^
X\fIfsync()\fP+\^+\^
X\fIftruncate()\fP+\^+\^
X\fIioctl()\fP+\^+\^
X\fIlseek()\fP+\^+\^
X_
X.TE
X.ce 1
X\fITable 1\fP
X.BP
X.TS
Xtab(+) center box expand;
Xc | c | c | cw(3.5i)
Xc | c | c | cw(3.5i)
Xl | l | c | lw(3.5i).
X\fBSystem+Interesting+Follow+Special Considerations\fR
X\fBCall+Arguments+Symlinks+Before & After the Syscall\fR
X=
X\fIchdir()\fP+One Path Name+yes+T{
X\fBAfter:\fP
XMake note of the system and path name of the \fIchdir()\fP argument.
XT}
X_
X\fIclose()\fP+File Descriptor+n/a+T{
X\fBAfter:\fP
XClose the local file descriptor
XT}
X_
X\fIcreat()\fP+One Path Name+yes+T{
X\fBBefore:\fP
XAllocate a local file descriptor as a place\-holder.
X\fIDup2()\fP always closes the file descriptor in
Xits second argument in anticipation
Xof putting the new file descriptor at that ordinate value.
XThat file descriptor must be closed locally before sending
Xthe request to the remote host.
X.sp 1
X\fBAfter:\fP
XIf the system call was not successful, close the local one.
XAlso,
Xthere may need to be some mapping of file descriptors.
XFor instance,
Xthe local file descriptor may be 5 while the remote may be 6.
XHence, every request on fd 5 must be mapped to 6.
XAlternatively,
Xthe server may take care of the mapping if the local host sends
Xthe local file descriptor number to the remote host.
XT}
X\fIopen()\fP+One Path Name+\^+\^
X\fIdup()\fP+File Descriptor+\^+\^
X\fIdup2()\fP+File Descriptor+\^+\^
X_
X\fIexecv()\fP+One Path Name+yes+T{
X\fBAfter:\fP
XThe text for the program to be run must be copied
Xto the local swap space and executed from there.
XIf it is just a shell file, then it could be run normally,
Xwith the shell causing a remote open.
XT}
X\fIexecve()\fP+\^+\^+\^
X_
X\fIexit()\fP+None+n/a+T{
X\fBAfter:\fP
XThe \fIexit()\fP must be also run locally.
XT}
X_
X\fIfork()\fP+None+n/a+T{
X\fBBefore:\fP
XThe \fIfork()\fP or \fIvfork()\fP should be run locally first
Xto determine if the resources are available.
XT}
X\fIvfork()\fP+\^+\^+\^
X_
X\fIlink()\fP+Two Path Names+no+T{
X\fBBefore:\fP
XBoth path names must be on the same remote (or local) host.
XIf not, we can simulate failure locally.
XT}
X_
X\fIread()\fP+File Descriptor++T{
X\fBAfter:\fP
XThe data that was actually read by the system call
Xmust be gotten from the remote host.
XT}
X\fIreadlink()\fP+One Path Name+no+\^
X\fIreadv()\fP+File Descriptor++\^
X_
X\fIrename()\fP+Two Path Names+yes+T{
X\fBBefore:\fP
XThe two path names must both be on the same remote (or local)
Xhost.
XT}
X_
X\fIsymlink()\fP+Two Path Names+yes+T{
X\fBBefore:\fP
XOnly the second path name should be checked for ``remoteness''.
XT}
X_
X\fIumask()\fP+None+n/a+T{
X\fBAfter:\fP
X\fIumask()\fP must also be run locally.
XT}
X_
X\fIwrite()\fP+File Descriptor+n/a+T{
X\fBBefore:\fP
XThe data to be written must be sent to the remote host.
XT}
X\fIwritev()\fP+\^+\^+\^
X.TE
X.ce 1
X\fITable 2\fP
SHAREOF
chmod 664 remote/doc/paper/appendixB
#
# remote/doc/paper/fig1
#
if [ -f remote/doc/paper/fig1 ]; then 
	echo -n 'Hit <return> to overwrite remote/doc/paper/fig1 or ^C to quit' 
	read ans 
	rm -f remote/doc/paper/fig1 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/doc/paper/fig1
X.KF
X.if "\*(.T"mag" \{\
X.	nr PS 12
X.	nr VS 14
X.	ps \n(PS
X.	vs \n(VS
X.\}
X.PP
X.PS
X#ifdef figure1
Xboxht = .3i
Xboxwid = .8i
Xmovewid = .2i
XSyscalls: [
X	A: box "read()"; move
X	B: box "open()"; move
X	C: box "stat()"; move
X	D: box "..."
X]
X
Xboxht = last [].ht+1.2i
Xboxwid = last [].wid+.1i
XUserlevel: box dashed with .n at last [].n + (0i, .3i)
Xline from Syscalls.A.s to Userlevel.s
Xline from Syscalls.B.s to Userlevel.s
Xline from Syscalls.C.s to Userlevel.s
Xline from Syscalls.D.s to Userlevel.s
X"\s+4A User's Program\s-4" at Userlevel.se + (0, .075i) rjust
X#endif
X
X#ifdef figure1
Xboxwid = boxwid + 1.5i
Xboxht = boxht + 1i
XSystem: box dashed with .n at last box.s - (0, .3i)
X
X#else
Xboxwid = 5.5i
Xboxht = 2i
XSystem: box dashed
X#endif
X"\s+4UNIX Kernel\s-4" at System.se + (0, .075i) rjust
X
X#ifdef figure1
Xarrow from Userlevel.s to System.n
X#else
Xarrow from System.n + (0, .3i) to System.n
X#endif
Xboxht = .3i
Xboxwid = 1.5i
XSysinterface: box "Syscall Interface" dashed .02i with .n at System.n
X
Xboxht = .3i
Xboxwid = .8i
Xmovewid = .2i
XRwuio: box "rwuio()" with .w at System.w + (.1i, 0); move
XCopen: box "copen()"
X
Xmovewid = (-.2i)
XEtc: box "..." with .e at System.e - (.1i, 0)
XStat1: box "stat1()" with .e at Etc.w - (.2i, 0)
X
Xarrow from Sysinterface.s to Copen.n
X#ifdef figure1
Xarrow from Sysinterface.s to Rwuio.n
Xarrow from Sysinterface.s to Etc.n
Xarrow from Sysinterface.s to Stat1.n
X#endif
X
X#ifdef figure1
XNamei: box "namei()" at System.c - (0, .4i)
X#endif
X#ifdef figure2
XNamei: box "namei()" at System.c - (0, .4i)
X#endif
X#ifdef figure3
XNamei: box wid 1.8*boxwid ht 2.5*boxht at System.c - (0, .5i)
X"namei()" at Namei above
XRemotecheck: box wid 1.15*boxwid ht 1.3*boxht with .se at Namei.se
X"check for" at Remotecheck above
X"``remoteness''" at Remotecheck below
X#endif
X
Xspline -> right .4i from Copen.e then to Namei.n - (.1i, 0)
X#ifdef figure1
Xspline -> left .4i from Stat1.w then to Namei.n + (.1i, 0)
Xspline -> down .2i from Etc.s + (.025i, 0) then to Namei.e
X#endif
Xboxht = 1i
Xboxwid = 3i
X
XDevices: box dashed with .n at System.s - (0, .3i)
X"\s+4Device Drivers\s-4" at Devices.se + (0, .075i) rjust
Xboxht = .5i
Xboxwid = 1i
X
X#ifdef figure1
XDisk: box dashed .02i with .n at Devices.n
X#endif
X
X#ifdef figure2
XDisk: box dashed .02i with .ne at Devices.ne - (.2i, 0)
XPseudo: box dashed .02i with .nw at Devices.nw + (.2i, 0)
X"Pseudo\-Disk" at Pseudo above
X"Interface" at Pseudo below
X#endif
X
X#ifdef figure3
XDisk: box dashed .02i with .ne at Devices.ne - (.2i, 0)
XNet: box dashed .02i with .nw at Devices.nw + (.2i, 0)
X"Network" at Net above
X"Connection" at Net below
X#endif
X
X"Disk" at Disk above
X"Interface" at Disk below
X
X#ifdef figure1
Xarrow from Rwuio.s to Disk.n - (.025, 0)
Xarrow from Namei.s to Disk.n + (.025, 0)
X#endif
X#ifdef figure2
Xarrow from Rwuio.s to Pseudo.n - (.025, 0)
Xarrow from Namei.s to Pseudo.n + (.025, 0)
X#endif
X#ifdef figure3
Xarrow from Rwuio.s to Net.n - (.033, 0)
Xarrow from Copen.s to Net.n
Xarrow from Namei.s to Disk.n + (.025, 0)
X#endif
X.PE
X.ce
X#ifdef figure1
X\fIFigure 1\fP
X#endif
X#ifdef figure2
X\fIFigure 2\fP
X#endif
X#ifdef figure3
X\fIFigure 3\fP
X#endif
X.SP
X.KE
SHAREOF
chmod 664 remote/doc/paper/fig1
#
# remote/doc/paper/fig1.mag
#
if [ -f remote/doc/paper/fig1.mag ]; then 
	echo -n 'Hit <return> to overwrite remote/doc/paper/fig1.mag or ^C to quit' 
	read ans 
	rm -f remote/doc/paper/fig1.mag 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/doc/paper/fig1.mag
SHAREOF
chmod 644 remote/doc/paper/fig1.mag
#
# remote/doc/paper/fig4
#
if [ -f remote/doc/paper/fig4 ]; then 
	echo -n 'Hit <return> to overwrite remote/doc/paper/fig4 or ^C to quit' 
	read ans 
	rm -f remote/doc/paper/fig4 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/doc/paper/fig4
X.KF
X.if "\*(.T"mag" \{\
X.	nr PS 12
X.	nr VS 14
X.	ps \n(PS
X.	vs \n(VS
X.\}
X.PP
X.PS
Xboxht = .3i
Xboxwid = .8i
Xmovewid = .2i
XSyscalls: [
X	A: box "read()"; move
X	B: box "open()"; move
X	C: box "stat()"; move
X	D: box "..."
X]
Xboxwid = last [].wid
XRemotecheck: box with .nw at Syscalls.A.sw - (0, .15i)
X"check for ``remoteness''" at Remotecheck
X
Xboxht = last [].ht+1.2i
Xboxwid = last [].wid+.1i
XUserlevel: box dashed with .n at last [].n + (0i, .3i)
Xarrow from Syscalls.A.s to (Syscalls.A.s.x, Remotecheck.n.y)
Xarrow from Syscalls.B.s to (Syscalls.B.s.x, Remotecheck.n.y)
Xarrow from Syscalls.C.s to (Syscalls.C.s.x, Remotecheck.n.y)
Xarrow from Syscalls.D.s to (Syscalls.D.s.x, Remotecheck.n.y)
Xarrow from Remotecheck.s to Userlevel.s - (0, .3i)
X"\s+4A User's Program\s-4" at Userlevel.se + (0, .075i) rjust
X.PE
X.ce
X\fIFigure 4\fP
X.SP
X.KE
SHAREOF
chmod 664 remote/doc/paper/fig4
#
# remote/doc/paper/fig5
#
if [ -f remote/doc/paper/fig5 ]; then 
	echo -n 'Hit <return> to overwrite remote/doc/paper/fig5 or ^C to quit' 
	read ans 
	rm -f remote/doc/paper/fig5 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/doc/paper/fig5
X.DS
X.if "\*(.T"mag" \{\
X.	nr PS 12
X.	nr VS 14
X.	ps \n(PS
X.	vs \n(VS
X.\}
X.PS
Xboxht = boxht/2
Xboxwid = boxwid*2
XProto: [
X	A: box "request"
X	B: box "response" with .n at last box.s - (0, .1)
X	C: box "request" with .n at last box.s - (0, .1)
X	D: box "response" with .n at last box.s - (0, .1)
X	E: box "..." with .n at last box.s - (0, .1)
X]
XLocal: box "Local Host" with .e at last [].w - (1i, 0)
XRemote: box "Remote Host" with .w at last [].e + (1i, 0)
Xarrow from Local.e to Proto.A.w
Xarrow from Local.e to Proto.C.w
Xarrow from Local.e to Proto.E.w
Xarrow from Remote.w to Proto.B.e
Xarrow from Remote.w to Proto.D.e
X.PE
X.DE
SHAREOF
chmod 664 remote/doc/paper/fig5
#
# remote/doc/paper/fig6
#
if [ -f remote/doc/paper/fig6 ]; then 
	echo -n 'Hit <return> to overwrite remote/doc/paper/fig6 or ^C to quit' 
	read ans 
	rm -f remote/doc/paper/fig6 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/doc/paper/fig6
X.DS
X.if "\*(.T"mag" \{\
X.	nr PS 12
X.	nr VS 14
X.	ps \n(PS
X.	vs \n(VS
X.\}
X.PS
Xboxht = boxht/2
Xboxwid = boxwid*2
XProto: [
X	A: box "read request"
X	B: box "read response" with .n at last box.s - (0, .1)
X	C: box "read request" with .n at last box.s - (0, .1)
X	D: box "read response" with .n at last box.s - (0, .1)
X	E: box "continue" with .n at last box.s - (0, .1)
X	F: box "read response" with .n at last box.s - (0, .1)
X	G: box "read response" with .n at last box.s - (0, .1)
X	H: box "..." invis with .n at last box.s - (0, .1)
X	I: box "stop \fIn\fP" with .n at last box.s - (0, .1)
X	J: box "read response" with .n at last box.s - (0, .1)
X	K: box "read response" with .n at last box.s - (0, .1)
X	L: box "..." invis with .n at last box.s - (0, .1)
X	M: box "acknowledge" with .n at last box.s - (0, .1)
X]
XLocal: box "Local Host" with .e at last [].w - (1i, 0)
XRemote: box "Remote Host" with .w at last [].e + (1i, 0)
Xarrow from Local.e to Proto.A.w
Xarrow from Local.e to Proto.C.w
Xarrow from Local.e to Proto.E.w
Xarrow from Local.e to Proto.I.w
Xarrow from Remote.w to Proto.B.e
Xarrow from Remote.w to Proto.D.e
Xarrow from Remote.w to Proto.F.e
Xarrow from Remote.w to Proto.G.e
Xarrow from Remote.w to Proto.J.e
Xarrow from Remote.w to Proto.K.e
Xarrow from Remote.w to Proto.M.e
X.PE
X.DE
SHAREOF
chmod 664 remote/doc/paper/fig6

sources-request@panda.UUCP (01/09/86)

Mod.sources:  Volume 3, Issue 78
Submitted by: tektronix!tekcrl!toddb

#!/bin/sh
#
# RFS, a kernel-resident remote file system.  Shar 2 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/doc/paper/remotefs
#	remote/doc/remotename.2
#	remote/doc/remoteon.2
#	remote/doc/rfs_server.8
#	remote/doc/rmtmnt.8
#	remote/file.c
#	remote/fileserver.c
#	remote/find.c
#	remote/info.c
#	remote/init.c
#
# remote/doc/paper/remotefs
#
if [ -f remote/doc/paper/remotefs ]; then 
	echo -n 'Hit <return> to overwrite remote/doc/paper/remotefs or ^C to quit' 
	read ans 
	rm -f remote/doc/paper/remotefs 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/doc/paper/remotefs
X.HS I
X.if "\*(.T"mag" \{\
X.	nr PS 12
X.	nr VS 14
X.\}
X.pl 9.75i
X.TR
X.DR
X.de CN
X..
X.TL
XDesign Considerations for Remote File Systems
X(Extended Abstract)
X.AU
XT. Brunhoff
X.AI
XComputer Environments Group
XApplied Research Group
XTektronix, inc.
X.AB
XThere have been several remote file systems written,
Xincluding one written by the author called \fBRemotefs\fR.
XThis paper covers the design choices
Xthat can be made at several software levels,
Xfrom where the hooks for a remote file system
Xlie in the operating system,
Xon up to the user interface,
Xand reveals those made by \fBRemotefs\fP.
XThe reader should have a strong familiarity
Xwith the 4.2 BSD kernel function \fInamei()\fP,
Xthe concept of mount points,
Xthe system call interface and
Xthe 4.2 BSD socket paradigm.
X.AE
X.SH
XHistory
X.PP
XThe Computer Research Labs within the Applied Research Group
Xhas approximately forty-five internally\-designed workstations,
Xcalled
X.I Magnolias,
Xtwenty newly announced Tektronix 4404 AI workstations,
Xcalled \fIPegasus\fP, a
X.I VAX 11/780
Xand a
X.I VAX 11/750.
XThe Computer Environments Group,
Xwithin the Computer Research Labs
Xcares for most of these machines and the software that runs on them.
X.PP
XAfter porting 4.2 BSD Unix to the
X.I Magnolia,
Xthe amount of software available quickly outgrew
Xthe capacity of its 35-megabyte winchester drives.
XTo alleviate this,
Xthe author designed and began in December of 1984 to write a
Xremote file system based on a implementation paradigm used
Xby K. McKusick in his implementation of the 4.2 BSD file system;
Xi.e., "write it in user-mode to fit in the kernel".
XThis paper is in part
Xabout that implementation,
Xand about design and
Ximplementation in general to achieve a remote (or distributed) file system.
XAt this writing,
Xthe design still lies mostly in the user level,
Xlinked in by the \fBld(1)\fP flag
X\fI\-lremote\fP,
Xwith a few new system calls.\(dg
X.FS \(dg
XThis remote file system,
Xknown simply as \fBRemotefs\fP,
Xshould not be confused with another,
Xmore complete remote file system,
Xcalled \fBDFS\fR.
XThe latter is available on the Tektronix 6000 series workstations.
X.FE
X.NH 1
XChoosing a Springboard for the Software
X.PP
XThe focus of I/O activity on 
X.B UNIX
Xis the inode;
Xeach time a file is open, read, written, locked, closed, etc.,
Xthe inode is referred to.
XThese system calls
Xconverge on the system call interface which dispatches calls to
Xthe appropriate internal routine.
XAny system calls that involve a path name must call \fInamei()\fP
Xfor the inode information, and similarly, any system calls that
Xdeal with file descriptors must refer to the inode information
Xgenerated by an \fIopen()\fP or \fIcreate()\fR.
XOnly then can the data on the disks be accessed.
X.so fig1.\*(.T
X.PP
XFor example, in Figure 1,
X\fIopen()\fP makes a request to the system call interface;
Xthe system call interface determines that the \fIopen()\fP system call must
Xbe executed (the kernel \fIopen()\fP is just a call to \fIcopen()\fP).
X\fICopen()\fP then calls \fInamei()\fP to get the inode information
Xwhich in turn calls the appropriate disk device driver to get the inode
Xfrom the correct disk.
XSubsequent \fIread()\fP
Xor \fIwrite()\fP calls use this information to access the disk.
XIt makes sense to make \fInamei()\fP the focal point for the remote
Xfile system implementation
Xbecause of its critical role.
XBut there are other approaches.
X.NH 2
X\&\.\.\. From the Device Driver
X.PP
XSince \fInamei()\fP gets its information from the
Xdisk via the disk driver,
Xwe have only to
Xreplace the disk driver with a \fIremote\fP disk driver.
XThis remote disk driver would be designed to send requests for disk
Xblocks directly to a remote host to be satisfied
Xfrom a single partition on its own disk.
X.so fig2.\*(.T
X.PP
XNow, following the previous example in Figure 2,
X\fInamei()\fP may instead encounter a mount point while
Xtrying to find an inode for a file,
Xand will get its inode information from the remote disk driver.
XSimilarly,
Xreads and writes
Xrequest blocks from the \fIremote\fP disk driver
Xusing this inode information.
X.PP
XThis is where early implementations put remote file systems.
XIt offers speed and a good deal of portability with
Xthe kernel changes limited to the device driver,
Xbut it limits usefulness because each partition
Xon every remote system must be mounted,
Xand access can only be read\-only.
X.NH 2
X\&\.\.\. In \fInamei()\fP
X.PP
XThere are two ways of checking for ``remoteness''
Xin \fInamei()\fP,
Xbut the key change to \fInamei()\fP is that it must fail in
Xits inode lookup when it encounters a path name component
Xon a remote machine; then it must return with a special error.
XThis \fInamei()\fP failure mechanism will be alluded to later.
X.PP
XOne method, depicted in Figure 3,
Xis to catch any reference to a special
Xsyntax of path name,
Xsuch as \fI/\.\.\|/host/pathname\fP,
X\fI/net/host/pathname\fP
Xor \fI//host/pathname\fP.
XThis is a cue to \fInamei()\fP
Xto return a special error code to the invoking system call.
XIt is then
Xthe responsibility of that system call to send
Xa request to a server on the remote host.
XThis special syntax is very convenient because the
X\fIhost\fP component of the path
Xneed not correspond to some existing ``mount point''.
XHence, hosts can be mounted and unmounted on demand
Xif the implementor cares to take the trouble.
X.so fig3.\*(.T
X.PP
XA second strategy is very similar
Xexcept that it uses a more natural
Xsyntax of \fI/host/pathname\fP
X(without needing symbolic links).
XAn important point is that the host cannot be ``mounted''
Xon a directory,
Xbut rather on a special mount point,
Xor even a plain file.
XThe reason for this is a bit obscure,
Xbut will be clarified shortly.
X.PP
XThe special path names like \fI/\.\.\|/host/pathname\fP
Xor mount points like \fI/host\fP are needed partly because no
XUNIX program should ever find these gateways through normal perusal of
Xa file system.
XImagine how long the command ``\fIfind / -print\fP'' would take
Xif it traversed every remote host as well as itself!
XFor this reason, using a directory for a mount point would
Xnot be appropriate.
X.PP
X\fBRemotefs\fP uses a plain file as a mount point because of some extra
Xbenefits:
Xthe simplicity of the code changes to \fInamei()\fP,
Xand not having to add another file type for \fBUNIX\fP utilities to learn.
XThe path name \fI/host\fP remains a valid local filename,
Xbut \fI/host/\fP or anything longer results in
Xa special case, which \fInamei\fP labels with the error
X\fBENOTDIR\fP
X(See Appendix A).
XIt is this place in the \fBUNIX\fP kernel
Xthat \fBRemotefs\fP detects all remote file references.
X.NH 3
XAn Aside: When to Follow a Symbolic Link in \fINamei()\fP.
X.NH 2
X\&\.\.\. At the User Level.
X.PP
XA slight variation of the above,
Xshown in Figure 4,
Xis to simply place the check for ``remoteness'' in
Xappropriate system calls with in the C runtime library,
X\fIlibc.a\fP.
X(see Appendix B for this list).
XUnfortunately,
Xthis requires the user level software to duplicate
Xwhat \fInamei()\fP does
Xwhenever a system call involving a path name returns the
Xerror \fBENOENT\fR or \fBENOTDIR\fR.
XThis implementation approach is typically slower,
Xbut very portable.
X.so fig4.\*(.T
X.NH 1
XFile Descriptors
X.PP
XOnce an \fIopen()\fP or \fIcreat()\fP has succeeded
Xon the remote host and returned a file descriptor, say \fIi\fP,
Xwe must allocate a real file descriptor, \fIj\fP, on the local machine.
XThis may be done in the kernel or user level code,
Xbut it is most important that the user's idea of the ordinate
Xvalue of \fIj\fP remain inviolate.
X.NH 2
XFile Descriptors Handled at User Level
X.NH 2
XFile Descriptors Handled at Kernel Level
X.NH 2
XInheriting File Descriptors Across a \fIfork()\fP or \fIexec()\fP
X.NH 2
XReading Directories on a Remote Host
X.NH 1
XChanging Directories
X.PP
XImplementing the ability to change
Xdirectories is a big win for any implementation
Xbecause interactive shells will then allow you to
Xperuse directories on remote hosts.
XHowever, inheritance of file descriptors must
Xbe implemented,
Xas explained in section 2.3.
XThe \fIchdir()\fP executing on the remote host
Xdoes nothing special.
XIf it succeeds, all is well.
XBut on the local side,
Xthe software cannot change state (the current
Xworking directory)
Xto match what has occurred on the remote machine.
XInstead,
Xit must simply be remembered it in some way.
X.NH 2
XInterpreting Pathnames
X.PP
XIf the remote file system software lies entirely in user\-level code,
Xthen the only solution is for the software
Xto remember \fIchdir()\fP's path name argument
Xand that the current directory is on a remote host.
XThen when a new path name is passed to a system call,
Xthe software need only to check to see if it is absolute
Xor relative (with or without a leading '/' character, respectively).
XIf it is relative,
Xthen the request must be sent to the remote host.
X.PP
XOn the other hand if the software uses a special
Xmount point like \fI/host\fP,
Xthe kernel can arrange
Xto make the process's working directory inode
Xto be the mount point's inode.
XThis is very convenient because no absolute vs. relative
Xchecks are necessary
Xand nothing need be added to \fInamei()\fP.
XFor example,
Xabsolute path names in a system call will still cause the mechanism
Xto function normally.
XAnd relative path names will immediately fail in \fInamei()\fP
X(remember our key change in section 1.2).
XSee Appendix A.
X.NH 2
XPwd(1) and Changing to ``/\.\.'' on the Remote Host
X.NH 1
XSpecial Problems
X.NH 2
X\fIExec()\fP
X.NH 2
X\fIFork()\fP and \fIvfork()\fP
X.NH 2
X\fISelect()\fP
X.NH 2
XUniqueness of Files Across Hosts
X.NH 1
XPermissions Across Hosts
X.NH 2
XDatabase Model
X.NH 2
XDynamic Model
X.NH 1
XServer Design
X.NH 2
XWhen to \fIfork()\fP
X.NH 2
XHow to Change Uid/Gid permissions
X.NH 2
XFile Descriptor Overload
X.NH 2
XCommunication Model
X.NH 3
XProtocol
X.NH 3
XWho Answers the Phone?
X.NH 3
XSpeed Improvements
X.PP
XImagine
Xa very loose view of the protocol (moving downward):
X.so fig5.\*(.T
XA remote file system implementation
Xhas a decidedly synchronous flavor to it,
Xand for most system calls,
Xnothing else is appropriate.
XBut \fIRead()\fP and \fIwrite()\fP system calls
Xlend themselves very well to optimization,
Xspecifically, lookahead.
X.PP
XA change in the protocol could be made
Xbased on expected requests.
XAfter,
Xsay, two consecutive \fIread()\fP requests
Xon the same file descriptor for the same number of bytes,
Xthe local host could ask the server to continue servicing
Xthe same request until further notice.
XThe response would contain the same information
Xthat would be expected on a normal request,
Xand would, of course,
Xterminate on an error or end\-of\-file.
XThe remote host, could easily detect and recover from a termination
Xof this kind, too.
XThe difficult part would be for the local host to try to stop
Xthe servicing before end\-of\-file.
XSo,
Xour protocol now would be
X.so fig6.\*(.T
XNotice that the responses may continue on beyond
Xthe request to stop,
Xbut the acknowledgment of the request to stop would put
Xthe hosts back in sync.
XThe remote host has only to reset its read pointer
Xback to the point where it had serviced
X\fIn\fP requests,
Xand the local host must read the responses up to and including
Xthe acknowledgment.
X.PP
XThe protocol also may
Xhave to refuse continuation service for file descriptors
Xthat read from devices.
X.PP
X\fIWrite()\fP is similar,
Xbut recovery when the remote host
Xreaches an end\-of\-file or encounters an error
Xwould be much more complicated, and in some cases impossible.
XThe local host,
Xon receipt of a request to stop from the remote host,
Xwould have to not only reset its idea of the write pointer,
Xbut perhaps the read pointer from which the data was gathered
Xto do the write.
XConsidering that the reading may have been done from multiple
Xfiles or the data was transformed in some way,
Xthe remote file system software may not be able to accomplish the task.
XIt appears to be only feasible if the implementor is willing to sacrifice
Xidentical behavior of user\-level software on remote vs. local file
Xsystems.
X.NH 1
XStatus of \fBRemotefs\fP
X.NH 1
XAppendix A
X.so appendixB.out
X.NH 1
XAppendix C
SHAREOF
chmod 664 remote/doc/paper/remotefs
#
# remote/doc/remotename.2
#
if [ -f remote/doc/remotename.2 ]; then 
	echo -n 'Hit <return> to overwrite remote/doc/remotename.2 or ^C to quit' 
	read ans 
	rm -f remote/doc/remotename.2 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/doc/remotename.2
X.TH REMOTENAME 2 "27 July 1983"
X.UC 4
X.SH NAME
Xremotename \- provide name information to the kernel
X.SH SYNOPSIS
X.nf
X.ft B
X#include <remote/remotefs.h>
X
Xremotename(action, name, namelen, path)
Xlong action;
Xcaddr_t name;
Xlong namelen;
Xchar *path;
X.fi
X.SH DESCRIPTION
X.I Remotename
Xis an interface for an exchange of information with
Xthe kernel about remote hosts.
XThe value of
X.I action,
Xdefined by NM_* symbolic constants in remote/remotefs.h,
Xdetermines what exchange takes place:
X.PP
XNM_SERVER
X.br
XThe current process is registered as the name server for the kernel.
XWhenever the kernel needs a path name translated into
Xan internet address,
Xthe current process will receive the SIGIO signal.
XArguments besides
X.I action
Xare ignored.
XIf there is already a process registered as the name server,
X.I remotename
Xwill fail.
X.PP
XNM_WHATNAME
X.br
XAfter receiving the SIGIO signal,
Xthe registered name server should
Xsupply this action to
X.I remotename
Xalong with a valid
Xcharacter pointer
Xin
X.I name
Xand its length in
X.I namelen.
XThe kernel will copy into that pointer
Xa null\-terminated string of the form "/single-component".
XIt is the name server's job to translate "single-component"
Xinto a valid internet address.
X.PP
XThe kernel obtains the single component from the second component
Xof a path name used in a system call by some user process.
XThe first component of that path name would have been a generic mount
Xpoint.
X.PP
XNM_NAMEIS
X.br
XAfter obtaining a valid internet address,
Xthe registered name server should
Xsupply this action to 
X.I remotename
Xalong with a valid
X.I name
Xand
X.I namelen
Xcontaining the internet address the way that
X.I connect(2)
Xwould expect it,
Xand a
X.I path
Xcontaining the nameserver's opion of what the null-terminated
Xmount point should
Xhave been.
X.PP
XNM_DEBUG
X.br
XTurns on debug level to the value in
X.I system.
X.SH "RETURN VALUE
X.I Remotename
Xreturns 0 if the action occurred, \-1 if
X.I name
Xor
X.I path
Xis an invalid address (when a valid one was expected),
Xor the user is not the super user.
X.SH ERRORS
X.TP 15
X[EPERM]
XThe caller is not the super-user
Xor the calling process is not the registered nameserver.
X.TP 15
X[EINVAL]
X.I Name
Xor
X.I path
Xare not valid addresses (if expected),
X.I namelen
Xis too long or
Xthe
X.I action
Xwas not recognized.
X.TP 15
X[ENOREMOTEFS]
XOn
X.I NM_WHATNAME
Xthere was no pathname for which the kernel needed a internet address.
X.TP 15
X[EBUSY]
XThe calling process is trying to register as the nameserver,
Xbut one already exists.
X.SH "SEE ALSO"
Xremoteon(2), remoteoff(2), rmtmnt(8), rfs_server(8)
X.SH BUGS
X.I NM_DEBUG
Xwill not be recognized unless the kernel is has the debug software
Xcompiled in.
SHAREOF
chmod 664 remote/doc/remotename.2
#
# remote/doc/remoteon.2
#
if [ -f remote/doc/remoteon.2 ]; then 
	echo -n 'Hit <return> to overwrite remote/doc/remoteon.2 or ^C to quit' 
	read ans 
	rm -f remote/doc/remoteon.2 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/doc/remoteon.2
X.TH REMOTEON 2 "27 July 1983"
X.UC 4
X.SH NAME
Xremoteon, remoteoff \- turn on and off remote file system
X.SH SYNOPSIS
X.nf
X.ft B
Xremoteon(path, pathlen, name, namelen)
Xchar *path;
Xint pathlen;
Xstruct sockaddr *name;
Xint namelen;
X.PP
X.ft B
Xremoteoff(path)
Xchar *path;
X.fi
X.SH DESCRIPTION
X.I Remoteon
Xannounces to the system that the file system
Xstarting with the root, aka "/", on the internet host
X.I name
Xhas been mounted on
Xthe plain file
X.I path;
Xfrom then on, references to any files below
X.I path
Xwill refer to
Xfiles below the root file system on the remote host,
X.I name.
X.I Path
Xis a pointer to a null-terminated string
Xcontaining the appropriate path name,
Xbut for storage purposes in the kernel,
X.I pathlen
Xmust also be provided.
X.I name
Xcan only be a valid internet address (this may be extended later),
Xand
X.I namelen
Xshould be the correct length,
Xnormally
X.I sizeof(struct sockaddr_in).
X.PP
X.I Path
Xmust exist already and be
Xa plain file.
XIts old contents
Xare still accessible while the remote file system
Xis mounted,
Xbut the file cannot be removed.
X.PP
XA special case for
X.I remoteon
Xand
X.I remoteoff
Xis when
X.I path
Xis a null pointer.
XThis tells the kernel to disallow
X.I (remoteoff)
Xor allow
X.I (remoteon)
Xremote access for the current
Xprocess,
Xand is intended primarily for use with a remote file server
Xto prevent remote file system loops.
XBy default,
Xall processes are allowed remote access.
XNote that while only the super-user may turn on or off the remote
Xfile system,
Xany user may turn on and off remote access for himself.
X.PP
X.I Remoteoff
Xannounces to the system that the
X.I path
Xfile is no longer to be a remote mount point.
XCurrently,
Xeven if
X.I remoteoff
Xfails,
Xthe remote file system is marked for closing and
Xno more usage is allowed.
XSystem calls that must be run on the remote system after
Xthis point will fail (return \-1).
X.SH "RETURN VALUE
X.I Remoteon
Xreturns 0 if the action occurred, \-1 if
X.I path
Xis inaccessible,
Xalready a remote mount point, not an appropriate file, if
X.I path
Xdoes not exist,
Xor if there are already too many remote file systems mounted.
X.PP
X.I Remoteoff
Xreturns 0 if the action occurred; \-1 if
Xif the file is inaccessible or
Xdoes not point to a remote file system,
Xor if there are active processes using the remote 
Xfile system.
X.SH ERRORS
X.I Remoteon
Xwill fail when one of the following occurs:
X.TP 15
X[EPERM]
XThe caller is not the super-user.
X.TP 15
X[ENOENT]
X.I Special
Xdoes not exist.
X.TP 15
X[EISDIR]
X.I Path
Xis not a plain file.
X.TP 15
X[EINVAL]
X.I Namelen
Xis too long.
X.TP 15
X[ENOBUFS]
Xthe system is out of mbuf structures.
X.TP 15
X[EFAULT]
X.I Name
Xpoints to a bad address.
X.TP 15
X[ETOOMANYREMOTE]
XThe action would overflow internal tables.
X.TP 15
X[EBUSY]
X.I Path
Xis already a remote mount point.
X.PP
X.I Remoteoff
Xmay fail with one of the following errors:
X.TP 15
X[EPERM]
XThe caller is not the super-user.
X.TP 15
X[ENOENT]
X.I Path
Xdoes not exist.
X.TP 15
X[EBUSY]
XA process is holding a reference to the remote file system.
X.SH "SEE ALSO"
Xrmtmnt(8), rfs_server(8)
SHAREOF
chmod 664 remote/doc/remoteon.2
#
# remote/doc/rfs_server.8
#
if [ -f remote/doc/rfs_server.8 ]; then 
	echo -n 'Hit <return> to overwrite remote/doc/rfs_server.8 or ^C to quit' 
	read ans 
	rm -f remote/doc/rfs_server.8 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/doc/rfs_server.8
X.TH RFS_SERVER 8  "18 October 1985"
X.UC 4
X.SH NAME
Xrfs_server \- remote file system server and kernel name server
X.SH SYNOPSIS
X.B /etc/rfs_server
X[ -s internet-service ]
X[ -v debug-level ]
X.SH DESCRIPTION
XThis is a server for the remote file system and
Xis intended to be started up in /etc/rc.
X.PP
X.PP
XThe optional flag
X.I \-s
Xand its argument,
X.I internet-service,
Xtells the server to accept calls on the named service
Xport described in /etc/services.
XWithout this argument, 
X.I rfs_server
Xuses the service
X.I remotefs.
X.PP
XThe optional flag
X.I \-v
Xand its argument,
X.I debug-level,
Xstarts up the server with the given initial debug level.
XThe argument should be a hexadecimal number containing one bit
Xfor each class of debug output desired.
X.PP
XThe server maintains three identities,
Xand each can be determined by the current command line using the
X.I ps(1)
Xcommand.
X.PP
XThe first identity is the
X.I sentry
Xof which there can only be one at any time.
XThe command line for this remains unaltered from the way it was started.
XThe function of the
X.I sentry
Xserver is to build a database of all hosts in /etc/hosts,
Xall users and groups in /etc/passwd and /etc/group,
Xand of all users' .rhost files.
XAfter this database has been built,
Xit waits 
Xfor connections from remote hosts.
X.PP
XThe second identity is a
X.I "gateway server"
Xand changes its command line
Xto tell which host it is a
X.I "gateway server"
Xfor.
XThis identity is the child of the
X.I sentry
Xafter the latter receives a connection from a remote host;
Xthere can only be one
X.I "gateway server"
Xfor each remote host.
XThe responsibilities of the
X.I "gateway server"
Xare to service context-free system calls for the remote host,
Xcreate other servers to handle context-sensitive system calls,
Xmaintain complete information about all remote processes being served,
Xand ensure at all times
Xthat only one server has control of the socket file
Xdescriptor to the remote machine being served.
X.PP
XThe third identity is that of a plain
X.I server,
Xand changes its command line to be similar to that
Xof the
X.I "gateway server"
Xexcept that the word
X.I gateway
Xis missing and it identifies its parent process.
XIts responsibilities
Xare to service context-free system calls for the remote host and
Xcreate other servers for remote processes that must inherit
Xcertain context information (e.g. remote current working directories,
Xand open file descriptors).
X.SH "DEBUG LEVELS"
XIt should be noted that the debug option is only useful with
Xa copy of the source code in hand and a server that has been
Xcompiled with the debug software turned on.
XThe current selection of the bits are:
X.PP
X.ta 1i 2.5i 4i
X	0x00000001	process switching
X.br
X	0x00000002	system calls
X.br
X	0x00000004	setuid/setgid, umask
X.br
X	0x00000008	file descriptor allocation
X.br
X	0x00000010	connections
X.br
X	0x00000020	server switching
X.br
X	0x00000040	nameserver
X.br
X	0x00000080	directory nuxi
X.br
X	0x00000100	message in and out
X.br
X	0x00000200	don't fork child for gateway (good for adb)
X.br
X	0x00000400	local/remote file decisions
X.br
X	0x00000800	don't remove log file on exit (except exit on error)
X.br
X	0x00001000	exec information
X.br
X	0x00002000	auto debug for 0x20 (server switching)
X.br
X	0x00004000	parsing messages to gateway
X.PP
XAnother method of setting the debug level in any identity of the
X.I rfs_server
Xis to place the desired hexidecimal level in the file /usr/tmp/rfs_debug
Xand to send the appropiate server signal number 5, aka
X.I SIGTRAP.
XThis method can be used with
X.I sentry
Xservers, any
X.I gateway
Xservers, and any other servers that are marked active.
XIt should not be used on sleeping servers.
X.PP
XIf any server receives SIGILL, SIGSEGV or SIGBUS,
Xit will arrange for its core file to be dumped in /usr/tmp.
X.SH "RESTARTING THE SERVER"
XThe best way to restart the
X.I sentry
Xserver (e.g. installing a new
X.I rfs_server),
Xis to simply run the new server.
XThe new server knows how to examine the previous log file
Xto discover the pid number of the previous server, and kill it.
X.PP
XIf you know that that will fail, then the second best way
Xis to send it the signal
X.I SIGTERM
X.PP
XSending
X.I SIGTERM
Xsignal to a
X.I "gateway server"
Xwill cause it and all of its children to gracefully go away.
X.SH "SEE ALSO"
Xremotename(2),
Xrmtmnt(8).
X.SH BUGS
XProbably.
SHAREOF
chmod 664 remote/doc/rfs_server.8
#
# remote/doc/rmtmnt.8
#
if [ -f remote/doc/rmtmnt.8 ]; then 
	echo -n 'Hit <return> to overwrite remote/doc/rmtmnt.8 or ^C to quit' 
	read ans 
	rm -f remote/doc/rmtmnt.8 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/doc/rmtmnt.8
X.TH RMTMNT 8  "18 October 1985"
X.UC 4
X.SH NAME
Xrmtmnt \- mount and dismount remote file systems
X.SH SYNOPSIS
X.B /etc/rmtmnt
X[ -s internet-service ] host path
X.PP
X.B /etc/rmtmnt
X-g path
X.PP
X.B /etc/rmtmnt
X-u path
X.PP
X.B /etc/rmtmnt
X.SH DESCRIPTION
XIn the first usage,
X.I rmtmnt
Xannounces to the system that the file system
Xstarting with the root, aka "/", on the internet host named
X.I host
Xhas been mounted on
Xthe plain file
X.I path;
Xfrom now on, references to any files below
X.I path
Xwill refer to
Xfiles below the root file system on the remote host,
X.I host.
XThe file
X.I path
Xmust exist already; it must be a file.
XIt becomes the name of the newly mounted root.
X.PP
XThe optional flag
X.I \-s
Xand argument
X.I internet-service
Xindicates that the kernel should use
Xthe named internet service (defined in /etc/services)
Xwhen connecting to that remote host.
X.PP
XThe second usage with the
X.I -g
Xflag indicates that the mount point is to be "generic".
XBy convention,
Xthe name of this path ought to be
X.I /net,
Xbut may be any valid path name.
XNo specific host is associated with the
Xpath name.
XInstead,
Xthe component following
X.I /net
Xis handed to the nameserver, usually
X.I rfs_server(8),
Xfor translation to an internet address.
XWhen the kernel receives the new address,
Xan implicit mount is made by the kernel.
X.PP
XThe third usage with the
X.I -u
Xflag informs the kernel that the internet host
Xmounted on
X.I path
Xshould be unmounted.
X.PP
XThe last usage,
Xhaving no arguments or flags
Xwill print out a complete status of all current mount points.
X.SH "SEE ALSO"
Xremoteon(2),
Xrfs_server(8).
X.SH BUGS
XImlicit mount points cannot be unmounted.
X.PP
XIf a command which has a current working directory
Xon a remote machine through an
X.I implicit
Xmount point
Xattempts to find the current working directory,
Xit will produce a pathname missing the second component,
Xand, hence, will fail.
XExplicit mount points work fine.
SHAREOF
chmod 664 remote/doc/rmtmnt.8
#
# remote/file.c
#
if [ -f remote/file.c ]; then 
	echo -n 'Hit <return> to overwrite remote/file.c or ^C to quit' 
	read ans 
	rm -f remote/file.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/file.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:	file.c,v $
X * Revision 2.0  85/12/07  18:21:11  toddb
X * First public release.
X * 
X */
Xstatic char	*rcsid = "$Header: file.c,v 2.0 85/12/07 18:21:11 toddb Rel $";
X#include	"server.h"
X#include	<errno.h>
X
Xextern int	fds_in_use;
Xextern int	errno;
X
X/*
X * here we allocate a file descriptor to a process and make note of our
X * total number of open file descriptors.  'fd' is the file descriptor
X * that the server itself got back, and remotefd is the file descriptor
X * that the remote process is expecting.
X */
Xallocate_fd(fd, proc, remotefd)
X	register int	fd,
X			remotefd;
X	register process	*proc;
X{
X	if (fd != -1)
X	{
X		proc->p_fds[ remotefd ] = fd;
X		debug3("allocate local fd %d, remote fd %d\n",
X			fd, remotefd);
X		fds_in_use++;
X		checkfiletype(fd);
X	}
X	else
X		remotefd = -1;
X	return(remotefd);
X}
X
Xdeallocate_fd(proc, remotefd)
X	register process	*proc;
X	register long	remotefd;
X{
X	register char	fd;
X	register long	retval;
X
X	if ((unsigned)remotefd >= NOFILE)
X	{
X		errno = EBADF;
X		return(-1);
X	}
X	fd = proc->p_fds[ remotefd ];
X	proc->p_fds[ remotefd ] = -1;
X	retval = close(fd);
X	fds_in_use--;
X	return(retval);
X}
SHAREOF
chmod 444 remote/file.c
#
# remote/fileserver.c
#
if [ -f remote/fileserver.c ]; then 
	echo -n 'Hit <return> to overwrite remote/fileserver.c or ^C to quit' 
	read ans 
	rm -f remote/fileserver.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/fileserver.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:	fileserver.c,v $
X * Revision 2.0  85/12/07  18:21:14  toddb
X * First public release.
X * 
X */
Xstatic char	*rcsid = "$Header: fileserver.c,v 2.0 85/12/07 18:21:14 toddb Rel $";
X#include <errno.h>
X#include <stdio.h>
X#include <ctype.h>
X#include <signal.h>
X#include "server.h"
X#include <sys/file.h>
X
Xextern long	errno;
Xextern long	from_servers;
Xextern long	to_gateway;
Xextern long	so_listen;
Xextern long	blocking_servers;
Xextern short	gateway_server;
Xextern short	current_ppid;
Xextern short	current_pid;
Xextern short	current_uid;
Xextern short	current_server;
Xextern char	mntpt[ MAXPATHLEN ];
Xextern char	*program;
Xextern char	*last_argaddr;
Xextern char	*logfile;
Xextern char	*service;
Xextern char	*syscallnames[];
Xextern boolean	i_am_gateway;
Xextern boolean	i_am_asleep;
Xextern boolean	i_have_control;
Xextern boolean	route_to_gateway;
Xextern boolean	watch_for_lock;
Xextern boolean	gateway_needs_control;
Xextern syscallmap	smap[];
Xextern process	*wildcard;
Xextern hosts	*host;
X
Xmain(argc, argv)
X	int argc;
X	char **argv;
X{
X	register hosts	*h;
X
X	setopts(argc, argv);
X	if ((remote_debug & 0x200) == 0 && fork())
X		exit(0);
X	current_pid = getpid();
X	setlogfile();
X	if ((so_listen = tcppassive()) < 0)
X		log_fatal("cannot open socket\n");
X	init();
X	for (;;)
X	{
X		if ((h = tcpaccept(so_listen)) == NULL)
X			break;
X		debug4("call on fd %d, portno %d, from host \"%s\"\n",
X			h->h_cmdfd, h->h_portnum, h->h_names[0]);
X		dumphost(h);
X		if (server(h))
X			exit(0);
X	}
X}
X
X/*
X * This is the top lexical level for the server.  We decide here
X * when to call for a next request and whether we are running the
X * new format remote fs or not.
X *
X * We also decide whether this is a connection from the mount program
X * on a remote host or not.  If it is, then we just want to assemble the
X * info that it gives us and not become a child server.
X */
X
Xserver(h)
X	register hosts	*h;
X{
X	long		pipefd[ 2 ];
X	struct message	msgbuf,
X			*getmsg();
X	register struct message	*msg = &msgbuf;
X	register process	*proc;
X	register long	cmd, len;
X
X	/*
X	 * Get the first message from this connection.
X	 */
X	alarm(5);
X	if (! (msg = getmsg(h->h_cmdfd)))
X	{
X		log("connection initiation lost to \"%s\"\n", h->h_names[0]);
X		close(h->h_cmdfd);
X		h->h_cmdfd = -1;
X		alarm(0);
X		return(FALSE);
X	}
X	alarm(0);
X
X	/*
X	 * may be a special command
X	 */
X	len = msg->m_hdlen;
X	if (msg->m_syscall == RSYS_nosys)
X	{
X		cmd = msg->m_args[0];
X		debug5("new client; cmd=%d\n", cmd);
X		switch(cmd) {
X		case CMD_SERVICE:
X			break;
X		case CMD_MOUNT:
X			gobble_last_msg(h->h_cmdfd, msg);
X			getbyteorder(h);
X			getrusers(h);
X			return(FALSE);
X		case CMD_NEEDMOUNT:
X			sendmount(h);
X			dont_gobble_msg(msg);
X			return(FALSE);
X		default:
X			log_fatal("unknown server directive = %d\n", cmd);
X		}
X	}
X	else
X	{
X		debug5("new client, not mounted by rmtmnt\n");
X		dont_gobble_msg(msg);
X		if (!h->h_mounted)
X			getmount(h);
X	}
X
X	/*
X	 * If we reach this point, then we are to be the gateway server.
X	 * There may ba a server still running.  Kill it.
X	 */
X	if (h->h_serverpid)
X		sendsig(h->h_serverpid, SIGTERM);
X
X	if ((remote_debug & 0x200) == 0 && vfork())
X	{
X		wait(0);
X		/*
X		 * we are the parent... just return.
X		 */
X		close(h->h_cmdfd);
X		h->h_cmdfd = -1;
X		return(FALSE);
X	}
X	else if ((remote_debug & 0x200) == 0 && (h->h_serverpid = fork()))
X		exit(0);
X	host = h;
X	wildcard->p_handler = gateway_server = current_pid = getpid();
X	set_label("active");
X	if ((remote_debug & 0x200) == 0)
X	{
X		setlogfile();
X		close(so_listen);
X	}
X	if (pipe(pipefd) < 0)
X		log_fatal("Can't open pipe\n");
X	from_servers = pipefd[ 0 ];
X	to_gateway = pipefd[ 1 ];
X
X	/*
X	 * Ok, now be a server!
X	 */
X	for(;;)
X	{
X		if (i_am_gateway && ! i_have_control)
X		{
X			gateway_listen();
X			continue;
X		}
X		/*
X		 * The gateway may be waiting for control.  Let's see.
X		 */
X		if (watch_for_lock)
X			if (gateway_needs_control
X			|| flock(2, LOCK_NB | LOCK_SH) < 0)
X			{
X				debug5("gateway wants control\n");
X				reroute(gateway_server, msg);
X				continue;
X			}
X			else
X				flock(2, LOCK_UN);
X			
X		if ((msg = getmsg(host->h_cmdfd)) == NULL)
X			break;
X		proc = change_to_proc(msg);
X		if (proc == NULL)
X			continue;
X
X		errno = 0;
X		(*smap[ msg->m_syscall ].s_server)(msg, proc);
X	}
X	debug5("done.\n");
X	if (i_am_gateway)
X		for (proc = host->h_proclist; proc; proc=proc->p_next)
X		{
X			/*
X			 * just hand it to the other server... he'll get eof
X			 */
X			if (proc->p_handler != current_pid)
X				sendsig(proc->p_handler, SIGIO);
X		}
X	else
X		say_something(S_EOF, 0);
X	if ((remote_debug & 0x800) == 0)
X		unlink(logfile);
X	return(TRUE);
X}
X
Xsetopts(argc, argv)
X	register int	argc;
X	register char	**argv;
X{
X	register int	error = FALSE;
X	register char	**p;
X	extern char	**environ;
X
X	program = argv[0];
X	last_argaddr = argv[argc-1];
X	for (argv++, argc--; argc; argv++, argc--)
X	{
X		if (**argv != '-')
X		{
X			log("arg \"%s\" is unknown\n",
X				*argv);
X			error = TRUE;
X		}
X		switch(argv[0][1]) {
X		case 'v':
X			if (argv[0][2])
X				remote_debug = atox(argv[0] + 2);
X			else if (isdigit(argv[1][0]))
X				argc--, remote_debug = atox(*(++argv));
X			break;
X		case 's':
X			if (argv[0][2])
X				service = argv[0] + 2;
X			else
X				argc--, service = *(++argv);
X			break;
X		default:
X			log("unknown flag = %s\n", *argv);
X			error = TRUE;
X		}
X	}
X	/*
X	 * Make sure that last_argaddr points to the last possible address
X	 */
X	p = environ;
X	while (*p)
X		p++;
X	if (p != environ)
X		p--;
X	if (*p)
X		last_argaddr = *p;
X	last_argaddr = (char *)ctob(btoc(last_argaddr)) - 1;
X	debug5("program addr=%x, last_argaddr=%x\n", program, last_argaddr);
X
X	if (error)
X		exit(1);
X}
X
X/*
X * ascii to hex
X */
Xatox(buf)
X	char    *buf;
X{
X	register char   *p;
X	register unsigned       num, nibble;
X
X	/*
X	 * now, take it out checking to make sure that the number is
X	 * valid.
X	 */
X	if (! buf)
X		return(0);
X	for(num=0, p = buf; *p; p++)
X	{
X		nibble = *p;
X		if (nibble >= 'A' && nibble <= 'F')
X			nibble -= 'A' - 10;
X		else if (nibble >= 'a' && nibble <= 'f')
X			nibble -= 'a' - 10;
X		else if (nibble >= '0' && nibble <= '9')
X			nibble -= '0';
X		else
X			return(0);
X		num = (num << 4) | nibble;
X	}
X	return(num);
X}
X
X/*
X * fork() and give the process on the top of the list to the child.
X */
Xbecome_server(msg)
X	register struct message	*msg;
X{
X	register long	pid, i;
X	register char	*fds;
X	register process	*proc = host->h_proclist;
X
X	/*
X	 * Have to change to uid 0 or we may be refused a fork
X	 */
X	change_to_uid(0);
X	i_am_asleep = TRUE;
X	if (pid = fork()) /* the parent loses control */
X	{
X		if (pid < 0)
X			log_fatal("cannot fork\n");
X		debug5("new server: pid=%d,mine=%d give him (%d)\n",
X			pid, current_pid, host->h_proclist->p_pid);
X		proc->p_handler = pid;
X		dont_gobble_msg(msg);
X		slumber(TRUE);
X		if (i_am_gateway)
X			current_server = pid;
X		return(FALSE);
X	}
X
X	/*
X	 * If we got this far, then we are no longer the gateway.  So set
X	 * our pid, etc.  Also, try to dup stderr so that flock will work.
X	 * If we can't do it, we are in big trouble.
X	 */
X	current_ppid = current_pid;
X	current_pid = getpid();
X	if (i_am_gateway)
X	{
X		close(from_servers);
X		if (blocking_servers)
X		{
X			watch_for_lock = TRUE;
X			route_to_gateway = TRUE;
X		}
X	}
X	else
X		say_something(S_NEWSERVER, proc->p_pid);
X	i_am_gateway = FALSE;
X	set_label("active");
X	wildcard->p_handler = current_pid;
X	proc->p_handler = current_pid;
X	if ((i = dup(2)) < 0)
X		log_fatal("cannot dup(2)\n");
X	dup2(i, 2);
X	close(i);
X	debug5("new server: pid=%d, ppid=%d\n", current_pid, getppid());
X
X	return(TRUE);
X}
X
X#ifdef RFSDEBUG
Xdumphost(h)
X	register hosts	*h;
X{
X	register rusers	*ruser;
X
X	if ((remote_debug & 0x10) == 0)
X		return;
X	log("host %s, local user = %s, ruser@%x\n",
X		*h->h_names,
X		h->h_default_user ? h->h_default_user->u_name : "default",
X		ruser = h->h_default_ruser);
X	log("\tr %s(%d)-->%s(%d)\n",
X		ruser->r_name, ruser->r_uid,
X		ruser->r_user->u_name, ruser->r_user->u_local_uid);
X	for(ruser = h->h_rusers; ruser; ruser=ruser->r_next)
X		log("\tr %s(%d)-->%s(%d)\n",
X			ruser->r_name, ruser->r_uid,
X			ruser->r_user->u_name, ruser->r_user->u_local_uid);
X}
X#endif RFSDEBUG
X
Xset_label(string)
X	register char	*string;
X{
X	char		process_label[ 100 ];
X	static char	*pend;
X	static short	pid;
X	register char	*pfrom, *pto;
X	register long	i;
X
X	if (pid != current_pid)
X	{
X		if (i_am_gateway)
X			sprintf(process_label, "%s gateway server: ",
X				host->h_names[0]);
X		else
X			sprintf(process_label, "%s server via %d: ",
X				host->h_names[0], pid);
X		pid = current_pid;
X		pend = program + strlen(process_label);
X		strncpy(program, process_label, last_argaddr - program);
X		pto = pend;
X		while (pto < last_argaddr)
X			*pto++ = ' ';
X	}
X	pto = pend;
X	pfrom = string;
X	while (pto < last_argaddr && *pfrom)
X		*pto++ = *pfrom++;
X	for (i=0; pto < last_argaddr && i<10; i++)
X		*pto++ = ' ';
X	if (pto <= last_argaddr)
X		*pto = '\0';
X}
SHAREOF
chmod 444 remote/fileserver.c
#
# remote/find.c
#
if [ -f remote/find.c ]; then 
	echo -n 'Hit <return> to overwrite remote/find.c or ^C to quit' 
	read ans 
	rm -f remote/find.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/find.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:	find.c,v $
X * Revision 2.0  85/12/07  18:21:23  toddb
X * First public release.
X * 
X */
Xstatic char	*rcsid = "$Header: find.c,v 2.0 85/12/07 18:21:23 toddb Rel $";
X#include	"server.h"
X#include	<stdio.h>
X#include	<signal.h>
X
Xextern hosts	*hostlist;
Xextern hosts	*host;
Xextern users	*userlist;
Xextern boolean	i_am_gateway;
Xextern short	current_pid;
X
Xprocess *findprocess(pid, uid)
X	register short	pid;
X	register short	uid;
X{
X	register process	*p;
X	register rusers	*ruser;
X
X	debug0("findproc: ", dumpprocs(host->h_proclist));
X	for(p = host->h_proclist; p; p=p->p_next)
X		if (p->p_pid == pid)
X		{
X			debug0("found pid %d\n", pid);
X			/*
X			 * If the user changes uid, then change with him.
X			 */
X			if (uid >= 0 && uid != p->p_uid)
X			{
X				debug2("pid %d changes uid %d->%d\n",
X					pid, p->p_uid, uid);
X				p->p_uid = uid;
X				if (ruser = findremuid(&host->h_rusers, uid))
X					p->p_ruser = ruser;
X				else
X					p->p_ruser = host->h_default_ruser;
X				debug2(" locally mapped to %s(%d)\n",
X					p->p_ruser->r_user->u_name,
X					p->p_ruser->r_user->u_local_uid);
X			}
X			toplist(&host->h_proclist, p);
X			return(p);
X		}
X	return(NULL);
X}
X
X/*
X * find the user structure whose name is 'name'.
X */
Xusers *findusername(name)
X	register char	*name;
X{
X	register users	*user;
X
X	for(user=userlist; user; user=user->u_next)
X		if (strcmp(user->u_name, name) == 0)
X		{
X			toplist(&userlist, user);
X			return(user);
X		}
X	return(NULL);
X}
X
Xhosts *findhostname(name)
X	register char	*name;
X{
X	register hosts	*h;
X	register int	i;
X	register char	**hnames;
X
X	for(h=hostlist; h; h=h->h_next)
X		for (i=0, hnames=h->h_names; hnames[ i ]; i++)
X			if (strcmp(hnames[ i ], name) == 0)
X			{
X				toplist(&hostlist, h);
X				return(h);
X			}
X	return(NULL);
X}
X
Xhosts *findhostaddr(addr)
X	register struct in_addr	*addr;
X{
X	register hosts	*h;
X
X	debug4("find %s...\n", inet_ntoa(*addr));
X	for(h=hostlist; h; h=h->h_next)
X		if (bcmp(addr, &h->h_addr, sizeof(struct in_addr)) == 0)
X		{
X			toplist(&hostlist, h);
X			debug4("\tis %s (%s)\n",
X				h->h_names[0], inet_ntoa(h->h_addr));
X			return(h);
X		}
X		else
X			debug4("\tnot %s (%s)\n",
X				h->h_names[0], inet_ntoa(h->h_addr));
X	log("no host entry for %s, continuing anyway.\n", inet_ntoa(*addr));
X	/*
X	 * Kludge up a hosts structure for this guy
X	 */
X	h = newhost();
X	h->h_names = newname(NULL, BOGUSHOST);
X	bcopy(addr, &h->h_addr, sizeof(struct in_addr));
X	addlist(&hostlist, h);
X	return(h);
X}
X
Xrusers *findremuid(list, uid)
X	register rusers	**list;
X	register int	uid;
X{
X	register rusers	*ruser;
X
X	for (ruser = *list; ruser; ruser=ruser->r_next)
X		if (ruser->r_uid == uid)
X		{
X			toplist(list, ruser);
X			return(ruser);
X		}
X	return(NULL);
X}
X
X/*
X * find the ruser structure whose name is 'name'.
X */
Xrusers *findrusername(list, name)
X	register rusers	**list;
X	register char	*name;
X{
X	register rusers	*ruser;
X
X	for(ruser = *list; ruser; ruser=ruser->r_next)
X		if (strcmp(ruser->r_name, name) == 0)
X		{
X			toplist(list, ruser);
X			return(ruser);
X		}
X	return(NULL);
X}
X
X#ifdef RFSDEBUG
Xdumpprocs(p)
X	register process	*p;
X{
X	register long	i, fd;
X
X	while(p)
X	{
X		log("proc@%x,pid=%d,uid=%d,next@%x,prev@%x,handler=%d\n",
X			p, p->p_pid, p->p_uid, p->p_next, p->p_prev,
X			p->p_handler);
X		log("\t%s(%d)->%s(%d),fds=",
X			p->p_ruser->r_name, p->p_ruser->r_uid,
X			p->p_ruser->r_user->u_name,
X			p->p_ruser->r_user->u_local_uid);
X		for (i=0; i<NOFILE; i++)
X			if ((fd = p->p_fds[ i ]) >= 0)
X				log("%d->%d ", i, fd);
X		log("\n");
X		p=p->p_next;
X	}
X}
X#endif RFSDEBUG
SHAREOF
chmod 444 remote/find.c
#
# remote/info.c
#
if [ -f remote/info.c ]; then 
	echo -n 'Hit <return> to overwrite remote/info.c or ^C to quit' 
	read ans 
	rm -f remote/info.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/info.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:	info.c,v $
X * Revision 2.0  85/12/07  18:21:28  toddb
X * First public release.
X * 
X */
Xstatic char	*rcsid = "$Header: info.c,v 2.0 85/12/07 18:21:28 toddb Rel $";
X#include	"server.h"
X#include	<stdio.h>
X#include	<sys/wait.h>
X#include	<sys/file.h>
X#include	<sys/stat.h>
X#include	<netdb.h>
X#include	<errno.h>
X
Xextern users	*default_user;
Xextern hosts	*host;
Xextern hosts	*thishost;
Xextern char	byteorder[];
Xextern char	*logfile;
Xextern long	serviceport;
Xextern long	errno;
Xextern short	current_pid;
Xextern process	*wildcard;
Xextern boolean	in_root_directory;
Xextern boolean	i_am_asleep;
X
Xgetbyteorder(h)
X	register hosts	*h;
X{
X	register char	*p;
X
X	/*
X	 * Read the byte order info.
X	 */
X	alarm(5);
X	p = (char *)h->h_byteorder;
X	if (read(h->h_cmdfd, p, 4) != 4)
X	{
X		log("can't read mount info from \"%s\"\n", h->h_names[0]);
X		alarm(0);
X		bzero(p, 4);
X		close(h->h_cmdfd);
X		h->h_cmdfd = -1;
X		return;
X	}
X	alarm(0);
X	if (bcmp(p, byteorder, 4) == 0)
X		h->h_byteorderok = TRUE;
X	else
X		h->h_byteorderok = FALSE;
X	debug4("byteorder=%d,%d,%d,%d: %s ours\n",
X		p[0], p[1], p[2], p[3],
X		h->h_byteorderok ? "same as" : "different than");
X}
X
Xgetrusers(h)
X	register hosts	*h;
X{
X	char	buf[ BUFSIZ ];
X	register rusers	*ruser;
X	register FILE	*input;
X	register char	*p;
X	register int	uid;
X
X	errno = 0;
X	/*
X	 * Read in the users from the remote host and squirrel them away.
X	 * Actually it is the actual password file from the remote
X	 * host, and we ignore most of the info, and save the user name and
X	 * uid.
X	 */
X	if ((input = fdopen(h->h_cmdfd, "r")) == NULL)
X		log_fatal("getrusers: cannot fdopen\n");
X
X	alarm(30);
X	while (fgets(buf, BUFSIZ, input))
X	{
X		/*
X		 * First, the user name.
X		 */
X		for(p=buf; *p && *p != ':'; p++) ;
X		*p = '\0';
X
X		/*
X		 * now the user id number
X		 */
X		for(p++; *p && *p != ':'; p++) ;
X		uid = atoi(p+1);
X
X		/*
X		 * Now we need to add the info to our database on this remote
X		 * host.  If the user is already present, just update the uid
X		 * number.  If the user is not present, and there is a default
X		 * local user for this remote host, use that.  If not, then
X		 * use the default user entry for this host (where the server
X		 * runs).
X		 */
X		if (ruser = findrusername(&h->h_rusers, buf))
X		{
X			debug2("(existing) ");
X			ruser->r_uid = uid;
X		}
X		else
X		{
X			debug2("(new, ");
X			ruser = newruser();
X			ruser->r_name = copy(buf);
X			ruser->r_uid = uid;
X			if (h->h_default_user)
X			{
X				debug2("%s default)", *h->h_names);
X				ruser->r_user = h->h_default_user;
X			}
X			else
X			{
X				ruser->r_user = default_user;
X				debug2("host default)");
X			}
X			addlist(&h->h_rusers, ruser);
X		}
X		debug2("host %s: user %s (%d) -> local user %s (%d)\n",
X			h->h_names[ 0 ], ruser->r_name, ruser->r_uid,
X			ruser->r_user->u_name, ruser->r_user->u_local_uid);
X	}
X	fclose(input);
X	h->h_cmdfd = -1;
X	alarm(0);
X	if (errno == EINTR)
X		log("can't get remote users from \"%s\"\n", h->h_names[0]);
X}
X
X/*
X * Try to obtain mount information for host 'h'.
X */
Xgetmount(h)
X	register hosts	*h;
X{
X	long	savefd = h->h_cmdfd;
X	struct message	msgbuf;
X	register struct message	*msg = &msgbuf;
X	register long	len;
X
X	if (thishost == h) /* our own machine */
X	{
X		log("we are talking to ourselves\n");
X		h->h_cmdfd = open("/etc/passwd", O_RDONLY);
X		bcopy(byteorder, h->h_byteorder, 4);
X		h->h_byteorderok = TRUE;
X	}
X	else
X	{
X		if ((h->h_cmdfd = tcpconnect(h)) < 0)
X			goto done;
X		len = R_MINRMSG + sizeof(long);
X		msg->m_hdlen = htons(len);
X		msg->m_totlen = htonl(len);
X		msg->m_syscall = htons(RSYS_nosys);
X		msg->m_args[ 0 ] = htonl(CMD_NEEDMOUNT);
X		if (!sndmsg(h->h_cmdfd, msg, len, 0, 0))
X		{
X			log("can't ask for mount info\n");
X			close(h->h_cmdfd);
X			goto done;
X		}
X		getbyteorder(h);
X	}
X	getrusers(h); /* getrusers() closes the file descriptor */
Xdone:
X	h->h_cmdfd = savefd;
X}
X
X/*
X * Send mount information.  This includes a 4-byte header containing the
X * byte order for our machine,  followed by /etc/passwd.
X */
Xsendmount(h)
X	register hosts	*h;
X{
X	char	buf[ BUFSIZ ];
X	register long	fd = open("/etc/passwd", O_RDONLY),
X			cnt;
X	register char	*p = buf;
X
X	write(h->h_cmdfd, byteorder, 4);
X	while ((cnt = read(fd, p, BUFSIZ)) > 0)
X		_rmtio(write, h->h_cmdfd, p, cnt);
X	close(h->h_cmdfd);
X	h->h_cmdfd = -1;
X	close(fd);
X}
X
X/*
X * Mourne the death of any children.
X */
Xmourne()
X{
X	union wait	status;
X	char		buf[ BUFSIZ ];
X	register char	*p = buf;
X	register long	pid;
X
X	while ((pid = wait3(&status, WNOHANG, 0)) > 0)
X	{
X		sprintf(p, "server %d found dead", pid);
X		p += strlen(p);
X		if (status.w_termsig)
X			sprintf(p, " by sig #%d", status.w_termsig);
X		p += strlen(p);
X		if (status.w_coredump)
X			sprintf(p, " with core dump", status.w_termsig);
X		p += strlen(p);
X		sprintf(p, " exit=%d\n", status.w_retcode);
X		debug5("%s", buf);
X		p = buf;
X	}
X}
X
X/*
X * Catch signals and only report.
X */
Xcatch(sig, code, scp)
X	register long	sig,
X			code;
X	register struct sigcontext	*scp;
X{
X	log("caught signal #%d...", sig);
X	if (sig == SIGILL || sig == SIGSEGV || sig == SIGBUS)
X	{
X		change_to_uid(0);
X		chdir("/usr/tmp");
X		log("aborting: code=%d, scp=%x, sp=%x, pc=%x, end of scp=%x\n",
X			code, scp, scp->sc_sp, scp->sc_pc, scp+1);
X		sendsig(current_pid, SIGEMT);
X		log_fatal("could not abort\n");
X	}
X	else if (sig == SIGTERM) /* quietly go away */
X	{
X		/*
X		 * unlink the file only if we are allowed to and if it is
X		 * not the sentry server's logfile.
X		 */
X		if ((remote_debug & 0x800) == 0 && host != NULL)
X			unlink(logfile);
X		cleanup();
X		log("goodbye.\n");
X		exit(0);
X	}
X	else
X		log_fatal("exiting\n");
X}
X
X/*
X * Receive a wakeup call.
X */
Xwakeup_call()
X{
X	if (! i_am_asleep)
X	{
X		log("recieved spurious wakeup call!\n");
X		return;
X	}
X	i_am_asleep = FALSE;
X}
X
X/*
X * Provide name server function for kernel.  At this point we have just
X * recieved a SIGURG signal because the kernel wants us to translate a
X * name.
X */
Xnameserver()
X{
X#ifdef CANREMOTE
X	char		path[ BUFSIZ ],
X			hostname[ BUFSIZ ];
X	struct sockaddr_in	sinbuf;
X	register char	*p1, *p2, *name;
X	register hosts	*h = NULL;
X	register struct sockaddr_in	*sin;
X
X	if (remotename(NM_WHATNAME, 0, BUFSIZ, path) < 0)
X		return;
X	/*
X	 * Find the end of the '/' prefix and copy up to the next '/' or
X	 * null character.
X	 */
X	p1 = path;
X	while (*p1 == '/')
X		p1++;
X	p2 = hostname;
X	*p2++ = '/';
X	while (*p1 && *p1 != '/')
X		*p2++ = *p1++;
X	*p2 = '\0';
X
X	/*
X	 * Now look it up.
X	 */
X	if (hostname[1])
X		h = findhostname(hostname+1);
X	if (h == NULL)
X	{
X		debug6("cannot find host for path \"%s\"\n", path);
X		sin = NULL;
X	}
X	else
X	{
X		sin = &sinbuf;
X		debug6("path %s mapped to host %s\n", path, h->h_names[0]);
X		bzero((char *)sin, sizeof (struct sockaddr_in));
X		bcopy(&h->h_addr, (char *)&sin->sin_addr,
X			sizeof(struct in_addr));
X		sin->sin_family = AF_INET;
X		sin->sin_port = serviceport;
X	}
X	remotename(NM_NAMEIS, sin, sizeof(struct sockaddr_in), hostname);
X#endif CANREMOTE
X}
X
X/*
X * Decide if a file is really a local file to the client or not.  We only
X * look for explicit references like
X *	name1/name2/../name3 ...
X * And we then check to see whether name2 is the root directory.  If it is
X * then we send the request back to the client.
X */
Xislocal(msg, type)
X	register struct message *msg;
X{
X	register char	*p;
X	register boolean	checktwopaths;
X	register short	syscall = msg->m_syscall;
X	register long	offset1,
X			offset2 = -1,
X			localcnt = 0;
X	register process	*proc;
X	char	buf[ BUFSIZ ];
X
X	debug10("cwd=%s\n", getwd(buf));
X	checktwopaths = (type & NEED_2REMOTE);
X
X	if (checktwopaths)
X		p = twopath1addr(msg);
X	else
X		p = path1addr(msg);
X	if ((offset1 = find_dotdot(p)) >= 0)
X		localcnt++;
X	if (checktwopaths)
X		if ((offset2 = find_dotdot(twopath2addr(msg))) >= 0)
X			localcnt++;
X	if (localcnt)
X	{
X		debug10("%d paths are remote: \"%s\" @ %d, \"%s\" @ %d\n",
X			localcnt,
X			checktwopaths ? twopath1addr(msg) : path1addr(msg),
X			offset1, checktwopaths ? twopath2addr(msg) : "",
X			offset2);
X		setup_proc(proc = wildcard, msg->m_uid, msg->m_pid);
X		proc->p_errno = -1;
X		proc->p_returnval = offset1;
X		sendreturn(proc, host->h_cmdfd, NULL, 1, offset2);
X	}
X	return(localcnt);
X}
X
X/*
X * kernel code stolen for speed.
X */
Xmyaccess(st, user, perm)
X	register struct stat	*st;
X	register long	perm;
X	register users	*user;
X{
X	register long	*gp, i;
X
X	perm <<= 6;
X	if (user->u_local_uid != st->st_uid) {
X		perm >>= 3;
X		gp = user->u_local_groups;
X		for (i=0; i < user->u_numgroups; i++, gp++)
X			if (st->st_gid == *gp)
X				goto found;
X		perm >>= 3;
Xfound:
X		;
X	}
X	if ((st->st_mode & perm) != 0)
X		return (TRUE);
X	return(FALSE);
X}
X
X/*
X * look for a component of ".." terminated by a '/' or a null character.
X * If we find one, examine the previous component to see if it is our
X * root directory.
X */
Xfind_dotdot(path)
X	register char	*path;
X{
X	struct stat	statb;
X	register char	*p;
X	register struct stat	*statp = &statb;
X	register long	retval;
X	extern struct stat	root;
X
X	for (p = path; *p;)
X	{
X		while (*p == '/')
X			p++;
X		if (p[0] == '.' && p[1] == '.'
X		&& (p[2] == '\0' || p[2] == '/'))
X		{
X			if (p == path)
X				if (in_root_directory)
X					return(0);
X				else
X					goto next_component;
X			*p = '\0'; /* we know it is a '.' */
X			retval = lstat(path, statp);
X			*p = '.';
X			if (retval < 0)
X				return(retval);
X			if (isroot(statp))
X				return(p - path + 1);
X		}
Xnext_component:
X		while (*p && *p != '/')
X			p++;
X	}
X	return(-1);
X}
SHAREOF
chmod 444 remote/info.c
#
# remote/init.c
#
if [ -f remote/init.c ]; then 
	echo -n 'Hit <return> to overwrite remote/init.c or ^C to quit' 
	read ans 
	rm -f remote/init.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/init.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:	init.c,v $
X * Revision 2.1  86/01/05  18:13:54  toddb
X * Added include for sys/stat.h because pyramid machines get upset.
X * 
X * Revision 2.0  85/12/07  18:21:37  toddb
X * First public release.
X * 
X */
Xstatic char	*rcsid = "$Header: init.c,v 2.1 86/01/05 18:13:54 toddb Exp $";
X#include	"server.h"
X#include	<stdio.h>
X#include	<pwd.h>
X#include	<grp.h>
X#include	<netdb.h>
X#include	<fcntl.h>
X#include	<sys/dir.h>
X#include	<sys/user.h>
X#include	<sys/signal.h>
X#include	<sys/ioctl.h>
X#include	<sys/stat.h>
X
Xextern hosts	*hostlist;
Xextern hosts	*thishost;
Xextern users	*userlist;
Xextern users	*default_user;
Xextern char	hostname[];
Xextern char	*service;
Xextern short	current_uid;
Xextern short	current_pid;
Xextern process	*wildcard;
Xextern struct sigvec	sig_vec;
Xextern struct sigvec	sig_name;
Xextern struct sigvec	sig_alarm;
Xextern struct sigvec	sig_ignore;
Xextern struct sigvec	sig_continue;
X#ifdef RFSDEBUG
Xextern struct sigvec	sig_debug;
X#endif
Xextern struct stat	root;
X
X/*
X * Initialize the host tables and user tables.
X */
Xinit()
X{
X	long	tt;
X	struct hostent	*gethostent();
X	struct passwd	*getpwent();
X	struct group	*getgrent();
X
X	/*
X	 * catch signals.
X	 */
X	sigvec(SIGHUP, &sig_ignore, (struct sigvec *)0);
X	sigvec(SIGINT, &sig_vec, (struct sigvec *)0);
X	sigvec(SIGQUIT, &sig_vec, (struct sigvec *)0);
X	sigvec(SIGILL, &sig_vec, (struct sigvec *)0);
X#ifdef RFSDEBUG
X	sigvec(SIGTRAP, &sig_debug, (struct sigvec *)0);
X#endif RFSDEBUG
X	/*	SIGIOT		*/
X	/*	SIGEMT		*/
X	/*	SIGFPE		*/
X	/*	SIGKILL		*/
X	sigvec(SIGBUS, &sig_vec, (struct sigvec *)0);
X	sigvec(SIGSEGV, &sig_vec, (struct sigvec *)0);
X	sigvec(SIGSYS, &sig_vec, (struct sigvec *)0);
X	sigvec(SIGPIPE, &sig_vec, (struct sigvec *)0);
X	sigvec(SIGALRM, &sig_alarm, (struct sigvec *)0);
X	sigvec(SIGTERM, &sig_vec, (struct sigvec *)0);
X	sigvec(SIGURG, &sig_name, (struct sigvec *)0);
X	/*	SIGSTOP		*/
X	/*	SIGTSTP		*/
X	/*	SIGCONT		*/
X	/*	SIGCHLD		*/
X	sigvec(SIGTTIN, &sig_vec, (struct sigvec *)0);
X	sigvec(SIGTTOU, &sig_vec, (struct sigvec *)0);
X	sigvec(SIGIO, &sig_continue, (struct sigvec *)0);
X	sigvec(SIGXCPU, &sig_vec, (struct sigvec *)0);
X	sigvec(SIGXFSZ, &sig_vec, (struct sigvec *)0);
X	sigvec(SIGVTALRM, &sig_vec, (struct sigvec *)0);
X	/*	SIGPROF		*/
X
X	/*
X	 * set up some important global values, including uid, pid,
X	 * the pipe file descriptors for messages to and from the gateway
X	 * server.  Register as the nameserver.  Get host name.  Get service.
X	 * Get root stat info.
X	 */
X	if (chdir("/") == -1)
X		log_fatal("cannot chdir(\"/\")\n");
X	wildcard = newprocess();
X	fcntl(2, F_SETFL, FAPPEND);
X	close(0);
X	close(1);
X	change_to_uid(0);
X	if (gethostname(hostname, HOSTNAMELEN) < 0 || *hostname == '\0')
X		log_fatal("host name not set!\n");
X	if (stat("/", &root) < 0)
X		log_fatal("cannot stat /\n");
X#ifdef CANREMOTE
X	if (remotename(NM_SERVER, 0, 0, 0) < 0)
X		log("cannot register as nameserver\n");
X	/*
X	 * Turn off remote access, if we have any.
X	 */
X	remoteoff(NULL);
X#endif
X	tt = open("/dev/tty", 2);
X
X	if (tt >= 0)
X	{
X		ioctl(tt, TIOCNOTTY, 0);
X		close(tt);
X	}
X	setpgrp(0,0);
X
X	initusers();
X	initgroups();
X	inithosts();
X	initrhosts();
X}
X
X/*
X * build the list of users on this host (where the server runs).
X */
Xinitusers()
X{
X	register struct passwd	*pw;
X	register users	*user;
X	char		buf[ BUFSIZ ];
X	register char	*pbuf = buf;
X
X	while(pw = getpwent())
X	{
X		if (*pw->pw_dir == '\0' || *pw->pw_name == '\0')
X		{
X			log("login \"%s\" has problems, dir=\"%s\"\n",
X				pw->pw_name, pw->pw_dir);
X			continue;
X		}
X		user = newuser();
X		user->u_local_uid = pw->pw_uid;
X		user->u_name = copy( pw->pw_name );
X		addgroup(user, pw->pw_gid);
X		user->u_dir = copy( pw->pw_dir );
X		sprintf(pbuf, "%s/.rhosts", pw->pw_dir);
X		user->u_rhosts = copy( pbuf );
X		addlist(&userlist, user);
X	}
X	endpwent();
X	if (user = findusername(DEFAULTUSER))
X		default_user = user;
X	else
X		log_fatal("The user \"%s\" must be in /etc/passwd (%s)\n",
X			DEFAULTUSER, "for default permissions");
X}
X
X/*
X * Build the list of groups that each user belongs to.
X */
Xinitgroups()
X{
X	register struct group	*gr;
X	register users	*user;
X	register char	**p;
X
X
X	while(gr = getgrent())
X	{
X		for (p = gr->gr_mem; *p; p++)
X			if (user = findusername(*p))
X				addgroup(user, gr->gr_gid);
X			else
X				log("group %s: bad user=%s\n",
X					gr->gr_name, *p);
X	}
X	endgrent();
X}
X
X/*
X * Then build the list of all hosts.
X */
Xinithosts()
X{
X	register struct hostent	*h;
X	register rusers	*ruser;
X	register hosts	*hst;
X	register users	*user;
X	register long	i;
X
X	while (h = gethostent())
X	{
X		hst = newhost();
X		hst->h_names = newname(hst->h_names, h->h_name);
X		for (i=0; h->h_aliases[ i ]; i++)
X			hst->h_names = newname(hst->h_names,
X					h->h_aliases[ i ]);
X
X		hst->h_addr = *((struct in_addr *)(h->h_addr));
X		addlist(&hostlist, hst);
X
X		/*
X		 * now if there exists a user on this machine having
X		 * the same name as the name of this host (NOT AN
X		 * ALIAS!), then that will be our defaut local user
X		 * to map to.  Be sure that we don't allow a machine
X		 * to be mapped onto a user if the uid is real small:
X		 * e.g. a machine named root, where all its user ids
X		 * become root using the remote fs!
X		 */
X		user = findusername(hst->h_names[ 0 ]);
X		if (user && user->u_local_uid <= UID_TOO_LOW)
X		{
X			log("host/user %s: uid %d too low for alias\n",
X				hst->h_names[ 0 ], user->u_local_uid);
X			user = NULL;
X		}
X		else if (user)
X		{
X			hst->h_default_user = user;
X			debug2("default user for host %s (%s) is %s\n",
X				hst->h_names[ 0 ],
X				inet_ntoa(hst->h_addr), user->u_name);
X		}
X		ruser = hst->h_default_ruser = newruser();
X		if (user)
X			ruser->r_user = user;
X		else
X			ruser->r_user = default_user;
X		ruser->r_uid = -1;
X		ruser->r_name = copy(BOGUSUSER);
X	}
X	endhostent();
X	if ((thishost = findhostname(hostname)) == NULL)
X		log_fatal("this host (\"%s\") is not in host file\n",
X			hostname);
X}
X
X/*
X * Now for each user that has a .rhosts file, assemble the
X * references and attach them to the appropriate host.
X */
Xinitrhosts()
X{
X	register hosts	*hst;
X	register rhost	*rh;
X	register users	*user;
X	char		buf[ BUFSIZ ];
X	register char	*pbuf = buf;
X
X	for (user=userlist; user; user=user->u_next)
X	{
X		setrhost(user->u_rhosts);
X		while (rh = getrhostent(pbuf))
X			if (hst = findhostname(rh->rh_host))
X				addremoteuser(hst, user, rh->rh_user);
X		endrhost();
X	}
X}
X
Xchar	*copy(string)
X	register char	*string;
X{
X	register char	*ret = malloc( strlen(string)+1 );
X
X	if (ret == NULL)
X		log_fatal("cannot allocate space\n");
X	strcpy(ret, string);
X	return(ret);
X}
X
X/*
X * Add a remote user to those recognized on a certain host.
X */
Xaddremoteuser(h, user, remoteuser)
X	register hosts	*h;
X	register users	*user;
X	register char	*remoteuser;
X{
X	register rusers	*ruser;
X	register long	old = FALSE;
X
X	debug2("\t%s!%s --> %s ", *h->h_names, remoteuser, user->u_name);
X	if ((ruser = findrusername(&h->h_rusers, remoteuser)) == NULL)
X	{
X		debug2("\n");
X		ruser = newruser();
X	}
X	else
X	{
X		old = TRUE;
X		if (strcmp(remoteuser, user->u_name) != 0)
X		{
X			debug2("(old, ignored)\n");
X			return;
X		}
X		else
X			debug2("(old)\n");
X	}
X	ruser->r_name = copy(remoteuser);
X	ruser->r_uid = -1;
X	ruser->r_user = user;
X	if (! old)
X		addlist(&h->h_rusers, ruser);
X}
SHAREOF
chmod 444 remote/init.c

sources-request@panda.UUCP (01/09/86)

Mod.sources:  Volume 3, Issue 79
Submitted by: tektronix!tekcrl!toddb

#!/bin/sh
#
# RFS, a kernel-resident remote file system.  Shar 3 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/list.c
#	remote/make.base
#	remote/make.base.M68
#	remote/make.base.magnolia
#	remote/make.base.pyramid
#	remote/make.base.vax
#	remote/make.base.vaxnorfs
#	remote/new.c
#	remote/newinit.c
#	remote/rhost.c
#	remote/rmtmnt.c
#	remote/route.c
#	remote/server.h
#	remote/serverdata.c
#	remote/serverdir.c
#
# remote/list.c
#
if [ -f remote/list.c ]; then 
	echo -n 'Hit <return> to overwrite remote/list.c or ^C to quit' 
	read ans 
	rm -f remote/list.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/list.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:	list.c,v $
X * Revision 2.0  85/12/07  18:21:44  toddb
X * First public release.
X * 
X */
Xstatic char	*rcsid = "$Header: list.c,v 2.0 85/12/07 18:21:44 toddb Rel $";
X#include	"server.h"
X#include	<stdio.h>
X
X/*
X * Stick a new item of any type on top of the list.
X */
Xl_list *addlist(list, item)
X	register l_list	**list;
X	register l_list	*item;
X{
X	item->l_next = *list;
X	if (*list)
X	{
X		item->l_prev = (*list)->l_prev;
X		(*list)->l_prev = item;
X	}
X	else
X		item->l_prev = item;
X	*list = item;
X	return(item);
X}
X
X/*
X * delete an item from a list.  The item itself is left intact.  It is
X * the responsibility of the caller to deal with the deleted item.
X */
Xl_list *deletelist(list, item)
X	register l_list	**list;
X	register l_list	*item;
X{
X	if (item == *list)
X	{
X		if (item->l_next == NULL)
X			*list = NULL;
X		else
X		{
X			*list = item->l_next;
X			item->l_next->l_prev = item->l_next;
X		}
X	}
X	else
X	{
X		item->l_prev->l_next = item->l_next;
X		if (item->l_next != NULL)
X			item->l_next->l_prev = item->l_prev;
X	}
X	return (*list);
X}
X
X/*
X * stick 'item' at the top of the 'list' ( if it isn't there
X * already.
X */
Xl_list *toplist(list, item)
X	register l_list	**list;
X	register l_list	*item;
X{
X	if (item == *list)
X		return;
X	item->l_prev->l_next = item->l_next;
X	if (item->l_next)
X		item->l_next->l_prev = item->l_prev;
X	item->l_next = (*list);
X	/*
X	 * if our target is the last on the list, then
X	 * be careful that we don't make a cycle.  Since
X	 * we want the head of the list's l_prev pointer
X	 * to point to the last in the list, we don't
X	 * have to do anything.
X	 */
X	if (item != (*list)->l_prev) /* NOT last on list */
X		item->l_prev = (*list)->l_prev;
X	(*list)->l_prev = item;
X	*list = item;
X}
SHAREOF
chmod 444 remote/list.c
#
# remote/make.base
#
if [ -f remote/make.base ]; then 
	echo -n 'Hit <return> to overwrite remote/make.base or ^C to quit' 
	read ans 
	rm -f remote/make.base 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/make.base
XSOBJS      = change.$O file.$O fileserver.$O find.$O \
X		info.$O init.$O list.$O new.$O \
X		rhost.$O route.$O serverdata.$O serverdir.$O serverio.$O \
X		serversyscall.$O
XCFILES     = change.c file.c fileserver.c find.c \
X		info.c init.c list.c new.c \
X		rhost.c route.c serverdata.c serverdir.c serverio.c \
X		serversyscall.c
X
Xall: $(ALL)
X
X$(RFS_SERVER): $(SOBJS)
X	$(CC) -o $@ $(SOBJS) $(LDFLAGS)
X	$(XINU) $(RFS_SERVER)
X$(RMTMNT): rmtmnt.$O
X	$(CC) -o $@ rmtmnt.$O $(LDFLAGS)
X	$(XINU) $(RMTMNT)
X$(DEBUG): debug.$O
X	$(CC) -o $@ debug.$O $(LDFLAGS)
X	$(XINU) $(DEBUG)
Xtags: $(CFILES)
X	ctags $(CFILES) $(INCLUDE)
X$(SOBJS): $(INCLUDE)
X
Xinstall: all
X	$(INSTALL) -c -m 755 $(RFS_SERVER) $(DEST)/etc/rfs_server
X	$(INSTALL_RMTMNT) -c -m 0755 $(RMTMNT) $(DEST)/etc/rmtmnt
SHAREOF
chmod 664 remote/make.base
#
# remote/make.base.M68
#
if [ -f remote/make.base.M68 ]; then 
	echo -n 'Hit <return> to overwrite remote/make.base.M68 or ^C to quit' 
	read ans 
	rm -f remote/make.base.M68 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/make.base.M68
XDEST           = /usr3/mag
XHOST	       =
XINCLUDE        = $(DEST)/usr/include/remote/remotefs.h server.h
XCFLAGS         = -G$(HOST) -O -DRFSDEBUG -DCANREMOTE -DBYTEORDER=3,2,1,0 -DREMOTEFS -DMACHTYPE=magnolia
XLDFLAGS        = -z
XCC             = cc68
XO	       = b
XRFS_SERVER     = rfs_server.x
XRMTMNT         = rmtmnt.x
XDEBUG          = debug.x
XINSTALL_RMTMNT = install68
XINSTALL        = install68
XALL	       = $(RFS_SERVER) $(RMTMNT)
XXINU	       = xinu68
X
X.SUFFIXES:
X.SUFFIXES: .b .c
X
X.c.b:
X	$(CC) $(CFLAGS) $< -c
SHAREOF
chmod 664 remote/make.base.M68
#
# remote/make.base.magnolia
#
if [ -f remote/make.base.magnolia ]; then 
	echo -n 'Hit <return> to overwrite remote/make.base.magnolia or ^C to quit' 
	read ans 
	rm -f remote/make.base.magnolia 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/make.base.magnolia
XHOST	       = tekcrl
XINCLUDE        = /usr/include/remote/remotefs.h server.h
XO              = o
XCFLAGS         = -G$(HOST) -O -DRFSDEBUG -DCANREMOTE -DBYTEORDER=3,2,1,0 -DREMOTEFS
XLDFLAGS        = -z
XRFS_SERVER     = rfs_server
XRMTMNT         = rmtmnt
XDEBUG          = debug
XINSTALL        = install68
XINSTALL_RMTMNT = install68
XDEST           =
XCC	       = cc
XALL	       = $(RFS_SERVER) $(RMTMNT)
XXINU	       = :
SHAREOF
chmod 664 remote/make.base.magnolia
#
# remote/make.base.pyramid
#
if [ -f remote/make.base.pyramid ]; then 
	echo -n 'Hit <return> to overwrite remote/make.base.pyramid or ^C to quit' 
	read ans 
	rm -f remote/make.base.pyramid 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/make.base.pyramid
XINCLUDE        = ../usr.include/remote/remotefs.h server.h
XO              = o
XLDFLAGS        = -z
XRFS_SERVER     = rfs_server
XINS_RFS_SERVER = rfs_server
XRMTMNT         = rmtmnt
XDEBUG          = debug
XINSTALL_RMTMNT = install
XINSTALL        = install
XDEST	       =
XCC             = cc
XALL	       = $(RFS_SERVER) $(RMTMNT)
XXINU	       = :
XDEFINES        = -DRFSDEBUG -DCANREMOTE -DBYTEORDER=3,2,1,0 -DREMOTEFS -I/usr/include/sys
XCFLAGS         = -O ${DEFINES} -I../usr.include
SHAREOF
chmod 644 remote/make.base.pyramid
#
# remote/make.base.vax
#
if [ -f remote/make.base.vax ]; then 
	echo -n 'Hit <return> to overwrite remote/make.base.vax or ^C to quit' 
	read ans 
	rm -f remote/make.base.vax 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/make.base.vax
XINCLUDE        = ../usr.include/remote/remotefs.h server.h
XO              = o
XLDFLAGS        = -z
XRFS_SERVER     = rfs_server
XINS_RFS_SERVER = rfs_server
XRMTMNT         = rmtmnt
XDEBUG          = debug
XINSTALL_RMTMNT = install
XINSTALL        = install
XDEST	       =
XCC             = cc
XALL	       = $(RFS_SERVER) $(RMTMNT)
XXINU	       = :
XDEFINES        = -DRFSDEBUG -DCANREMOTE -DBYTEORDER=0,1,2,3 -DREMOTEFS
XCFLAGS         = -O ${DEFINES} -I../usr.include
SHAREOF
chmod 664 remote/make.base.vax
#
# remote/make.base.vaxnorfs
#
if [ -f remote/make.base.vaxnorfs ]; then 
	echo -n 'Hit <return> to overwrite remote/make.base.vaxnorfs or ^C to quit' 
	read ans 
	rm -f remote/make.base.vaxnorfs 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/make.base.vaxnorfs
XINCLUDE        = ../usr.include/remote/remotefs.h server.h
XO              = o
XLDFLAGS        = -z
XRFS_SERVER     = rfs_server
XINS_RFS_SERVER = rfs_server
XRMTMNT         = rmtmnt
XDEBUG          = debug
XINSTALL_RMTMNT = :
XINSTALL        = install
XDEST	       =
XCC             = cc
XALL	       = $(RFS_SERVER)
XXINU	       = :
XCFLAGS         = -O -DRFSDEBUG -DBYTEORDER=0,1,2,3 -DNREMOTE=1 -I../usr.include
SHAREOF
chmod 664 remote/make.base.vaxnorfs
#
# remote/new.c
#
if [ -f remote/new.c ]; then 
	echo -n 'Hit <return> to overwrite remote/new.c or ^C to quit' 
	read ans 
	rm -f remote/new.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/new.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:	new.c,v $
X * Revision 2.0  85/12/07  18:21:48  toddb
X * First public release.
X * 
X */
Xstatic char	*rcsid = "$Header: new.c,v 2.0 85/12/07 18:21:48 toddb Rel $";
X#include	"server.h"
X#include	<stdio.h>
X
Xextern short	current_pid;
Xextern hosts	*host;
X
Xusers *newuser()
X{
X	register users	*user;
X
X	user = (users *)malloc(sizeof(users));
X	if (user == NULL)
X		log_fatal("cannot allocate space\n");
X	bzero(user, sizeof(users));
X	return(user);
X}
X
Xhosts *newhost()
X{
X	register hosts	*h;
X
X	h = (hosts *)malloc(sizeof(hosts));
X	if (h == NULL)
X		log_fatal("cannot allocate space\n");
X	bzero(h, sizeof(hosts));
X	h->h_cmdfd = -1;
X	return(h);
X}
X
Xrusers *newruser()
X{
X	register rusers	*ruser;
X
X	ruser = (rusers *)malloc(sizeof(rusers));
X	if (ruser == NULL)
X		log_fatal("cannot allocate space\n");
X	bzero(ruser, sizeof(rusers));
X	return(ruser);
X}
X
Xprocess *newprocess()
X{
X	register process	*p;
X
X	p = (process *)malloc(sizeof(process));
X	if (p == NULL)
X		log_fatal("cannot allocate space\n");
X	bzero(p, sizeof(process));
X	return(p);
X}
X
Xfreeproc(p)
X	register process *p;
X{
X	if (p->p_execfd >= 0)
X		close(p->p_execfd);
X	free(p);
X}
X
Xchar	**newname(namelist, name)
X	register char	**namelist;
X	register char	*name;
X{
X	register long	i = 0;
X
X	if (namelist == NULL)
X		namelist = (char **)malloc(sizeof(char *) * 2);
X	else
X	{
X		/*
X		 * count the elements in the list now.
X		 */
X		for (i=0; namelist && namelist[i]; i++) ;
X
X		namelist = (char **)realloc(namelist, sizeof(char *) * (i+2));
X	}
X	namelist[ i++ ] = copy(name);
X	namelist[ i ] = NULL;
X	return(namelist);
X}
X
X/*
X * Add a group to 'user' unless he has exceeded the limit or the group
X * is already in his domain.
X */
Xaddgroup(user, gid)
X	register users	*user;
X	register short	gid;
X{
X	register long	i = 0,
X			*gr = user->u_local_groups;
X
X	for (i=0; i < user->u_numgroups; i++)
X		if (gr[ i ] == gid)
X			return;
X	if (i >= NGROUPS)
X		return;
X	gr[ user->u_numgroups++ ] = gid;
X}
X
Xprocess *add_new_process(uid, pid)
X	register short	uid, pid;
X{
X	register process	*p;
X	register long	i;
X
X	debug0("allocate new proc: pid=%d uid=%d host=%s\n",
X		pid, uid, host->h_names[0]);
X	setup_proc(p = newprocess(), uid, pid);
X	addlist(&host->h_proclist, p);
X
X	/*
X	 * Initialize the file descriptors for this process.
X	 */
X	for(i=0; i<NOFILE; i++)
X		p->p_fds[ i ] = 0x80;	/* -128 */
X
X	return(p);
X}
X
Xsetup_proc(proc, uid, pid)
X	register process	*proc;
X	register short	uid, pid;
X{
X	register rusers	*ruser;
X
X	proc->p_pid = pid;
X	proc->p_uid = uid;
X	proc->p_handler = current_pid;
X	proc->p_returnval = 0;
X	proc->p_execfd = -1;
X	if (ruser = findremuid(&host->h_rusers, uid))
X		proc->p_ruser = ruser;
X	else
X		proc->p_ruser = host->h_default_ruser;
X}
SHAREOF
chmod 444 remote/new.c
#
# remote/newinit.c
#
if [ -f remote/newinit.c ]; then 
	echo -n 'Hit <return> to overwrite remote/newinit.c or ^C to quit' 
	read ans 
	rm -f remote/newinit.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/newinit.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:	init.c,v $
X * Revision 2.0  85/12/07  18:21:37  toddb
X * First public release.
X * 
X */
Xstatic char	*rcsid = "$Header: init.c,v 2.0 85/12/07 18:21:37 toddb Rel $";
X#include	"server.h"
X#include	<stdio.h>
X#include	<pwd.h>
X#include	<grp.h>
X#include	<netdb.h>
X#include	<fcntl.h>
X#include	<sys/dir.h>
X#include	<sys/user.h>
X#include	<sys/signal.h>
X#include	<sys/ioctl.h>
X
Xextern hosts	*hostlist;
Xextern hosts	*thishost;
Xextern users	*userlist;
Xextern users	*default_user;
Xextern char	hostname[];
Xextern char	*service;
Xextern short	current_uid;
Xextern short	current_pid;
Xextern process	*wildcard;
Xextern struct sigvec	sig_vec;
Xextern struct sigvec	sig_name;
Xextern struct sigvec	sig_alarm;
Xextern struct sigvec	sig_ignore;
Xextern struct sigvec	sig_continue;
X#ifdef RFSDEBUG
Xextern struct sigvec	sig_debug;
X#endif
Xextern struct stat	root;
X
X/*
X * Initialize the host tables and user tables.
X */
Xinit()
X{
X	long	tt;
X	struct hostent	*gethostent();
X	struct passwd	*getpwent();
X	struct group	*getgrent();
X
X	/*
X	 * catch signals.
X	 */
X	sigvec(SIGHUP, &sig_ignore, (struct sigvec *)0);
X	sigvec(SIGINT, &sig_vec, (struct sigvec *)0);
X	sigvec(SIGQUIT, &sig_vec, (struct sigvec *)0);
X	sigvec(SIGILL, &sig_vec, (struct sigvec *)0);
X#ifdef RFSDEBUG
X	sigvec(SIGTRAP, &sig_debug, (struct sigvec *)0);
X#endif RFSDEBUG
X	/*	SIGIOT		*/
X	/*	SIGEMT		*/
X	/*	SIGFPE		*/
X	/*	SIGKILL		*/
X	sigvec(SIGBUS, &sig_vec, (struct sigvec *)0);
X	sigvec(SIGSEGV, &sig_vec, (struct sigvec *)0);
X	sigvec(SIGSYS, &sig_vec, (struct sigvec *)0);
X	sigvec(SIGPIPE, &sig_vec, (struct sigvec *)0);
X	sigvec(SIGALRM, &sig_alarm, (struct sigvec *)0);
X	sigvec(SIGTERM, &sig_vec, (struct sigvec *)0);
X	sigvec(SIGURG, &sig_name, (struct sigvec *)0);
X	/*	SIGSTOP		*/
X	/*	SIGTSTP		*/
X	/*	SIGCONT		*/
X	/*	SIGCHLD		*/
X	sigvec(SIGTTIN, &sig_vec, (struct sigvec *)0);
X	sigvec(SIGTTOU, &sig_vec, (struct sigvec *)0);
X	sigvec(SIGIO, &sig_continue, (struct sigvec *)0);
X	sigvec(SIGXCPU, &sig_vec, (struct sigvec *)0);
X	sigvec(SIGXFSZ, &sig_vec, (struct sigvec *)0);
X	sigvec(SIGVTALRM, &sig_vec, (struct sigvec *)0);
X	/*	SIGPROF		*/
X
X	/*
X	 * set up some important global values, including uid, pid,
X	 * the pipe file descriptors for messages to and from the gateway
X	 * server.  Register as the nameserver.  Get host name.  Get service.
X	 * Get root stat info.
X	 */
X	if (chdir("/") == -1)
X		log_fatal("cannot chdir(\"/\")\n");
X	wildcard = newprocess();
X	fcntl(2, F_SETFL, FAPPEND);
X	close(0);
X	close(1);
X	change_to_uid(0);
X	if (gethostname(hostname, HOSTNAMELEN) < 0 || *hostname == '\0')
X		log_fatal("host name not set!\n");
X	if (stat("/", &root) < 0)
X		log_fatal("cannot stat /\n");
X#ifdef CANREMOTE
X	if (remotename(NM_SERVER, 0, 0, 0) < 0)
X		log("cannot register as nameserver\n");
X	/*
X	 * Turn off remote access, if we have any.
X	 */
X	remoteoff(NULL);
X#endif
X	tt = open("/dev/tty", 2);
X
X	if (tt >= 0)
X	{
X		ioctl(tt, TIOCNOTTY, 0);
X		close(tt);
X	}
X	setpgrp(0,0);
X
X	initusers();
X	initgroups();
X	inithosts();
X	initrhosts();
X}
X
X/*
X * build the list of users on this host (where the server runs).
X */
Xinitusers()
X{
X	register struct passwd	*pw;
X	register users	*user;
X	char		buf[ BUFSIZ ];
X	register char	*pbuf = buf;
X
X	while(pw = getpwent())
X	{
X		if (*pw->pw_dir == '\0' || *pw->pw_name == '\0')
X		{
X			log("login \"%s\" has problems, dir=\"%s\"\n",
X				pw->pw_name, pw->pw_dir);
X			continue;
X		}
X		user = newuser();
X		user->u_local_uid = pw->pw_uid;
X		user->u_name = copy( pw->pw_name );
X		addgroup(user, pw->pw_gid);
X		user->u_dir = copy( pw->pw_dir );
X		sprintf(pbuf, "%s/.rhosts", pw->pw_dir);
X		user->u_rhosts = copy( pbuf );
X		addlist(&userlist, user);
X	}
X	endpwent();
X	if (user = findusername(DEFAULTUSER))
X		default_user = user;
X	else
X		log_fatal("The user \"%s\" must be in /etc/passwd (%s)\n",
X			DEFAULTUSER, "for default permissions");
X}
X
X/*
X * Build the list of groups that each user belongs to.
X */
Xinitgroups()
X{
X	register struct group	*gr;
X	register users	*user;
X	register char	**p;
X
X
X	while(gr = getgrent())
X	{
X		for (p = gr->gr_mem; *p; p++)
X			if (user = findusername(*p))
X				addgroup(user, gr->gr_gid);
X			else
X				log("group %s: bad user=%s\n",
X					gr->gr_name, *p);
X	}
X	endgrent();
X}
X
X/*
X * Then build the list of all hosts.
X */
Xinithosts()
X{
X	register struct hostent	*h;
X	register rusers	*ruser;
X	register hosts	*hst;
X	register users	*user;
X	register long	i;
X	boolean		duplicate;
X
X	while (h = gethostent())
X	{
X		/*
X		 * One physical host may have more than one physical
X		 * address each having a unique host name associated
X		 * with it.  If we find any entry having one of its aliases
X		 * match a previous alias, then simply fold all aliases
X		 * into it, and continue.
X		 */
X		duplicate = FALSE;
X		for (i = -1; i < 0 || h->h_aliases[ i ]; i++)
X		{
X			if (i < 0)
X				hst = findhost(h->h_name);
X			else
X				hst = findhost(h->h_aliases[i]);
X			if (hst)
X			{
X				duplicate = TRUE;
X				break;
X			}
X		}
X
X		/*
X		 * If we have a redundant host... add all the names
X		 * in; newname will remove redundant copies.
X		 */
X		if (!duplicate)
X			hst = newhost();
X		hst->h_names = newname(hst->h_names, h->h_name);
X		for (i=0; h->h_aliases[ i ]; i++)
X			hst->h_names = newname(hst->h_names,
X					h->h_aliases[ i ]);
X		if (duplicate)
X
X		hst->h_addr = *((struct in_addr *)(h->h_addr));
X		addlist(&hostlist, hst);
X
X		/*
X		 * now if there exists a user on this machine having
X		 * the same name as the name of this host (NOT AN
X		 * ALIAS!), then that will be our defaut local user
X		 * to map to.  Be sure that we don't allow a machine
X		 * to be mapped onto a user if the uid is real small:
X		 * e.g. a machine named root, where all its user ids
X		 * become root using the remote fs!
X		 */
X		user = findusername(hst->h_names[ 0 ]);
X		if (user && user->u_local_uid <= UID_TOO_LOW)
X		{
X			log("host/user %s: uid %d too low for alias\n",
X				hst->h_names[ 0 ], user->u_local_uid);
X			user = NULL;
X		}
X		else if (user)
X		{
X			hst->h_default_user = user;
X			debug2("default user for host %s (%s) is %s\n",
X				hst->h_names[ 0 ],
X				inet_ntoa(hst->h_addr), user->u_name);
X		}
X		ruser = hst->h_default_ruser = newruser();
X		if (user)
X			ruser->r_user = user;
X		else
X			ruser->r_user = default_user;
X		ruser->r_uid = -1;
X		ruser->r_name = copy(BOGUSUSER);
X	}
X	endhostent();
X	if ((thishost = findhostname(hostname)) == NULL)
X		log_fatal("this host (\"%s\") is not in host file\n",
X			hostname);
X}
X
X/*
X * Now for each user that has a .rhosts file, assemble the
X * references and attach them to the appropriate host.
X */
Xinitrhosts()
X{
X	register hosts	*hst;
X	register rhost	*rh;
X	register users	*user;
X	char		buf[ BUFSIZ ];
X	register char	*pbuf = buf;
X
X	for (user=userlist; user; user=user->u_next)
X	{
X		setrhost(user->u_rhosts);
X		while (rh = getrhostent(pbuf))
X			if (hst = findhostname(rh->rh_host))
X				addremoteuser(hst, user, rh->rh_user);
X		endrhost();
X	}
X}
X
Xchar	*copy(string)
X	register char	*string;
X{
X	register char	*ret = malloc( strlen(string)+1 );
X
X	if (ret == NULL)
X		log_fatal("cannot allocate space\n");
X	strcpy(ret, string);
X	return(ret);
X}
X
X/*
X * Add a remote user to those recognized on a certain host.
X */
Xaddremoteuser(h, user, remoteuser)
X	register hosts	*h;
X	register users	*user;
X	register char	*remoteuser;
X{
X	register rusers	*ruser;
X	register long	old = FALSE;
X
X	debug2("\t%s!%s --> %s ", *h->h_names, remoteuser, user->u_name);
X	if ((ruser = findrusername(&h->h_rusers, remoteuser)) == NULL)
X	{
X		debug2("\n");
X		ruser = newruser();
X	}
X	else
X	{
X		old = TRUE;
X		if (strcmp(remoteuser, user->u_name) != 0)
X		{
X			debug2("(old, ignored)\n");
X			return;
X		}
X		else
X			debug2("(old)\n");
X	}
X	ruser->r_name = copy(remoteuser);
X	ruser->r_uid = -1;
X	ruser->r_user = user;
X	if (! old)
X		addlist(&h->h_rusers, ruser);
X}
SHAREOF
chmod 664 remote/newinit.c
#
# remote/rhost.c
#
if [ -f remote/rhost.c ]; then 
	echo -n 'Hit <return> to overwrite remote/rhost.c or ^C to quit' 
	read ans 
	rm -f remote/rhost.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/rhost.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:	rhost.c,v $
X * Revision 2.0  85/12/07  18:21:52  toddb
X * First public release.
X * 
X */
Xstatic char	*rcsid = "$Header: rhost.c,v 2.0 85/12/07 18:21:52 toddb Rel $";
X#include	<stdio.h>
X#include	"server.h"
X
Xstatic char	*rhostpath;
Xstatic FILE	*fd;
Xstatic rhost	rh;
X
Xsetrhost(path)
X	register char	*path;
X{
X	extern int	errno;
X
X	if ((fd = fopen(path, "r")) != 0)
X		debug2("rhost %s\n", path);
X	errno = 0;
X}
X
Xrhost *getrhostent(buf)
X	register char	*buf;
X{
X	register char	*p;
X
X	while (1)
X	{
X		if (fd == NULL || fgets(buf, BUFSIZ, fd) == NULL)
X			return(NULL);
X
X		/*
X		 * assign the first token to rh_host and then look for the
X		 * second token on the line.  If there is none, then
X		 * don't return this entry because we can never map
X		 * a remote user id name of "" to anything meaningful.
X		 */
X		rh.rh_host = buf;
X		for (p=buf; *p && *p != ' ' && *p != '\n'; p++) ;
X		if (*p == '\n' || *p == '\0')
X			continue;
X
X		/*
X		 * remove the newline on the end
X		 */
X		rh.rh_user = p+1;
X		*p = '\0';
X		for (p++; *p && *p != ' ' && *p != '\n'; p++) ;
X		*p = '\0';
X		break;
X	}
X	return(&rh);
X}
X
Xendrhost()
X{
X	if (fd)
X	{
X		fclose(fd);
X		fd = NULL;
X	}
X}
SHAREOF
chmod 444 remote/rhost.c
#
# remote/rmtmnt.c
#
if [ -f remote/rmtmnt.c ]; then 
	echo -n 'Hit <return> to overwrite remote/rmtmnt.c or ^C to quit' 
	read ans 
	rm -f remote/rmtmnt.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/rmtmnt.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:	rmtmnt.c,v $
X * Revision 2.0  85/12/07  18:21:56  toddb
X * First public release.
X * 
X */
Xstatic char	*rcsid = "$Header: rmtmnt.c,v 2.0 85/12/07 18:21:56 toddb Rel $";
X#include	"server.h"
X#include	<stdio.h>
X#include	<sys/file.h>
X#include	<netdb.h>
X#include	<signal.h>
X#include	<setjmp.h>
X#include	<nlist.h>
X
Xextern int	errno;		/* for errors */
Xchar		*service;	/* service name */
Xchar		byteorder[4] = { BYTEORDER };
X
X/*
X * for slow or dead remote hosts, we catch alarms.
X */
Xint		onalrm();
Xstruct sigvec	vec = { onalrm, 0, 0 };
X
X/*
X * Displaying current mount points requires that we read kernel space.
X */
Xstruct nlist	nl[] = {
X#ifdef magnolia
X	{ "remote_info" },
X#else
X	{ "_remote_info" },
X#endif
X	{ "" },
X};
X#ifdef magnolia
Xchar		*kernel = "/magix";
X#else
Xchar		*kernel = "/vmunix";
X#endif
X
Xmain(argc, argv)
X	int	argc;
X	char	**argv;
X{
X	long	generic = FALSE,
X		unmount = FALSE;
X	char	*mntpt = NULL,
X		*host = NULL;
X
X	/*
X	 * Parse the args.
X	 */
X	for (argv++, argc--; argc; argv++, argc--)
X	{
X		if (**argv != '-')
X			break;
X		switch(argv[0][1]) {
X		case 's':	/* service name */
X			if (argv[0][2])
X				service = argv[0]+2;
X			else
X				argv++, argc--, service = argv[0];
X			break;
X		case 'g':	/* Make this a generic mount point */
X			generic = TRUE;
X			break;
X		case 'u':	/* unmount this mount point */
X			unmount = TRUE;
X			break;
X		default:
X			fprintf(stderr, "unknown option = %s\n", *argv);
X			usage();
X			exit(1);
X		}
X	}
X
X	if (! generic && ! unmount && argc-- > 0)
X		host = *argv++;
X	if (argc-- > 0)
X	{
X		mntpt = *argv++;
X		if (*mntpt != '/')
X		{
X			fprintf(stderr, "mount point must begin with '/'\n");
X			mntpt = NULL;
X		}
X	}
X	else
X	{
X		show();
X		exit(0);
X	}
X
X	if (argc > 0
X	|| (generic && unmount)
X	|| (mntpt == NULL))
X		usage();
X
X	if (unmount)
X		turnoff(mntpt);
X	else
X		turnon(mntpt, host);
X}
X
X/*
X * Display the current mount points in the kernal.
X */
Xshow()
X{
X	long		index = 0,
X			diff,
X			now,
X			kfd;
X	char		buf[BUFSIZ],
X			*p;
X	struct sockaddr_in hostaddr;
X	struct sockaddr_in	*sys;
X	struct servent *servp;
X	struct hostent	*hostent;
X	struct remoteinfo rinfo[ R_MAXSYS ],
X			*rp;
X	struct mbuf	bufs[ R_MAXSYS ],
X			*m;
X
X	servp = getservbyname(REMOTE_FS_SERVER, "tcp");
X	/*
X	 * Get the address of the remote mount point information
X	 * and read kernel memory.
X	 */
X	nlist(kernel, nl);
X	if(nl[0].n_type == 0)
X		log_fatal("no %s for namelist\n", kernel);
X	kfd = open("/dev/kmem", 0);
X	if(kfd < 0)
X		log_fatal("cannot open /dev/kmem\n");
X	lseek(kfd, (long)nl[0].n_value, 0);
X	read(kfd, rinfo, sizeof(struct remoteinfo) * R_MAXSYS);
X
X	/*
X	 * Now get the mbufs on each mount point.
X	 */
X	m = bufs;
X	time(&now);
X	for (index=0, rp = rinfo; rp < rinfo+R_MAXSYS; rp++, index++)
X	{
X		buf[0] = '\0';
X		if (rp->r_name || rp->r_mntpt)
X			printf("%d: ", index);
X		else
X			continue;
X		if (rp->r_name)
X		{
X			lseek(kfd, (long)rp->r_name, 0);
X			read(kfd, m, sizeof(struct mbuf));
X			rp->r_name = m++;
X			sys = mtod(rp->r_name, struct sockaddr_in *);
X			hostent = gethostbyaddr(&sys->sin_addr,
X				sizeof (struct in_addr), sys->sin_family);
X			if (hostent == NULL)
X			{
X				log("no host entry for %s\n",
X					inet_ntoa(sys->sin_addr));
X				continue;
X			}
X			bprintf(buf, "%s(%s) on ",
X				hostent->h_name, inet_ntoa(sys->sin_addr));
X		}
X		else
X			bprintf(buf, "generic mount point ");
X		bprintf(buf, "%s", rp->r_mntpath);
X		if (rp->r_mntpt == NULL)
X			bprintf(buf, ", implied");
X		if (rp->r_name && sys->sin_port != servp->s_port)
X			bprintf(buf, ", port %d", sys->sin_port);
X		if (rp->r_sock)
X			bprintf(buf, ", connected");
X		if (rp->r_close)
X			bprintf(buf, ", closing");
X		if (rp->r_users)
X			bprintf(buf, ", %d process%s",
X				rp->r_users, rp->r_users > 1 ? "es" : "");
X		if (rp->r_nfile)
X			bprintf(buf, ", %d open file%s",
X				rp->r_nfile, rp->r_nfile > 1 ? "s" : "");
X		if (rp->r_nchdir)
X			bprintf(buf, ", %d chdir%s",
X				rp->r_nchdir, rp->r_nchdir > 1 ? "'s" : "");
X		if (rp->r_opening)
X			bprintf(buf, ", opening");
X		if (rp->r_failed)
X		{
X			bprintf(buf, ", connect failed, retry ");
X			diff = rp->r_age - now;
X			if (diff <= 0)
X				bprintf(buf, "time reached");
X			else
X			{
X				bprintf(buf, "in ");
X				if (diff / 60)
X					bprintf(buf, "%d minute%s", diff/60,
X						(diff/60) > 1 ? "s" : "");
X				if (diff / 60 && diff % 60)
X					bprintf(buf, " and ");
X				if (diff % 60)
X					bprintf(buf, "%d second%s", diff%60,
X						(diff%60) > 1 ? "s" : "");
X			}
X		}
X		else if(rp->r_sock == NULL && rp->r_age)
X		{
X			bprintf(buf, ", last closed %s",
X				ctime(&rp->r_age));
X			buf[ strlen(buf)-1 ] = '\0'; /* remove newline */
X		}
X		printf("%s\n", buf);
X	}
X}
X
X/*
X * buffer printf.  i.e. do a printf into a buffer, appending to whatever
X * is there.  Split long lines.
X */
Xbprintf(buf, x0,x1,x2,x3,x4,x5,x6,x7,x8,x9)
X	char	*buf;
X{
X	char	xbuf[ BUFSIZ ],
X		*pfrom, *pto, c;
X	long	col;
X
X	sprintf(xbuf, x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);
X	for (pto = buf; *pto; pto++) ;
X	for (pfrom = xbuf, col=0; *pfrom; pfrom++, col++)
X	{
X		c = *pfrom;
X		*pto++ = c;
X		if (c == '\n')
X			col = -1;
X		else if (c == ' ' && col > 50)
X		{
X			*pto++ = '\n';
X			*pto++ = '\t';
X			col = 7;
X		}
X	}
X	*pto = '\0';
X}
X
X/*
X * Do a mount.
X */
Xturnon(mntpt, host)
X	char	*mntpt, *host;
X{
X	int	index, ret, fdout, fdin;
X	struct message msgbuf, *msg = &msgbuf;
X	struct sockaddr_in	sys;
X	char	buf[ BUFSIZ ];
X
X	if (strlen(mntpt) >= R_MNTPATHLEN)
X		log_fatal("mount point must be < %d chars\n", R_MNTPATHLEN);
X
X	/*
X	 * Connect to the machine and send it our byte order and
X	 * password file.
X	 */
X	if (host)
X	{
X		if ((fdout = tcpname(&sys, host)) < 0)
X			log("system unreachable now...");
X		index = remoteon(mntpt, strlen(mntpt)+1,
X			&sys, sizeof(struct sockaddr_in));
X	}
X	else
X		index = remoteon(mntpt, strlen(mntpt), 0, 0);
X	if (index == -1)
X		log_fatal("cant mount remote fs\n");
X	else if (host && fdout < 0)
X		log(" system mounted anyway\n");
X	if (host == NULL)
X		return;
X	if ((fdin = open("/etc/passwd", O_RDONLY)) == -1)
X		log_fatal("can't open /etc/passwd\n");
X	msg->m_syscall = htons(RSYS_nosys);
X	msg->m_hdlen = htons(R_MINRMSG + sizeof(long));
X	msg->m_totlen = htonl(R_MINRMSG + sizeof(long));
X	msg->m_args[0] = htonl(CMD_MOUNT);
X	write(fdout, msg, R_MINRMSG + sizeof(long));
X	write(fdout, byteorder, 4);
X	while ((ret = read(fdin, buf, BUFSIZ)) > 0)
X		write(fdout, buf, ret);
X	close(fdout);
X	close(fdin);
X	return;
X}
X
Xturnoff(mntpt)
X	char	*mntpt;
X{
X	int	index, fd;
X
X	index = remoteoff(mntpt);
X	if (index == -1)
X		log_fatal("can't unmount remote fs\n");
X	close(fd);
X}
X
Xusage()
X{
X	fprintf(stderr, "Usage:\t%s\n\t%s\n\t%s\n",
X		"rmtmnt [-sservicename] -g path",
X		"rmtmnt [-sservicename] host path",
X		"rmtmnt");
X	exit(1);
X}
X
Xtcpname(sin, host)
X	struct sockaddr_in *sin;
X	char	*host;
X{
X	struct servent *servp;
X	struct hostent *hostp;
X	int s;
X
X	servp = getservbyname(service ? service : REMOTE_FS_SERVER, "tcp");
X
X	if (servp == NULL) {
X		fprintf(stderr, "%s: unknown service\n", REMOTE_FS_SERVER);
X		exit(1);
X	}
X
X	hostp = gethostbyname(host);
X	if (hostp == NULL) {
X		fprintf(stderr, "%s: unknown host\en", host);
X		exit(1);
X	}
X	bzero((char *)sin, sizeof (struct sockaddr_in));
X	bcopy(hostp->h_addr, (char *)&sin->sin_addr, hostp->h_length);
X	sin->sin_family = hostp->h_addrtype;
X	sin->sin_port = servp->s_port;
X
X	/*
X	 * Ok, now make sure that the connection will work
X	 */
X	if (sigvec(SIGALRM, &vec, (struct sigvec *)0) == -1) {
X		perror("signals");
X		return(-1);
X	}
X	s = socket(AF_INET, SOCK_STREAM, 0);
X	if (s < 0)
X		return(-1);
X	alarm(5);
X	if(connect(s, sin, sizeof(struct sockaddr_in)) < 0) {
X		alarm(0);
X		return(-1);
X	}
X	alarm(0);
X	return(s);
X}
X
Xonalrm(sig)
X{
X	fprintf(stderr, "timeout: ");
X}
X
Xlog_fatal(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9)
X{
X	log(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);
X	exit(1);
X}
X
Xlog(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9)
X{
X	if (errno)
X		perror("rmtmnt");
X	errno = 0;
X	fprintf(stderr, x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);
X}
SHAREOF
chmod 444 remote/rmtmnt.c
#
# remote/route.c
#
if [ -f remote/route.c ]; then 
	echo -n 'Hit <return> to overwrite remote/route.c or ^C to quit' 
	read ans 
	rm -f remote/route.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/route.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:	route.c,v $
X * Revision 2.2  86/01/05  18:14:47  toddb
X * Added a forgotten case to gateway_listen(): S_CORRUPTED.
X * 
X * Revision 2.1  85/12/19  15:53:23  toddb
X * Changed declaration of a local variable (sigmask) because it conflicts
X * with a 4.3 define.
X * 
X * Revision 2.0  85/12/07  18:22:04  toddb
X * First public release.
X * 
X */
Xstatic char	*rcsid = "$Header: route.c,v 2.2 86/01/05 18:14:47 toddb Exp $";
X#include	"server.h"
X#include	<sys/file.h>
X#include	<sys/time.h>
X#include	<setjmp.h>
X#include	<errno.h>
X
Xextern short	current_pid;
Xextern short	current_ppid;
Xextern short	gateway_server;
Xextern short	current_server;
Xextern long	blocking_servers;
Xextern long	to_gateway;
Xextern long	from_servers;
Xextern long	errno;
Xextern boolean	i_am_gateway;
Xextern boolean	i_have_control;
Xextern boolean	gateway_needs_control;
Xextern boolean	route_to_gateway;
Xextern boolean	watch_for_lock;
Xextern boolean	i_am_asleep;
Xextern hosts	*host;
X
X/*
X * Reroute to the server whose pid is 'pid'.
X */
Xreroute(pid, msg)
X	register short	pid;
X	register struct message	*msg;
X{
X	if (route_to_gateway)
X	{
X		debug5("routing changed from server %d to gateway\n", pid);
X		route_to_gateway = FALSE;
X		pid = gateway_server;
X	}
X	watch_for_lock = gateway_needs_control = FALSE;
X	dont_gobble_msg(msg);
X
X	if (pid == current_pid)
X		log_fatal("reroute myself???\n");
X	debug5("%d waking up %d\n", current_pid, pid);
X
X	/*
X	 * If we are the gateway, there may be some servers that are blocking
X	 * on a request.  If so, then we lock file descriptor 2 with an
X	 * shared lock.  This tells the server to always check to see if
X	 * the lock goes up to an exclusive lock.  If so, then the server
X	 * must then return control to the gateway.
X	 */
X	if (i_am_gateway)
X	{
X		set_label("reading messages");
X		i_have_control = FALSE;
X		if (blocking_servers)
X			if (flock(2, LOCK_NB | LOCK_SH) < 0)
X				log_fatal("cannot lock fd 2\n");
X	}
X
X	i_am_asleep = TRUE;
X	if (pid == gateway_server)
X		say_something(S_THIS_IS_YOURS, gateway_server);
X	else
X		wake_up(pid);
X	slumber(FALSE);
X	if (! i_am_gateway)
X	{
X		/*
X		 * Check for the lock on fd 2.  But even if the gateway wants
X		 * control, go ahead an serve this request.
X		 */
X		if (flock(2, LOCK_NB | LOCK_EX) < 0)
X			if (flock(2, LOCK_NB | LOCK_SH) >= 0)
X			{
X				debug5("watch for lock on each request\n");
X				watch_for_lock = TRUE;
X				flock(2, LOCK_UN);
X			}
X			else
X			{
X				debug5("Gateway wants control\n");
X				gateway_needs_control = TRUE;
X			}
X		else
X			flock(2, LOCK_UN);
X	}
X}
X
X
X/*
X * Tell the gateway something.
X */
Xsay_something(cmd, arg)
X	register long	cmd, arg;
X{
X	gtmsgs		gmsg[2];
X	register gtmsgs	*g = gmsg;
X	register long	len = sizeof(gtmsgs);
X
X
X	if (cmd == S_NEWSERVER)	/* actually 2 messages */
X	{
X		g->g_server = current_ppid;
X		g->g_cmd = cmd;
X		g->g_pid = current_pid;
X		cmd = S_NEWPROCESS;
X		g++;
X		len += sizeof(gtmsgs);
X	}
X	g->g_server = current_pid;
X	g->g_cmd = cmd;
X	g->g_pid = arg;
X
X	debug5("say: cmd=%d, arg=%d\n", cmd, arg);
X	if (write(to_gateway, gmsg, len) != len)
X		log_fatal("pid %d: can't write to gateway!!\n",
X			current_pid);
X}
X
X/*
X * Read message from servers.  We do the allocation of space and maintain it.
X */
Xgtmsgs *read_gtmsgs()
X{
X	static gtmsgs	*msgs;
X	static long	current_len,
X			len_needed = 10;
X	register long	red;
X	register gtmsgs	*g;
X
X	/*
X	 * Allocate space for the current read.
X	 */
X	if (current_len < len_needed)
X	{
X		if (msgs)
X			msgs = (gtmsgs *)realloc(msgs,
X				len_needed * sizeof(gtmsgs));
X		else
X			msgs = (gtmsgs *)malloc(len_needed * sizeof(gtmsgs));
X		current_len = len_needed;
X	}
X
X	/*
X	 * Now read the messages.
X	 */
X	red = read(from_servers, msgs, (current_len-1) * sizeof(gtmsgs));
X	if (red % sizeof(gtmsgs) != 0)
X		log_fatal("partial message on read = %d\n", red);
X	red /= sizeof(gtmsgs);
X	if (red == current_len-1)
X		len_needed++;
X	msgs[ red ].g_server = 0;
X#ifdef RFSDEBUG
X	for (g=msgs; g->g_server; g++)
X		debug14("red: server %d, cmd %d, pid=%d\n",
X			g->g_server, g->g_cmd, g->g_pid);
X#endif RFSDEBUG
X	return(msgs);
X}
X	
X/*
X * This process is called to gather incomming messages from servers out
X * there with something interesting to say.  We return TRUE if we have
X * read a message from a process that is relinquishing control, FALSE
X * otherwise.
X */
Xgateway_listen()
X{
X	register process	*proc;
X	register gtmsgs		*msgs, *g;
X	short			dequeue();
X	register short		cmd, i, pid, server;
X
X	msgs = read_gtmsgs();
X
X	errno = 0;
X	for (g=msgs; g->g_server; g++)
X	{
X		pid    = g->g_pid;
X		server = g->g_server;
X		cmd    = g->g_cmd;
X
X		switch(cmd) {
X		case S_NEWSERVER: /* a new server forked by another server */
X			debug5("hear: %d forks new server %d\n", server, pid);
X			break;
X		case S_NEWPROCESS: /* a new process is being served */
X			proc = add_new_process(0, pid);
X			proc->p_handler = server;
X			debug5("hear: pid %d serving pid %d\n", server, pid);
X			break;
X		case S_PROCEXIT: /* some server's client did an exit() call */
X			debug5("hear: proc exit from server %d: pid=%d\n",
X				server, pid);
X			if ((proc = findprocess(pid, -1)) == NULL)
X				log("can't find pid %d!\n", pid);
X			else
X			{
X				deletelist(&host->h_proclist, proc);
X				freeproc(proc);
X			}
X			break;
X		case S_I_WOULD_BLOCK: /* server will block on I/O */
X			debug5("hear: server %d blocks\n", server);
X			blocking_servers++;
X			goto gateway_control;
X		case S_ALLDONE:	/* an existing server is ready to die */
X		case S_EOF:	/* a server got eof on command socket */
X			mourne();
X			debug5("hear: server %d %s... ", server,
X				cmd == S_ALLDONE ? "dead" : "got eof");
X			for (proc=host->h_proclist; proc; proc=proc->p_next)
X				if (proc->p_handler == server)
X				{
X					debug5("free proc %d...", proc->p_pid);
X					deletelist(&host->h_proclist, proc);
X					freeproc(proc);
X				}
X			debug5("\n");
X			/* fall through */
X		case S_THIS_IS_YOURS: /* just relinquish control */
X	gateway_control:
X			/*
X			 * Always unlock when we have control.
X			 */
X			flock(2, LOCK_UN);
X			if (cmd == S_THIS_IS_YOURS)
X				debug5("hear: server %d gives us control\n",
X					server);
X			/*
X			 * Now that we have control, see about dequeing
X			 * a server that is ready to go.  If there is one,
X			 * Then change this message so that it looks like
X			 * a message from ourself saying to reroute to
X			 * 'server'.
X			 */
X			server = dequeue();
X			if (server > 0)
X			{
X				debug5("server %d ready to go\n", server);
X				wake_up(server);
X			}
X			else
X			{
X				debug5("gateway pid %d continuing\n",
X					current_pid);
X				set_label("active");
X				i_have_control = TRUE;
X			}
X			break;
X		case S_I_AM_READY:
X			debug5("hear: server %d ready\n", server);
X			blocking_servers--;
X			if (flock(2, LOCK_EX) < 0)
X				log_fatal("cannot lock fd 2\n");
X			queue(server);
X			break;
X		case S_CORRUPTED:
X			log_fatal("corrupted input stream\n");
X			break;
X		default:
X			log("unknown message from %d = %d\n", server, cmd);
X			break;
X		}
X	}
X
X	return(FALSE);
X}
X
Xwake_up(pid)
X	long	pid;
X{
X	sendsig(pid, SIGIO);
X}
X
Xsendsig(pid, sig)
X	long	pid,
X		sig;
X{
X	register func	logger;
X	extern long	log(), log_fatal();
X
X	change_to_uid(0);
X	if (kill(pid, sig) < 0)
X	{
X		if (errno == ESRCH)
X			logger = log;
X		else
X			logger = log_fatal;
X		logger("couldn't signal %d w/ sig=%d\n", pid, sig);
X		return(FALSE);
X	}
X	return(TRUE);
X}
X
Xstatic short	*server_queue;
Xstatic short	server_len;
Xstatic short	last_server;
X/*
X * Put a server on a queue to be run again.  Fifo queue.
X */
Xqueue(pid)
X	register short	pid;
X{
X	if (++last_server > server_len)
X	{
X		server_len++;
X		if (server_queue == NULL)
X			server_queue = (short *)malloc(sizeof(short));
X		else
X			server_queue = (short *)realloc(server_queue,
X				server_len*sizeof(short));
X	}
X	server_queue[ last_server - 1 ] = pid;
X}
X
X/*
X * Get the first server off the queue.  Blech!  We have to copy all the
X * queue back one.
X */
Xshort dequeue()
X{
X	register short	retval, i;
X
X	if (last_server == 0)
X		return(0);
X	retval = server_queue[ 0 ];
X	for (i=1; i<last_server; i++)
X		server_queue[ i-1 ] = server_queue[ i ];
X	last_server--;
X	return( retval );
X}
X
X/*
X * Go to sleep awaiting a wakup call.  Do not return until we receive it.
X * However, if we are the gateway, we, of course MUST return and go
X * on reading messages.
X *
X * Since there is a window between testing the i_am_asleep flag and doing
X * the pause, in which we could be awakened, we must always jump around
X * this loop using longjmp() from the interrupt routine.
X */
Xslumber(forked)
X	boolean	forked;
X{
X	register long	signalmask;
X
X	if (i_am_gateway)
X	{
X		set_label("reading messages");
X		i_have_control = FALSE;
X		return;
X	}
X	set_label("asleep");
X	signalmask = sigblock(1<<(SIGIO-1));
X	while (i_am_asleep)
X		sigpause(signalmask);
X	sigsetmask(signalmask);
X
X	debug5("pid %d continuing%s\n",
X		current_pid, forked ? "after fork" : "");
X	set_label("active");
X	mourne();
X}
SHAREOF
chmod 444 remote/route.c
#
# remote/server.h
#
if [ -f remote/server.h ]; then 
	echo -n 'Hit <return> to overwrite remote/server.h or ^C to quit' 
	read ans 
	rm -f remote/server.h 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/server.h
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 * $Header: server.h,v 2.0 85/12/07 18:22:12 toddb Rel $
X *
X * $Log:	server.h,v $
X * Revision 2.0  85/12/07  18:22:12  toddb
X * First public release.
X * 
X */
X#include	<sys/param.h>
X#include	<sys/mbuf.h>
X#include	<sys/socket.h>
X#include	<netinet/in.h>
X#include	<remote/remotefs.h>
X
Xtypedef	unsigned char	boolean;
X
X/*
X * The maximum number of longs in a message that we accept
X */
X#define	MAXMSGS		((R_MAXMBUFS*MLEN)/sizeof(long))
X/*
X * The name of a host for which we have no record.  And the name of the user
X * to use if we don't recognize the user on the remote host.
X */
X#define	BOGUSHOST	"unknown host"
X#define	BOGUSUSER	"unknown user"
X#define DEFAULTUSER	"guest"
X
X/*
X * The uid number below which we reserve for privilaged users.
X */
X#define	UID_TOO_LOW	20
X
X/*
X * This is to make the debug? macro work for the server.
X *
X * The bits and what they turn on are as follows
X *	0x00000001	process switching
X *	0x00000002	system calls
X *	0x00000004	setuid/setgid, umask
X *	0x00000008	file descriptor allocation
X *	0x00000010	connections
X *	0x00000020	server switching
X *	0x00000040	nameserver
X *	0x00000080	directory nuxi
X *	0x00000100	message in and out
X *	0x00000200	don't fork child for gateway (good for adb)
X *	0x00000400	local/remote file decisions
X *	0x00000800	don't remove log file on exit (except exit on error)
X *	0x00001000	exec information
X *	0x00002000	auto debug for 0x20 (server switching)
X *	0x00004000	parsing messages to gateway
X */
X#define	rmt_debug	log
X#ifndef RFSDEBUG
X#define dumphost()
X#endif RFSDEBUG
X
X/*
X * The size of the initial allocation for internal io buffers.
X */
X#define	BIGBUF		(8*1024)
X
X/*
X * other Manifest constants...
X */
X#define	HOSTNAMELEN	255
X
X/*
X * Map a file descriptor from the user's fd to our own internal fd.
X */
X#define	MAPFD(fd, proc)			\
X	(((unsigned)fd > NOFILE) ? -1 : (proc)->p_fds[ fd ] )
X/*
X * requirements for different system calls.
X */
X#define	NEED_ZIP	0x000	/* don't need anything special */
X#define	NEED_CWD	0x001	/* need the current working directory set */
X#define	NEED_PERM	0x002	/* need the user and group ids set */
X#define	NEED_FD		0x004	/* need a file descriptor allocated */
X#define	NEED_2PATH	0x010	/* uses two paths */
X#define	NEED_MYSERVER	0x020	/* must be run by the assigned server */
X#define	NEED_2REMOTE	0x040	/* both paths must be remote */
X
X/*
X * Commands to the server sent by external programs (like rmtmnt, to mount
X * a remote system.
X */
X#define	CMD_SERVICE	1
X#define	CMD_MOUNT	2	/* here is mount information */
X#define	CMD_NEEDMOUNT	3	/* give me mount information */
X#define	CMD_WHOAMI	4	/* what uid am I on your host */
X
X/*
X * Finally, some commands that are sent to the gateway server by other
X * servers.
X */
X#define	S_NEWSERVER	0
X#define	S_NEWPROCESS	1
X#define	S_ALLDONE	2
X#define	S_THIS_IS_YOURS	3
X#define	S_PROCEXIT	4
X#define	S_EOF		5
X#define	S_I_WOULD_BLOCK	6
X#define	S_I_AM_READY	7
X#define	S_CORRUPTED	8
X
X/*
X * Macros for getting the address of the paths out of the incomming message.
X * Note that path1addr is for system calls that deal with only one path,
X * and twopath1addr() and twopath2addr() are for system calls that have
X * two paths (in the latter cases, path2 appears in the same position
X * as path1 does for single path system calls).
X */
X#define	path1addr(msg)		((char *)&(msg)->m_args[R_PATHSTART])
X#define	twopath1addr(msg)	((char *)(msg) + (msg)->m_args[R_PATHOFF])
X#define	twopath2addr(msg)	((char *)&(msg)->m_args[R_PATHSTART])
X
X/*
X * Macro for preventing getmsg(), and thereby gobble_last_msg() from
X * reading the last message.  This is used when control is being passed
X * from one server to another.
X */
X#define	dont_gobble_msg(msg)	(msg)->m_totlen = 0
X
X/*
X * Macro for determining whether a stat structure reflects the root inode
X * of our machine or not.
X */
X#define	isroot(p)	(p->st_ino == root.st_ino && p->st_dev == root.st_dev)
X
X/*
X * This structure is one-to-one with each local user where the server runs.
X * Note that the u_next and u_prev pointers must be located
X * in the first and second spots of the structure, respectively so that
X * they can be modified by the linked-list routines.
X */
Xtypedef struct users_type	users;
Xstruct users_type {
X	users	*u_next;	/* pointers for linked list, both forward... */
X	users	*u_prev;	/* ... and back. */
X	char	*u_name;	/* The ascii name of same. */
X	char	*u_dir;		/* login directory for same */
X	char	*u_rhosts;	/* path of the user's rhost file */
X	short	u_local_uid;	/* A user id number on the local host */
X	long	u_local_groups[NGROUPS];/* The groups this user belongs to */
X	char	u_numgroups;	/* The number of groups in u_local_groups */
X};
X
X/*
X * Remote user specification.
X */
Xtypedef struct ruser_type	rusers;
Xstruct ruser_type {
X	rusers	*r_next;
X	rusers	*r_prev;
X	short     r_uid;	/* Uid number on remote host ... */
X	char	*r_name;	/* Uid name on remote host ... */
X	users	*r_user;	/* corresponding local user */
X};
X
X/*
X * This is the important stuff.  There is one of these structures for
X * each pid that we are providing service to.
X */
Xtypedef struct process_type	process;
Xstruct process_type {
X	process		*p_next;
X	process		*p_prev;
X	long		p_returnval;	/* return value from last syscall */
X	rusers		*p_ruser;	/* info about the owner of this pid */
X	short		p_pid;		/* process id number on remote host */
X	short		p_uid;		/* remote uid that was last known */
X	short		p_handler;	/* the handler for this process */
X	short		p_errno;	/* errno for the system call */
X	char		p_execfd;	/* file descriptor of exec file */
X	boolean		p_execstarted;	/* whether we have done first read */
X	char		p_fds[ NOFILE ];/* fd's assoc. with this pid */
X};
X
X/*
X * This structure keeps track of the possible hosts that may make a connection
X * the the remote fs server.  Note that the h_next and hprev pointers must be
X * located in the first and second spots of the structure, respectively,
X * so that they can be modified by the linked-list routines.
X */
Xtypedef struct hosts_type	hosts;
Xstruct hosts_type {
X	hosts	*h_next;
X	hosts	*h_prev;
X	char	**h_names;	/* name (and aliases) of a host */
X	rusers	*h_rusers;	/* the user list for this host */
X	users	*h_default_user;/* default local user (if defined */
X	rusers	*h_default_ruser;/* default when the remote user is unknown */
X	long	h_portnum;	/* port number that we connected on */
X	char	*h_mntpt;	/* mount point for this machine */
X	process	*h_proclist;	/* processes we know about on this host */
X	struct in_addr	h_addr;	/* network address */
X	union h_bytes {
X		long	hu_mounted; /* non-zero if host has been mounted */
X		u_char	hu_byteorder[4]; /* byte order for this host */
X	} h_bytes;
X#define		h_mounted	h_bytes.hu_mounted
X#define		h_byteorder	h_bytes.hu_byteorder
X	char	h_cmdfd;	/* file descriptor for commands */
X	boolean	h_byteorderok;	/* true if byte order same as ours */
X	short	h_serverpid;	/* gateway server for this host */
X};
X
X/*
X * This structure is the mask structure that the linked list routines use
X * to modify any linked-list type of structure.  Note that l_next and l_prev
X * must be in the first and second spots.
X */
Xtypedef struct l_list_type	l_list;
Xstruct l_list_type {
X	l_list	*l_next;
X	l_list	*l_prev;
X	long	l_data;		/* never used */
X};
X
X/*
X * This structure is for convenience: it simply defines an easy way of
X * storing the host/user line found in a .rhost file.
X */
Xtypedef struct rhost_type	rhost;
Xstruct rhost_type {
X	char	*rh_host;
X	char	*rh_user;
X};
X
X/*
X * Each message from the servers to the gateway, is placed into this
X * structure, the "gateway message".
X */
Xtypedef struct gtmsg_type	gtmsgs;
Xstruct gtmsg_type {
X	short	g_server;	/* server that sent the message. */
X	short	g_pid;		/* pid of whom this message is about */
X	short	g_cmd;		/* what this message is about */
X};
X
X/*
X * Finally, this is the way we keep database info on the system calls
X * themselves.
X */
Xtypedef struct syscallmap	syscallmap;
Xstruct syscallmap {
X	func	s_server;
X	func	s_syscall;
X	char	s_type;
X};
X
Xrhost	*getrhostent();
Xhosts	*tcpaccept();
Xhosts	*findhostaddr();
Xhosts	*findhostname();
Xhosts	*newhost();
Xl_list	*toplist();
Xl_list	*bottomlist();
Xl_list	*addlist();
Xl_list	*deletelist();
Xprocess *newprocess();
Xprocess	*findprocess();
Xprocess	*change_to_proc();
Xprocess	*add_new_process();
Xusers	*finduid();
Xusers	*findusername();
Xusers	*newuser();
Xrusers	*findremuid();
Xrusers	*findrusername();
Xrusers	*newruser();
Xchar	**newname();
Xchar	*copy();
Xchar	*malloc();
Xchar	*realloc();
Xchar	*get_data_buf();
Xshort	*newshortlist();
SHAREOF
chmod 444 remote/server.h
#
# 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

sources-request@panda.UUCP (01/09/86)

Mod.sources:  Volume 3, Issue 80
Submitted by: tektronix!tekcrl!toddb

#!/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/serverio.c
#	remote/serversyscall.c
#	remote/shells
#	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
#	remote/usr.include.PYR2.5/syscall.h.diff
#	remote/usr.include.VAX4.3
#	remote/usr.include.VAX4.2
#	remote/usr.include.VAX4.2/syscall.h.diff
#	remote/usr.src.lib.libc
#	remote/usr.src.lib.libc/Makefile
#	remote/usr.src.lib.libc/gen
#	remote/usr.src.lib.libc/gen/pyr.errlst.c.diff
#	remote/usr.src.lib.libc/gen/vax.errlst.c.diff
#	remote/usr.src.lib.libc/pyr
#	remote/usr.src.lib.libc/pyr/sys
#	remote/usr.src.lib.libc/pyr/sys/remotename.s
#	remote/usr.src.lib.libc/pyr/sys/remoteoff.s
#	remote/usr.src.lib.libc/pyr/sys/remoteon.s
#	remote/usr.src.lib.libc/vax
#	remote/usr.src.lib.libc/vax/sys
#	remote/usr.src.lib.libc/vax/sys/remotename.c
#	remote/usr.src.lib.libc/vax/sys/remoteoff.c
#	remote/usr.src.lib.libc/vax/sys/remoteon.c
#	remote/usr.sys.PYR2.5
#	remote/usr.sys.PYR2.5/conf
#	remote/usr.sys.PYR2.5/conf/makefromsource.diff
#	remote/usr.sys.PYR2.5/h
#
# 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.0  85/12/07  18:22:33  toddb
X * First public release.
X * 
X */
Xstatic char	*rcsid = "$Header: serverio.c,v 2.0 85/12/07 18:22:33 toddb Rel $";
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_addr, (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.0  85/12/07  18:22:44  toddb
X * First public release.
X * 
X */
Xstatic char	*rcsid = "$Header: serversyscall.c,v 2.0 85/12/07 18:22:44 toddb Rel $";
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 = ENOEXEC;
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
#
mkdir remote/shells
chmod 775 remote/shells
#
# 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 documentatino 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
#
mkdir remote/usr.include.PYR2.5
chmod 775 remote/usr.include.PYR2.5
#
# 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
#
mkdir remote/usr.include.VAX4.2
chmod 775 remote/usr.include.VAX4.2
if [ -f remote/usr.include.VAX4.3 ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.include.VAX4.2 or ^C to quit' 
	read ans 
	rm -rf remote/usr.include.VAX4.3 
fi
ln -s remote/usr.include.VAX4.2 remote/usr.include.VAX4.3
#
# 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
#
mkdir remote/usr.src.lib.libc
chmod 775 remote/usr.src.lib.libc
#
# 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
#
mkdir remote/usr.src.lib.libc/gen
chmod 775 remote/usr.src.lib.libc/gen
#
# 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
#
# remote/usr.src.lib.libc/pyr
#
mkdir remote/usr.src.lib.libc/pyr
chmod 775 remote/usr.src.lib.libc/pyr
#
# remote/usr.src.lib.libc/pyr/sys
#
mkdir remote/usr.src.lib.libc/pyr/sys
chmod 775 remote/usr.src.lib.libc/pyr/sys
#
# remote/usr.src.lib.libc/pyr/sys/remotename.s
#
if [ -f remote/usr.src.lib.libc/pyr/sys/remotename.s ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.src.lib.libc/pyr/sys/remotename.s or ^C to quit' 
	read ans 
	rm -f remote/usr.src.lib.libc/pyr/sys/remotename.s 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.src.lib.libc/pyr/sys/remotename.s
X#include "syscall.h"
X	.globl cerror
X	.globl _remotename
X	.align 2
X_remotename:
X	###entry###
X	movw	pr0,tr1
X	movw	pr1,tr2
X	movw	pr2,tr3
X	movw	pr3,tr4
X	movw	pr4,tr5
X	movw	$/**/SYS_remotename, tr0
X	callk $0
X	cmpw	$0,tr0
X	bne	err
X	movw	tr1,pr0
X	ret
Xerr:
X	jump cerror
SHAREOF
chmod 644 remote/usr.src.lib.libc/pyr/sys/remotename.s
#
# remote/usr.src.lib.libc/pyr/sys/remoteoff.s
#
if [ -f remote/usr.src.lib.libc/pyr/sys/remoteoff.s ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.src.lib.libc/pyr/sys/remoteoff.s or ^C to quit' 
	read ans 
	rm -f remote/usr.src.lib.libc/pyr/sys/remoteoff.s 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.src.lib.libc/pyr/sys/remoteoff.s
X#include "syscall.h"
X	.globl cerror
X	.globl _remoteoff
X	.align 2
X_remoteoff:
X	###entry###
X	movw	pr0,tr1
X	movw	$/**/SYS_remoteoff, tr0
X	callk $0
X	cmpw	$0,tr0
X	bne	err
X	movw	tr1,pr0
X	ret
Xerr:
X	jump cerror
SHAREOF
chmod 644 remote/usr.src.lib.libc/pyr/sys/remoteoff.s
#
# remote/usr.src.lib.libc/pyr/sys/remoteon.s
#
if [ -f remote/usr.src.lib.libc/pyr/sys/remoteon.s ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.src.lib.libc/pyr/sys/remoteon.s or ^C to quit' 
	read ans 
	rm -f remote/usr.src.lib.libc/pyr/sys/remoteon.s 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.src.lib.libc/pyr/sys/remoteon.s
X#include "syscall.h"
X	.globl cerror
X	.globl _remoteon
X	.align 2
X_remoteon:
X	###entry###
X	movw	pr0,tr1
X	movw	pr1,tr2
X	movw	pr2,tr3
X	movw	pr3,tr4
X	movw	$/**/SYS_remoteon, tr0
X	callk $0
X	cmpw	$0,tr0
X	bne	err
X	movw	tr1,pr0
X	ret
Xerr:
X	jump cerror
SHAREOF
chmod 644 remote/usr.src.lib.libc/pyr/sys/remoteon.s
#
# remote/usr.src.lib.libc/vax
#
mkdir remote/usr.src.lib.libc/vax
chmod 775 remote/usr.src.lib.libc/vax
#
# remote/usr.src.lib.libc/vax/sys
#
mkdir remote/usr.src.lib.libc/vax/sys
chmod 775 remote/usr.src.lib.libc/vax/sys
#
# remote/usr.src.lib.libc/vax/sys/remotename.c
#
if [ -f remote/usr.src.lib.libc/vax/sys/remotename.c ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.src.lib.libc/vax/sys/remotename.c or ^C to quit' 
	read ans 
	rm -f remote/usr.src.lib.libc/vax/sys/remotename.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.src.lib.libc/vax/sys/remotename.c
X/* remotename.c 4.2 85/10/25 */
X
X#include "SYS.h"
X
XSYSCALL(remotename)
X	ret
SHAREOF
chmod 644 remote/usr.src.lib.libc/vax/sys/remotename.c
#
# remote/usr.src.lib.libc/vax/sys/remoteoff.c
#
if [ -f remote/usr.src.lib.libc/vax/sys/remoteoff.c ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.src.lib.libc/vax/sys/remoteoff.c or ^C to quit' 
	read ans 
	rm -f remote/usr.src.lib.libc/vax/sys/remoteoff.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.src.lib.libc/vax/sys/remoteoff.c
X/* remoteoff.c 4.2 85/10/25 */
X
X#include "SYS.h"
X
XSYSCALL(remoteoff)
X	ret
SHAREOF
chmod 644 remote/usr.src.lib.libc/vax/sys/remoteoff.c
#
# remote/usr.src.lib.libc/vax/sys/remoteon.c
#
if [ -f remote/usr.src.lib.libc/vax/sys/remoteon.c ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.src.lib.libc/vax/sys/remoteon.c or ^C to quit' 
	read ans 
	rm -f remote/usr.src.lib.libc/vax/sys/remoteon.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.src.lib.libc/vax/sys/remoteon.c
X/* remoteon.c 4.2 85/10/25 */
X
X#include "SYS.h"
X
XSYSCALL(remoteon)
X	ret
SHAREOF
chmod 644 remote/usr.src.lib.libc/vax/sys/remoteon.c
#
# remote/usr.sys.PYR2.5
#
mkdir remote/usr.sys.PYR2.5
chmod 775 remote/usr.sys.PYR2.5
#
# remote/usr.sys.PYR2.5/conf
#
mkdir remote/usr.sys.PYR2.5/conf
chmod 775 remote/usr.sys.PYR2.5/conf
#
# remote/usr.sys.PYR2.5/conf/makefromsource.diff
#
if [ -f remote/usr.sys.PYR2.5/conf/makefromsource.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/conf/makefromsource.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.PYR2.5/conf/makefromsource.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.PYR2.5/conf/makefromsource.diff
X*** /usr/toddb/crl/pyr/conf/makefromsource	Wed Sep 18 00:25:15 1985
X--- makefromsource	Thu Jan  2 15:18:44 1986
X***************
X*** 31,37
X  # Compile options that are passed to all other source files:
X  #   do not change (other than adding new options)
X  #
X! OPTIONS	= -DKERNEL -DINET -DRcsIdent -DNITP=8 -DXT -DWATCH
X  
X  CFLAGS	= ${PROFILE} -O $(OPTIONS) ${DUALCPU}
X  ENTRY	= _initcpus
X
X--- 31,37 -----
X  # Compile options that are passed to all other source files:
X  #   do not change (other than adding new options)
X  #
X! OPTIONS	= -DKERNEL -DINET -DRcsIdent -DNITP=8 -DXT -DWATCH -DREMOTEFS
X  
X  CFLAGS	= ${PROFILE} -O $(OPTIONS) ${DUALCPU}
X  ENTRY	= _initcpus
X***************
X*** 87,92
X  	-mv param.c oldparam.c
X  	cp ../conf/param.c .
X  
X  FRC:
X  # MAKEFROMBINARY ENDS HERE -- Do not delete this line.
X  
X
X--- 87,99 -----
X  	-mv param.c oldparam.c
X  	cp ../conf/param.c .
X  
X+ ../remote/rmt_data.c: ../remote/rmt_data_template ../remote/remotefs.h \
X+     ../sys/init_sysent.c
X+ 	cat ../remote/rmt_data_template > ../remote/nrmt_data.c
X+ 	/lib/cpp ${CFLAGS} ../sys/init_sysent.c | sh ../remote/remote_mkdata \
X+ 		../remote/remotefs.h >> ../remote/nrmt_data.c
X+ 	mv ../remote/nrmt_data.c ../remote/rmt_data.c
X+ 
X  FRC:
X  # MAKEFROMBINARY ENDS HERE -- Do not delete this line.
X  
X***************
X*** 101,107
X  	netimp debug 
X  
X  LIBS	= sys${LIB} io${LIB} net${LIB} ether${LIB} drw${LIB} \
X! 	imp${LIB} dbg${LIB} 
X  
X  # The following lines are automatically generated; do not modify them manually.
X  # LISTS BEGIN HERE -- Do not delete this line: make lists uses it
X
X--- 108,114 -----
X  	netimp debug 
X  
X  LIBS	= sys${LIB} io${LIB} net${LIB} ether${LIB} drw${LIB} \
X! 	imp${LIB} dbg${LIB} remote${LIB}
X  
X  # The following lines are automatically generated; do not modify them manually.
X  # LISTS BEGIN HERE -- Do not delete this line: make lists uses it
X***************
X*** 205,210
X  debugOBJS= \
X  	debug1.o debug2.o debug3.o dis.o 
X  
X  CFILES= \
X  	${sysSRCS} ${ioSRCS} ${netSRCS} ${netinetSRCS} ${etherSRCS} \
X  	${dr11wSRCS} ${netimpSRCS} ${debugSRCS} 
X
X--- 212,227 -----
X  debugOBJS= \
X  	debug1.o debug2.o debug3.o dis.o 
X  
X+ remoteSRCS= \
X+ 	../remote/rmt_data.c ../remote/rmt_exec.c ../remote/rmt_final.c \
X+ 	../remote/rmt_general.c ../remote/rmt_generic.c ../remote/rmt_io.c \
X+ 	../remote/rmt_subr.c ../remote/rmt_syscall1.c ../remote/rmt_syscall2.c \
X+ 	../remote/rmt_syscall3.c
X+ 
X+ remoteOBJS= \
X+ 	rmt_data.o rmt_exec.o rmt_final.o rmt_general.o rmt_generic.o \
X+ 	rmt_io.o rmt_subr.o rmt_syscall1.o rmt_syscall2.o rmt_syscall3.o
X+ 
X  CFILES= \
X  	${sysSRCS} ${ioSRCS} ${netSRCS} ${netinetSRCS} ${etherSRCS} \
X  	${dr11wSRCS} ${netimpSRCS} ${debugSRCS} ${remoteSRCS}
X***************
X*** 207,213
X  
X  CFILES= \
X  	${sysSRCS} ${ioSRCS} ${netSRCS} ${netinetSRCS} ${etherSRCS} \
X! 	${dr11wSRCS} ${netimpSRCS} ${debugSRCS} 
X  
X  MLFILES= \
X  	../ml/asm.s ../ml/ml.s 
X
X--- 224,230 -----
X  
X  CFILES= \
X  	${sysSRCS} ${ioSRCS} ${netSRCS} ${netinetSRCS} ${etherSRCS} \
X! 	${dr11wSRCS} ${netimpSRCS} ${debugSRCS} ${remoteSRCS}
X  
X  MLFILES= \
X  	../ml/asm.s ../ml/ml.s 
X***************
X*** 244,250
X  	../netinet/ip_var.h ../netinet/tcp.h ../netinet/tcp_debug.h \
X  	../netinet/tcp_fsm.h ../netinet/tcp_seq.h ../netinet/tcp_timer.h \
X  	../netinet/tcp_var.h ../netinet/tcpip.h ../netinet/udp.h \
X! 	../netinet/udp_var.h 
X  # LISTS END HERE -- Do not delete this line: make lists uses it
X  
X  # Special treatment for these files (symbolic links) which are used to
X
X--- 261,267 -----
X  	../netinet/ip_var.h ../netinet/tcp.h ../netinet/tcp_debug.h \
X  	../netinet/tcp_fsm.h ../netinet/tcp_seq.h ../netinet/tcp_timer.h \
X  	../netinet/tcp_var.h ../netinet/tcpip.h ../netinet/udp.h \
X! 	../netinet/udp_var.h ../remote/remotefs.h
X  # LISTS END HERE -- Do not delete this line: make lists uses it
X  
X  # Special treatment for these files (symbolic links) which are used to
X***************
X*** 308,313
X  dbg${LIB}: $(debugOBJS)
X  	ar cr $@ $? && ranlib $@
X  
X  
X  ml.o:	${MLFILES}
X  	rm -f mltemp.[cs]
X
X--- 325,332 -----
X  dbg${LIB}: $(debugOBJS)
X  	ar cr $@ $? && ranlib $@
X  
X+ remote${LIB}: $(remoteOBJS)
X+ 	ar cr $@ $? && ranlib $@
X  
X  ml.o:	${MLFILES}
X  	rm -f mltemp.[cs]
X***************
X*** 763,768
X  	${LD} -x -r $@ && mv a.out $@
X  dis.o: ../debug/dis.c
X  	${CC} -I. -c ${CFLAGS} ../debug/dis.c
X  	${LD} -x -r $@ && mv a.out $@
X  # RULES END HERE -- Do not delete this line: make rules uses it
X  
X
X--- 782,817 -----
X  	${LD} -x -r $@ && mv a.out $@
X  dis.o: ../debug/dis.c
X  	${CC} -I. -c ${CFLAGS} ../debug/dis.c
X+ 	${LD} -x -r $@ && mv a.out $@
X+ rmt_data.o: ../remote/rmt_data.c
X+ 	${CC} -I. -c -DRFSDEBUG ${CFLAGS} ../remote/rmt_data.c
X+ 	${LD} -x -r $@ && mv a.out $@
X+ rmt_exec.o: ../remote/rmt_exec.c
X+ 	${CC} -I. -c -DRFSDEBUG ${CFLAGS} ../remote/rmt_exec.c
X+ 	${LD} -x -r $@ && mv a.out $@
X+ rmt_final.o: ../remote/rmt_final.c
X+ 	${CC} -I. -c -DRFSDEBUG ${CFLAGS} ../remote/rmt_final.c
X+ 	${LD} -x -r $@ && mv a.out $@
X+ rmt_general.o: ../remote/rmt_general.c
X+ 	${CC} -I. -c -DRFSDEBUG ${CFLAGS} ../remote/rmt_general.c
X+ 	${LD} -x -r $@ && mv a.out $@
X+ rmt_generic.o: ../remote/rmt_generic.c
X+ 	${CC} -I. -c -DRFSDEBUG ${CFLAGS} ../remote/rmt_generic.c
X+ 	${LD} -x -r $@ && mv a.out $@
X+ rmt_io.o: ../remote/rmt_io.c
X+ 	${CC} -I. -c -DRFSDEBUG ${CFLAGS} ../remote/rmt_io.c
X+ 	${LD} -x -r $@ && mv a.out $@
X+ rmt_subr.o: ../remote/rmt_subr.c
X+ 	${CC} -I. -c -DRFSDEBUG ${CFLAGS} ../remote/rmt_subr.c
X+ 	${LD} -x -r $@ && mv a.out $@
X+ rmt_syscall1.o: ../remote/rmt_syscall1.c
X+ 	${CC} -I. -c -DRFSDEBUG ${CFLAGS} ../remote/rmt_syscall1.c
X+ 	${LD} -x -r $@ && mv a.out $@
X+ rmt_syscall2.o: ../remote/rmt_syscall2.c
X+ 	${CC} -I. -c -DRFSDEBUG ${CFLAGS} ../remote/rmt_syscall2.c
X+ 	${LD} -x -r $@ && mv a.out $@
X+ rmt_syscall3.o: ../remote/rmt_syscall3.c
X+ 	${CC} -I. -c -DRFSDEBUG ${CFLAGS} ../remote/rmt_syscall3.c
X  	${LD} -x -r $@ && mv a.out $@
X  # RULES END HERE -- Do not delete this line: make rules uses it
X  
SHAREOF
chmod 664 remote/usr.sys.PYR2.5/conf/makefromsource.diff
#
# remote/usr.sys.PYR2.5/h
#
mkdir remote/usr.sys.PYR2.5/h
chmod 775 remote/usr.sys.PYR2.5/h

sources-request@panda.UUCP (01/09/86)

Mod.sources:  Volume 3, Issue 81
Submitted by: tektronix!tekcrl!toddb

#!/bin/sh
#
# RFS, a kernel-resident remote file system.  Shar 5 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/usr.sys.PYR2.5/h/errno.h.diff
#	remote/usr.sys.VAX4.2/h/param.h.diff
#	remote/usr.sys.VAX4.3/h/param.h.diff
#	remote/usr.sys.PYR2.5/h/param.h.diff
#	remote/usr.sys.PYR2.5/h/user.h.diff
#	remote/usr.sys.PYR2.5/sys
#	remote/usr.sys.PYR2.5/sys/init_sysent.c.diff
#	remote/usr.sys.PYR2.5/sys/kern_exec.c.diff
#	remote/usr.sys.PYR2.5/sys/kern_exit.c.diff
#	remote/usr.sys.PYR2.5/sys/kern_trap.c.diff
#	remote/usr.sys.PYR2.5/sys/sys_inode.c.diff
#	remote/usr.sys.PYR2.5/sys/ufs_nami.c.diff
#	remote/usr.sys.PYR2.5/sys/ufs_syscalls.c.diff
#	remote/usr.sys.PYR2.5/sys/uipc_socket.c.diff
#	remote/usr.sys.VAX4.2
#	remote/usr.sys.VAX4.2/conf
#	remote/usr.sys.VAX4.3/conf/files.diff
#	remote/usr.sys.VAX4.2/conf/files.diff
#	remote/usr.sys.VAX4.2/conf/makefile.vax.diff
#	remote/usr.sys.VAX4.2/h
#	remote/usr.sys.VAX4.3/h/errno.h.diff
#	remote/usr.sys.VAX4.2/h/errno.h.diff
#	remote/usr.sys.VAX4.2/h/user.h.diff
#	remote/usr.sys.VAX4.2/machine
#	remote/usr.sys.VAX4.2/machine/trap.c.diff
#	remote/usr.sys.VAX4.2/sys
#	remote/usr.sys.VAX4.2/sys/init_sysent.c.diff
#	remote/usr.sys.VAX4.2/sys/kern_exec.c.diff
#	remote/usr.sys.VAX4.2/sys/kern_exit.c.diff
#	remote/usr.sys.VAX4.2/sys/sys_inode.c.diff
#	remote/usr.sys.VAX4.2/sys/ufs_nami.c.diff
#	remote/usr.sys.VAX4.2/sys/ufs_syscalls.c.diff
#	remote/usr.sys.VAX4.2/sys/uipc_socket.c.diff
#	remote/usr.sys.VAX4.3
#	remote/usr.sys.VAX4.3/conf
#	remote/usr.sys.VAX4.3/conf/Makefile.vax.diff
#	remote/usr.sys.VAX4.3/conf/makefile.vax.diff
#	remote/usr.sys.VAX4.3/h
#	remote/usr.sys.VAX4.3/h/user.h.diff
#	remote/usr.sys.VAX4.3/machine
#	remote/usr.sys.VAX4.3/machine/trap.c.diff
#	remote/usr.sys.VAX4.3/sys
#	remote/usr.sys.VAX4.3/sys/init_sysent.c.diff
#
# remote/usr.sys.PYR2.5/sys
#
mkdir remote/usr.sys.PYR2.5/sys
chmod 775 remote/usr.sys.PYR2.5/sys
#
# remote/usr.sys.VAX4.2
#
mkdir remote/usr.sys.VAX4.2
chmod 775 remote/usr.sys.VAX4.2
#
# remote/usr.sys.VAX4.2/conf
#
mkdir remote/usr.sys.VAX4.2/conf
chmod 775 remote/usr.sys.VAX4.2/conf
#
# remote/usr.sys.VAX4.2/h
#
mkdir remote/usr.sys.VAX4.2/h
chmod 775 remote/usr.sys.VAX4.2/h
#
# remote/usr.sys.VAX4.2/machine
#
mkdir remote/usr.sys.VAX4.2/machine
chmod 775 remote/usr.sys.VAX4.2/machine
#
# remote/usr.sys.VAX4.2/sys
#
mkdir remote/usr.sys.VAX4.2/sys
chmod 775 remote/usr.sys.VAX4.2/sys
#
# remote/usr.sys.VAX4.3
#
mkdir remote/usr.sys.VAX4.3
chmod 775 remote/usr.sys.VAX4.3
#
# remote/usr.sys.VAX4.3/conf
#
mkdir remote/usr.sys.VAX4.3/conf
chmod 775 remote/usr.sys.VAX4.3/conf
#
# remote/usr.sys.VAX4.3/h
#
mkdir remote/usr.sys.VAX4.3/h
chmod 775 remote/usr.sys.VAX4.3/h
#
# remote/usr.sys.VAX4.3/machine
#
mkdir remote/usr.sys.VAX4.3/machine
chmod 775 remote/usr.sys.VAX4.3/machine
#
# remote/usr.sys.VAX4.3/sys
#
mkdir remote/usr.sys.VAX4.3/sys
chmod 775 remote/usr.sys.VAX4.3/sys
#
# remote/usr.sys.PYR2.5/h/errno.h.diff
#
if [ -f remote/usr.sys.PYR2.5/h/errno.h.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/h/errno.h.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.PYR2.5/h/errno.h.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.PYR2.5/h/errno.h.diff
XThese changes add three new error numbers for the sake of RFS.
X***************
X*** 90,95
X  #define	EUSERS		68		/* Too many users */
X  #define	EDQUOT		69		/* Disc quota exceeded */
X  
X  
X  /*-----------------System V unique errno's----------------------*/
X  #define	ENOMSG	100	/* No message of desired type		*/
X
X--- 90,99 -----
X  #define	EUSERS		68		/* Too many users */
X  #define	EDQUOT		69		/* Disc quota exceeded */
X  
X+ /* remote fs stuff */
X+ #define EISREMOTE	70		/* file is on a remote system */
X+ #define ETOOMANYREMOTE	71		/* too many remote file systems */
X+ #define	ENOREMOTEFS	72		/* no remote file system */
X  
X  /*-----------------System V unique errno's----------------------*/
X  #define	ENOMSG	100	/* No message of desired type		*/
SHAREOF
chmod 664 remote/usr.sys.PYR2.5/h/errno.h.diff
#
# remote/usr.sys.PYR2.5/h/param.h.diff
#
if [ -f remote/usr.sys.PYR2.5/h/param.h.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/h/param.h.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.PYR2.5/h/param.h.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.PYR2.5/h/param.h.diff
XThis addition defines NREMOTE, the number of remote mount points.
X***************
X*** 26,27
X   * Machine-independent constants
X   */
X
X--- 26,30 -----
X   * Machine-independent constants
X   */
X+ #ifdef REMOTEFS
X+ #define	NREMOTE	8		/* number of remote file systems */
X+ #endif REMOTEFS
SHAREOF
chmod 664 remote/usr.sys.PYR2.5/h/param.h.diff
if [ -f remote/usr.sys.VAX4.2/h/param.h.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/h/param.h.diff or ^C to quit' 
	read ans 
	rm -rf remote/usr.sys.VAX4.2/h/param.h.diff 
fi
ln remote/usr.sys.PYR2.5/h/param.h.diff remote/usr.sys.VAX4.2/h/param.h.diff
if [ -f remote/usr.sys.VAX4.3/h/param.h.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/h/param.h.diff or ^C to quit' 
	read ans 
	rm -rf remote/usr.sys.VAX4.3/h/param.h.diff 
fi
ln remote/usr.sys.PYR2.5/h/param.h.diff remote/usr.sys.VAX4.3/h/param.h.diff
#
# remote/usr.sys.PYR2.5/h/user.h.diff
#
if [ -f remote/usr.sys.PYR2.5/h/user.h.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/h/user.h.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.PYR2.5/h/user.h.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.PYR2.5/h/user.h.diff
XThese changes keep track of the per-process RFS information.
X***************
X*** 169,174
X  		dev_t nc_dev;		/* dev of cached directory */
X  		time_t nc_time;		/* time stamp for cache entry */
X  	} u_ncache;
X  	int	u_stack[1];
X  };
X  
X
X--- 169,184 -----
X  		dev_t nc_dev;		/* dev of cached directory */
X  		time_t nc_time;		/* time stamp for cache entry */
X  	} u_ncache;
X+ #ifdef REMOTEFS
X+ 	short	u_rmtoffset[2];		/* path offset for local segment */
X+ 	short	u_rmtcdir;		/* system # of remote current dir */
X+ 	long	u_rmtsys;		/* room for 32 systems */
X+ 					/* one bit for each remote system */
X+ #ifdef pyr /* Pyramid */
X+ 	int	u_ap;
X+ #define		u_arg	u_ap
X+ #endif pyr
X+ #endif REMOTEFS
X  	int	u_stack[1];
X  };
X  
SHAREOF
chmod 664 remote/usr.sys.PYR2.5/h/user.h.diff
#
# remote/usr.sys.PYR2.5/sys/init_sysent.c.diff
#
if [ -f remote/usr.sys.PYR2.5/sys/init_sysent.c.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/sys/init_sysent.c.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.PYR2.5/sys/init_sysent.c.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.PYR2.5/sys/init_sysent.c.diff
XThese two changes add in the new RFS systems calls, remoteon(), remoteoff()
Xand  remotename().  If the second hunk fails, then you have some system
Xcall numbers that are not in standard Pyramid 2.5.
X***************
X*** 124,129
X   */
X  int	setuniverse(), ugetcsbase();
X  
X  /* BEGIN JUNK */
X  int	profil();		/* 'cuz sys calls are interruptible */
X  int	vhangup();		/* should just do in exit() */
X
X--- 124,138 -----
X   */
X  int	setuniverse(), ugetcsbase();
X  
X+ #ifdef REMOTEFS
X+ /*
X+  * remote file sys stuff (toddb@du)
X+  */
X+ int	remoteon(),
X+ 	remoteoff(),
X+ 	remotename();
X+ #endif REMOTEFS
X+ 
X  /* BEGIN JUNK */
X  int	profil();		/* 'cuz sys calls are interruptible */
X  int	vhangup();		/* should just do in exit() */
X***************
X*** 324,329
X  #endif NSA
X  	{ setprocesshost, 1},	/* 166 = setprocesshost */
X  	{ getprocesshost, 1},	/* 167 = getprocesshost */
X  };
X  int	nsysent = sizeof (sysent) / sizeof (sysent[0]);
X  
X
X--- 333,347 -----
X  #endif NSA
X  	{ setprocesshost, 1},	/* 166 = setprocesshost */
X  	{ getprocesshost, 1},	/* 167 = getprocesshost */
X+ #ifdef REMOTEFS
X+ 	{ remoteon, 4 },	/* 168 = remoteon */
X+ 	{ remoteoff, 1 },	/* 169 = remoteoff */
X+ 	{ remotename, 5 },	/* 170 = remotename */
X+ #else REMOTEFS
X+ 	{ nosys, 0},		/* 168 = reserved for REMOTEFS */
X+ 	{ nosys, 0},		/* 169 = reserved for REMOTEFS */
X+ 	{ nosys, 0},		/* 170 = reserved for REMOTEFS */
X+ #endif REMOTEFS
X  };
X  int	nsysent = sizeof (sysent) / sizeof (sysent[0]);
X  
SHAREOF
chmod 664 remote/usr.sys.PYR2.5/sys/init_sysent.c.diff
#
# remote/usr.sys.PYR2.5/sys/kern_exec.c.diff
#
if [ -f remote/usr.sys.PYR2.5/sys/kern_exec.c.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/sys/kern_exec.c.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.PYR2.5/sys/kern_exec.c.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.PYR2.5/sys/kern_exec.c.diff
XThe following changes implement local execution of an object file that
Xlives on another host.
X***************
X*** 58,63
X  #include "../h/cmap.h"
X  #include "../h/vmmac.h"
X  #include "../h/debug.h"
X  
X  int  *swapstack();
X  
X
X--- 58,69 -----
X  #include "../h/cmap.h"
X  #include "../h/vmmac.h"
X  #include "../h/debug.h"
X+ #ifdef REMOTEFS
X+ /*
X+  * needed only if EISREMOTE isn't in /usr/include/errno.h
X+  */
X+ #include "../h/errno.h"
X+ #endif REMOTEFS
X  
X  int  *swapstack();
X  
X***************
X*** 76,81
X  	register char *cp;
X  	register struct buf *bp;
X  	register int na, ne, ucp, ap, c, i;
X  	register int indir, uid, gid;
X  	register char *sharg;
X  	register struct inode *ip;
X
X--- 82,93 -----
X  	register char *cp;
X  	register struct buf *bp;
X  	register int na, ne, ucp, ap, c, i;
X+ #ifdef REMOTEFS
X+ 	register int indir;
X+ 	int uid, gid; /* have to take address */
X+ 	struct inode *ip; /* have to take address */
X+ 	int	remote = -1;
X+ #else REMOTEFS
X  	register int indir, uid, gid;
X  	register struct inode *ip;
X  #endif REMOTEFS
X***************
X*** 77,83
X  	register struct buf *bp;
X  	register int na, ne, ucp, ap, c, i;
X  	register int indir, uid, gid;
X- 	register char *sharg;
X  	register struct inode *ip;
X  	register swblk_t bno;
X  	char cfname[MAXNAMLEN + 1];
X
X--- 89,94 -----
X  	int	remote = -1;
X  #else REMOTEFS
X  	register int indir, uid, gid;
X  	register struct inode *ip;
X  #endif REMOTEFS
X  	register char *sharg;
X***************
X*** 79,84
X  	register int indir, uid, gid;
X  	register char *sharg;
X  	register struct inode *ip;
X  	register swblk_t bno;
X  	char cfname[MAXNAMLEN + 1];
X  	char cfarg[SHSIZE];
X
X--- 90,97 -----
X  #else REMOTEFS
X  	register int indir, uid, gid;
X  	register struct inode *ip;
X+ #endif REMOTEFS
X+ 	register char *sharg;
X  	register swblk_t bno;
X  	char cfname[MAXNAMLEN + 1];
X  	char cfarg[SHSIZE];
X***************
X*** 105,110
X   *	(7) do a ret
X   */
X  	if ((ip = namei(uchar, LOOKUP, 1)) == NULL)
X  		return;
X  	sysVinfo.sV_sysexec++;
X  	bno = 0;
X
X--- 118,128 -----
X   *	(7) do a ret
X   */
X  	if ((ip = namei(uchar, LOOKUP, 1)) == NULL)
X+ #ifdef REMOTEFS
X+ 		if (u.u_error == EISREMOTE)
X+ 			remote = remote_execinfo(&ip, &uid, &gid, fname);
X+ 	if (u.u_error)
X+ #endif REMOTEFS
X  		return;
X  	sysVinfo.sV_sysexec++;
X  	bno = 0;
X***************
X*** 110,115
X  	bno = 0;
X  	bp = 0;
X  	indir = 0;
X  	uid = u.u_uid;
X  	gid = u.u_gid;
X  	if (ip->i_mode & ISUID)
X
X--- 128,136 -----
X  	bno = 0;
X  	bp = 0;
X  	indir = 0;
X+ #ifdef REMOTEFS
X+ if (remote < 0) {
X+ #endif REMOTEFS
X  	uid = u.u_uid;
X  	gid = u.u_gid;
X  	if (ip->i_mode & ISUID)
X***************
X*** 148,153
X  	if (u.u_error)
X  		goto bad;
X  	u.u_count = resid;
X  #ifndef lint
X  	if (resid > sizeof(u.u_exdata) - sizeof(u.u_exdata.Ux_A) &&
X  	    u.u_exdata.ux_shell[0] != '#') {
X
X--- 169,180 -----
X  	if (u.u_error)
X  		goto bad;
X  	u.u_count = resid;
X+ #ifdef REMOTEFS
X+ }
X+ 
X+ remote_again:
X+ 
X+ #endif REMOTEFS
X  #ifndef lint
X  	if (resid > sizeof(u.u_exdata) - sizeof(u.u_exdata.Ux_A) &&
X  	    u.u_exdata.ux_shell[0] != '#') {
X***************
X*** 224,229
X  		    (unsigned)(u.u_dent.d_namlen + 1));
X  		cfname[MAXCOMLEN] = 0;
X  		indir = 1;
X  		iput(ip);
X  		/* Security hole fix: don't allow SUID-root exec'able
X  		   scripts whose name starts with '-'.... allows
X
X--- 251,259 -----
X  		    (unsigned)(u.u_dent.d_namlen + 1));
X  		cfname[MAXCOMLEN] = 0;
X  		indir = 1;
X+ #ifdef REMOTEFS
X+ 		if (remote < 0)
X+ #endif REMOTEFS
X  		iput(ip);
X  		/* Security hole fix: don't allow SUID-root exec'able
X  		   scripts whose name starts with '-'.... allows
X***************
X*** 233,238
X  			return;
X  		}
X  		ip = namei(schar, LOOKUP, 1);
X  		if (ip == NULL)
X  			return;
X  		goto again;
X
X--- 263,280 -----
X  			return;
X  		}
X  		ip = namei(schar, LOOKUP, 1);
X+ #ifdef REMOTEFS
X+ 		if (ip == NULL) {
X+ 			if (u.u_error == EISREMOTE)
X+ 				remote = remote_execinfo(&ip, 0, 0, 0);
X+ 			if (u.u_error)
X+ 				return;
X+ 			if (ip == NULL)
X+ 				goto remote_again;
X+ 		}
X+ 		else
X+ 			remote = -1;
X+ #else REMOTEFS
X  		if (ip == NULL)
X  			return;
X  #endif REMOTEFS
X***************
X*** 235,240
X  		ip = namei(schar, LOOKUP, 1);
X  		if (ip == NULL)
X  			return;
X  		goto again;
X  	}
X  
X
X--- 277,283 -----
X  #else REMOTEFS
X  		if (ip == NULL)
X  			return;
X+ #endif REMOTEFS
X  		goto again;
X  	}
X  
X***************
X*** 332,337
X  		bcopy((caddr_t)cfname, (caddr_t)u.u_dent.d_name,
X  		    (unsigned)(u.u_dent.d_namlen + 1));
X  	}
X  	getxfile(ip, (int)(nc + (na+4)*NBPW), uid, gid);
X  	if (u.u_error) {
X  badarg:
X
X--- 375,383 -----
X  		bcopy((caddr_t)cfname, (caddr_t)u.u_dent.d_name,
X  		    (unsigned)(u.u_dent.d_namlen + 1));
X  	}
X+ #ifdef REMOTEFS
X+ 	getxfile(ip, (int)(nc + (na+4)*NBPW), uid, gid, remote);
X+ #else REMOTEFS
X  	getxfile(ip, (int)(nc + (na+4)*NBPW), uid, gid);
X  #endif REMOTEFS
X  	if (u.u_error) {
X***************
X*** 333,338
X  		    (unsigned)(u.u_dent.d_namlen + 1));
X  	}
X  	getxfile(ip, (int)(nc + (na+4)*NBPW), uid, gid);
X  	if (u.u_error) {
X  badarg:
X  		for (c = 0; c < nc; c += CLSIZE*PAGSIZ) {
X
X--- 379,385 -----
X  	getxfile(ip, (int)(nc + (na+4)*NBPW), uid, gid, remote);
X  #else REMOTEFS
X  	getxfile(ip, (int)(nc + (na+4)*NBPW), uid, gid);
X+ #endif REMOTEFS
X  	if (u.u_error) {
X  badarg:
X  		for (c = 0; c < nc; c += CLSIZE*PAGSIZ) {
X***************
X*** 627,632
X   * Set up page tables and other structures for the process to be
X   * executed, and read in from the file.
X   */
X  getxfile(ip, nargc, uid, gid)
X  	register struct inode *ip;
X  {
X
X--- 674,682 -----
X   * Set up page tables and other structures for the process to be
X   * executed, and read in from the file.
X   */
X+ #ifdef REMOTEFS
X+ getxfile(ip, nargc, uid, gid, remote)
X+ #else REMOTEFS
X  getxfile(ip, nargc, uid, gid)
X  #endif REMOTEFS
X  	register struct inode *ip;
X***************
X*** 628,633
X   * executed, and read in from the file.
X   */
X  getxfile(ip, nargc, uid, gid)
X  	register struct inode *ip;
X  {
X  	register size_t ts, ds, uss, css;
X
X--- 678,684 -----
X  getxfile(ip, nargc, uid, gid, remote)
X  #else REMOTEFS
X  getxfile(ip, nargc, uid, gid)
X+ #endif REMOTEFS
X  	register struct inode *ip;
X  {
X  	register size_t ts, ds, uss, css;
X***************
X*** 632,637
X  {
X  	register size_t ts, ds, uss, css;
X  	register int pagi;
X  	register struct proc *p;
X  	register struct file *fp;
X  	register int flag;		/* used to keep proc flags */
X
X--- 683,691 -----
X  {
X  	register size_t ts, ds, uss, css;
X  	register int pagi;
X+ #ifdef REMOTEFS
X+ 	register int	oldtextsize;
X+ #endif REMOTEFS
X  	register struct proc *p;
X  	register struct file *fp;
X  	register int flag;		/* used to keep proc flags */
X***************
X*** 650,655
X  		pagi = SPAGI;
X  	else
X  		pagi = 0;
X  	if (u.u_exdata.ux_tsize!=0 && (ip->i_xflag&ITEXTFILE)==0 &&
X  						ip->i_count!=1) {
X  		SPINLOCK(&file_lock);
X
X--- 704,720 -----
X  		pagi = SPAGI;
X  	else
X  		pagi = 0;
X+ #ifdef REMOTEFS
X+ 	if (remote >= 0) {
X+ 		/*
X+ 		 * Prevent xalloc() from making a shared or paged text.
X+ 		 */
X+ 		pagi = 0;
X+ 		oldtextsize = u.u_exdata.ux_tsize;
X+ 		u.u_exdata.ux_dsize += u.u_exdata.ux_tsize;
X+ 		u.u_exdata.ux_tsize = 0;
X+ 	}
X+ #endif REMOTEFS
X  	if (u.u_exdata.ux_tsize!=0 && (ip->i_xflag&ITEXTFILE)==0 &&
X  						ip->i_count!=1) {
X  		SPINLOCK(&file_lock);
X***************
X*** 802,807
X  	 * Read in the data segment if we are not going to page in this
X  	 * process.
X  	 */
X  	if (pagi == 0) {
X  		u.u_error =
X  		    rdwri(UIO_READ, ip,
X
X--- 867,877 -----
X  	 * Read in the data segment if we are not going to page in this
X  	 * process.
X  	 */
X+ #ifdef REMOTEFS
X+ 	if (remote >= 0)
X+ 		u.u_error = remote_execread(remote, oldtextsize);
X+ 	else
X+ #endif REMOTEFS
X  	if (pagi == 0) {
X  		u.u_error =
X  		    rdwri(UIO_READ, ip,
SHAREOF
chmod 664 remote/usr.sys.PYR2.5/sys/kern_exec.c.diff
#
# remote/usr.sys.PYR2.5/sys/kern_exit.c.diff
#
if [ -f remote/usr.sys.PYR2.5/sys/kern_exit.c.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/sys/kern_exit.c.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.PYR2.5/sys/kern_exit.c.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.PYR2.5/sys/kern_exit.c.diff
XThe following changes ensure that upon exit, a process notifies any remote
Xservers that may know about him, that he is indeed dead.
X***************
X*** 59,64
X  #include "../h/quota.h"
X  #include "../h/cmap.h"
X  #include "../h/text.h"
X  
X  /*
X   * Exit system call: pass back caller's arg
X
X--- 59,67 -----
X  #include "../h/quota.h"
X  #include "../h/cmap.h"
X  #include "../h/text.h"
X+ #ifdef REMOTEFS
X+ #include "../remote/remotefs.h"
X+ #endif REMOTEFS
X  
X  /*
X   * Exit system call: pass back caller's arg
X***************
X*** 99,104
X  	vmsizmon();
X  #endif
X  	p = u.u_procp;
X  
X  	gpid = p->p_gpid;
X  	/*
X
X--- 102,114 -----
X  	vmsizmon();
X  #endif
X  	p = u.u_procp;
X+ #ifdef REMOTEFS
X+ 	/*
X+ 	 * First, release our server.
X+ 	 */
X+ 	if (p->p_flag & SREMOTE)
X+ 		remote_exit();
X+ #endif REMOTEFS
X  
X  	gpid = p->p_gpid;
X  	/*
SHAREOF
chmod 664 remote/usr.sys.PYR2.5/sys/kern_exit.c.diff
#
# remote/usr.sys.PYR2.5/sys/kern_trap.c.diff
#
if [ -f remote/usr.sys.PYR2.5/sys/kern_trap.c.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/sys/kern_trap.c.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.PYR2.5/sys/kern_trap.c.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.PYR2.5/sys/kern_trap.c.diff
XThese changes enable syscall() to start up a remote version of a system
Xcall if the normal system call fails with error == EISREMOTE.
X***************
X*** 47,52
X  #include "../h/vmmac.h"
X  #include "../h/vmmeter.h"
X  #include "../h/debug.h"
X  
X  extern int kernstrt;
X  #define	USER	040		/* user-mode flag added to type */
X
X--- 47,59 -----
X  #include "../h/vmmac.h"
X  #include "../h/vmmeter.h"
X  #include "../h/debug.h"
X+ #ifdef REMOTEFS
X+ #include "../remote/remotefs.h"
X+ /*
X+  * needed only if EISREMOTE isn't in /usr/include/errno.h
X+  */
X+ #include "../h/errno.h"
X+ #endif REMOTEFS
X  
X  extern int kernstrt;
X  #define	USER	040		/* user-mode flag added to type */
X***************
X*** 395,400
X  	register long syst_sec, syst_usec;
X  	register int s;
X  	register int onslave = 0;
X  
X  	SETGR9();	/* for dual cpu, put mastercpu into gr9 */
X  	spl0();		/* move up to system base priority level */
X
X--- 402,411 -----
X  	register long syst_sec, syst_usec;
X  	register int s;
X  	register int onslave = 0;
X+ #ifdef REMOTEFS
X+ 	extern u_char remote_sysmap[];
X+ 	register int rmt_syscall, runremote, rmtcalled, rmtcnt;
X+ #endif REMOTEFS
X  
X  	SETGR9();	/* for dual cpu, put mastercpu into gr9 */
X  	spl0();		/* move up to system base priority level */
X***************
X*** 418,424
X  		if (u.u_error == 0 && u.u_eosys == JUSTRETURN)
X  			u.u_error = EINTR;
X  	} else {
X! 		(*(callproc->sy_call))(arg1, arg2, arg3, arg4, arg5, arg6);
X  	}
X  
X  	if (u.u_eosys != RESTARTSYS)
X
X--- 429,461 -----
X  		if (u.u_error == 0 && u.u_eosys == JUSTRETURN)
X  			u.u_error = EINTR;
X  	} else {
X! #ifdef REMOTEFS
X! 		if (index < 512) {
X! 			rmt_syscall = remote_sysmap[ index ];
X! 			rmtcalled = FALSE;
X! 			rmtcnt = 0;
X! 
X! 			u.u_eosys = JUSTRETURN;
X! 			while (! rmtcalled) {
X! 				runremote = (rmt_syscall != RSYS_nosys
X! 					    && u.u_procp->p_flag & SREMOTE);
X! 				if (runremote)
X! 					rmtcalled = remote_startup(rmtcnt,
X! 						rmt_syscall, arg1, arg2, arg3,
X! 						arg4, arg5, arg6);
X! 				if (! rmtcalled) {
X! 					(*callproc->sy_call)(arg1, arg2, arg3,
X! 						arg4, arg5, arg6);
X! 					if (u.u_error != EISREMOTE)
X! 						rmtcalled = TRUE;
X! 					else
X! 						rmtcnt++;
X! 				}
X! 			}
X! 		} else
X! #endif REMOTEFS
X! 			(*(callproc->sy_call))(arg1, arg2, arg3,
X! 				arg4, arg5, arg6);
X  	}
X  
X  	if (u.u_eosys != RESTARTSYS)
SHAREOF
chmod 664 remote/usr.sys.PYR2.5/sys/kern_trap.c.diff
#
# remote/usr.sys.PYR2.5/sys/sys_inode.c.diff
#
if [ -f remote/usr.sys.PYR2.5/sys/sys_inode.c.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/sys/sys_inode.c.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.PYR2.5/sys/sys_inode.c.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.PYR2.5/sys/sys_inode.c.diff
XThis change repairs a semantic change in ino_close() that assumes
Xthe only other file descriptor type is DTYPE_SOCKET.  If patch tells
Xyou
X	Reversed (or previously applied) patch detected!
XThen you already have the fix and you must undo what patch does.
X***************
X*** 516,522
X  	for (ffp = file; ffp < fileNFILE; ffp++) {
X  		if (ffp == fp)
X  			continue;
X! 		if (ffp->f_type == DTYPE_SOCKET)		/* XXX */
X  			continue;
X  		if (ffp->f_count && (ip = (struct inode *)ffp->f_data) &&
X  		    ip->i_rdev == dev && (ip->i_mode&IFMT) == mode)
X
X--- 516,522 -----
X  	for (ffp = file; ffp < fileNFILE; ffp++) {
X  		if (ffp == fp)
X  			continue;
X! 		if (ffp->f_type != DTYPE_INODE)	/* semantic fix (toddb@du) */
X  			continue;
X  		if (ffp->f_count && (ip = (struct inode *)ffp->f_data) &&
X  		    ip->i_rdev == dev && (ip->i_mode&IFMT) == mode)
SHAREOF
chmod 664 remote/usr.sys.PYR2.5/sys/sys_inode.c.diff
#
# remote/usr.sys.PYR2.5/sys/ufs_nami.c.diff
#
if [ -f remote/usr.sys.PYR2.5/sys/ufs_nami.c.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/sys/ufs_nami.c.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.PYR2.5/sys/ufs_nami.c.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.PYR2.5/sys/ufs_nami.c.diff
XThese changes are the primary hook into the operating system for detecting
Xa "remote" file.
X***************
X*** 145,150
X  	unsigned hash;			/* value of name hash for entry */
X  	union nchash *nhp;		/* cache chain head for entry */
X  	int isdotdot;			/* != 0 if current name is ".." */
X  
X  	sysVinfo.sV_namei++;
X  	lockparent = flag & LOCKPARENT;
X
X--- 145,153 -----
X  	unsigned hash;			/* value of name hash for entry */
X  	union nchash *nhp;		/* cache chain head for entry */
X  	int isdotdot;			/* != 0 if current name is ".." */
X+ #ifdef REMOTEFS
X+ 	long    remote;
X+ #endif REMOTEFS
X  
X  	sysVinfo.sV_namei++;
X  	lockparent = flag & LOCKPARENT;
X***************
X*** 189,194
X  	 * Check accessiblity of directory.
X  	 */
X  	if ((dp->i_mode&IFMT) != IFDIR) {
X  		u.u_error = ENOTDIR;
X  		goto bad;
X  	}
X
X--- 192,214 -----
X  	 * Check accessiblity of directory.
X  	 */
X  	if ((dp->i_mode&IFMT) != IFDIR) {
X+ #ifdef REMOTEFS
X+ 		remote = isremote(dp, cp, nbp->b_un.b_addr);
X+ 
X+ 		/*
X+ 		 * If it is really local, then start again at the root.
X+ 		 */
X+ 		if (remote < 0) {
X+ 			iput(dp);
X+ 			dp = rootdir;
X+ 			ilockx(dp);
X+ 			dp->i_count++;
X+ 			fs = dp->i_fs;
X+ 			cp = nbp->b_un.b_addr;
X+ 			goto dirloop2;
X+ 		}
X+ 		else if (! remote)
X+ #endif REMOTEFS
X  		u.u_error = ENOTDIR;
X  		goto bad;
X  	}
X***************
X*** 604,609
X  					u.u_error = EPERM;
X  					goto bad;
X  				}
X  			}
X  		}
X  #ifdef NSA
X
X--- 624,640 -----
X  					u.u_error = EPERM;
X  					goto bad;
X  				}
X+ #ifdef REMOTEFS
X+ 				/*
X+ 				 * don't allow anyone to remove a remote mount
X+ 				 * point.
X+ 				 */
X+ 				if (rmt_host(dp, &i)) {
X+ 					iput(u.u_pdir);
X+ 					u.u_error = EBUSY;
X+ 					goto bad;
X+ 				}
X+ #endif REMOTEFS
X  			}
X  		}
X  #ifdef NSA
X***************
X*** 786,791
X  
X  		if (len + pathlen >= MAXPATHLEN - 1 ||
X  		    ++nlink > MAXSYMLINKS) {
X  			u.u_error = ELOOP;
X  			goto bad2;
X  		}
X
X--- 817,824 -----
X  
X  		if (len + pathlen >= MAXPATHLEN - 1 ||
X  		    ++nlink > MAXSYMLINKS) {
X+ 			printf("nlink=%d,len=%d,pathlen=%d:LOOP\n",
X+ 				nlink, len, pathlen);
X  			u.u_error = ELOOP;
X  			goto bad2;
X  		}
SHAREOF
chmod 664 remote/usr.sys.PYR2.5/sys/ufs_nami.c.diff
#
# remote/usr.sys.PYR2.5/sys/ufs_syscalls.c.diff
#
if [ -f remote/usr.sys.PYR2.5/sys/ufs_syscalls.c.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/sys/ufs_syscalls.c.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.PYR2.5/sys/ufs_syscalls.c.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.PYR2.5/sys/ufs_syscalls.c.diff
XThese changes modify chdirec(), which is called by chroot() and chdir(),
Xso that you can be allowed to do a chdir() to a remote mount point.
XIn addition, the changes ensure that we adjust internal pointers when doing
Xa chdir() OUT of a remote mount point.
X***************
X*** 104,109
X  	register struct inode **ipp;
X  {
X  	register struct inode *ip;
X  
X  	ip = namei(uchar, LOOKUP, 1);
X  	if (ip == NULL)
X
X--- 104,112 -----
X  	register struct inode **ipp;
X  {
X  	register struct inode *ip;
X+ #ifdef REMOTEFS
X+ 	int	i;
X+ #endif REMOTEFS
X  
X  	ip = namei(uchar, LOOKUP, 1);
X  	if (ip == NULL)
X***************
X*** 109,114
X  	if (ip == NULL)
X  		return;
X  	if ((ip->i_mode&IFMT) != IFDIR) {
X  		u.u_error = ENOTDIR;
X  		goto bad;
X  	}
X
X--- 112,123 -----
X  	if (ip == NULL)
X  		return;
X  	if ((ip->i_mode&IFMT) != IFDIR) {
X+ #ifdef REMOTEFS
X+ 		if (rmt_hostdir(ip, &i) != NULL)
X+ 			u.u_error = remotechdir(i);
X+ 		else
X+ 			u.u_error = ENOTDIR;
X+ #else REMOTEFS
X  		u.u_error = ENOTDIR;
X  #endif REMOTEFS
X  		goto bad;
X***************
X*** 110,115
X  		return;
X  	if ((ip->i_mode&IFMT) != IFDIR) {
X  		u.u_error = ENOTDIR;
X  		goto bad;
X  	}
X  	if (access(ip, IEXEC))
X
X--- 119,125 -----
X  			u.u_error = ENOTDIR;
X  #else REMOTEFS
X  		u.u_error = ENOTDIR;
X+ #endif REMOTEFS
X  		goto bad;
X  	}
X  	if (access(ip, IEXEC))
X***************
X*** 114,119
X  	}
X  	if (access(ip, IEXEC))
X  		goto bad;
X  	iunlock(ip);
X  	if (*ipp)
X  		irele(*ipp);
X
X--- 124,132 -----
X  	}
X  	if (access(ip, IEXEC))
X  		goto bad;
X+ #ifdef REMOTEFS
X+ 	remotechdir(-1);
X+ #endif REMOTEFS
X  	iunlock(ip);
X  	if (*ipp)
X  		irele(*ipp);
SHAREOF
chmod 664 remote/usr.sys.PYR2.5/sys/ufs_syscalls.c.diff
#
# remote/usr.sys.PYR2.5/sys/uipc_socket.c.diff
#
if [ -f remote/usr.sys.PYR2.5/sys/uipc_socket.c.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/sys/uipc_socket.c.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.PYR2.5/sys/uipc_socket.c.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.PYR2.5/sys/uipc_socket.c.diff
XThese changes Fix a bug in soreceive() that caused infinite loop if a
Xpacket was received while doing uiomove() and the MSG_PEEK flag was set.
XIf you have this fix, then patch will tell you:
X
X        Reversed (or previously applied) patch detected!
X
XIf it does, you should just reinstall your original uipc_socket.c.
XIf you have a different version of the fix or another modification that
Xaffects this code, then patch will tell you that "Hunk #1 failed"; you
Xmust install the patch by hand.
X***************
X*** 659,665
X  		error =
X  		    uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio);
X  		s = splnet();
X! 		if (len == m->m_len) {
X  			eor = (int)m->m_act;
X  			if (flags & MSG_PEEK)
X  				m = m->m_next;
X
X--- 659,665 -----
X  		error =
X  		    uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio);
X  		s = splnet();
X! 		if (moff+len == m->m_len) { /* infinite loop fix (toddb@du) */
X  			eor = (int)m->m_act;
X  			if (flags & MSG_PEEK)
X  				m = m->m_next;
SHAREOF
chmod 664 remote/usr.sys.PYR2.5/sys/uipc_socket.c.diff
#
# remote/usr.sys.VAX4.2/conf/files.diff
#
if [ -f remote/usr.sys.VAX4.2/conf/files.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/conf/files.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.VAX4.2/conf/files.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.2/conf/files.diff
XThe files added here identify the RFS source code.
X***************
X*** 107,108
X  sys/vm_swp.c		standard
X  sys/vm_text.c		standard
X
X--- 107,118 -----
X  sys/vm_swp.c		standard
X  sys/vm_text.c		standard
X+ remote/rmt_data.c	optional remotefs
X+ remote/rmt_exec.c	optional remotefs
X+ remote/rmt_final.c	optional remotefs
X+ remote/rmt_general.c	optional remotefs
X+ remote/rmt_generic.c	optional remotefs
X+ remote/rmt_io.c		optional remotefs
X+ remote/rmt_subr.c	optional remotefs
X+ remote/rmt_syscall1.c	optional remotefs
X+ remote/rmt_syscall2.c	optional remotefs
X+ remote/rmt_syscall3.c	optional remotefs
SHAREOF
chmod 664 remote/usr.sys.VAX4.2/conf/files.diff
if [ -f remote/usr.sys.VAX4.3/conf/files.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/conf/files.diff or ^C to quit' 
	read ans 
	rm -rf remote/usr.sys.VAX4.3/conf/files.diff 
fi
ln remote/usr.sys.VAX4.2/conf/files.diff remote/usr.sys.VAX4.3/conf/files.diff
#
# remote/usr.sys.VAX4.2/conf/makefile.vax.diff
#
if [ -f remote/usr.sys.VAX4.2/conf/makefile.vax.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/conf/makefile.vax.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.VAX4.2/conf/makefile.vax.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.2/conf/makefile.vax.diff
XThis change teaches the makefile how to make rmt_data.c from
X../remote/remotefs.h, ../remote/rmt_data_template and ../sys/init_sysent.c.
X***************
X*** 166,168
X  
X  %RULES
X  
X
X--- 166,175 -----
X  
X+ ../remote/rmt_data.c: ../remote/rmt_data_template ../remote/remotefs.h \
X+     ../sys/init_sysent.c
X+ 	cat ../remote/rmt_data_template > ../remote/nrmt_data.c
X+ 	/lib/cpp ${CFLAGS} ../sys/init_sysent.c | sh ../remote/remote_mkdata \
X+ 		../remote/remotefs.h >> ../remote/nrmt_data.c
X+ 	mv ../remote/nrmt_data.c ../remote/rmt_data.c
X+ 
X  %RULES
X  
SHAREOF
chmod 664 remote/usr.sys.VAX4.2/conf/makefile.vax.diff
#
# remote/usr.sys.VAX4.2/h/errno.h.diff
#
if [ -f remote/usr.sys.VAX4.2/h/errno.h.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/h/errno.h.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.VAX4.2/h/errno.h.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.2/h/errno.h.diff
XThese changes add three new error numbers for the sake of RFS.
X***************
X*** 94,96
X  #define	EPROCLIM	67		/* Too many processes */
X  #define	EUSERS		68		/* Too many users */
X  #define	EDQUOT		69		/* Disc quota exceeded */
X
X--- 94,101 -----
X  #define	EPROCLIM	67		/* Too many processes */
X  #define	EUSERS		68		/* Too many users */
X  #define	EDQUOT		69		/* Disc quota exceeded */
X+ 
X+ /* remote fs stuff */
X+ #define EISREMOTE	70		/* file is on a remote system */
X+ #define ETOOMANYREMOTE	71		/* too many remote file systems */
X+ #define	ENOREMOTEFS	72		/* no remote file system */
SHAREOF
chmod 664 remote/usr.sys.VAX4.2/h/errno.h.diff
if [ -f remote/usr.sys.VAX4.3/h/errno.h.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/h/errno.h.diff or ^C to quit' 
	read ans 
	rm -rf remote/usr.sys.VAX4.3/h/errno.h.diff 
fi
ln remote/usr.sys.VAX4.2/h/errno.h.diff remote/usr.sys.VAX4.3/h/errno.h.diff
#
# remote/usr.sys.VAX4.2/h/user.h.diff
#
if [ -f remote/usr.sys.VAX4.2/h/user.h.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/h/user.h.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.VAX4.2/h/user.h.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.2/h/user.h.diff
XThese changes keep track of the per-process RFS information.
X***************
X*** 140,145
X  		unsigned pr_off;	/* pc offset */
X  		unsigned pr_scale;	/* pc scaling */
X  	} u_prof;
X  	int	u_stack[1];
X  };
X  
X
X--- 140,155 -----
X  		unsigned pr_off;	/* pc offset */
X  		unsigned pr_scale;	/* pc scaling */
X  	} u_prof;
X+ #ifdef REMOTEFS
X+ 	short	u_rmtoffset[2];		/* path offset for local segment */
X+ 	short	u_rmtcdir;		/* system # of remote current dir */
X+ 	long	u_rmtsys;		/* room for 32 systems */
X+ 					/* one bit for each remote system */
X+ #ifdef pyr /* Pyramid */
X+ 	int	*u.u_ap;
X+ #define		u_arg	u_ap
X+ #endif pyr
X+ #endif REMOTEFS
X  	int	u_stack[1];
X  };
X  
SHAREOF
chmod 664 remote/usr.sys.VAX4.2/h/user.h.diff
#
# remote/usr.sys.VAX4.2/machine/trap.c.diff
#
if [ -f remote/usr.sys.VAX4.2/machine/trap.c.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/machine/trap.c.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.VAX4.2/machine/trap.c.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.2/machine/trap.c.diff
XThese changes enable syscall() to start up a remote version of a system
Xcall if the normal system call fails with error == EISREMOTE.
X***************
X*** 25,30
X  #ifdef SYSCALLTRACE
X  #include "../sys/syscalls.c"
X  #endif
X  
X  #include "../vax/mtpr.h"
X  
X
X--- 25,37 -----
X  #ifdef SYSCALLTRACE
X  #include "../sys/syscalls.c"
X  #endif
X+ #ifdef REMOTEFS
X+ #include "../remote/remotefs.h"
X+ /*
X+  * needed only if EISREMOTE isn't in /usr/include/errno.h
X+  */
X+ #include "../h/errno.h"
X+ #endif REMOTEFS
X  
X  #include "../vax/mtpr.h"
X  
X***************
X*** 193,198
X  	register struct proc *p;
X  	int opc;
X  	struct timeval syst;
X  
X  	syst = u.u_ru.ru_stime;
X  	if (!USERMODE(locr0[PS]))
X
X--- 200,214 -----
X  	register struct proc *p;
X  	int opc;
X  	struct timeval syst;
X+ #ifdef REMOTEFS
X+ 	/*
X+ 	 * It is imperative that these declarations come after other register
X+ 	 * declarations, because the (standard) code below depends upon the
X+ 	 * order of allocation.
X+ 	 */
X+ 	extern u_char remote_sysmap[];
X+ 	register long rmt_syscall, runremote, rmt_called, rmt_cnt;
X+ #endif REMOTEFS
X  
X  	syst = u.u_ru.ru_stime;
X  	if (!USERMODE(locr0[PS]))
X***************
X*** 233,238
X  		if (u.u_error == 0 && u.u_eosys == JUSTRETURN)
X  			u.u_error = EINTR;
X  	} else {
X  		u.u_eosys = JUSTRETURN;
X  #ifdef SYSCALLTRACE
X  		if (syscalltrace) {
X
X--- 249,258 -----
X  		if (u.u_error == 0 && u.u_eosys == JUSTRETURN)
X  			u.u_error = EINTR;
X  	} else {
X+ #ifdef REMOTEFS
X+ 		rmt_syscall = remote_sysmap[ code ];
X+ 		rmt_called = FALSE;
X+ 		rmt_cnt = 0;
X  		u.u_eosys = JUSTRETURN;
X  		while (! rmt_called) {
X  			runremote = (rmt_syscall != RSYS_nosys
X***************
X*** 234,239
X  			u.u_error = EINTR;
X  	} else {
X  		u.u_eosys = JUSTRETURN;
X  #ifdef SYSCALLTRACE
X  		if (syscalltrace) {
X  			register int i;
X
X--- 254,275 -----
X  		rmt_called = FALSE;
X  		rmt_cnt = 0;
X  		u.u_eosys = JUSTRETURN;
X+ 		while (! rmt_called) {
X+ 			runremote = (rmt_syscall != RSYS_nosys
X+ 				    && u.u_procp->p_flag & SREMOTE);
X+ 			if (runremote)
X+ 				rmt_called = remote_startup(rmt_cnt,
X+ 					rmt_syscall);
X+ 			if (! rmt_called) {
X+ 				(*callp->sy_call)();
X+ 				if (u.u_error != EISREMOTE)
X+ 					rmt_called = TRUE;
X+ 				else
X+ 					rmt_cnt++;
X+ 			}
X+ 		}
X+ #else REMOTEFS
X+ 		u.u_eosys = JUSTRETURN;
X  #ifdef SYSCALLTRACE
X  		if (syscalltrace) {
X  			register int i;
X***************
X*** 254,259
X  		}
X  #endif
X  		(*(callp->sy_call))();
X  	}
X  	locr0[PS] &= ~PSL_C;
X  	if (u.u_eosys == RESTARTSYS)
X
X--- 290,296 -----
X  		}
X  #endif
X  		(*(callp->sy_call))();
X+ #endif REMOTEFS
X  	}
X  	locr0[PS] &= ~PSL_C;
X  	if (u.u_eosys == RESTARTSYS)
SHAREOF
chmod 664 remote/usr.sys.VAX4.2/machine/trap.c.diff
#
# remote/usr.sys.VAX4.2/sys/init_sysent.c.diff
#
if [ -f remote/usr.sys.VAX4.2/sys/init_sysent.c.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/sys/init_sysent.c.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.VAX4.2/sys/init_sysent.c.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.2/sys/init_sysent.c.diff
XThese two changes add in the new RFS systems calls, remoteon(), remoteoff()
Xand  remotename().  If the second hunk fails, then you have some system
Xcall numbers that are not in standard 4.2BSD.
X***************
X*** 99,99
X  /* BEGIN JUNK */
X
X--- 99,107 -----
X+ #ifdef REMOTEFS
X+ /*
X+  * remote file sys stuff (toddb@du)
X+  */
X+ int	remoteon(),		/* remote file sys stuff */
X+ 	remoteoff(),
X+ 	remotename();
X+ #endif REMOTEFS
X  /* BEGIN JUNK */
X***************
X*** 270,274
X  	2, setquota,			/* 148 = quota */
X  	4, qquota,			/* 149 = qquota */
X  	3, getsockname,			/* 150 = getsockname */
X  };
X  int	nsysent = sizeof (sysent) / sizeof (sysent[0]);
X
X--- 278,291 -----
X  	2, setquota,			/* 148 = quota */
X  	4, qquota,			/* 149 = qquota */
X  	3, getsockname,			/* 150 = getsockname */
X+ #ifdef REMOTEFS
X+ 	4, remoteon,			/* 151 = remoteon */
X+ 	1, remoteoff,			/* 152 = remoteoff */
X+ 	4, remotename,			/* 153 = remotename */
X+ #else REMOTEFS
X+ 	0, nosys,			/* 151 = nosys */
X+ 	0, nosys,			/* 152 = nosys */
X+ 	0, nosys,			/* 153 = nosys */
X+ #endif REMOTEFS
X  };
X  int	nsysent = sizeof (sysent) / sizeof (sysent[0]);
SHAREOF
chmod 664 remote/usr.sys.VAX4.2/sys/init_sysent.c.diff
#
# remote/usr.sys.VAX4.2/sys/kern_exec.c.diff
#
if [ -f remote/usr.sys.VAX4.2/sys/kern_exec.c.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/sys/kern_exec.c.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.VAX4.2/sys/kern_exec.c.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.2/sys/kern_exec.c.diff
XThe following changes implement local execution of an object file that
Xlives on another host.
X***************
X*** 28,33
X  #include "../h/uio.h"
X  #include "../h/nami.h"
X  #include "../h/acct.h"
X  
X  #ifdef vax
X  #include "../vax/mtpr.h"
X
X--- 28,39 -----
X  #include "../h/uio.h"
X  #include "../h/nami.h"
X  #include "../h/acct.h"
X+ #ifdef REMOTEFS
X+ /*
X+  * needed only if EISREMOTE isn't in /usr/include/errno.h
X+  */
X+ #include "../h/errno.h"
X+ #endif REMOTEFS
X  
X  #ifdef vax
X  #include "../vax/mtpr.h"
X***************
X*** 57,62
X  	int na, ne, ucp, ap, c;
X  	int indir, uid, gid;
X  	char *sharg;
X  	struct inode *ip;
X  	swblk_t bno;
X  	char cfname[MAXCOMLEN + 1];
X
X--- 63,72 -----
X  	int na, ne, ucp, ap, c;
X  	int indir, uid, gid;
X  	char *sharg;
X+ #ifdef REMOTEFS
X+ 	struct inode *ip; /* have to take address */
X+ 	int	remote = -1;
X+ #else REMOTEFS
X  	struct inode *ip;
X  #endif REMOTEFS
X  	swblk_t bno;
X***************
X*** 58,63
X  	int indir, uid, gid;
X  	char *sharg;
X  	struct inode *ip;
X  	swblk_t bno;
X  	char cfname[MAXCOMLEN + 1];
X  	char cfarg[SHSIZE];
X
X--- 68,74 -----
X  	int	remote = -1;
X  #else REMOTEFS
X  	struct inode *ip;
X+ #endif REMOTEFS
X  	swblk_t bno;
X  	char cfname[MAXCOMLEN + 1];
X  	char cfarg[SHSIZE];
X***************
X*** 64,69
X  	int resid;
X  
X  	if ((ip = namei(uchar, LOOKUP, 1)) == NULL)
X  		return;
X  	bno = 0;
X  	bp = 0;
X
X--- 75,86 -----
X  	int resid;
X  
X  	if ((ip = namei(uchar, LOOKUP, 1)) == NULL)
X+ #ifdef REMOTEFS
X+ 		if (u.u_error == EISREMOTE)
X+ 			remote = remote_execinfo(&ip, &uid, &gid,
X+ 				((struct execa *)u.u_ap)->fname);
X+ 	if (u.u_error)
X+ #endif REMOTEFS
X  		return;
X  	bno = 0;
X  	bp = 0;
X***************
X*** 68,73
X  	bno = 0;
X  	bp = 0;
X  	indir = 0;
X  	uid = u.u_uid;
X  	gid = u.u_gid;
X  	if (ip->i_mode & ISUID)
X
X--- 85,93 -----
X  	bno = 0;
X  	bp = 0;
X  	indir = 0;
X+ #ifdef REMOTEFS
X+ if (remote < 0) {
X+ #endif REMOTEFS
X  	uid = u.u_uid;
X  	gid = u.u_gid;
X  	if (ip->i_mode & ISUID)
X***************
X*** 106,111
X  	if (u.u_error)
X  		goto bad;
X  	u.u_count = resid;
X  #ifndef lint
X  	if (u.u_count > sizeof(u.u_exdata) - sizeof(u.u_exdata.Ux_A) &&
X  	    u.u_exdata.ux_shell[0] != '#') {
X
X--- 126,137 -----
X  	if (u.u_error)
X  		goto bad;
X  	u.u_count = resid;
X+ #ifdef REMOTEFS
X+ }
X+ 
X+ remote_again:
X+ 
X+ #endif REMOTEFS
X  #ifndef lint
X  	if (u.u_count > sizeof(u.u_exdata) - sizeof(u.u_exdata.Ux_A) &&
X  	    u.u_exdata.ux_shell[0] != '#') {
X***************
X*** 171,176
X  		    (unsigned)(u.u_dent.d_namlen + 1));
X  		cfname[MAXCOMLEN] = 0;
X  		indir = 1;
X  		iput(ip);
X  		ip = namei(schar, LOOKUP, 1);
X  		if (ip == NULL)
X
X--- 197,205 -----
X  		    (unsigned)(u.u_dent.d_namlen + 1));
X  		cfname[MAXCOMLEN] = 0;
X  		indir = 1;
X+ #ifdef REMOTEFS
X+ 		if (remote < 0)
X+ #endif REMOTEFS
X  		iput(ip);
X  		ip = namei(schar, LOOKUP, 1);
X  #ifdef REMOTEFS
X***************
X*** 173,178
X  		indir = 1;
X  		iput(ip);
X  		ip = namei(schar, LOOKUP, 1);
X  		if (ip == NULL)
X  			return;
X  		goto again;
X
X--- 202,219 -----
X  #endif REMOTEFS
X  		iput(ip);
X  		ip = namei(schar, LOOKUP, 1);
X+ #ifdef REMOTEFS
X+ 		if (ip == NULL) {
X+ 			if (u.u_error == EISREMOTE)
X+ 				remote = remote_execinfo(&ip, 0, 0, 0);
X+ 			if (u.u_error)
X+ 				return;
X+ 			if (ip == NULL)
X+ 				goto remote_again;
X+ 		}
X+ 		else
X+ 			remote = -1;
X+ #else REMOTEFS
X  		if (ip == NULL)
X  			return;
X  #endif REMOTEFS
X***************
X*** 175,180
X  		ip = namei(schar, LOOKUP, 1);
X  		if (ip == NULL)
X  			return;
X  		goto again;
X  	}
X  
X
X--- 216,222 -----
X  #else REMOTEFS
X  		if (ip == NULL)
X  			return;
X+ #endif REMOTEFS
X  		goto again;
X  	}
X  
X***************
X*** 244,249
X  		bcopy((caddr_t)cfname, (caddr_t)u.u_dent.d_name,
X  		    (unsigned)(u.u_dent.d_namlen + 1));
X  	}
X  	getxfile(ip, nc + (na+4)*NBPW, uid, gid);
X  	if (u.u_error) {
X  badarg:
X
X--- 286,294 -----
X  		bcopy((caddr_t)cfname, (caddr_t)u.u_dent.d_name,
X  		    (unsigned)(u.u_dent.d_namlen + 1));
X  	}
X+ #ifdef REMOTEFS
X+ 	getxfile(ip, nc + (na+4)*NBPW, uid, gid, remote);
X+ #else REMOTEFS
X  	getxfile(ip, nc + (na+4)*NBPW, uid, gid);
X  #endif REMOTEFS
X  	if (u.u_error) {
X***************
X*** 245,250
X  		    (unsigned)(u.u_dent.d_namlen + 1));
X  	}
X  	getxfile(ip, nc + (na+4)*NBPW, uid, gid);
X  	if (u.u_error) {
X  badarg:
X  		for (c = 0; c < nc; c += CLSIZE*NBPG) {
X
X--- 290,296 -----
X  	getxfile(ip, nc + (na+4)*NBPW, uid, gid, remote);
X  #else REMOTEFS
X  	getxfile(ip, nc + (na+4)*NBPW, uid, gid);
X+ #endif REMOTEFS
X  	if (u.u_error) {
X  badarg:
X  		for (c = 0; c < nc; c += CLSIZE*NBPG) {
X***************
X*** 303,308
X  /*
X   * Read in and set up memory for executed file.
X   */
X  getxfile(ip, nargc, uid, gid)
X  	register struct inode *ip;
X  	int nargc, uid, gid;
X
X--- 349,357 -----
X  /*
X   * Read in and set up memory for executed file.
X   */
X+ #ifdef REMOTEFS
X+ getxfile(ip, nargc, uid, gid, remote)
X+ #else REMOTEFS
X  getxfile(ip, nargc, uid, gid)
X  #endif REMOTEFS
X  	register struct inode *ip;
X***************
X*** 304,309
X   * Read in and set up memory for executed file.
X   */
X  getxfile(ip, nargc, uid, gid)
X  	register struct inode *ip;
X  	int nargc, uid, gid;
X  {
X
X--- 353,359 -----
X  getxfile(ip, nargc, uid, gid, remote)
X  #else REMOTEFS
X  getxfile(ip, nargc, uid, gid)
X+ #endif REMOTEFS
X  	register struct inode *ip;
X  	int nargc, uid, gid;
X  {
X***************
X*** 309,314
X  {
X  	register size_t ts, ds, ss;
X  	int pagi;
X  
X  	if (u.u_exdata.ux_mag == 0413)
X  		pagi = SPAGI;
X
X--- 359,367 -----
X  {
X  	register size_t ts, ds, ss;
X  	int pagi;
X+ #ifdef REMOTEFS
X+ 	int	oldtextsize;
X+ #endif REMOTEFS
X  
X  	if (u.u_exdata.ux_mag == 0413)
X  		pagi = SPAGI;
X***************
X*** 314,319
X  		pagi = SPAGI;
X  	else
X  		pagi = 0;
X  	if (u.u_exdata.ux_tsize!=0 && (ip->i_flag&ITEXT)==0 &&
X  	    ip->i_count!=1) {
X  		register struct file *fp;
X
X--- 367,383 -----
X  		pagi = SPAGI;
X  	else
X  		pagi = 0;
X+ #ifdef REMOTEFS
X+ 	if (remote >= 0) {
X+ 		/*
X+ 		 * Prevent xalloc() from making a shared or paged text.
X+ 		 */
X+ 		pagi = 0;
X+ 		oldtextsize = u.u_exdata.ux_tsize;
X+ 		u.u_exdata.ux_dsize += u.u_exdata.ux_tsize;
X+ 		u.u_exdata.ux_tsize = 0;
X+ 	}
X+ #endif REMOTEFS
X  	if (u.u_exdata.ux_tsize!=0 && (ip->i_flag&ITEXT)==0 &&
X  	    ip->i_count!=1) {
X  		register struct file *fp;
X***************
X*** 370,375
X  	u.u_smap = u.u_csmap;
X  	vgetvm(ts, ds, ss);
X  
X  	if (pagi == 0)
X  		u.u_error =
X  		    rdwri(UIO_READ, ip,
X
X--- 434,444 -----
X  	u.u_smap = u.u_csmap;
X  	vgetvm(ts, ds, ss);
X  
X+ #ifdef REMOTEFS
X+ 	if (remote >= 0)
X+ 		u.u_error = remote_execread(remote, oldtextsize);
X+ 	else
X+ #endif REMOTEFS
X  	if (pagi == 0)
X  		u.u_error =
X  		    rdwri(UIO_READ, ip,
SHAREOF
chmod 664 remote/usr.sys.VAX4.2/sys/kern_exec.c.diff
#
# remote/usr.sys.VAX4.2/sys/kern_exit.c.diff
#
if [ -f remote/usr.sys.VAX4.2/sys/kern_exit.c.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/sys/kern_exit.c.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.VAX4.2/sys/kern_exit.c.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.2/sys/kern_exit.c.diff
XThe following changes ensure that upon exit, a process notifies any remote
Xservers that may know about him, that he is indeed dead.
X***************
X*** 33,38
X  #include "../h/file.h"
X  #include "../h/mbuf.h"
X  #include "../h/inode.h"
X  
X  /*
X   * Exit system call: pass back caller's arg
X
X--- 33,41 -----
X  #include "../h/file.h"
X  #include "../h/mbuf.h"
X  #include "../h/inode.h"
X+ #ifdef REMOTEFS
X+ #include "../remote/remotefs.h"
X+ #endif REMOTEFS
X  
X  /*
X   * Exit system call: pass back caller's arg
X***************
X*** 66,71
X  	vmsizmon();
X  #endif
X  	p = u.u_procp;
X  	p->p_flag &= ~(STRC|SULOCK);
X  	p->p_flag |= SWEXIT;
X  	p->p_sigignore = ~0;
X
X--- 69,81 -----
X  	vmsizmon();
X  #endif
X  	p = u.u_procp;
X+ #ifdef REMOTEFS
X+ 	/*
X+ 	 * First, release our server.
X+ 	 */
X+ 	if (p->p_flag & SREMOTE)
X+ 		remote_exit();
X+ #endif REMOTEFS
X  	p->p_flag &= ~(STRC|SULOCK);
X  	p->p_flag |= SWEXIT;
X  	p->p_sigignore = ~0;
SHAREOF
chmod 664 remote/usr.sys.VAX4.2/sys/kern_exit.c.diff
#
# remote/usr.sys.VAX4.2/sys/sys_inode.c.diff
#
if [ -f remote/usr.sys.VAX4.2/sys/sys_inode.c.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/sys/sys_inode.c.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.VAX4.2/sys/sys_inode.c.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.2/sys/sys_inode.c.diff
XThis change repairs a semantic change in ino_close() that assumes
Xthe only other file descriptor type is DTYPE_SOCKET.  If patch tells
Xyou
X	Reversed (or previously applied) patch detected!
XThen you already have the fix and you must undo what patch does.
X
X***************
X*** 351,357
X  	 * two different inodes.
X  	 */
X  	for (fp = file; fp < fileNFILE; fp++) {
X! 		if (fp->f_type == DTYPE_SOCKET)		/* XXX */
X  			continue;
X  		if (fp->f_count && (ip = (struct inode *)fp->f_data) &&
X  		    ip->i_rdev == dev && (ip->i_mode&IFMT) == mode)
X
X--- 351,357 -----
X  	 * two different inodes.
X  	 */
X  	for (fp = file; fp < fileNFILE; fp++) {
X! 		if (fp->f_type != DTYPE_INODE)	/* XXX */
X  			continue;
X  		if (fp->f_count && (ip = (struct inode *)fp->f_data) &&
X  		    ip->i_rdev == dev && (ip->i_mode&IFMT) == mode)
SHAREOF
chmod 664 remote/usr.sys.VAX4.2/sys/sys_inode.c.diff
#
# remote/usr.sys.VAX4.2/sys/ufs_nami.c.diff
#
if [ -f remote/usr.sys.VAX4.2/sys/ufs_nami.c.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/sys/ufs_nami.c.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.VAX4.2/sys/ufs_nami.c.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.2/sys/ufs_nami.c.diff
XThese changes are the primary hook into the operating system for detecting
Xa "remote" file.
X***************
X*** 97,102
X  	struct inode *pdp;		/* saved dp during symlink work */
X  	int i;
X  	int lockparent;
X  
X  	lockparent = flag & LOCKPARENT;
X  	flag &= ~LOCKPARENT;
X
X--- 97,105 -----
X  	struct inode *pdp;		/* saved dp during symlink work */
X  	int i;
X  	int lockparent;
X+ #ifdef REMOTEFS
X+ 	long	remote;
X+ #endif REMOTEFS
X  
X  	lockparent = flag & LOCKPARENT;
X  	flag &= ~LOCKPARENT;
X***************
X*** 145,150
X  	 * Check accessiblity of directory.
X  	 */
X  	if ((dp->i_mode&IFMT) != IFDIR) {
X  		u.u_error = ENOTDIR;
X  		goto bad;
X  	}
X
X--- 148,169 -----
X  	 * Check accessiblity of directory.
X  	 */
X  	if ((dp->i_mode&IFMT) != IFDIR) {
X+ #ifdef REMOTEFS
X+ 		remote = isremote(dp, cp, nbp->b_un.b_addr);
X+ 		/*
X+ 		 * If it is really local, then start again at the root.
X+ 		 */
X+ 		if (remote < 0) {
X+ 			iput(dp);
X+ 			dp = rootdir;
X+ 			ilock(dp);
X+ 			dp->i_count++;
X+ 			fs = dp->i_fs;
X+ 			cp = nbp->b_un.b_addr;
X+ 			goto dirloop2;
X+ 		}
X+ 		else if (! remote)
X+ #endif REMOTEFS
X  		u.u_error = ENOTDIR;
X  		goto bad;
X  	}
X***************
X*** 382,387
X  					iput(u.u_pdir);
X  					goto bad;
X  				}
X  			}
X  		}
X  		brelse(nbp);
X
X--- 401,417 -----
X  					iput(u.u_pdir);
X  					goto bad;
X  				}
X+ #ifdef REMOTEFS
X+ 				/*
X+ 				 * don't allow anyone to remove a remote mount
X+ 				 * point.
X+ 				 */
X+ 				if (rmt_host(dp, &i)) {
X+ 					iput(u.u_pdir);
X+ 					u.u_error = EBUSY;
X+ 					goto bad;
X+ 				}
X+ #endif REMOTEFS
X  			}
X  		}
X  		brelse(nbp);
SHAREOF
chmod 664 remote/usr.sys.VAX4.2/sys/ufs_nami.c.diff
#
# remote/usr.sys.VAX4.2/sys/ufs_syscalls.c.diff
#
if [ -f remote/usr.sys.VAX4.2/sys/ufs_syscalls.c.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/sys/ufs_syscalls.c.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.VAX4.2/sys/ufs_syscalls.c.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.2/sys/ufs_syscalls.c.diff
XThese changes modify chdirec(), which is called by chroot() and chdir(),
Xso that you can be allowed to do a chdir() to a remote mount point.
XIn addition, the changes ensure that we adjust internal pointers when doing
Xa chdir() OUT of a remote mount point.
X
X***************
X*** 67,72
X  chdirec(ipp)
X  	register struct inode **ipp;
X  {
X  	register struct inode *ip;
X  	struct a {
X  		char	*fname;
X
X--- 67,75 -----
X  chdirec(ipp)
X  	register struct inode **ipp;
X  {
X+ #ifdef REMOTEFS
X+ 	int	i;
X+ #endif REMOTEFS
X  	register struct inode *ip;
X  	struct a {
X  		char	*fname;
X***************
X*** 76,81
X  	if (ip == NULL)
X  		return;
X  	if ((ip->i_mode&IFMT) != IFDIR) {
X  		u.u_error = ENOTDIR;
X  		goto bad;
X  	}
X
X--- 79,89 -----
X  	if (ip == NULL)
X  		return;
X  	if ((ip->i_mode&IFMT) != IFDIR) {
X+ #ifdef REMOTEFS
X+ 		if (rmt_hostdir(ip, &i) != NULL)
X+ 			u.u_error = remotechdir(i);
X+ 		else
X+ #endif REMOTEFS
X  		u.u_error = ENOTDIR;
X  		goto bad;
X  	}
X***************
X*** 81,86
X  	}
X  	if (access(ip, IEXEC))
X  		goto bad;
X  	iunlock(ip);
X  	if (*ipp)
X  		irele(*ipp);
X
X--- 89,97 -----
X  	}
X  	if (access(ip, IEXEC))
X  		goto bad;
X+ #ifdef REMOTEFS
X+ 	remotechdir(-1);
X+ #endif REMOTEFS
X  	iunlock(ip);
X  	if (*ipp)
X  		irele(*ipp);
SHAREOF
chmod 664 remote/usr.sys.VAX4.2/sys/ufs_syscalls.c.diff
#
# remote/usr.sys.VAX4.2/sys/uipc_socket.c.diff
#
if [ -f remote/usr.sys.VAX4.2/sys/uipc_socket.c.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/sys/uipc_socket.c.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.VAX4.2/sys/uipc_socket.c.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.2/sys/uipc_socket.c.diff
XThese changes Fix a bug in soreceive() that caused infinite loop if a
Xpacket was received while doing uiomove() and the MSG_PEEK flag was set.
XIf you have this fix, then patch will tell you:
X
X	Reversed (or previously applied) patch detected!
X
XIf it does, you should just reinstall your original uipc_socket.c.
XIf you have a different version of the fix or another modification that
Xaffects this code, then patch will tell you that "Hunk #1 failed"; you
Xmust install the patch by hand.
X
X***************
X*** 546,552
X  		error =
X  		    uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio);
X  		s = splnet();
X! 		if (len == m->m_len) {
X  			eor = (int)m->m_act;
X  			if (flags & MSG_PEEK)
X  				m = m->m_next;
X
X--- 550,556 -----
X  		error =
X  		    uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio);
X  		s = splnet();
X! 		if (moff+len == m->m_len) {
X  			eor = (int)m->m_act;
X  			if (flags & MSG_PEEK)
X  				m = m->m_next;
SHAREOF
chmod 664 remote/usr.sys.VAX4.2/sys/uipc_socket.c.diff
#
# remote/usr.sys.VAX4.3/conf/Makefile.vax.diff
#
if [ -f remote/usr.sys.VAX4.3/conf/Makefile.vax.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.3/conf/Makefile.vax.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.VAX4.3/conf/Makefile.vax.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.3/conf/Makefile.vax.diff
XThis change teaches the Makefile how to make remote/rmt_data.c from
Xsys/init_sysent.c and remote/rmt_data_template.
X***************
X*** 145,150
X  param.o: param.c Makefile
X  	${CC} -c ${CFLAGS} ${PARAM} param.c
X  
X  %RULES
X  
X  # DO NOT DELETE THIS LINE -- make depend uses it
X
X--- 145,157 -----
X  param.o: param.c Makefile
X  	${CC} -c ${CFLAGS} ${PARAM} param.c
X  
X+ ../remote/rmt_data.c: ../remote/rmt_data_template ../remote/remotefs.h \
X+     ../sys/init_sysent.c
X+ 	cat ../remote/rmt_data_template > ../remote/nrmt_data.c
X+ 	/lib/cpp ${CFLAGS} ../sys/init_sysent.c | sh ../remote/remote_mkdata \
X+ 		../remote/remotefs.h >> ../remote/nrmt_data.c
X+ 	mv ../remote/nrmt_data.c ../remote/rmt_data.c
X+ 
X  %RULES
X  
X  # DO NOT DELETE THIS LINE -- make depend uses it
SHAREOF
chmod 664 remote/usr.sys.VAX4.3/conf/Makefile.vax.diff
#
# remote/usr.sys.VAX4.3/conf/makefile.vax.diff
#
if [ -f remote/usr.sys.VAX4.3/conf/makefile.vax.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.3/conf/makefile.vax.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.VAX4.3/conf/makefile.vax.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.3/conf/makefile.vax.diff
XThis change teaches the Makefile how to make remote/rmt_data.c from
Xsys/init_sysent.c and remote/rmt_data_template.
X***************
X*** 145,150
X  param.o: param.c makefile
X  	${CC} -c ${CFLAGS} ${PARAM} param.c
X  
X  %RULES
X  
X  # DO NOT DELETE THIS LINE -- make depend uses it
X
X--- 145,157 -----
X  param.o: param.c Makefile
X  	${CC} -c ${CFLAGS} ${PARAM} param.c
X  
X+ ../remote/rmt_data.c: ../remote/rmt_data_template ../remote/remotefs.h \
X+     ../sys/init_sysent.c
X+ 	cat ../remote/rmt_data_template > ../remote/nrmt_data.c
X+ 	/lib/cpp ${CFLAGS} ../sys/init_sysent.c | sh ../remote/remote_mkdata \
X+ 		../remote/remotefs.h >> ../remote/nrmt_data.c
X+ 	mv ../remote/nrmt_data.c ../remote/rmt_data.c
X+ 
X  %RULES
X  
X  # DO NOT DELETE THIS LINE -- make depend uses it
SHAREOF
chmod 664 remote/usr.sys.VAX4.3/conf/makefile.vax.diff
#
# remote/usr.sys.VAX4.3/h/user.h.diff
#
if [ -f remote/usr.sys.VAX4.3/h/user.h.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.3/h/user.h.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.VAX4.3/h/user.h.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.3/h/user.h.diff
XThese changes keep track of the per-process RFS information.
X***************
X*** 121,126
X  	} u_ncache;
X  	struct	nameidata u_nd;
X  
X  	int	u_stack[1];
X  };
X  
X
X--- 121,137 -----
X  	} u_ncache;
X  	struct	nameidata u_nd;
X  
X+ #ifdef REMOTEFS
X+ 	short	u_rmtoffset[2];		/* path offset for local segment */
X+ 	short	u_rmtcdir;		/* system # of remote current dir */
X+ 	long	u_rmtsys;		/* room for 32 systems */
X+ 					/* one bit for each remote system */
X+ #ifdef pyr /* Pyramid */
X+ 	int	*u.u_ap;
X+ #define		u_arg	u_ap
X+ #endif pyr
X+ #endif REMOTEFS
X+ 
X  	int	u_stack[1];
X  };
X  
SHAREOF
chmod 664 remote/usr.sys.VAX4.3/h/user.h.diff
#
# remote/usr.sys.VAX4.3/machine/trap.c.diff
#
if [ -f remote/usr.sys.VAX4.3/machine/trap.c.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.3/machine/trap.c.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.VAX4.3/machine/trap.c.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.3/machine/trap.c.diff
XThese changes enable syscall() to start up a remote version of a system
Xcall if the normal system call fails with error == EISREMOTE.
X***************
X*** 23,28
X  #ifdef SYSCALLTRACE
X  #include "../sys/syscalls.c"
X  #endif
X  
X  #include "mtpr.h"
X  
X
X--- 23,35 -----
X  #ifdef SYSCALLTRACE
X  #include "../sys/syscalls.c"
X  #endif
X+ #ifdef REMOTEFS
X+ #include "../remote/remotefs.h"
X+ /*
X+  * needed only if EISREMOTE isn't in /usr/include/errno.h
X+  */
X+ #include "../h/errno.h"
X+ #endif REMOTEFS
X  
X  #include "mtpr.h"
X  
X***************
X*** 191,196
X  	register struct proc *p;
X  	int opc;
X  	struct timeval syst;
X  
X  	syst = u.u_ru.ru_stime;
X  	if (!USERMODE(locr0[PS]))
X
X--- 198,212 -----
X  	register struct proc *p;
X  	int opc;
X  	struct timeval syst;
X+ #ifdef REMOTEFS
X+ 	/*
X+ 	 * It is imperative that these declarations come after other register
X+ 	 * declarations, because the (standard) code below depends upon the
X+ 	 * order of allocation.
X+ 	 */
X+ 	extern u_char remote_sysmap[];
X+ 	register long rmt_syscall, runremote, rmt_called, rmt_cnt;
X+ #endif REMOTEFS
X  
X  	syst = u.u_ru.ru_stime;
X  	if (!USERMODE(locr0[PS]))
X***************
X*** 223,228
X  		if (u.u_error == 0 && u.u_eosys != RESTARTSYS)
X  			u.u_error = EINTR;
X  	} else {
X  		u.u_eosys = NORMALRETURN;
X  #ifdef SYSCALLTRACE
X  		if (syscalltrace) {
X
X--- 239,248 -----
X  		if (u.u_error == 0 && u.u_eosys != RESTARTSYS)
X  			u.u_error = EINTR;
X  	} else {
X+ #ifdef REMOTEFS
X+ 		rmt_syscall = remote_sysmap[ code ];
X+ 		rmt_called = FALSE;
X+ 		rmt_cnt = 0;
X  		u.u_eosys = NORMALRETURN;
X  		while (! rmt_called) {
X  			runremote = (rmt_syscall != RSYS_nosys
X***************
X*** 224,229
X  			u.u_error = EINTR;
X  	} else {
X  		u.u_eosys = NORMALRETURN;
X  #ifdef SYSCALLTRACE
X  		if (syscalltrace) {
X  			register int i;
X
X--- 244,265 -----
X  		rmt_called = FALSE;
X  		rmt_cnt = 0;
X  		u.u_eosys = NORMALRETURN;
X+ 		while (! rmt_called) {
X+ 			runremote = (rmt_syscall != RSYS_nosys
X+ 				    && u.u_procp->p_flag & SREMOTE);
X+ 			if (runremote)
X+ 				rmt_called = remote_startup(rmt_cnt,
X+ 					rmt_syscall);
X+ 			if (! rmt_called) {
X+ 				(*callp->sy_call)();
X+ 				if (u.u_error != EISREMOTE)
X+ 					rmt_called = TRUE;
X+ 				else
X+ 					rmt_cnt++;
X+ 			}
X+ 		}
X+ #else REMOTEFS
X+ 		u.u_eosys = NORMALRETURN;
X  #ifdef SYSCALLTRACE
X  		if (syscalltrace) {
X  			register int i;
X***************
X*** 244,249
X  		}
X  #endif
X  		(*(callp->sy_call))();
X  	}
X  	if (u.u_eosys == NORMALRETURN) {
X  		if (u.u_error) {
X
X--- 280,286 -----
X  		}
X  #endif
X  		(*(callp->sy_call))();
X+ #endif REMOTEFS
X  	}
X  	if (u.u_eosys == NORMALRETURN) {
X  		if (u.u_error) {
SHAREOF
chmod 664 remote/usr.sys.VAX4.3/machine/trap.c.diff
#
# remote/usr.sys.VAX4.3/sys/init_sysent.c.diff
#
if [ -f remote/usr.sys.VAX4.3/sys/init_sysent.c.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.3/sys/init_sysent.c.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.VAX4.3/sys/init_sysent.c.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.3/sys/init_sysent.c.diff
XThese two changes add in the new RFS systems calls, remoteon(), remoteoff()
Xand  remotename().  If the second hunk fails, then you have some system
Xcall numbers that are not in standard 4.2BSD.
X***************
X*** 95,100
X  #define	compat(n, name)	0, nosys
X  #endif
X  
X  /* BEGIN JUNK */
X  #ifdef vax
X  int	resuba();
X
X--- 95,108 -----
X  #define	compat(n, name)	0, nosys
X  #endif
X  
X+ #ifdef REMOTEFS
X+ /*
X+  * remote file sys stuff (toddb@du)
X+  */
X+ int	remoteon(),		/* remote file sys stuff */
X+ 	remoteoff(),
X+ 	remotename();
X+ #endif REMOTEFS
X  /* BEGIN JUNK */
X  #ifdef vax
X  int	resuba();
X***************
X*** 269,274
X  	2, setquota,			/* 148 = quota */
X  	4, qquota,			/* 149 = qquota */
X  	3, getsockname,			/* 150 = getsockname */
X  	0, nosys,			/* 151 = nosys */
X  	0, nosys,			/* 152 = nosys */
X  	0, nosys,			/* 153 = nosys */
X
X--- 277,287 -----
X  	2, setquota,			/* 148 = quota */
X  	4, qquota,			/* 149 = qquota */
X  	3, getsockname,			/* 150 = getsockname */
X+ #ifdef REMOTEFS
X+ 	4, remoteon,			/* 151 = remoteon */
X+ 	1, remoteoff,			/* 152 = remoteoff */
X+ 	4, remotename,			/* 153 = remotename */
X+ #else REMOTEFS
X  	0, nosys,			/* 151 = nosys */
X  	0, nosys,			/* 152 = nosys */
X  	0, nosys,			/* 153 = nosys */
X***************
X*** 272,277
X  	0, nosys,			/* 151 = nosys */
X  	0, nosys,			/* 152 = nosys */
X  	0, nosys,			/* 153 = nosys */
X  	0, nosys,			/* 154 = nosys */
X  };
X  int	nsysent = sizeof (sysent) / sizeof (sysent[0]);
X
X--- 285,291 -----
X  	0, nosys,			/* 151 = nosys */
X  	0, nosys,			/* 152 = nosys */
X  	0, nosys,			/* 153 = nosys */
X+ #endif REMOTEFS
X  	0, nosys,			/* 154 = nosys */
X  };
X  int	nsysent = sizeof (sysent) / sizeof (sysent[0]);
SHAREOF
chmod 664 remote/usr.sys.VAX4.3/sys/init_sysent.c.diff

sources-request@panda.UUCP (01/09/86)

Mod.sources:  Volume 3, Issue 82
Submitted by: tektronix!tekcrl!toddb

#!/bin/sh
#
# RFS, a kernel-resident remote file system.  Shar 6 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/usr.sys.VAX4.3/sys/kern_exec.c.diff
#	remote/usr.sys.VAX4.3/sys/kern_exit.c.diff
#	remote/usr.sys.VAX4.3/sys/ufs_namei.c.diff
#	remote/usr.sys.VAX4.3/sys/ufs_syscalls.c.diff
#	remote/usr.sys.remote
#	remote/usr.sys.remote/remote_mkdata
#	remote/usr.sys.remote/remotefs.h
#	remote/usr.sys.remote/rmt_data_template
#	remote/usr.sys.remote/rmt_exec.c
#	remote/usr.sys.remote/rmt_final.c
#	remote/usr.sys.remote/rmt_syscall3.c
#
# remote/usr.sys.VAX4.3/sys/kern_exec.c.diff
#
if [ -f remote/usr.sys.VAX4.3/sys/kern_exec.c.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.3/sys/kern_exec.c.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.VAX4.3/sys/kern_exec.c.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.3/sys/kern_exec.c.diff
XThe following changes implement local execution of an object file that
Xlives on another host.
X***************
X*** 27,32
X  #include "acct.h"
X  #include "exec.h"
X  
X  #ifdef vax
X  #include "../vax/mtpr.h"
X  #endif
X
X--- 27,36 -----
X  #include "acct.h"
X  #include "exec.h"
X  
X+ #ifdef REMOTEFS
X+ #include "../h/errno.h"
X+ #endif REMOTEFS
X+ 
X  #ifdef vax
X  #include "../vax/mtpr.h"
X  #endif
X***************
X*** 55,61
X  	int na, ne, ucp, ap, len, cc;
X  	int indir, uid, gid;
X  	char *sharg;
X! 	struct inode *ip;
X  	swblk_t bno;
X  	char cfname[MAXCOMLEN + 1];
X  #define	SHSIZE	32
X
X--- 59,70 -----
X  	int na, ne, ucp, ap, len, cc;
X  	int indir, uid, gid;
X  	char *sharg;
X! #ifdef REMOTEFS
X! 	struct inode *ip; /* have to take address */
X! 	int	remote = -1;
X! #else REMOTEFS
X! 	register struct inode *ip;
X! #endif REMOTEFS
X  	swblk_t bno;
X  	char cfname[MAXCOMLEN + 1];
X  #define	SHSIZE	32
X***************
X*** 71,76
X  	ndp->ni_segflg = UIO_USERSPACE;
X  	ndp->ni_dirp = ((struct execa *)u.u_ap)->fname;
X  	if ((ip = namei(ndp)) == NULL)
X  		return;
X  	bno = 0;
X  	bp = 0;
X
X--- 80,91 -----
X  	ndp->ni_segflg = UIO_USERSPACE;
X  	ndp->ni_dirp = ((struct execa *)u.u_ap)->fname;
X  	if ((ip = namei(ndp)) == NULL)
X+ #ifdef REMOTEFS
X+ 		if (u.u_error == EISREMOTE)
X+ 			remote = remote_execinfo(&ip, &uid, &gid,
X+ 				&exdata, ((struct execa *)u.u_ap)->fname);
X+ 	if (u.u_error)
X+ #endif REMOTEFS
X  		return;
X  	bno = 0;
X  	bp = 0;
X***************
X*** 75,80
X  	bno = 0;
X  	bp = 0;
X  	indir = 0;
X  	uid = u.u_uid;
X  	gid = u.u_gid;
X  	if (ip->i_mode & ISUID)
X
X--- 90,99 -----
X  	bno = 0;
X  	bp = 0;
X  	indir = 0;
X+ 
X+ #ifdef REMOTEFS
X+ if (remote < 0) {
X+ #endif REMOTEFS
X  	uid = u.u_uid;
X  	gid = u.u_gid;
X  	if (ip->i_mode & ISUID)
X***************
X*** 112,117
X  	    0, 1, &resid);
X  	if (u.u_error)
X  		goto bad;
X  #ifndef lint
X  	if (resid > sizeof(exdata) - sizeof(exdata.ex_exec) &&
X  	    exdata.ex_shell[0] != '#') {
X
X--- 131,143 -----
X  	    0, 1, &resid);
X  	if (u.u_error)
X  		goto bad;
X+ #ifdef REMOTEFS
X+ }
X+ 
X+ remote_again:
X+ 
X+ #endif REMOTEFS
X+ 
X  #ifndef lint
X  	if (resid > sizeof(exdata) - sizeof(exdata.ex_exec) &&
X  	    exdata.ex_shell[0] != '#') {
X***************
X*** 170,176
X  				bcopy((caddr_t)cp, (caddr_t)cfarg, SHSIZE);
X  		}
X  		indir = 1;
X! 		iput(ip);
X  		ndp->ni_nameiop = LOOKUP | FOLLOW;
X  		ndp->ni_segflg = UIO_SYSSPACE;
X  		ip = namei(ndp);
X
X--- 196,205 -----
X  				bcopy((caddr_t)cp, (caddr_t)cfarg, SHSIZE);
X  		}
X  		indir = 1;
X! #ifdef REMOTEFS
X! 		if (remote < 0)
X! #endif REMOTEFS
X! 			iput(ip);
X  		ndp->ni_nameiop = LOOKUP | FOLLOW;
X  		ndp->ni_segflg = UIO_SYSSPACE;
X  		ip = namei(ndp);
X***************
X*** 174,179
X  		ndp->ni_nameiop = LOOKUP | FOLLOW;
X  		ndp->ni_segflg = UIO_SYSSPACE;
X  		ip = namei(ndp);
X  		if (ip == NULL)
X  			return;
X  		bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)cfname,
X
X--- 203,220 -----
X  		ndp->ni_nameiop = LOOKUP | FOLLOW;
X  		ndp->ni_segflg = UIO_SYSSPACE;
X  		ip = namei(ndp);
X+ #ifdef REMOTEFS
X+ 		if (ip == NULL) {
X+ 			if (u.u_error == EISREMOTE)
X+ 				remote = remote_execinfo(&ip, 0, 0, 0);
X+ 			if (u.u_error)
X+ 				return;
X+ 			if (ip == NULL)
X+ 				goto remote_again;
X+ 		}
X+ 		else
X+ 			remote = -1;
X+ #else REMOTEFS
X  		if (ip == NULL)
X  			return;
X  #endif REMOTEFS
X***************
X*** 176,181
X  		ip = namei(ndp);
X  		if (ip == NULL)
X  			return;
X  		bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)cfname,
X  		    MAXCOMLEN);
X  		cfname[MAXCOMLEN] = '\0';
X
X--- 217,223 -----
X  #else REMOTEFS
X  		if (ip == NULL)
X  			return;
X+ #endif REMOTEFS
X  		bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)cfname,
X  		    MAXCOMLEN);
X  		cfname[MAXCOMLEN] = '\0';
X***************
X*** 268,274
X  		bdwrite(bp);
X  	bp = 0;
X  	nc = (nc + NBPW-1) & ~(NBPW-1);
X! 	getxfile(ip, &exdata.ex_exec, nc + (na+4)*NBPW, uid, gid);
X  	if (u.u_error) {
X  badarg:
X  		for (cc = 0; cc < nc; cc += CLSIZE*NBPG) {
X
X--- 310,322 -----
X  		bdwrite(bp);
X  	bp = 0;
X  	nc = (nc + NBPW-1) & ~(NBPW-1);
X! 
X! #ifdef REMOTEFS
X!         getxfile(ip, &exdata.ex_exec, nc + (na+4)*NBPW, uid, gid, remote);
X! #else REMOTEFS
X!         getxfile(ip, &exdata.ex_exec, nc + (na+4)*NBPW, uid, gid);
X! #endif REMOTEFS
X! 
X  	if (u.u_error) {
X  badarg:
X  		for (cc = 0; cc < nc; cc += CLSIZE*NBPG) {
X***************
X*** 376,381
X  /*
X   * Read in and set up memory for executed file.
X   */
X  getxfile(ip, ep, nargc, uid, gid)
X  	register struct inode *ip;
X  	register struct exec *ep;
X
X--- 424,432 -----
X  /*
X   * Read in and set up memory for executed file.
X   */
X+ #ifdef REMOTEFS
X+ getxfile(ip, ep, nargc, uid, gid, remote)
X+ #else REMOTEFS
X  getxfile(ip, ep, nargc, uid, gid)
X  #endif REMOTEFS
X  	register struct inode *ip;
X***************
X*** 377,382
X   * Read in and set up memory for executed file.
X   */
X  getxfile(ip, ep, nargc, uid, gid)
X  	register struct inode *ip;
X  	register struct exec *ep;
X  	int nargc, uid, gid;
X
X--- 428,434 -----
X  getxfile(ip, ep, nargc, uid, gid, remote)
X  #else REMOTEFS
X  getxfile(ip, ep, nargc, uid, gid)
X+ #endif REMOTEFS
X  	register struct inode *ip;
X  	register struct exec *ep;
X  	int nargc, uid, gid;
X***************
X*** 383,388
X  {
X  	size_t ts, ds, ids, uds, ss;
X  	int pagi;
X  
X  	if (ep->a_magic == 0413)
X  		pagi = SPAGI;
X
X--- 435,443 -----
X  {
X  	size_t ts, ds, ids, uds, ss;
X  	int pagi;
X+ #ifdef REMOTEFS
X+ 	int	oldtextsize;
X+ #endif REMOTEFS
X  
X  	if (ep->a_magic == 0413)
X  		pagi = SPAGI;
X***************
X*** 388,393
X  		pagi = SPAGI;
X  	else
X  		pagi = 0;
X  	if (ip->i_flag & IXMOD) {			/* XXX */
X  		u.u_error = ETXTBSY;
X  		goto bad;
X
X--- 443,459 -----
X  		pagi = SPAGI;
X  	else
X  		pagi = 0;
X+ #ifdef REMOTEFS
X+ 	if (remote >= 0) {
X+ 		/*
X+ 		 * Prevent xalloc() from making a shared or paged text.
X+ 		 */
X+ 		pagi = 0;
X+ 		oldtextsize = ep->a_text;
X+ 		ep->a_data += ep->a_text;
X+ 		ep->a_text = 0;
X+ 	}
X+ #endif REMOTEFS
X  	if (ip->i_flag & IXMOD) {			/* XXX */
X  		u.u_error = ETXTBSY;
X  		goto bad;
X***************
X*** 452,457
X  	u.u_smap = u.u_csmap;
X  	vgetvm(ts, ds, ss);
X  
X  	if (pagi == 0)
X  		u.u_error =
X  		    rdwri(UIO_READ, ip,
X
X--- 518,528 -----
X  	u.u_smap = u.u_csmap;
X  	vgetvm(ts, ds, ss);
X  
X+ #ifdef REMOTEFS
X+ 	if (remote >= 0)
X+ 		u.u_error = remote_execread(remote, oldtextsize, ep);
X+ 	else
X+ #endif REMOTEFS
X  	if (pagi == 0)
X  		u.u_error =
X  		    rdwri(UIO_READ, ip,
SHAREOF
chmod 664 remote/usr.sys.VAX4.3/sys/kern_exec.c.diff
#
# remote/usr.sys.VAX4.3/sys/kern_exit.c.diff
#
if [ -f remote/usr.sys.VAX4.3/sys/kern_exit.c.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.3/sys/kern_exit.c.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.VAX4.3/sys/kern_exit.c.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.3/sys/kern_exit.c.diff
XThe following changes ensure that upon exit, a process notifies any remote
Xservers that may know about him, that he is indeed dead.
X***************
X*** 23,28
X  #include "mbuf.h"
X  #include "inode.h"
X  #include "syslog.h"
X  
X  /*
X   * Exit system call: pass back caller's arg
X
X--- 23,31 -----
X  #include "mbuf.h"
X  #include "inode.h"
X  #include "syslog.h"
X+ #ifdef REMOTEFS
X+ #include "../remote/remotefs.h"
X+ #endif REMOTEFS
X  
X  /*
X   * Exit system call: pass back caller's arg
X***************
X*** 56,61
X  	vmsizmon();
X  #endif
X  	p = u.u_procp;
X  	p->p_flag &= ~(STRC|SULOCK);
X  	p->p_flag |= SWEXIT;
X  	p->p_sigignore = ~0;
X
X--- 59,71 -----
X  	vmsizmon();
X  #endif
X  	p = u.u_procp;
X+ #ifdef REMOTEFS
X+ 	/*
X+ 	 * First, release our server.
X+ 	 */
X+ 	if (p->p_flag & SREMOTE)
X+ 		remote_exit();
X+ #endif REMOTEFS
X  	p->p_flag &= ~(STRC|SULOCK);
X  	p->p_flag |= SWEXIT;
X  	p->p_sigignore = ~0;
SHAREOF
chmod 664 remote/usr.sys.VAX4.3/sys/kern_exit.c.diff
#
# remote/usr.sys.VAX4.3/sys/ufs_namei.c.diff
#
if [ -f remote/usr.sys.VAX4.3/sys/ufs_namei.c.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.3/sys/ufs_namei.c.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.VAX4.3/sys/ufs_namei.c.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.3/sys/ufs_namei.c.diff
XThese changes are the primary hook into the operating system for detecting
Xa "remote" file.
X***************
X*** 149,154
X  	int isdotdot;			/* != 0 if current name is ".." */
X  	int flag;			/* op ie, LOOKUP, CREATE, or DELETE */
X  	off_t enduseful;		/* pointer past last used dir slot */
X  
X  	lockparent = ndp->ni_nameiop & LOCKPARENT;
X  	docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE;
X
X--- 149,157 -----
X  	int isdotdot;			/* != 0 if current name is ".." */
X  	int flag;			/* op ie, LOOKUP, CREATE, or DELETE */
X  	off_t enduseful;		/* pointer past last used dir slot */
X+ #ifdef REMOTEFS
X+ 	int remote;
X+ #endif
X  
X  	lockparent = ndp->ni_nameiop & LOCKPARENT;
X  	docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE;
X***************
X*** 202,207
X  	 * Check accessiblity of directory.
X  	 */
X  	if ((dp->i_mode&IFMT) != IFDIR) {
X  		u.u_error = ENOTDIR;
X  		goto bad;
X  	}
X
X--- 205,226 -----
X  	 * Check accessiblity of directory.
X  	 */
X  	if ((dp->i_mode&IFMT) != IFDIR) {
X+ #ifdef REMOTEFS
X+ 		remote = isremote(dp, cp, nbp->b_un.b_addr);
X+ 		/*
X+ 		 * If it is really local, then start again at the root.
X+ 		 */
X+ 		if (remote < 0) {
X+ 			iput(dp);
X+ 			dp = rootdir;
X+ 			ILOCK(dp);
X+ 			dp->i_count++;
X+ 			fs = dp->i_fs;
X+ 			cp = nbp->b_un.b_addr;
X+ 			goto dirloop2;
X+ 		}
X+ 		else if (! remote)
X+ #endif REMOTEFS
X  		u.u_error = ENOTDIR;
X  		goto bad;
X  	}
X***************
X*** 642,647
X  					u.u_error = EPERM;
X  					goto bad;
X  				}
X  			}
X  		}
X  		nbp->av_forw = freenamebuf;
X
X--- 661,677 -----
X  					u.u_error = EPERM;
X  					goto bad;
X  				}
X+ #ifdef REMOTEFS
X+ 				/*
X+ 				 * don't allow anyone to remove a remote mount
X+ 				 * point.
X+ 				 */
X+ 				if (rmt_host(dp, &i)) {
X+ 					iput(ndp->ni_pdir);
X+ 					u.u_error = EBUSY;
X+ 					goto bad;
X+ 				}
X+ #endif REMOTEFS
X  			}
X  		}
X  		nbp->av_forw = freenamebuf;
SHAREOF
chmod 664 remote/usr.sys.VAX4.3/sys/ufs_namei.c.diff
#
# remote/usr.sys.VAX4.3/sys/ufs_syscalls.c.diff
#
if [ -f remote/usr.sys.VAX4.3/sys/ufs_syscalls.c.diff ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.3/sys/ufs_syscalls.c.diff or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.VAX4.3/sys/ufs_syscalls.c.diff 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.3/sys/ufs_syscalls.c.diff
XThese changes modify chdirec(), which is called by chroot() and chdir(),
Xso that you can be allowed to do a chdir() to a remote mount point.
XIn addition, the changes ensure that we adjust internal pointers when doing
Xa chdir() OUT of a remote mount point.
X
X***************
X*** 51,56
X  chdirec(ipp)
X  	register struct inode **ipp;
X  {
X  	register struct inode *ip;
X  	struct a {
X  		char	*fname;
X
X--- 51,59 -----
X  chdirec(ipp)
X  	register struct inode **ipp;
X  {
X+ #ifdef REMOTEFS
X+ 	int	i;
X+ #endif REMOTEFS
X  	register struct inode *ip;
X  	struct a {
X  		char	*fname;
X***************
X*** 64,69
X  	if (ip == NULL)
X  		return;
X  	if ((ip->i_mode&IFMT) != IFDIR) {
X  		u.u_error = ENOTDIR;
X  		goto bad;
X  	}
X
X--- 67,77 -----
X  	if (ip == NULL)
X  		return;
X  	if ((ip->i_mode&IFMT) != IFDIR) {
X+ #ifdef REMOTEFS
X+ 		if (rmt_hostdir(ip, &i) != NULL)
X+ 			u.u_error = remotechdir(i);
X+ 		else
X+ #endif REMOTEFS
X  		u.u_error = ENOTDIR;
X  		goto bad;
X  	}
X***************
X*** 69,74
X  	}
X  	if (access(ip, IEXEC))
X  		goto bad;
X  	IUNLOCK(ip);
X  	if (*ipp)
X  		irele(*ipp);
X
X--- 77,85 -----
X  	}
X  	if (access(ip, IEXEC))
X  		goto bad;
X+ #ifdef REMOTEFS
X+ 	remotechdir(-1);
X+ #endif REMOTEFS
X  	IUNLOCK(ip);
X  	if (*ipp)
X  		irele(*ipp);
SHAREOF
chmod 664 remote/usr.sys.VAX4.3/sys/ufs_syscalls.c.diff
#
# remote/usr.sys.remote
#
mkdir remote/usr.sys.remote
chmod 775 remote/usr.sys.remote
#
# remote/usr.sys.remote/remote_mkdata
#
if [ -f remote/usr.sys.remote/remote_mkdata ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.remote/remote_mkdata or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.remote/remote_mkdata 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.remote/remote_mkdata
X#!/bin/sh
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 software 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#  comment remains an unaltered part of the software.
X#
X
Xif [ ! -f "$1" ]
Xthen
X	echo "Usage:"
X	echo "	/lib/cpp -DKERNEL ... ..../init_sysent.c | $0 ..../remotefs.h"
X	exit 1
Xfi
X
XREMOTE=$1
X
X#
X# First, get the complete list of remote system calls and put them
X# into memory for awk.
X#
XMEM=`sed -e '/^#define[ 	]*RSYS_/!d' \
X	-e 's/.*RSYS_\([^ 	]*\)	\([0-9]*\)$/mem[\2]="\1";last=\2;/' \
X	< $REMOTE`
X#
X# Then, compile a list of all system calls from a cpp expanded listing
X# of sys/init_sysent.c which should be on standard input.
X# The only kludge here is that we must change internal names for system
X# calls:
X#      internal	      changed
X#	name		 to
X#     ----------     ----------
X#	rexit		exit
X#	saccess		access
X#
Xsed	-e '1,/^struct[ 	]*sysent[ 	]*sysent[ 	]*\[\]/d' \
X	-e '/^};/,$d' \
X	-e '/^#/d' \
X	-e 's/	*[0-9], *//' \
X	-e 's/,.*//' \
X	-e 's/^rexit$/exit/' \
X	-e 's/^saccess$/access/' \
X	-e '/^[ 	]*$/d' \
X| tail +2 \
X| cat -n \
X| awk '
XBEGIN {
X	'"$MEM"'
X	syscall = 0;
X	column = 0;
X	printf "u_char\tremote_sysmap[] = {\n"
X}
X{
X	while (syscall < $1) {
X		if (column % 2 == 0)
X			printf "\t"
X		printf "%-31s", "RSYS_nosys,"
X		if (column % 2 == 1)
X			printf "\n"
X		syscall++
X		column++
X	}
X
X	if (column % 2 == 0)
X		printf "\t"
X	len = length($2);
X	found = 0;
X	for (i=0; i <= last; i++) {
X		if (mem[ i ] == $2) {
X			found = 1;
X			break;
X		}
X	}
X	if (found) {
X		printf "RSYS_%s,", $2
X		len = 25-len;
X	}
X	else {
X		printf "RSYS_nosys,  /* %s */", $2
X		len = 12 - len;
X	}
X	if (column % 2 == 1)
X		printf "\n"
X	else
X		while (len-- > 0)
X			printf " "
X	column++;
X	syscall++
X} END {
X	if (column % 2 == 0)
X		printf "\n"
X	printf "};\n"
X}'
SHAREOF
chmod 664 remote/usr.sys.remote/remote_mkdata
#
# remote/usr.sys.remote/remotefs.h
#
if [ -f remote/usr.sys.remote/remotefs.h ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.remote/remotefs.h or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.remote/remotefs.h 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.remote/remotefs.h
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 * $Header: remotefs.h,v 2.1 86/01/05 18:17:01 toddb Exp $
X *
X * $Log:	remotefs.h,v $
X * Revision 2.1  86/01/05  18:17:01  toddb
X * Added ifdef'ed constants for pyramids: FREMOTE, SREMOTE and SNOREMOTE.
X * 
X * Revision 2.0  85/12/07  18:17:35  toddb
X * First public release.
X * 
X */
X#ifndef RFSDEBUG
X#define debug0()
X#define debug1()
X#define debug2()
X#define debug3()
X#define debug4()
X#define debug5()
X#define debug6()
X#define debug7()
X#define debug8()
X#define debug9()
X#define debug10()
X#define debug11()
X#define debug12()
X#define debug13()
X#define debug14()
X#define rmt_showmsg()
X#else RFSDEBUG
X/*
X * Each of the debugging macros are defined here.  With this scheme we
X * are able to turn on any portion of the debugging with very little overhead
X * This appears to be better than similar schemes that test if
X * remote_debug <= some-level,  because they force the software into having
X * more and more debug software run as the number gets higher.
X */
Xextern long	remote_debug;
X
X#define debug0	(!(remote_debug&0x00001)) ? 0:rmt_debug /* exec info */
X#define debug1	(!(remote_debug&0x00002)) ? 0:rmt_debug /* startup activity */
X#define debug2	(!(remote_debug&0x00004)) ? 0:rmt_debug /* rmt_copypath() */
X#define debug3	(!(remote_debug&0x00008)) ? 0:rmt_debug /* unused */
X#define debug4	(!(remote_debug&0x00010)) ? 0:rmt_debug /* remote_fork */
X#define debug5	(!(remote_debug&0x00020)) ? 0:rmt_debug /* remote[on|off] */
X#define debug6	(!(remote_debug&0x00040)) ? 0:rmt_debug /* file descriptors */
X#define debug7	(!(remote_debug&0x00080)) ? 0:rmt_debug /* isremote() */
X#define debug8	(!(remote_debug&0x00100)) ? 0:rmt_debug /* file remoteness */
X#define debug9	(!(remote_debug&0x00200)) ? 0:rmt_debug /* connection startup */
X#define debug10	(!(remote_debug&0x00400)) ? 0:rmt_debug /* msg setup */
X#define debug11	(!(remote_debug&0x00800)) ? 0:rmt_debug /* msg exceptions */
X#define debug12	(!(remote_debug&0x01000)) ? 0:rmt_debug /* shutdowns */
X#define debug13	(!(remote_debug&0x02000)) ? 0:rmt_debug /* path translation */
X#define debug14	(!(remote_debug&0x04000)) ? 0:rmt_debug /* chdir() activity */
X#define debug15	(!(remote_debug&0x08000)) ? 0:rmt_debug /* msg content */
X#define debug16	(!(remote_debug&0x10000)) ? 0:rmt_debug /* msg data content */
X#define debug17	(!(remote_debug&0x20000)) ? 0:rmt_debug /* unused */
X#define debug18	(!(remote_debug&0x40000)) ? 0:rmt_debug /* unused */
X#define debug19	(!(remote_debug&0x80000)) ? 0:rmt_debug /* unused */
X
X#endif RFSDEBUG
X
X/*
X * Flags for file structures and proc structures.  These should really be
X * in file.h and proc.h, but are here for now.  Note that you must have
X * the fix in ino_close() if DTYPE_REMOTE is defined as 3.
X */
X#define		DTYPE_REMOTE		3  /* file.h: remote file descriptor */
X#ifdef pyr
X#define		SREMOTE		0x00080000 /* proc.h: activity has occured */
X#define		SNOREMOTE	0x80000000 /* proc.h: disallow remote access */
X#define		FREMOTE		04000	   /* file.h: this is a remote file */
X#endif pyr
X#if vax || magnolia || P4400
X#define		SREMOTE		0x08000000 /* proc.h: activity has occured */
X#define		SNOREMOTE	0x10000000 /* proc.h: disallow remote access */
X#define		FREMOTE		08000	   /* file.h: this is a remote file */
X#endif vax || magnolia || P4400
X
X/*
X * Defines for the name server.
X */
X#define		server_alive(p)					\
X			((p) 					\
X			&& (p)->p_stat != NULL			\
X			&& remote_ns.rn_pid == (p)->p_pid)
X
X#define		NM_SERVER	0	/* register as name server */
X#define		NM_WHATNAME	1	/* what name does the kernel need? */
X#define		NM_NAMEIS	2	/* the name is... */
X#define		NM_DEBUG	3	/* turn on debugging */
X
X/*
X * Some manifest constants.
X */
X#define		TRUE		1
X#define		FALSE		0
X#define		REMOTE_FS_SERVER	"remotefs"
X#define		R_MAXSYS	NREMOTE	/* defined in param.h */
X#define		R_MNTPATHLEN	30
X#define		R_MAXMSG	((MAXPATHLEN * 2) + MLEN)
X#define		R_RETRY		(60*5)	/* retry time for connections */
X
X/*
X * State of the data being sent.
X */
X#define		R_NOTHINGSENT	1
X#define		R_DATANOTSENT	2
X#define		R_MSGNOTRED	3
X#define		R_DATANOTRED	4
X
X/*
X * internal flags passed to rmt_msgfin() and rmt_datafin().
X */
X#define		RFLG_DATAV	0x1	/* data to remotemsg() is a vector */
X#define		RFLG_RD		0x2	/* data to remotemsg() to be read */
X#define		RFLG_WR		0x4	/* data to remotemsg() to be written */
X#define		RFLG_INFO	0x8	/* send message only (don't receive */
X
X/*
X * known indices of data in the message.
X */
X#define		R_PATHOFF	3	/* to server (Offset to 2nd path) */
X#define		R_PATHSTART	4	/* to server start of actual path */
X#define		R_DATA		2	/* to server */
X#define		R_RETVAL	0	/* from server */
X#define		R_EXECUID	1	/* from server (exec setuid) */
X#define		R_EXECGID	2	/* from server (exec setgid) */
X#define		R_EXECREADONLY	3	/* from server (exec text read-only) */
X#define		R_EXECDATA	4	/* from server (start of exec info) */
X
X/*
X * Maximum size for the message arg data in long words.  NOT LONGWORDS!!  This
X * should be the largest of the following three sizes among all machines
X * that will use the remote file system:
X *
X *	sizeof(struct exec) * sizeof(long) + R_EXECDATA * sizeof(long)
X *	(# of stat struct members + 1) * sizeof(long)
X */
X#define		R_MAXARGS	18
X
X/*
X * Maximum and minimum message length in bytes that we will ever need on a
X * receive (big enough for a stat(), lstat() or fstat(), and small enough for
X * a return with no other values.
X */
X#define		R_MINRMSG	(sizeof(struct message)-R_MAXARGS*sizeof(long))
X#define		R_MAXRMSG	(sizeof(struct message))
X
X/*
X * The maximum number of mbufs that we need to send a message with
X * two paths, each 1024 characters long.  This is used only in the user
X * level implementation.
X */
X#define		R_MAXMBUFS	(R_MINRMSG+(MAXPATHLEN*2))/MLEN
X
X/*
X * Here, we describe incomming and outgoing messages.  Note that the number
X * of cells in m_args is only for incomming messages.  An outgoing message
X * may consume much more.
X */
Xstruct message {
X	long	m_totlen;	/* length of total message (including data) */
X	short	m_uid;		/* uid of client */
X	short	m_pid;		/* pid of client */
X	short	m_hdlen;	/* length of header (excluding data) */
X	short	m_syscall;	/* syscall number */
X#define		m_errno m_syscall /* errno (for server) */
X	long	m_args[R_MAXARGS];/* remaining arguments or return values */
X};
X
X/*
X * This structure describes the kernel information kept for each
X * connection to a remote server.
X */
Xstruct remoteinfo {
X	char	r_mntpath[ R_MNTPATHLEN ];	/* path of mount point */
X	u_char		r_close:1;	/* True if connection to be closed */
X	u_char		r_received:1;	/* True if an incomming msg in r_msg */
X	u_char		r_failed:1;	/* connection failed */
X	u_char		r_opening:1;	/* connection in process of opening */
X	u_char		r_refcnt;	/* a reference count of active use */
X	short		r_sender;	/* owner of outgoing data */
X	short		r_recver;	/* owner of incomming data */
X	u_short		r_users;	/* count of users using this */
X	u_short		r_nfile;	/* count of open files */
X	u_short		r_nchdir;	/* count of chdir() to this host */
X	struct mbuf	*r_name;	/* socket address of remote host */
X	struct inode 	*r_mntpt;	/* inode of mount point */
X					/* if null, then global */
X	struct socket	*r_sock;	/* socket with active connection */
X#define	r_age		r_msg.m_totlen	/* used for cacheing name lookups */
X#define	r_openerr	r_msg.m_errno	/* used to relay connection errors */
X	struct message	r_msg;		/* incomming message */
X};
X
Xtypedef int			(*func)();
X
X/*
X * This describes all info associated with each syscall.  Note that while
X * the flag information is available, most syscalls don't reference it
X * because they have the flag hard coded in-line.  It exists for the
X * sake of routines like read and write which cannot hard code the flags
X * very easily.  The follow flag is useful only for system calls that involve
X * pathnames.  The before entry is to tell syscall whether to try to
X * call the remote syscall routine before calling the real system call.
X * The size here make each table entry a
X * power of 2 in size (16 bytes) which the compiler can make faster code for.
X */
Xstruct syscalls {
X	func	sys_gen;
X	func	sys_spec;
X	long	sys_flag;
X	short	sys_follow;
X	short	sys_before;
X};
Xtypedef struct syscalls		syscalls;
X
X/*
X * This structure simply describes the process willing to act as a
X * name server for the remote file system, and the information passing
X * to and from it.
X */
Xstruct nameserver {
X	struct proc	*rn_proc;	/* process registered as nameserver */
X	struct mbuf	*rn_name;	/* input from name server */
X	char		*rn_path;	/* path to translate */
X	short		rn_pathlen;	/* length of path to translate */
X	short		rn_pid;		/* pid of process (for uniqueness) */
X};
X
X/*
X * System calls
X * Note that these have nothing to do with either the vax or magnolia idea
X * of the system calls.  They are simply an index into the systems calls
X * that we are concerned with.
X */
X#define	RSYS_fork	0
X#define	RSYS_read	1
X#define	RSYS_write	2
X#define	RSYS_open	3
X#define	RSYS_close	4
X#define	RSYS_creat	5
X#define	RSYS_link	6
X#define	RSYS_unlink	7
X#define	RSYS_chdir	8
X#define	RSYS_mknod	9
X#define	RSYS_chmod	10
X#define	RSYS_chown	11
X#define	RSYS_stat	12
X#define	RSYS_lseek	13
X#define	RSYS_access	14
X#define	RSYS_lstat	15
X#define	RSYS_dup	16
X#define	RSYS_ioctl	17
X#define	RSYS_symlink	18
X#define	RSYS_readlink	19
X#define	RSYS_fstat	20
X#define	RSYS_dup2	21
X#define	RSYS_fcntl	22
X#define	RSYS_fsync	23
X#define	RSYS_readv	24
X#define	RSYS_writev	25
X#define	RSYS_fchown	26
X#define	RSYS_fchmod	27
X#define	RSYS_rename	28
X#define	RSYS_truncate	29
X#define	RSYS_ftruncate	30
X#define	RSYS_flock	31
X#define	RSYS_mkdir	32
X#define	RSYS_rmdir	33
X#define	RSYS_utimes	34
X#define	RSYS_exit	35
X#define	RSYS_vfork	36
X#define	RSYS_execinfo	37
X#define	RSYS_execread	38
X#define RSYS_execve	39
X#define	RSYS_nosys	40
X#define	RSYS_qlseek	41
X
X/*
X * This macro fills in some of the information needed on every transfer
X * and returns the byte (not longword) offset of the next free byte.
X */
X#define introduce(buf, sysnum)						\
X				((buf)->m_pid = htons(u.u_procp->p_pid),\
X				 (buf)->m_uid = htons(u.u_uid),		\
X				 (buf)->m_syscall = htons(sysnum),	\
X				 (R_MINRMSG))
X#define introduce_1extra(buf, sysnum, x1)				\
X				((buf)->m_pid = htons(u.u_procp->p_pid),\
X				 (buf)->m_uid = htons(u.u_uid),		\
X				 (buf)->m_syscall = htons(sysnum),	\
X				 (buf)->m_args[0] = htonl(x1),		\
X				 (R_MINRMSG + sizeof(long)))
X#define introduce_2extra(buf, sysnum, x1, x2)				\
X				((buf)->m_pid = htons(u.u_procp->p_pid),\
X				 (buf)->m_uid = htons(u.u_uid),		\
X				 (buf)->m_syscall = htons(sysnum),	\
X				 (buf)->m_args[0] = htonl(x1),		\
X				 (buf)->m_args[1] = htonl(x2),		\
X				 (R_MINRMSG + 2*sizeof(long)))
X/*
X * This macro defines whether a host is being used or not.
X * The rmtclearhosts() and rmtcopyhosts() are for expansion if someone
X * wants to use more than 32 hosts.
X */
X#define	rmthostused(rsys)		(u.u_rmtsys  &  (1<<rsys))
X#define	rmtusehost(rsys)		(u.u_rmtsys  |= (1<<rsys))
X#define	rmtunusehost(rsys)		(u.u_rmtsys  &= ~(1<<rsys))
X#define	rmtclearhosts()			(u.u_rmtsys   =  0)
X#define	rmtcopyhosts(dest,hosts)	(dest         =  hosts)
X
X#ifdef pyr
X/*
X * Pyramid changed the name on ctob and btoc
X **/
X#define	ctob(x)	ptob(x)
X#define	btoc(x)	btop(x)
X#endif
SHAREOF
chmod 444 remote/usr.sys.remote/remotefs.h
#
# remote/usr.sys.remote/rmt_data_template
#
if [ -f remote/usr.sys.remote/rmt_data_template ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.remote/rmt_data_template or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.remote/rmt_data_template 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.remote/rmt_data_template
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 * $Header: rmt_data_template,v 2.0 85/12/07 18:19:42 toddb Rel $
X *
X * $Log:	rmt_data_template,v $
X * Revision 2.0  85/12/07  18:19:42  toddb
X * First public release.
X * 
X */
X#include	"../h/errno.h"
X#include	"../h/param.h"
X#include	"../h/mbuf.h"
X#include	"../h/socket.h"
X#include	"../remote/remotefs.h"
X
X
Xextern int
X		rmt_access(),
X		rmt_chdir(),
X		rmt_chmod(),
X		rmt_chown(),
X		rmt_dup(),
X		rmt_dup2(),
X		rmt_error(),
X		remote_exit(),
X		rmt_fcntl(),
X		rmt_flock(),
X		remote_fork(),
X		rmt_fsync(),
X		rmt_ioctl(),
X		rmt_lseek(),
X		rmt_mknod(),
X		rmt_noop(),
X		rmt_onearg(),
X		rmt_open(),
X		rmt_readlink(),
X		rmt_stat(),
X		rmt_truncate(),
X		rmt_utimes(),
X		rmt_execinfo(),
X		rmt_execread(),
X		rmt_execve(),
X		remote_fd(),
X		remote_path1(),
X		remote_path2(),
X		rmt_datafin();
X
X/*
X * This table depends on the order of system calls as defined in
X * sys/sys/init_sysent.c, and our local map in remote_sysmap, which
X * is generated (and appended to this file) by the program mkdata.
X * The latter is a table of indices into remote_syscall[].
X * Remote_syscall[] is a table containing general and specific actions
X * for each system call, whether to follow symbolic links in namei and
X * flags that are passed to rmt_msgfin() and rmt_datafin().
X */
X
Xsyscalls	remote_syscall[] = {
X/*
X * general	specific    flags to	follow	call before
X *			  rmt_fin()   symlinks	real syscall
X */
X{ remote_fork,	rmt_noop,    RFLG_INFO,	FALSE,	TRUE	}, /* RSYS_fork */
X{ remote_fd,	rmt_datafin,  RFLG_RD,	FALSE,	TRUE	}, /* RSYS_read */
X{ remote_fd,	rmt_datafin,  RFLG_WR,	FALSE,	TRUE	}, /* RSYS_write */
X{ remote_path1,	rmt_open,	0,	TRUE,	FALSE	}, /* RSYS_open */
X{ remote_fd,	rmt_onearg,  RFLG_INFO,	FALSE,	TRUE	}, /* RSYS_close */
X{ remote_path1,	rmt_open,	0,	TRUE,	FALSE	}, /* RSYS_creat */
X{ remote_path2,	rmt_noop,	0,	FALSE,	FALSE	}, /* RSYS_link */
X{ remote_path1,	rmt_onearg,	0,	FALSE,	FALSE	}, /* RSYS_unlink */
X{ remote_path1,	rmt_chdir,	0,	TRUE,	FALSE	}, /* RSYS_chdir */
X{ remote_path1,	rmt_mknod,	0,	FALSE,	FALSE	}, /* RSYS_mknod */
X{ remote_path1,	rmt_chmod,	0,	TRUE,	FALSE	}, /* RSYS_chmod */
X{ remote_path1,	rmt_chown,	0,	FALSE,	FALSE	}, /* RSYS_chown */
X{ remote_path1,	rmt_stat,	0,	TRUE,	FALSE	}, /* RSYS_stat */
X{ remote_fd,	rmt_lseek,	0,	FALSE,	TRUE	}, /* RSYS_lseek */
X{ remote_path1,	rmt_access,	0,	FALSE,	FALSE	}, /* RSYS_lstat */
X{ remote_path1,	rmt_stat,	0,	TRUE,	FALSE	}, /* RSYS_access */
X{ remote_fd,	rmt_dup,	0,	FALSE,	TRUE	}, /* RSYS_dup */
X{ remote_fd,	rmt_ioctl,	0,	FALSE,	TRUE	}, /* RSYS_ioctl */
X{ remote_path2,	rmt_noop,	0,	TRUE,	FALSE	}, /* RSYS_symlink */
X{ remote_path1,	rmt_readlink,  RFLG_RD,	FALSE,	FALSE	}, /* RSYS_readlink */
X{ remote_fd,	rmt_stat,	0,	FALSE,	TRUE	}, /* RSYS_fstat */
X{ remote_fd,	rmt_dup2,	0,	FALSE,	TRUE	}, /* RSYS_dup2 */
X{ remote_fd,	rmt_fcntl,	0,	FALSE,	TRUE	}, /* RSYS_fcntl */
X{ remote_fd,	rmt_onearg,  RFLG_INFO,	FALSE,	TRUE	}, /* RSYS_fsync */
X{ remote_fd,	rmt_datafin, RFLG_RD|RFLG_DATAV,
X					FALSE,	TRUE	},/* RSYS_readv */
X{ remote_fd,	rmt_datafin, RFLG_WR|RFLG_DATAV,
X					FALSE,	TRUE	},/* RSYS_writev */
X{ remote_fd,	rmt_chown,	0,	FALSE,	TRUE	}, /* RSYS_fchown */
X{ remote_fd,	rmt_chmod,	0,	FALSE,	TRUE	}, /* RSYS_fchmod */
X{ remote_path2,	rmt_noop,	0,	TRUE,	FALSE	}, /* RSYS_rename */
X{ remote_path1,	rmt_truncate,	0,	TRUE,	FALSE	}, /* RSYS_truncate */
X{ remote_fd,	rmt_truncate,	0,	FALSE,	TRUE	}, /* RSYS_ftruncate */
X{ remote_fd,	rmt_flock,	0,	FALSE,	TRUE	}, /* RSYS_flock */
X{ remote_path1,	rmt_mknod,	0,	FALSE,	FALSE	}, /* RSYS_mkdir */
X{ remote_path1,	rmt_onearg,	0,	FALSE,	FALSE	}, /* RSYS_rmdir */
X{ remote_path1,	rmt_noop,	0,	TRUE,	FALSE	}, /* RSYS_utimes */
X{ remote_exit,	rmt_noop,      RFLG_INFO,FALSE,	TRUE	}, /* RSYS_exit */
X{ remote_fork,	rmt_noop,    RFLG_INFO,	FALSE,	TRUE	}, /* RSYS_vfork */
X{ remote_path1,	rmt_execinfo,	0,	TRUE,	FALSE	}, /* RSYS_execinfo */
X{ rmt_error,	rmt_noop,	0,	FALSE,	FALSE	}, /* RSYS_execread */
X{ remote_path1,	rmt_error,	0,	TRUE,	FALSE	}, /* RSYS_execve */
X{ rmt_error,	rmt_noop,	0,	FALSE,	FALSE	}, /* RSYS_nosys */
X{ rmt_error,	rmt_noop,	0,	FALSE,	FALSE	}, /* RSYS_qlseek */
X};
X
Xstruct remoteinfo	remote_info[ R_MAXSYS ];
Xstruct remoteinfo	*remote_generic;
Xlong			remote_debug;
Xlong			remote_sysindex;
Xlong			remote_maxchunk = (1024*10);
Xstruct mbuf		*remote_path;
Xstruct nameserver	remote_ns;
X
X/*
X * The following list maps all of the actual system call numbers into our
X * idea of the system call numbers.  THIS IS GENERATED AUTOMATICALLY...
X * DO NOT MODIFY!
X */
SHAREOF
chmod 444 remote/usr.sys.remote/rmt_data_template
#
# remote/usr.sys.remote/rmt_exec.c
#
if [ -f remote/usr.sys.remote/rmt_exec.c ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.remote/rmt_exec.c or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.remote/rmt_exec.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.remote/rmt_exec.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 * $Header: rmt_exec.c,v 2.1 85/12/30 16:45:30 toddb Exp $
X *
X * $Log:	rmt_exec.c,v $
X * Revision 2.1  85/12/30  16:45:30  toddb
X * fixed syntax error for 4.3.
X * 
X * Revision 2.0  85/12/07  18:17:54  toddb
X * First public release.
X * 
X */
X#ifndef pyr /* Pyramid */
X#include	"../machine/reg.h"
X#include	"../machine/pte.h"
X#include	"../machine/psl.h"
X#endif
X
X#include	"../h/param.h"
X#include	"../h/systm.h"
X#include	"../h/map.h"
X#include	"../h/dir.h"
X#include	"../h/user.h"
X#include	"../h/kernel.h"
X#include	"../h/proc.h"
X#include	"../h/file.h"
X#include	"../h/uio.h"
X#include	"../remote/remotefs.h"
X#include	"../h/mbuf.h"
X#include	"../netinet/in.h"
X#include	"../h/vm.h"
X#include	"../h/errno.h"
X#ifdef BSD4_3
X#include	"../h/namei.h"
X#include	"../h/exec.h"
X#else BSD4_3
X#include	"../h/nami.h"
X#endif BSD4_3
X
X#ifdef vax
X#include "../vax/mtpr.h"
X#endif
X
Xextern struct remoteinfo	remote_info[];
Xextern long			remote_sysindex;
Xextern long			remote_maxchunk;
X
X#ifdef magnolia
X#define	DEMAND_PAGED	0513
X#define	SHARED_TEXT	0510
X#else magnolia
X#define	DEMAND_PAGED	0413
X#define	SHARED_TEXT	0410
X#endif magnolia
X
X/*
X * Get execution info for a file that is on a remote system.  At this point
X * we know that the file is remote.  We must send one request to get the
X * header and then if all is ok, we will be asked for the file to be sent over
X * en-masse.
X */
X#ifdef BSD4_3
Xremote_execinfo(ip, auid, agid, pexdata, fname)
X	struct exec	*pexdata;
X#else BSD4_3
Xremote_execinfo(ip, auid, agid, fname)
X#endif BSD4_3
X	register struct inode	**ip;
X	long	*auid, *agid;
X	register char	*fname;
X{
X	long	error,
X		sysindex = remote_sysindex,
X		uid, gid,
X		hdrsize,
X		execsize;
X	struct inode	*namei();
X	struct remoteinfo	*rp = remote_info + remote_sysindex;
X	struct message	*msg;
X
X	u.u_error = 0;
X	error = remote_path1(RSYS_execinfo);
X	if (error) {
X		/*
X		 * Try again if its a local file.
X		 */
X		if (error < 0 && fname) {
X#ifdef BSD4_3
X			struct nameidata *ndp = &u.u_nd;
X
X			ndp->ni_dirp = (caddr_t) fname;
X			if ((*ip = namei(ndp)) == NULL)
X#else BSD4_3
X			u.u_dirp = (caddr_t) fname;
X			if ((*ip = namei(uchar, LOOKUP, 1)) == NULL)
X#endif BSD4_3
X				if (u.u_error == 0 || u.u_error == EISREMOTE)
X					u.u_error = ELOOP;
X			return(remote_sysindex);
X		}
X		else if (error < 0)
X			error = ENOENT;
X		u.u_error = error;
X		return(-1);
X	}
X	/*
X	 * The R_RETVAL cell contains the total size of the file.  So that
X	 * had better be >= the size of the header + size of text + size
X	 * of data.
X	 */
X	msg = &rp->r_msg;
X#ifdef BSD4_3
X	bcopy(msg->m_args+R_EXECDATA,
X		(caddr_t)pexdata, sizeof(struct exec));
X	if (pexdata->a_magic == DEMAND_PAGED)
X		hdrsize = CLBYTES;
X	else
X		hdrsize = sizeof(sizeof(struct exec));
X#else BSD4_3
X	bcopy(msg->m_args+R_EXECDATA,
X		(caddr_t)&u.u_exdata, sizeof (u.u_exdata));
X	if (u.u_exdata.ux_mag == DEMAND_PAGED)
X		hdrsize = CLBYTES;
X	else
X		hdrsize = sizeof(u.u_exdata.Ux_A);
X#endif BSD4_3
X
X	execsize = ntohl(msg->m_args[ R_RETVAL ]);
X	debug0("obj=%d,hrd=%d,error=%d,tx=%d,dat=%d\n",
X		execsize, hdrsize, u.u_error,
X#ifdef BSD4_3
X		pexdata->a_text, pexdata->a_text
X#else BSD4_3
X		u.u_exdata.ux_tsize, u.u_exdata.ux_dsize
X#endif BSD4_3
X		);
X
X#ifdef BSD4_3
X	if (pexdata->a_text + pexdata->a_data + hdrsize > execsize
X	 && *((char *)pexdata) != '#') {
X		error = ENOEXEC;
X		goto bad;
X	}
X#else BSD4_3
X	if (u.u_exdata.ux_tsize + u.u_exdata.ux_dsize + hdrsize > execsize
X	 && u.u_exdata.ux_shell[0] != '#') {
X		error = ENOEXEC;
X		goto bad;
X	}
X#endif BSD4_3
X
X	if ((u.u_procp->p_flag&STRC) && msg->m_args[ R_EXECREADONLY ]) {
X		error = EACCES;
X		goto bad;
X	}
X	if (auid) { /* first time thru for this exec... set uid/gid stuff */
X		uid = ntohl(msg->m_args[ R_EXECUID ]);
X		if (uid < 0)
X			uid = u.u_uid;
X		gid = ntohl(msg->m_args[ R_EXECGID ]);
X		if (gid < 0)
X			gid = u.u_gid;
X		*auid = uid;
X		*agid = gid;
X	}
X	return(sysindex);
X
Xbad:
X	u.u_error = error;
X	return(-1);
X}
X
X/*
X * This is the simple routine that is called by remote_path1 as the
X * specific routine for handling RSYS_execinfo.  remote_execinfo() is
X * called from exec, and remote_execinfo() calls remote_path1() who in
X * turn calls rmt_execinfo().
X */
Xrmt_execinfo(sysindex, m)
X	long	sysindex;
X	struct mbuf	*m;
X{
X	struct message *msg = mtod(m, struct message *);
X#ifdef BSD4_3
X	msg->m_args[0] = htonl(sizeof (struct exec));
X#else BSD4_3
X	msg->m_args[0] = htonl(sizeof (u.u_exdata));
X#endif BSD4_3
X	return (rmt_msgfin(sysindex, m, 0));
X}
X
X/*
X * Read into memory an executable file from a remote system.
X */
X#ifdef BSD4_3
Xremote_execread(sysindex, oldtextsize, ep)
X	register struct exec *ep;
X	register int	sysindex, oldtextsize;
X#else BSD4_3
Xremote_execread(sysindex, oldtextsize)
X	register int	sysindex, oldtextsize;
X#endif BSD4_3
X{
X	struct remoteinfo	*rp = remote_info + sysindex;
X	struct uio auio;
X	struct iovec aiov[2];
X	struct mbuf	*m;
X	struct message	*msg;
X	register long	hdrsize, datasize, textsize, error, len, magic;
X	register struct proc	*p = u.u_procp;
X	long	iovlen;
X
X#ifdef BSD4_3
X	datasize = (int)ep->a_data;
X	magic = ep->a_magic;
X#define HEADERSIZE	sizeof(struct exec);
X#else BSD4_3
X	datasize = (int)u.u_exdata.ux_dsize;
X	magic = u.u_exdata.ux_mag;
X#define HEADERSIZE	sizeof(u.u_exdata.Ux_A);
X#endif BSD4_3
X	if (datasize <= 0) {
X		u.u_error = ENOEXEC;
X		return(-1);
X	}
X
X	/*
X	 * We are guarenteed that at this point the text size is zero.
X	 * But we know what the old text size was passed along for the sake of
X	 * shared-text programs:  the binaries for these do not
X	 * necessarily have the data page-aligned in the file (as we
X	 * assume that demand-paged programs do), but instead,
X	 * it is aligned when it is read in.  We must do the same here.
X	 */
X	if (oldtextsize && magic == SHARED_TEXT) {
X		aiov[0].iov_len = oldtextsize;
X		aiov[1].iov_len = datasize - oldtextsize;
X		iovlen = 2;
X		aiov[0].iov_base = (char *)ctob(tptov(p, 0));
X		aiov[1].iov_base = (char *)ctob(btoc(oldtextsize));
X		debug0("execrd: %d @ %x, %d @ %x ",
X			aiov[0].iov_len, aiov[0].iov_base,
X			aiov[1].iov_len, aiov[1].iov_base);
X	}
X	else {
X		iovlen = 1;
X		aiov[0].iov_base = (char *)ctob(dptov(p, 0)),
X		aiov[0].iov_len = datasize;
X		debug0("execrd: %d @ %x ", aiov[0].iov_len, aiov[0].iov_base);
X	}
X	auio.uio_offset = 0;
X	auio.uio_segflg = 0;
X	if (magic == DEMAND_PAGED)
X		hdrsize = CLBYTES;
X	else
X		hdrsize = HEADERSIZE;
X
X	/*
X	 * Now ask for it in remote_maxchunk size chunks.
X	 */
X	debug0("hdsz=%d, datasz=%d, rd ", hdrsize, datasize);
X	error = 0;
X	while (datasize >= 0) {
X		auio.uio_resid = MIN(datasize, remote_maxchunk);
X		if (auio.uio_resid == 0)
X			datasize = -1;
X		else {
X			if (aiov[0].iov_len <= 0 && iovlen == 2) {
X				aiov[0] = aiov[1];
X				iovlen = 1;
X			}
X			auio.uio_iov = aiov;
X			auio.uio_iovcnt = iovlen;
X			datasize -= auio.uio_resid;
X		}
X		MGET(m, M_WAIT, MT_DATA);
X		if (m == NULL)
X			return(ENOBUFS);
X		msg = mtod(m, struct message *);
X		len = introduce_2extra(msg, RSYS_execread, hdrsize,
X			auio.uio_resid);
X		m->m_len = len;
X		msg->m_hdlen = htons(len);
X		msg->m_totlen = htonl(len);
X#ifdef RFSDEBUG
X		if (auio.uio_resid) {
X			debug0("\n %d: %d@%d", auio.uio_resid,
X				aiov[0].iov_len, aiov[0].iov_base);
X			if (iovlen == 2)
X				debug0(",%d@%d.",
X					aiov[1].iov_len, aiov[1].iov_base);
X		}
X		rmt_showmsg(msg, FALSE);
X#endif RFSDEBUG
X		if (datasize >= 0)
X			error = remoteio(sysindex, &m, &auio, RFLG_RD);
X		else
X			remoteio(sysindex, &m, 0, RFLG_INFO);
X#ifdef RFSDEBUG
X		msg = &rp->r_msg;
X		rmt_showmsg(msg, TRUE);
X#endif RFSDEBUG
X		/*
X		 * If there are any errors, simply send the last
X		 * message: we're all done.
X		 */
X		if (error && datasize >= 0)
X			datasize = 0;
X		else if (error)
X			return(error);
X	}
X
X	debug0("\n");
X	return ( error );
X}
SHAREOF
chmod 444 remote/usr.sys.remote/rmt_exec.c
#
# remote/usr.sys.remote/rmt_final.c
#
if [ -f remote/usr.sys.remote/rmt_final.c ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.remote/rmt_final.c or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.remote/rmt_final.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.remote/rmt_final.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 * $Header: rmt_final.c,v 2.1 85/12/30 16:51:01 toddb Exp $
X *
X * $Log:	rmt_final.c,v $
X * Revision 2.1  85/12/30  16:51:01  toddb
X * Made rmt_copypath() compatible between 4.2 and 4.3 by adding a c-version
X * of copystr() and copyinstr() for 4.2 versions (copystr() and copyinstr()
X * are assembler routines in 4.3).
X * 
X * Revision 2.0  85/12/07  18:20:12  toddb
X * First public release.
X * 
X */
X#include	"../h/param.h"
X#ifndef pyr /* Pyramid */
X#include	"../machine/pte.h"
X#endif
X#include	"../h/systm.h"
X#include	"../h/map.h"
X#include	"../h/dir.h"
X#include	"../h/user.h"
X#include	"../h/kernel.h"
X#include	"../h/proc.h"
X#include	"../h/mbuf.h"
X#include	"../h/socket.h"
X#include	"../h/file.h"
X#include	"../remote/remotefs.h"
X#include	"../h/errno.h"
X#include	"../netinet/in.h"
X#include	"../h/uio.h"
X
Xextern struct remoteinfo	remote_info[];
X
X/*
X * rmt_msgfin() finalizes the message by adding in the header and total
X * lengths and sending the message.  It returns the return value found in the
X * reply.
X */
Xrmt_msgfin(sysindex, m, flags)
X	long	sysindex, flags;
X	struct mbuf	*m;
X{
X	long	error, len;
X	struct message	*msg = mtod(m, struct message *);
X	struct remoteinfo	*rp = remote_info + sysindex;
X
X	/*
X	 * If the length has been set (by remote_path[12]), then don't
X	 * meddle, otherwise assign it.
X	 */
X	if (msg->m_hdlen == 0)
X		len = m->m_len;
X	else
X		len = msg->m_hdlen;
X	msg->m_hdlen = htons(len);
X	msg->m_totlen = htonl(len);
X		
X	rmt_showmsg(msg, FALSE);
X	error = remoteio(sysindex, &m, 0, flags);
X
X	if (! error) {
X		if ((flags & RFLG_INFO) == 0) {
X			msg = &rp->r_msg;
X			rmt_showmsg(msg, TRUE);
X			if ((error = msg->m_errno) == 0)
X				u.u_r.r_val1 = msg->m_args[R_RETVAL];
X		}
X		else
X			u.u_r.r_val1 = 0;
X	}
X	return ( error );
X}
X
X/*
X * rmt_datafin() finalizes a message and fixes up the header and total
X * lengths (like rmt_msgfin()) and sends a message plus data.  It returns
X * the return value found in the reply.
X */
Xrmt_datafin(sysindex, m, flags)
X	long	sysindex, flags;
X	struct mbuf	*m;
X{
X	register long	i, error, len;
X	struct message	*msg = mtod(m, struct message *);
X	short	syscall = ntohs(msg->m_syscall);
X	struct remoteinfo	*rp = remote_info + sysindex;
X	struct uio auio, *uio;
X	struct iovec aiov[16], *iov = aiov;
X	struct a {
X		long	fd;
X		char	*databuf;
X		long	datalen;
X	} *uap = (struct a *)u.u_ap;
X
X	/*
X	 * Package up the data.
X	 * If the length has been set (by remote_path1 for readlink),
X	 * then don't meddle, otherwise assign it the length of the first
X	 * (and only) mbuf.
X	 */
X	if (msg->m_hdlen == 0)
X		msg->m_hdlen = htons(len = m->m_len);
X	else
X		msg->m_hdlen = htons(len = msg->m_hdlen);
X	if (flags & (RFLG_RD | RFLG_WR)) {
X		uio = &auio;
X		uio->uio_iov = iov;
X		uio->uio_segflg = 0;
X		uio->uio_offset = 0;
X		if (flags & RFLG_DATAV) {
X			uio->uio_iovcnt = uap->datalen;
X			error = copyin((caddr_t)uap->databuf, (caddr_t)iov,
X			    (unsigned)(uap->datalen * sizeof (struct iovec)));
X			if (error)
X				goto done;
X			uio->uio_resid = 0;
X			for (i = 0; i < uio->uio_iovcnt; i++) {
X				if (iov->iov_len < 0) {
X					error = EINVAL;
X					goto done;
X				}
X				uio->uio_resid += iov->iov_len;
X				iov++;
X			}
X		}
X		else {
X			iov->iov_base = uap->databuf;
X			iov->iov_len = uio->uio_resid = uap->datalen;
X			uio->uio_iovcnt = 1;
X		}
X		if (uio->uio_resid < 0) {
X			error = EINVAL;
X			goto done;
X		}
X		if (flags & RFLG_WR)
X			msg->m_totlen = htonl(len + uio->uio_resid);
X		else
X			msg->m_totlen = htonl(len);
X	}
X	else {
X		uio = NULL;
X		msg->m_totlen = htonl(len);
X	}
X	rmt_showmsg(msg, FALSE);
X	error = remoteio(sysindex, &m, uio, flags);
X	m = NULL;
X	if (error)
X		goto done;
X
X	msg = &rp->r_msg;
X	rmt_showmsg(msg, TRUE);
X	if ((error = msg->m_errno) == 0)
X		u.u_r.r_val1 = msg->m_args[R_RETVAL];
Xdone:
X	if (m)
X		m_free(m);
X	return ( error );
X}
X
X/*
X * Copy a path into a string of mbufs.  The source pointer may be in user
X * space, in which case we must use uchar() to copy.  Note that this routine
X * expects 'm' to point to the first mbuf in the current chain:  it will
X * append to the end of the chain, and update the length of the message
X * in msg->m_hdlen.
X */
Xrmt_copypath(psrc, m, copy_from_user)
X	register char	*psrc;
X	register struct mbuf	*m;
X{
X	register char	*pdest;
X	register int	error,
X			totlen,
X			room;
X	register struct mbuf	*m2;
X	struct message	*msg = mtod(m, struct message *);
X	int		copystr(),
X			copyinstr(),
X			got;
X	func		copier = copy_from_user ? copyinstr : copystr;
X
X	/*
X	 * find the end of the mbuf chain.
X	 */
X	while (m->m_next)
X		m = m->m_next;
X	m2 = m;
X	pdest = mtod(m, char *) + m->m_len;
X	totlen = msg->m_hdlen;
X
X	debug2("copy %s path @%x-->%x, len=%d\n",
X		copy_from_user ? "user" : "kernel", psrc, pdest, totlen);
X
X	room = MLEN - m->m_len;
X	for(;;) {
X		got = 0;	/* copy*str adds copied bytes to 'got' */
X		error = (*copier)(psrc, pdest, room, (u_int *)&got);
X		if (error && error != ENOENT)
X			return(error);
X		m2->m_len += got;
X		totlen += got;
X		if (got < room)
X			break;
X		MGET(m, M_WAIT, MT_DATA);
X		if (m == NULL)
X			return(ENOBUFS);
X		m2 = m2->m_next = m;
X		m2->m_len = 0;
X		room = MLEN;
X		pdest = mtod(m2, char *);
X		psrc += got;
X	}
X	msg->m_hdlen = totlen;
X	debug2("len now=%d\n", totlen);
X
X	return(0);
X}
X
X#ifdef BSD4_3
X#else BSD4_3
X/*
X * C version of copyinstr() from 4.3.
X */
Xcopyinstr(src, dest, maxlength, lencopied)
X	register char	*src, *dest;
X	register int	maxlength;
X	register int	*lencopied;
X{
X	register int	c;
X	int		dummy;
X
X	if (!maxlength)
X		return(EFAULT);
X	if (lencopied == NULL)
X		lencopied = &dummy;
X	for(;;) {
X		c = *dest++ = fubyte(src++);
X		if (c == -1) {
X			*(dest-1) = 0;
X			return(EFAULT);
X		}
X		if (--maxlength < 0)
X			return(ENOENT);
X		(*lencopied)++;
X		if (c == 0)
X			return(0);
X	}
X}
X
X/*
X * C version of copystr() from 4.3.
X */
Xcopystr(src, dest, maxlength, lencopied)
X	register char	*src, *dest;
X	register int	maxlength;
X	register int	*lencopied;
X{
X	int		dummy;
X
X	if (!maxlength)
X		return(EFAULT);
X	if (lencopied == NULL)
X		lencopied = &dummy;
X	for(;;) {
X		if (--maxlength < 0)
X			return(ENOENT);
X		(*lencopied)++;
X		if ((*dest++ = *src++) == 0)
X			return(0);
X	}
X}
X#endif BSD4_3
X
X#ifdef RFSDEBUG
X
Xrmt_debug(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9)
X{
X	printf(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);
X}
X
Xrmt_showmsg(msg, fromserver)
X	struct message	*msg;
X	int	fromserver;
X{
X	long	end, len, pid, uid, totlen;
X
X	if ((remote_debug & 0x18000) == 0)
X		return;
X	if (fromserver)
X		len = msg->m_hdlen,
X		totlen = msg->m_totlen,
X		pid = msg->m_pid,
X		uid = msg->m_uid;
X	else
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	debug15("%s srvr: 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		debug15(",err=%d,ret=%d",
X			msg->m_errno,
X			msg->m_args[ R_RETVAL ]);
X		end = R_RETVAL+1;
X	}
X	else
X	{
X		debug15(",syscall=%d", htons(msg->m_syscall));
X		end = 0;
X	}
X	for (; end<len; end++)
X		debug16(",0x%x", ntohl(msg->m_args[ end ]));
X	rmt_debug("\n");
X}
X#endif RFSDEBUG
SHAREOF
chmod 444 remote/usr.sys.remote/rmt_final.c
#
# remote/usr.sys.remote/rmt_syscall3.c
#
if [ -f remote/usr.sys.remote/rmt_syscall3.c ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.remote/rmt_syscall3.c or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.remote/rmt_syscall3.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.remote/rmt_syscall3.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 * $Header: rmt_syscall3.c,v 2.0 85/12/07 18:19:35 toddb Rel $
X *
X * $Log:	rmt_syscall3.c,v $
X * Revision 2.0  85/12/07  18:19:35  toddb
X * First public release.
X * 
X */
X#include	"../h/param.h"
X#ifndef pyr	/* Pyramid */
X#include	"../machine/pte.h"
X#endif
X#include	"../h/systm.h"
X#include	"../h/map.h"
X#include	"../h/dir.h"
X#include	"../h/user.h"
X#include	"../h/kernel.h"
X#include	"../h/proc.h"
X#include	"../h/inode.h"
X#include	"../h/mbuf.h"
X#include	"../h/socket.h"
X#include	"../remote/remotefs.h"
X#include	"../h/file.h"
X#include	"../h/stat.h"
X#include	"../h/errno.h"
X#include	"../netinet/in.h"
X
Xextern long	rmtrw(), rmtioctl(), rmtselect(), rmtclose();
Xstruct 	fileops remoteops =
X	{ rmtrw, rmtioctl, rmtselect, rmtclose };
Xrmtrw()	{ return(0); }
Xrmtioctl()	{ return(0); }
Xrmtselect()	{ return(0); }
Xrmtclose()	{ return(0); }
X
Xextern struct remoteinfo	remote_info[];
Xextern struct remoteinfo	*remote_generic;
X
X/*
X * Remote open()
X */
Xrmt_open (sysindex, m)
X	long	sysindex;
X	struct mbuf	*m;
X{
X	register long	fd, error;
X	register struct message *msg = mtod(m, struct message *);
X	register struct file	*fp;
X	struct file		*falloc();
X	register struct a {
X		char	*path;
X		long	flags,
X			mode;
X	} *uap = (struct a *)u.u_ap;
X
X	/*
X	 * Initialize the file structure.
X	 */
X	if ((fp = falloc()) == NULL)
X		return(-1);
X	fp->f_type = DTYPE_REMOTE;
X	fp->f_ops = &remoteops;
X	fd = u.u_r.r_val1;
X	fp->f_data = (caddr_t)sysindex;
X	fp->f_flag = (uap->mode&FMASK) | FREMOTE;
X	remote_info[ sysindex ].r_nfile++;
X
X	if (ntohs(msg->m_syscall) == RSYS_creat) {
X		uap->mode = uap->flags;
X		uap->flags = FWRITE|FCREAT|FTRUNC;
X		msg->m_syscall = htons(RSYS_open);
X	}
X	msg->m_args[ 0 ] = htonl(uap->flags);
X	msg->m_args[ 1 ] = htonl(uap->mode);
X	msg->m_args[ 2 ] = htonl(fd);
X	msg->m_args[ 3 ] = htonl(u.u_cmask);
X
X	/*
X	 * Now send it.
X	 */
X	error = rmt_msgfin(sysindex, m, 0);
X	if (error)
X		rmt_deallocfd(fd);
X	else {
X		msg = &remote_info[ sysindex ].r_msg;
X		fp->f_offset = msg->m_args[1];
X	}
X	return(error);
X}
X
X/*
X * Remote readlink()
X */
Xrmt_readlink (sysindex, m)
X	long	sysindex;
X	struct mbuf	*m;
X{
X	struct message	*msg = mtod(m, struct message *);
X	struct a {
X		char	*path;
X		char	*buf;
X		long	len;
X	} *uap = (struct a *)u.u_ap;
X
X
X	msg->m_args[ 0 ] = htonl(uap->len);
X	/*
X	 * Now send it.
X	 */
X	return( rmt_datafin(sysindex, m, RFLG_RD) );
X}
X
X/*
X * Remote stat() and lstat() and fstat()
X */
Xrmt_stat (sysindex, m)
X	long	sysindex;
X	struct mbuf	*m;
X{
X	long	error, i;
X	struct message *msg = mtod(m, struct message *);
X	struct remoteinfo *rp = remote_info + sysindex;
X	struct a {
X		long	fd_or_path;
X		struct stat	*statp;
X	} *uap = (struct a *)u.u_ap;
X	struct stat	st;
X
X	if (ntohl(msg->m_syscall) == RSYS_fstat)
X		m->m_len = R_MINRMSG + sizeof(long);
X	if (error = rmt_msgfin(sysindex, m, 0))
X		return( error );
X	msg = &rp->r_msg;
X	i = R_RETVAL + 1;
X	st.st_dev	  = ntohl(msg->m_args[ i++ ]);
X	st.st_ino	  = ntohl(msg->m_args[ i++ ]);
X	st.st_mode	  = ntohl(msg->m_args[ i++ ]);
X	st.st_nlink	  = ntohl(msg->m_args[ i++ ]);
X	st.st_uid	  = ntohl(msg->m_args[ i++ ]);
X	st.st_gid	  = ntohl(msg->m_args[ i++ ]);
X	st.st_rdev	  = ntohl(msg->m_args[ i++ ]);
X	st.st_size	  = ntohl(msg->m_args[ i++ ]);
X	st.st_atime	  = ntohl(msg->m_args[ i++ ]);
X	st.st_mtime	  = ntohl(msg->m_args[ i++ ]);
X	st.st_ctime	  = ntohl(msg->m_args[ i++ ]);
X	st.st_blksize	  = ntohl(msg->m_args[ i++ ]);
X	st.st_blocks 	  = ntohl(msg->m_args[ i++ ]);
X	st.st_spare1 = sysindex+1;
X	st.st_spare2 = 0;
X	st.st_spare3 = 0;
X	st.st_spare4[0] = st.st_spare4[1] = 0;
X	if (msg->m_args[ i ]) { /* this is the remote root */
X		if (rp->r_mntpt == NULL)
X			rp = remote_generic;
X		if (rp && rp->r_mntpt != NULL) {
X			st.st_dev = rp->r_mntpt->i_dev;
X			st.st_ino = rp->r_mntpt->i_number;
X		}
X	}
X	(void)copyout((caddr_t)&st, (caddr_t)uap->statp, sizeof(struct stat));
X	return(0);
X}
X
X/*
X * Remote truncate() and ftrucate()
X */
Xrmt_truncate (sysindex, m)
X	long	sysindex;
X	struct mbuf	*m;
X{
X	long	i = 0;
X	struct message *msg = mtod(m, struct message *);
X	struct a {
X		long	fd_or_path;
X		long	len;
X	} *uap = (struct a *)u.u_ap;
X
X	if (htons(msg->m_syscall) == RSYS_ftruncate)
X		i++;
X	msg->m_args[ i ] = htonl(uap->len);
X	/*
X	 * Now send it.
X	 */
X	return( rmt_msgfin(sysindex, m, 0) );
X}
X
X/*
X * Remote utimes()
X */
Xrmt_utimes (sysindex, m)
X	long	sysindex;
X	struct mbuf	*m;
X{
X	struct message	*msg = mtod(m, struct message *);
X	struct a {
X		char	*path;
X		struct timeval	*timevalp;
X	} *uap = (struct a *)u.u_ap;
X	struct timeval	*tv = uap->timevalp;
X
X	msg->m_args[ 0 ] = htonl(tv[0].tv_sec);
X	msg->m_args[ 1 ] = htonl(tv[0].tv_usec);
X	msg->m_args[ 2 ] = htonl(tv[1].tv_sec);
X	msg->m_args[ 3 ] = htonl(tv[1].tv_usec);
X
X	/*
X	 * Now send it.
X	 */
X	return( rmt_msgfin(sysindex, m, 0) );
X}
SHAREOF
chmod 444 remote/usr.sys.remote/rmt_syscall3.c

sources-request@panda.UUCP (01/09/86)

Mod.sources:  Volume 3, Issue 83
Submitted by: tektronix!tekcrl!toddb

#!/bin/sh
#
# RFS, a kernel-resident remote file system.  Shar 7 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/usr.sys.remote/rmt_general.c
#	remote/usr.sys.remote/rmt_generic.c
#	remote/usr.sys.remote/rmt_io.c
#	remote/usr.sys.remote/rmt_subr.c
#	remote/usr.sys.remote/rmt_syscall1.c
#	remote/usr.sys.remote/rmt_syscall2.c
#
# remote/usr.sys.remote/rmt_general.c
#
if [ -f remote/usr.sys.remote/rmt_general.c ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.remote/rmt_general.c or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.remote/rmt_general.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.remote/rmt_general.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 * $Header: rmt_general.c,v 2.0 85/12/07 18:18:06 toddb Rel $
X *
X * $Log:	rmt_general.c,v $
X * Revision 2.0  85/12/07  18:18:06  toddb
X * First public release.
X * 
X */
X#include	"../h/param.h"
X#ifndef pyr	/* Pyramid */
X#include	"../machine/pte.h"
X#endif
X#include	"../h/systm.h"
X#include	"../h/map.h"
X#include	"../h/dir.h"
X#include	"../h/user.h"
X#include	"../h/kernel.h"
X#include	"../h/proc.h"
X#ifdef BSD4_3
X#include	"../h/namei.h"
X#else BSD4_3
X#include	"../h/nami.h"
X#endif BSD4_3
X#include	"../h/inode.h"
X#include	"../h/mbuf.h"
X#include	"../h/socket.h"
X#include	"../remote/remotefs.h"
X#include	"../h/errno.h"
X#include	"../netinet/in.h"
X#include	"../h/file.h"
X
Xextern long	remote_sysindex;
Xextern struct mbuf	*remote_path;
Xextern u_char	remote_sysmap[];
Xextern syscalls	remote_syscall[];
Xextern struct remoteinfo	remote_info[];
X
X/*
X * This routine is the main gateway into the remote software.  It should
X * be called from syscall().  Note that sysnum is already mapped to our
X * idea of the system call number.
X */
X#ifdef pyr	/* Pyramid */
Xremote_startup(pass, sysnum, arg1, arg2, arg3, arg4, arg5, arg6)
X#else pyr
Xremote_startup(pass, sysnum)
X#endif
X	long	sysnum, pass;
X{
X	struct a {
X		long	arg1,
X			arg2;
X	} *uap = (struct a *)u.u_ap;
X	long	error, sysindex;
X	extern long	remote_fd();
X	register syscalls	*sp = remote_syscall + sysnum;
X	register struct file	*fp;
X	register struct proc	*p;
X	register func	general = sp->sys_gen;
X	register unsigned	fd1,
X				fd2;
X#ifdef pyr	/* Pyramid */
X	long	args[ 6 ];
X
X	args[0] = arg1;
X	args[1] = arg2;
X	args[2] = arg3;
X	args[3] = arg4;
X	args[4] = arg5;
X	args[5] = arg6;
X	u.u_ap = args;
X	uap = (struct a *) args;
X#endif pyr
X
X	debug1("%d strt:#%d,pass%d,%s\n",
X		u.u_procp->p_pid, sysnum, pass,
X		pass == 0 ? (!sp->sys_before ? "too soon" : "before") :
X			    (pass == 1       ? "do it"    : "too late"));
X
X	/*
X	 * For the greatest of speed we check here for invalid or non-
X	 * remote file descriptors.  Make sure that we let a dup2() go
X	 * through, even if the first fd is non-remote.
X	 */
X	if (general == remote_fd) {
X		/*
X		 * Gross kludge from v7 for the bourne shell.
X		 */
X		fd1 = uap->arg1;
X		if (sysnum == RSYS_dup && (fd1 &~ 077)) {
X			fd1 &= 077;
X			sysnum = RSYS_dup2;
X		}
X		error = 2;
X		if (fd1 >= NOFILE
X		|| (fp = u.u_ofile[fd1]) == NULL
X		|| (fp->f_flag & FREMOTE) == 0)
X			error--;
X		if (sysnum != RSYS_dup2)
X			error--;
X		else {
X			fd2 = uap->arg2;
X			if (fd2 >= NOFILE
X			|| (fp = u.u_ofile[fd2]) == NULL
X			|| (fp->f_flag & FREMOTE) == 0)
X				error--;
X		}
X		if (! error)
X			return(FALSE);
X		uap->arg1 = fd1;
X	}
X	/*
X	 * Check to see if this is being done too soon.  Note that this is
X	 * on the else side of the check for remote_fd.  i.e., this code
X	 * assumes that remote_fd() routines should always be done before
X	 * the real routines.
X	 */
X	else if (pass == 0) {
X		u.u_rmtoffset[0] = -1;
X		u.u_rmtoffset[1] = -1;
X		if (! sp->sys_before)
X			return(FALSE);
X	}
X	else if (pass > 1) {
X		u.u_error = EISREMOTE;
X		return(TRUE);
X	}
X
X	/*
X	 * finally, if the user has turned off remote access for himself,
X	 * then just return.
X	 */
X	p = u.u_procp;
X	if (p->p_flag & SNOREMOTE)
X		return(FALSE);
X	u.u_error = 0;
X
X	/*
X	 * do the remote syscall.
X	 */
X	error = (*general)(sysnum);
X	debug1("%d startup done: ret1=%d, ret2=%d, err=%d\n",
X		u.u_procp->p_pid, u.u_r.r_val1, u.u_r.r_val2, error);
X	if (error < 0)	/* call the real system call */
X		return(FALSE);
X	u.u_error = error;
X	return(TRUE);
X}
X
X/*
X * This routine handles most system calls that have no special requirements
X * and have a single path in their first argument.
X */
Xremote_path1(sysnum)
X	int	sysnum;
X{
X	struct a {
X		char	*path;
X	} *uap = (struct a *)u.u_ap;
X	long	sysindex, len;
X	struct message *msg;
X	struct mbuf	*m;
X	register syscalls	*sp = remote_syscall + sysnum;
X	register long		error;
X
X	/*
X	 * Get the path mbuf chain and its length.  Also the remote sys #.
X	 */
X	if ((m = remote_path) == NULL)
X		return(ENOBUFS);
X	for (len=0; m; m = m->m_next)
X		len += m->m_len;
X	m = remote_path;
X	remote_path = NULL;
X	sysindex = remote_sysindex;
X
X	/*
X	 * Initialize the message and call the specific syscall handler.
X	 */
X	msg = mtod(m, struct message *);
X	introduce(msg, sysnum);
X	msg->m_hdlen = len;
X	error = (*sp->sys_spec)(sysindex, m, sysnum);
X
X	if (error < 0) {
X		msg = &remote_info[ sysindex ].r_msg;
X#ifdef BSD4_3
X#else BSD4_3
X		u.u_dirp = (caddr_t) u.u_arg[0];
X#endif BSD4_3
X		u.u_rmtoffset[0] = msg->m_args[0];
X		return ( -1 );
X	}
X	return ( error );
X}
X/*
X * This routine handles all two-path system calls.
X *
X *	RSYS_link: the placement of path2 determines where
X *		we run the syscall because path2 is the file
X * 		that is created.  Isremote() must also resolve the
X *		path1 so that the remote link will know what file to
X *		link it to.  Both path1 and path2 must be on the same
X *		system.  Unfortunately, in kernel mode, we don't know
X *		which path was found to be remote: we must check both again.
X *	RSYS_rename: Same as RSYS_link.
X *	RSYS_symlink: path2 is the only possible remote file and
X *		path1 does not need to be resolved because symlink()
X *		blindly creats a symbolic link to it.
X */
Xremote_path2(sysnum)
X	int	sysnum;
X{
X	struct a {
X		char	*path1;
X		char	*path2;
X	} *uap = (struct a *)u.u_ap;
X	long	sysindex,
X		len,
X		error;
X	struct message	*msg;
X	struct mbuf	*m;
X
X	if ((m = remote_path) == NULL)
X		return(ENOBUFS);
X	/*
X	 * If this is rename or link, then throw away what is in remote_path
X	 * because we don't know which path it refers to .
X	 */
X	remote_path = NULL;
X	if (sysnum != RSYS_symlink) {
X		m_freem(m);
X		m = NULL;
X		sysindex = rmt_checkpath(uap->path2, &m, sysnum);
X		if (sysindex < 0)
X			return(-1);
X	}
X	else
X		sysindex = remote_sysindex;
X	/*
X	 * Ok, path2 is now safely in our mbuf.  Set the PATHOFF field for
X	 * the beginning of where path1 will be.
X	 */
X	msg = mtod(m, struct message *);
X	introduce_1extra(msg, sysnum, u.u_cmask);
X	msg->m_args[ R_PATHOFF ] = htonl(msg->m_hdlen);
X
X	/*
X	 * If its a symbolic link, we can just copy the path onto the
X	 * end of our mbuf chain.
X	 */
X	if (sysnum == RSYS_symlink) {
X		error = rmt_copypath(uap->path1, m, TRUE);
X		if (error) {
X			m_freem(m);
X			return(error);
X		}
X	}
X	/*
X	 * Link and rename have to have path1 on the same system as path2.
X	 */
X	else if (rmt_checkpath(uap->path1, &m, sysnum) != sysindex) {
X		m_freem(m);
X		return(-1);
X	}
X
X	error = rmt_msgfin(sysindex, m, 0);
X
X	if(error < 0)
X		if (sysnum != RSYS_rename && sysnum != RSYS_link) {
X			msg = &remote_info[ sysindex ].r_msg;
X#ifdef BSD4_3
X#else BSD4_3
X			u.u_dirp = (caddr_t) u.u_arg[0];
X#endif BSD4_3
X			u.u_rmtoffset[0] = msg->m_args[0];
X			u.u_rmtoffset[1] = ntohl(msg->m_args[1]);
X			return ( -1 );
X		}
X		else
X			error = EISREMOTE;
X	return( error );
X}
X
X/*
X * Check a remote file for its "remoteness".  After namei() is called (in
X * the kernel) and isremote() is called as a result, we can get the result
X * from remote_path and put it on the end of 'mhead'.
X */
Xrmt_checkpath(path, mhead, sysnum)
X	char	*path;
X	struct mbuf	**mhead;
X	long	sysnum;
X{
X	char	*psrc, *pdest;
X	struct mbuf	*m;
X	struct message	*msg;
X	long	len;
X	struct inode	*ip;
X
X#ifdef BSD4_3
X	register struct nameidata *ndp = &u.u_nd;
X	long	follow = remote_syscall[ sysnum ].sys_follow ? FOLLOW : 0;
X
X	ndp->ni_nameiop = LOOKUP | follow;
X	ndp->ni_segflg = UIO_USERSPACE;
X	ndp->ni_dirp = (caddr_t)path;
X	ip = namei(ndp);
X#else BSD4_3
X	u.u_dirp = path;
X	ip = namei(uchar, LOOKUP, remote_syscall[ sysnum ].sys_follow);
X#endif BSD4_3
X	if (ip != NULL || u.u_error != EISREMOTE) {
X		if (ip)
X			iput(ip);
X		return(-1);
X	}
X	u.u_error = 0;
X
X	if (remote_path == NULL)
X		return(-1);
X	if (*mhead == NULL)
X		*mhead = remote_path;
X	else {
X		/*
X		 * If we were handed an mbuf, then we tack the new string
X		 * of mbufs on the end.  Note that we bump the offset so that
X		 * the mtod(m, char *) points to the beginning of the path.
X		 */
X		for (m = *mhead; m->m_next; )
X			m = m->m_next;
X		m->m_next = remote_path;
X		msg = mtod(remote_path, struct message *);
X		len = msg->m_hdlen - (R_MINRMSG + R_PATHSTART*sizeof(long));
X		remote_path->m_off += R_MINRMSG + R_PATHSTART*sizeof(long);
X		remote_path->m_len -= R_MINRMSG + R_PATHSTART*sizeof(long);
X		msg = mtod(*mhead, struct message *);
X		msg->m_hdlen += len;
X	}
X	remote_path = NULL;
X	return(remote_sysindex);
X}
X
X/*
X * Remote exit()
X */
Xremote_exit()
X{
X	struct remoteinfo	*rp, *rmt_hostdir();
X	struct file	*fp;
X	long	i;
X	struct mbuf	*m;
X	struct message *msg;
X
X	/*
X	 * Throw away remote file descriptors.
X	 */
X	for (i=0; i<NOFILE; i++)
X		if ((fp = u.u_ofile[ i ]) && (fp->f_flag & FREMOTE))
X			rmt_deallocfd(i);
X	u.u_procp->p_flag &= ~SREMOTE;
X	if (rp = rmt_hostdir(u.u_cdir, &i))
X		rp->r_nchdir--;
X	/*
X	 * Send the exit message to every remote system to which we
X	 * have a connection.
X	 */
X	for (rp = remote_info, i=0; i<R_MAXSYS; i++, rp++)
X		if (rmthostused(i) && rp->r_sock) {
X			/*
X			 * If ours is the last usage of this connection, then
X			 * shut it down.
X			 */
X			debug4("%d off #%d, now %d usrs\n", u.u_procp->p_pid,
X				i, rp->r_users-1); 
X			if (--rp->r_users <= 0 && rp->r_sock) {
X				if (rp->r_close)
X					rmt_shutdown(i);
X				else
X					rmt_closehost(rp);
X				continue;
X			}
X			MGET(m, M_WAIT, MT_DATA);
X			if (m == NULL)
X				break;
X			msg = mtod(m, struct message *);
X			msg->m_hdlen = m->m_len = introduce(msg, RSYS_exit);
X			rmt_msgfin(i, m, RFLG_INFO);
X		}
X
X	return( -1 ); /* do the real syscall, too */
X}
X
X/*
X * Remote fork()
X */
Xremote_fork(sysnum)
X	long	sysnum;
X{
X	register long		i, child, pid, ppid, val1;
X	long			rmtdir = u.u_rmtcdir,
X				sysindex;
X	struct message		*msg;
X	register struct remoteinfo	*rp;
X	struct remoteinfo	*rmt_hostdir();
X	struct mbuf	*m;
X	register struct file	*fp;
X	long			rmtsys;	
X
X	/*
X	 * We may not need to even notify anyone, if this process is not
X	 * doing anything interesting.  If there are no open files or
X	 * a remote current working directory, then do no more.
X	 */
X	rmtcopyhosts(rmtsys, u.u_rmtsys);
X	rmtclearhosts();
X	for (i=0; i<NOFILE; i++) {
X		if ((fp = u.u_ofile[ i ]) && (fp->f_flag & FREMOTE)) {
X			remote_info[ (int)fp->f_data ].r_nfile++;
X			rmtusehost((int)fp->f_data);
X		}
X	}
X	if (rp = rmt_hostdir(u.u_cdir, &sysindex)) {
X		rmtusehost(sysindex);
X		rp->r_nchdir++;
X	}
X
X	/*
X	 * Do the fork.
X	 */
X	if (sysnum == RSYS_vfork)
X		vfork();
X	else
X		fork();
X	val1 = u.u_r.r_val1;
X	child = u.u_r.r_val2;
X	if (u.u_error)
X		child = FALSE;
X	if (u.u_error || u.u_rmtsys == 0)
X		goto done;
X
X	if (child) {
X		ppid = u.u_procp->p_ppid;
X		pid = u.u_procp->p_pid;
X		u.u_procp->p_flag |= SREMOTE; /* set remote flag in child */
X		u.u_rmtcdir = rmtdir;
X	}
X	else { /* parent */
X		/* "if I am the parent && this is a vfork" */
X		if (sysnum == RSYS_vfork)
X			goto done;
X		ppid = u.u_procp->p_pid;
X		pid = u.u_r.r_val1;
X	}
X	/*
X	 * Parent (fork() only) and child tell all remote hosts.
X	 * Also, bump the count of users using all connections.
X	 */
X	for (rp=remote_info, i=0; i<R_MAXSYS; i++, rp++)
X		if (rmthostused(i) && rp->r_sock) {
X			if(child)
X				rp->r_users++;
X			debug4("fork: %s %d notify %s(%d), users=%d\n",
X				child ? "chld" : "prnt", u.u_procp->p_pid,
X				rp->r_mntpath, i, rp->r_users);
X			MGET(m, M_WAIT, MT_DATA);
X			if (m == NULL)
X				continue;
X			msg = mtod(m, struct message *);
X			msg->m_hdlen = m->m_len =
X				introduce_2extra(msg, sysnum, pid, ppid);
X			rmt_msgfin(i, m, RFLG_INFO);
X		}
X	/*
X	 * In the kernel, the r_val[12] elements get tromped on by the
X	 * io to the server hosts, so restore them here.
X	 * The 'u.u_error = 0;' is so that we don't run the real syscall
X	 * (already run) and so that any io errors while notifying servers
X	 * don't returned to the user... otherwise he might think the fork
X	 * or vfork failed.
X	 */
X	u.u_r.r_val1 = val1;
X	u.u_r.r_val2 = child;
X	u.u_error = 0;
Xdone:
X	if (! child)
X		rmtcopyhosts(u.u_rmtsys, rmtsys);
X	return(u.u_error);
X}
X
X/*
X * This routine handles most system calls having a file descriptor as
X * its first argument.  We are guarenteed at this point that uap->fd is
X * a valid remote file descriptor.  We optimize for reads and writes.
X */
Xremote_fd(sysnum)
X	register long	sysnum;
X{
X	struct a {
X		long	fd;
X		char	*buf;
X		long	len;
X	} *uap = (struct a *)u.u_ap;
X	register long	sysindex, error;
X	register struct message	*msg;
X	register struct mbuf	*m;
X	register syscalls	*sp = remote_syscall + sysnum;
X	register struct file	*fp = u.u_ofile[ uap->fd ];
X
X	MGET(m, M_WAIT, MT_DATA);
X	if (m == NULL)
X		return(ENOBUFS);
X	msg = mtod(m, struct message *);
X	msg->m_hdlen = 0; /* rmt_datafin() or rmt_msgfin() will assign this */
X	m->m_len = introduce_2extra(msg, sysnum, uap->fd, uap->len);
X
X	sysindex = (long)fp->f_data;
X	error = (*sp->sys_spec)(sysindex, m, sp->sys_flag);
X	if (! error)
X		switch (sysnum) {
X		case RSYS_read:
X		case RSYS_write:
X		case RSYS_readv:
X		case RSYS_writev:
X			fp->f_offset += u.u_r.r_val1;
X			break;
X		}
X	return(error);
X}
X
X/*
X * Deallocate a file descriptor.
X */
Xrmt_deallocfd(fd)
X	int	fd;
X{
X	register struct file	*fp;
X	register struct remoteinfo	*rp;
X	register unsigned	system;
X
X	fp = u.u_ofile[fd];
X	u.u_ofile[fd] = NULL;
X	if (fp == NULL
X	|| ((system = (unsigned)fp->f_data) >= R_MAXSYS)) {
X		debug6("dealloc: fp=%x,fd=%d,sys=%d,pid=%d\n",
X			fp, fd, system, u.u_procp->p_pid);
X		return;
X	}
X
X	remote_info[ (int)fp->f_data ].r_nfile--;
X	closef(fp);
X}
SHAREOF
chmod 444 remote/usr.sys.remote/rmt_general.c
#
# remote/usr.sys.remote/rmt_generic.c
#
if [ -f remote/usr.sys.remote/rmt_generic.c ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.remote/rmt_generic.c or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.remote/rmt_generic.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.remote/rmt_generic.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 * $Header: rmt_generic.c,v 2.2 86/01/02 13:52:32 toddb Exp $
X *
X * $Log:	rmt_generic.c,v $
X * Revision 2.2  86/01/02  13:52:32  toddb
X * Ifdef'ed calls to sockargs() for the differences in 4.2 vs. 4.3.
X * 
X * Revision 2.1  85/12/30  16:58:59  toddb
X * Isremote() was not freeing it's chain of mbufs if rmt_copypath() failed.
X * Now it does.
X * 
X * Revision 2.0  85/12/07  18:18:27  toddb
X * First public release.
X * 
X */
X#include "../h/param.h"
X#include "../h/systm.h"
X#include "../h/inode.h"
X#include "../h/dir.h"
X#ifdef BSD4_3
X#include "../h/namei.h"
X#else BSD4_3
X#include "../h/nami.h"
X#endif BSD4_3
X#ifndef pyr	/* Pyramid */
X#include "../machine/pte.h"
X#endif
X#include "../h/user.h"
X#include "../h/proc.h"
X#include "../h/buf.h"
X#include "../h/file.h"
X#include "../h/uio.h"
X#include "../h/mbuf.h"
X#include "../h/socket.h"
X#include "../h/socketvar.h"
X#include "../h/errno.h"
X#include "../remote/remotefs.h"
X
Xextern	long		remote_sysindex;
Xextern struct mbuf	*remote_path;
Xextern struct remoteinfo remote_info[];
Xextern struct remoteinfo *remote_generic;
Xextern struct nameserver	remote_ns;
X
X/*
X * Remote "mount point" definition.
X */
X#ifdef pyr	/* Pyramid */
Xremoteon(arg1, arg2, arg3, arg4)
X{
X#ifdef BSD4_3
X	register struct nameidata *ndp = &u.u_nd;
X#else BSD4_3
X#endif BSD4_3
X	struct a {
X		char	*path;
X		unsigned pathlen;
X		caddr_t	name;
X		unsigned namelen;
X	} ua;
X	register struct a *uap = &ua;
X	register struct inode		*ip;
X	register struct remoteinfo	*rp;
X	struct remoteinfo		*rmt_findslot(),
X					*rmt_host();
X	register int			error = 0;
X	long				sysnum;
X	struct mbuf *m = NULL;
X
X	uap->path = (char *)arg1;
X	uap->pathlen = (unsigned)arg2;
X	uap->name = (caddr_t)arg3;
X	uap->namelen = (unsigned)arg4;
X#else pyr
Xremoteon()
X{
X#ifdef BSD4_3
X	register struct nameidata *ndp = &u.u_nd;
X#else BSD4_3
X#endif BSD4_3
X	register struct a {
X		char	*path;
X		unsigned pathlen;
X		caddr_t	name;
X		unsigned namelen;
X	} *uap = (struct a *)u.u_ap;
X	register struct inode		*ip;
X	register struct remoteinfo	*rp;
X	struct remoteinfo		*rmt_findslot(),
X					*rmt_host();
X	register int			error = 0;
X	long				sysnum;
X	struct mbuf *m = NULL;
X#endif
X
X	if (uap->path == NULL) {
X		u.u_procp->p_flag &= ~SNOREMOTE;
X		return;
X	}
X	if (!suser())
X		return;
X#ifdef BSD4_3
X	ndp->ni_nameiop = LOOKUP;
X	ndp->ni_segflg = UIO_USERSPACE;
X	ndp->ni_dirp = (caddr_t)uap->path;
X	ip = namei(ndp);
X#else BSD4_3
X	ip = namei(uchar, LOOKUP, 0);
X#endif BSD4_3
X	debug5("remote on ip=%x,path=%x,pthlen=%d,name=%x,nmlen=%d\n",
X		ip, uap->path, uap->pathlen, uap->name, uap->namelen);
X	if (ip == NULL)
X		return;
X	if (uap->pathlen >= R_MNTPATHLEN)
X		uap->pathlen = R_MNTPATHLEN - 1;
X
X	/*
X	 * Check for all kinds of errors.
X	 */
X	if (rmt_host(ip, &sysnum) || (uap->name == NULL && remote_generic))
X		error = EBUSY;
X	else if ((ip->i_mode&IFMT) == IFDIR)
X		error = EISDIR;
X	else if (uap->name)
X#ifdef BSD4_3
X		error = sockargs(&m, uap->name, uap->namelen, MT_SONAME);
X#else BSD4_3
X		error = sockargs(&m, uap->name, uap->namelen);
X#endif BSD4_3
X	if (error)
X		goto out;
X
X	/*
X	 * Everything is ok... so put it in our list.
X	 */
X	rp = rmt_findslot(&sysnum);
X	if (rp == NULL)
X		error = ETOOMANYREMOTE;
X	else {
X		debug5("rp=%x, m=%x ip=%x sys=%d\n", rp, m, ip, sysnum);
X		rp->r_mntpt = ip;
X		if ((rp->r_name = m) == NULL)
X			remote_generic = rp;
X		(void)copyin((caddr_t)uap->path, (caddr_t)rp->r_mntpath,
X			MIN(uap->pathlen, R_MNTPATHLEN));
X		u.u_r.r_val1 = sysnum;
X		iunlock(ip);
X		return;
X	}
X
Xout:
X	u.u_error = error;
X	iput(ip);
X}
X
X/*
X * Turn off the remote file system.  If the path to unmount is NULL, then
X * turn off all remote access for this process.
X */
X#ifdef pyr	/* Pyramid */
Xremoteoff(arg1)
X{
X#ifdef BSD4_3
X	register struct nameidata *ndp = &u.u_nd;
X#else BSD4_3
X#endif BSD4_3
X	struct a {
X		char	*path;
X	} ua;
X	register struct a *uap = &ua;
X	register struct inode *ip;
X	register struct remoteinfo	*rp;
X	struct remoteinfo		*rmt_host();
X	long			sysnum;
X
X	uap->path = (char *)arg1;
X#else pyr
Xremoteoff()
X{
X#ifdef BSD4_3
X	register struct nameidata *ndp = &u.u_nd;
X#else BSD4_3
X#endif BSD4_3
X	register struct a {
X		char	*path;
X	} *uap = (struct a *)u.u_ap;
X	register struct inode *ip;
X	register struct remoteinfo	*rp;
X	struct remoteinfo		*rmt_host();
X	long			sysnum;
X#endif pyr
X
X	if (uap->path == NULL) {
X		u.u_procp->p_flag |= SNOREMOTE;
X		return;
X	}
X	if (!suser())
X		return;
X#ifdef BSD4_3
X	ndp->ni_nameiop = LOOKUP;
X	ndp->ni_segflg = UIO_USERSPACE;
X	ndp->ni_dirp = (caddr_t)uap->path;
X	ip = namei(ndp);
X#else BSD4_3
X	ip = namei(uchar, LOOKUP, 0);
X#endif BSD4_3
X	if (ip == NULL || (rp = rmt_host(ip, &sysnum)) == NULL) {
X		if (ip)
X			iput(ip);
X		debug5("remoteoff: nope! ip=%x error=%d\n",
X			ip, u.u_error);
X		u.u_error = EINVAL;
X		return;
X	}
X
X	debug5("remote off ip=%x\n", ip);
X	iput(ip);
X
X	/*
X	 * Now try to shut it down. 
X	 */
X	rp->r_close = TRUE;
X	if (u.u_error = rmt_shutdown(sysnum))
X		return;
X	u.u_r.r_val1 = remote_sysindex;
X	/*
X	 * reinitialize the structure for the next time,
X	 * freeing the mbuf and closing the socket.
X	 */
X	rp->r_refcnt = 0;
X	rp->r_nchdir = 0;
X	rp->r_nfile = 0;
X	if (rp->r_mntpt)
X		irele(rp->r_mntpt);
X	rp->r_mntpt = 0;
X	if (rp->r_name)
X		(void)m_free(rp->r_name);
X	else
X		remote_generic = NULL;
X	rp->r_name = 0;
X	return;
X}
X
X/*
X * This provides the nameserver function allowing
X * name information to pass to and from a server and the kernel.
X */
X#ifdef pyr	/* Pyramid */
Xremotename(arg1, arg2, arg3, arg4)
X{
X	struct a {
X		long	action;
X		caddr_t	name;
X		long	namelen;
X		char	*path;
X	} ap;
X	register struct a *uap = &ap;
X	register long	error = 0;
X	struct mbuf		*m;
X	register struct proc	*p = u.u_procp;
X
X	uap->action = (long)arg1;
X	uap->name = (caddr_t)arg2;
X	uap->namelen = (long)arg3;
X	uap->path = (char *)arg4;
X#else pyr
Xremotename()
X{
X	register struct a {
X		long	action;
X		caddr_t	name;
X		long	namelen;
X		char	*path;
X	} *uap = (struct a *)u.u_ap;
X	register long	error = 0;
X	struct mbuf		*m;
X	register struct proc	*p = u.u_procp;
X#endif pyr
X
X	if ((uap->action == NM_WHATNAME || uap->action == NM_NAMEIS)
X	&& ! server_alive(p))
X		error = EPERM;
X	else switch (uap->action) {
X	case NM_SERVER:		/* register as name server */
X	{
X		struct proc	*p2;
X		short		pid;
X
X		if (!suser())
X			return;
X		p2 = remote_ns.rn_proc;
X		pid = remote_ns.rn_pid;
X		if (server_alive(p2))
X			error = EBUSY;
X		else {
X			remote_ns.rn_proc = p;
X			remote_ns.rn_pid = p->p_pid;
X		}
X		break;
X	}
X	case NM_WHATNAME:
X		if (remote_ns.rn_path)
X			error = copyout((caddr_t)remote_ns.rn_path,
X				(caddr_t)uap->path,
X				MIN(uap->namelen, remote_ns.rn_pathlen));
X		else
X			error = ENOREMOTEFS;
X		break;
X	case NM_NAMEIS:
X	{
X		register char	*cp;
X
X		m = remote_ns.rn_name;
X		if (m) {
X			debug13("free old mbuf@%x\n", m);
X			m_free(m); /* free extra mbuf */
X			m = remote_ns.rn_name = NULL;
X		}
X#ifdef BSD4_3
X		error = sockargs(&m, uap->name, uap->namelen, MT_SONAME);
X#else BSD4_3
X		error = sockargs(&m, uap->name, uap->namelen);
X#endif BSD4_3
X		if (error == 0) {
X			cp = mtod(m, char *) + m->m_len;
X			if (error = copyin((caddr_t)uap->path, (caddr_t)cp,
X			    MIN(R_MNTPATHLEN, MLEN - m->m_len))) {
X				m_free(m);
X				m = NULL;
X			}
X			debug13("nmsrv: %s@%x\n", cp, m);
X		}
X		remote_ns.rn_name = m;
X		wakeup(&remote_ns.rn_name);
X		break;
X	}
X#ifdef RFSDEBUG
X	case NM_DEBUG:
X		remote_debug = (long)uap->name;
X		printf("dbg=%d\n", remote_debug);
X		break;
X#endif RFSDEBUG
X	default:
X		error = EINVAL;
X		break;
X	}
X	if (error)
X		u.u_error = error;
X}
X
X/*
X * This is the routine called by namei() when it encounters what it thinks
X * might be a remote mount point.
X */
Xisremote(ip, path, base)
X	register struct inode *ip;
X	char		*path, *base;
X{
X	struct remoteinfo *rmt_host(), *rmt_findhost();
X	register short	offset;
X	register struct remoteinfo *rp;
X	register struct mbuf	*m;
X	register struct message	*msg;
X	register int	error;
X	long			sysnum;
X
X	rp = rmt_host(ip, &sysnum);
X	if (rp == NULL) {
X		debug7("%s, ip=\"%x\" is not remote\n", path, ip);
X		return(FALSE);
X	}
X	if (remote_path)
X		m_freem(remote_path);
X	remote_path = NULL;
X
X	/*
X	 * Adjust the path so that if there is a leading '/', the path
X	 * will start there.
X	 */
X	if (path != base && *path != '/' && *(path-1) == '/')
X		path--;
X
X	/*
X	 * Although we know the file is remote, it may have a loop back
X	 * to this side; a simple case being if the path is '..' while
X	 * in the root directory of the remote system.  If this is the case
X	 * then the server will reply with errno == -1, remote_path[12]()
X	 * will assign u.u_rmtoffset[0,1] and the real system call will be
X	 * run again, bringing us back to here.  We know that that has
X	 * happened if either of u.u_rmtoffset[0,1] is >= 0.  We then
X	 * just adjust the path handed to us by namei() and return
X	 * -1 which signals namei() to begin again with the new
X	 * path with directory set to root (/).
X	 */
X	if ((u.u_procp->p_flag & SREMOTE) == 0) {
X		u.u_rmtcdir = -1;
X		offset = -1;
X	}
X	else if ((offset = u.u_rmtoffset[0]) >= 0)
X		u.u_rmtoffset[0] = -1;
X	else if ((offset = u.u_rmtoffset[1]) >= 0)
X		u.u_rmtoffset[1] = -1;
X	if (offset >= 0) {
X		register char	*pstart = path + offset;
X		register char	*p = path;
X
X		debug8("restart path %s locally, offset=%d\n", path, offset);
X		if (offset) /* validate offset value */
X			while (p <= pstart)
X				if (*p++ == '\0') {
X					u.u_error = EINVAL;
X					return(FALSE);
X				} 
X		if (base != pstart) {
X			path = base;
X			do {
X				*path++ = *pstart;
X			} while (*pstart++);
X		}
X		return(-1);
X	}
X
X	/*
X	 * We have a remote mount point.  However, it may be in the midst of
X	 * shutting down from some error.  This mount point may also be
X	 * a "generic" mount point, in which case, we must figure out
X	 * the host.
X	 */
X	if (rp->r_name == NULL) {
X		rp = rmt_findhost(&path, &sysnum);
X		if (rp == NULL) {
X			debug8("isremote: can't map path %s\n", path);
X			return(TRUE);
X		}
X	}
X	if (rp->r_close) {
X		debug8("isremote: host %s is closing\n", rp->r_mntpath);
X		u.u_error = ENOREMOTEFS;
X		return(TRUE);
X	}
X	u.u_error = EISREMOTE;
X	remote_sysindex = sysnum;
X	/*
X	 * Set the remote flag for this user and bump the
X	 * user count.
X	 */
X	u.u_procp->p_flag |= SREMOTE;
X	if (! rmthostused(sysnum)) {
X		rp->r_users++;
X		rmtusehost(sysnum);
X		debug4("%d uses rmt %d\n", u.u_procp->p_pid, sysnum);
X	}
X	rmtusehost(sysnum);
X	debug7("%s, ip=%x is remote, idx=%d\n", path, ip, remote_sysindex);
X	MGET(m, M_WAIT, MT_DATA);
X	if (m != NULL) {
X		msg = mtod(m, struct message *);
X		msg->m_hdlen = R_MINRMSG + R_PATHSTART*sizeof(long);
X		m->m_len = R_MINRMSG + R_PATHSTART*sizeof(long);
X		if (error = rmt_copypath(path, m, FALSE)) {
X			m_freem(m);
X			u.u_error = error;
X			return(TRUE);
X		}
X		remote_path = m;
X	}
X	else
X		u.u_error = ENOBUFS;
X	return(TRUE);
X}
SHAREOF
chmod 444 remote/usr.sys.remote/rmt_generic.c
#
# remote/usr.sys.remote/rmt_io.c
#
if [ -f remote/usr.sys.remote/rmt_io.c ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.remote/rmt_io.c or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.remote/rmt_io.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.remote/rmt_io.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 * $Header: rmt_io.c,v 2.1 85/12/30 16:53:01 toddb Exp $
X *
X * $Log:	rmt_io.c,v $
X * Revision 2.1  85/12/30  16:53:01  toddb
X * Changed shutdown messages for the remotefs from debug messages to 
X * printf messages.  Also fixed a bug where the return value field in
X * rp->r_msg.m_args[ R_RETVAL ] was getting cleared for process `x'
X * by process `y' when process `y' was executing an INFO_ONLY type
X * of remote system call (like close or fork).  This bug was causing
X * random system calls (like read or write) to return 0 when it should
X * have returned something non-zero.
X * 
X * Revision 2.0  85/12/07  18:18:51  toddb
X * First public release.
X * 
X */
X#include "../h/param.h"
X#include "../h/dir.h"
X#ifndef pyr	/* Pyramid */
X#include "../machine/pte.h"
X#endif
X#include "../h/user.h"
X#include "../h/proc.h"
X#include "../h/buf.h"
X#include "../h/uio.h"
X#include "../h/mbuf.h"
X#include "../h/socket.h"
X#include "../h/socketvar.h"
X#include "../h/protosw.h"
X#include "../h/errno.h"
X#include "../remote/remotefs.h"
X#include "../h/inode.h"
X#include "../h/kernel.h"
X#include "../netinet/in.h"
X
Xextern struct remoteinfo	remote_info[];
Xextern struct remoteinfo	*remote_generic;
X
X/*
X * Obtain a connection to 'system'.
X */
Xremote_getconnection(system)
X	register int	system;
X{
X	register struct remoteinfo	*rp = remote_info + system;
X	register err, s, opening = FALSE;
X	short	uid;
X	struct socket *so = NULL;
X
X	if (! rp->r_name) {
X		rmt_unuse(rp, system);
X		return(ENOREMOTEFS);	/* no address to call. */
X	}
X
X	/*
X	 * Lock out other processes from doing an open at the same time.
X	 */
X	if (rp->r_opening) {
X		if (setjmp(&u.u_qsave)) {
X			rmt_unuse(rp, system);
X			return(EINTR);
X		}
X		while (rp->r_opening)
X			sleep((caddr_t)&rp->r_sock);
X		if (rp->r_sock)
X			return(0);
X		rmt_unuse(rp, system);
X		return(rp->r_openerr);
X	}
X	/*
X	 * We may already have a connection
X	 */
X	else if (rp->r_sock)
X		return(0);
X	/*
X	 * If we have failed previously, it may be time to try again.
X	 */
X	else if (rp->r_failed) {
X		if (rp->r_age > time.tv_sec)
X			return(rp->r_openerr);
X		rp->r_failed = FALSE;
X	}
X	rp->r_opening = TRUE;
X
X	/*
X	 * pseudo loop to avoid labels...
X	 */
X	do {
X		/*
X		 * Fortunately, there is security with ports.  Unfortunately,
X		 * you must be root to do it.  So we change our uid for a
X		 * brief moment.
X		 */
X		uid = u.u_uid;
X		if (setjmp(&u.u_qsave)) {
X			u.u_uid = uid;
X			if (u.u_error == 0)
X				err = EINTR;
X			break;
X		}
X
X		/*
X		 * first, make a socket for the connection; then connect.  (the
X		 * connection code is basically connect(2)).
X		 */
X		if (err = socreate(AF_INET, &rp->r_sock, SOCK_STREAM, 0))
X			break;
X
X		so = rp->r_sock;
X		debug9("connect...");
X		err = soconnect(so, rp->r_name);
X		u.u_uid = uid;
X		if (err)
X			break;
X
X		s = splnet();
X		if ((so->so_state & SS_NBIO) &&
X		    (so->so_state & SS_ISCONNECTING)) {
X			err = EINPROGRESS;
X			splx(s);
X			break;
X		}
X		while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
X			debug9(".");
X			sleep((caddr_t)&so->so_timeo, PZERO+1);
X		}
X		err = so->so_error;
X		so->so_error = 0;
X		rp->r_sock = so;
X		rp->r_sender = rp->r_recver = -1;
X		sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, NULL);
X		splx(s);
X	} while (FALSE);
X
X	if (err) {
X		rp->r_sock = 0;
X		rp->r_openerr = err;
X		rp->r_failed = TRUE;
X		rp->r_age = time.tv_sec + R_RETRY;
X		debug9("err=%d\n", err);
X		rmt_unuse(rp, system);
X		if (so)
X			soclose(so);
X	}
X	else
X		debug9(" done.\n");
X	rp->r_opening = FALSE;
X	wakeup((caddr_t)&rp->r_sock);
X	return(err);
X}
X
X/*
X * Back out of references to a remote host.
X */
Xrmt_unuse(rp, system)
X	register struct remoteinfo *rp;
X	register long	system;
X{
X	rp->r_users--;
X	rmtunusehost(system);
X	if (u.u_rmtsys == 0)
X		u.u_procp->p_flag &= ~SREMOTE;
X}
X
X/*
X * Send out the message.
X */
Xremoteio(system, m, uio, flags)
X	register int	system;
X	register struct mbuf	**m;
X	register struct uio *uio;
X	int	flags;
X{
X	register int	error, signaled = 0, position;
X	register struct remoteinfo	*rp = remote_info + system;
X	register struct socket	*so;
X	register struct iovec *iov;
X	register struct proc	*p;
X	long	soreceive(), sosend();
X	long	oldmask;
X
X
X	/*
X	 * get a connection.
X	 */
X	if ((so = rp->r_sock) == NULL)
X		if (error = remote_getconnection(system)) {
X			(void) m_freem(*m);
X			return(error);
X		}
X		else
X			so = rp->r_sock;
X
X	/*
X	 * "Hold" SIGTSTP and SIGSTOP signals until we are done.
X	 */
X	p = u.u_procp;
X	oldmask = (1 << (SIGTSTP-1))
X		| (1 << (SIGSTOP-1));
X	oldmask = (p->p_sigmask & oldmask);
X	p->p_sigmask |= (1 << (SIGTSTP-1))
X			| (1 << (SIGSTOP-1));
X
X	/*
X	 * Note that we re-do the setjmp each time we change state.
X	 * Two reasons: 1) we are effectively ignoring interrupts until
X	 * either the message has been completely sent or has been
X	 * completely recieved. 2) setjmp() restores register variables to
X	 * their state at the time of the call and since we modify them
X	 * all the time, we need to re-save the state.
X	 */
X	position = R_NOTHINGSENT;
X	rp->r_refcnt++; /* we are actively using conection */
X
X	while(position != 0) {
X		if (setjmp(&u.u_qsave)) {
X			error = EINTR;
X			debug10("signal to %d\n", u.u_procp->p_pid);
X			if (rp->r_close)
X				goto remoteio_done;
X			signaled++;
X			continue;
X		}
X
X		switch (position) {
X		case R_NOTHINGSENT:
X			/*
X			 * make sure that this is not someone elses data.
X			 */
X			if (signaled)
X				goto remoteio_done;
X			while (!rp->r_close && rp->r_sender >= 0) {
X				debug10("I am %d, not %d. Goodnight.\n",
X					u.u_procp->p_pid, rp->r_sender);
X				sleep((caddr_t)&rp->r_sender, PZERO+1);
X			}
X			if (rp->r_close)
X				goto remoteio_done;
X
X			/*
X			 * We update position BEFORE we call tcp_usrreq()
X			 * because we are guarenteed that the data will be
X			 * sent just by making the call.  i.e. we will never
X			 * come back to this point once we've been here.
X			 */
X			if (uio && (flags & RFLG_WR))
X				position = R_DATANOTSENT;
X			else
X				position = R_MSGNOTRED;
X			rp->r_sender = u.u_procp->p_pid;
X			debug10("%d sending... ", rp->r_sender);
X			error = (*so->so_proto->pr_usrreq)(so,
X				PRU_SEND, *m, 0, 0);
X			if (error) {
X				printf("error=%d on sending msg\n", error);
X				rp->r_close = TRUE;
X				goto remoteio_done;
X			}
X			*m = 0;
X			break;
X
X		case R_DATANOTSENT:
X			debug10("%d data\n", u.u_procp->p_pid);
X			if (error = rmt_uio(rp, uio, sosend))
X				flushmsg(rp, uio->uio_resid, FALSE);
X			position = R_MSGNOTRED;
X			break;
X
X		case R_MSGNOTRED:
X			/*
X			 * Finally, read from the socket.  Also, if
X			 * we have been interrupted, now is the time to
X			 * notify the other side.
X			 */
X			rp->r_sender = -1;
X			wakeup(&rp->r_sender);
X			if (flags & RFLG_INFO) {
X				position = 0;
X				break;
X			}
X			debug10("%d recving\n", u.u_procp->p_pid);
X			if (signaled)
X				sendrsig(system);
X			error = rmt_getmsg(system);
X			rp->r_received = FALSE;
X			if (error || rp->r_close)
X				goto remoteio_done;
X			if (uio && (flags & RFLG_RD))
X				position = R_DATANOTRED;
X			else {
X				rp->r_recver = -1;
X				position = 0;
X				wakeup(&rp->r_recver);
X			}
X			break;
X		case R_DATANOTRED:
X			debug10("%d recving data\n", u.u_procp->p_pid);
X			if (rp->r_msg.m_args[ R_RETVAL ] > uio->uio_resid) {
X				printf("usr needs %d, srvr says %d\n",
X					uio->uio_resid,
X					rp->r_msg.m_args[ R_RETVAL ]);
X				rp->r_close = TRUE;
X				goto remoteio_done;
X			}
X					
X			uio->uio_resid = rp->r_msg.m_args[ R_RETVAL ];
X			if (error = rmt_uio(rp, uio, soreceive)) {
X				flushmsg(rp, uio->uio_resid, TRUE);
X				break;
X			}
X			rp->r_recver = -1;
X			wakeup(&rp->r_recver);
X			position = 0;
X			break;
X		}
X	}
Xremoteio_done:
X	/*
X	 * Restore mask by first taking out SIGTSTP and SIGSTOP, whatever
X	 * their values.  And then or'ing in the original value.
X	 */
X	p = u.u_procp;
X	p->p_sigmask &= ~((1 << (SIGTSTP-1))
X			| (1 << (SIGSTOP-1)));
X	p->p_sigmask |= oldmask;
X
X	rp->r_refcnt--; /* we are done with this transaction */
X	if (rp->r_close)
X		error = ECONNABORTED;
X	if (error) {
X		debug11("remoteio: err=%d, close=%s\n",
X			error, rp->r_close ? "true" : "false");
X		rmt_shutdown(system);
X	}
X	return(error);
X}
X
X/*
X * Force io to happen and consume all of uio->uio_resid.
X */
Xrmt_uio(rp, uio, sockfunc)
X	register struct remoteinfo	*rp;
X	register struct uio	*uio;
X	register func		sockfunc;
X{
X	register struct socket	*so = rp->r_sock;
X	label_t	qsave;
X	register long	error = 0,
X			flag = (sockfunc == soreceive)
X				? SS_CANTRCVMORE : SS_CANTSENDMORE;
X
X	bcopy(&u.u_qsave, &qsave, sizeof(label_t));
X	if (setjmp(&u.u_qsave)) {
X		debug11("rmt_uio: sig %d\n", u.u_procp->p_pid);
X		if (rp->r_close)
X			error = ECONNABORTED;
X	}
X	while(uio->uio_resid > 0 && ! error && (so->so_state & flag) == 0)
X		error = (*sockfunc)(so, 0, uio, 0, 0);
X	bcopy(&qsave, &u.u_qsave, sizeof(label_t));
X	if (so->so_state & flag) {
X		rp->r_close = TRUE;
X		error = ECONNABORTED;
X	}
X	return(error);
X}
X
X/*
X * Obtain the next message from the server.  We don't return from this
X * routine until our personal message has been received or an error
X * has occured.
X */
Xrmt_getmsg(system)
X	register int	system;
X{
X	struct proc	*p = NULL;
X	struct remoteinfo	*rp = remote_info + system;
X	struct socket *so = rp->r_sock;
X	struct uio	auio;
X	struct iovec	iov;
X	register long	msglen, len, error = 0;
X	long		soreceive();
X
X	for(;;) {
X		iov.iov_len = auio.uio_resid = R_MINRMSG+sizeof(long);
X		auio.uio_segflg = 1;	/* kernel bcopy */
X		auio.uio_iov = &iov;
X		auio.uio_iovcnt = 1;
X		auio.uio_offset = 0;
X		iov.iov_base = (caddr_t)&rp->r_msg;
X
X		/*
X		 * Since we may have been usurped by this time, or a different
X		 * syscall may have been repsponded to, we must make sure
X		 * that we are the recipient of this message.  In fact,
X		 * the message may have already arrived.
X		 */
X		while (rp->r_recver != u.u_procp->p_pid && rp->r_recver != -1)
X			sleep((caddr_t)&rp->r_recver, PZERO+1);
X		if (rp->r_recver == u.u_procp->p_pid && rp->r_received) {
X			auio.uio_resid = 0;
X			break;
X		}
X		rp->r_recver = u.u_procp->p_pid;
X
X		/*
X		 * get the message.
X		 */
X		if (error = rmt_uio(rp, &auio, soreceive)) {
X			debug11("1st: err=%d\n", error);
X			break;
X		}
X#ifndef magnolia
X		rp->r_msg.m_totlen  = ntohl(rp->r_msg.m_totlen);
X		rp->r_msg.m_hdlen   = ntohs(rp->r_msg.m_hdlen);
X		rp->r_msg.m_pid     = ntohs(rp->r_msg.m_pid);
X		rp->r_msg.m_uid     = ntohs(rp->r_msg.m_uid);
X		rp->r_msg.m_errno = ntohs(rp->r_msg.m_errno);
X		rp->r_msg.m_args[ R_RETVAL ]
X			    = ntohl(rp->r_msg.m_args[ R_RETVAL ]);
X#endif
X		msglen = rp->r_msg.m_hdlen;
X		if (msglen > R_MAXRMSG
X		 || msglen < R_MINRMSG+sizeof(long)
X		 || auio.uio_offset < R_MINRMSG+sizeof(long)) {
X			debug11("msg len=%d, off=%d!\n",
X				msglen, auio.uio_offset);
X			error = ECONNABORTED;
X			break;
X		}
X
X		/*
X		 * We may need a few more bytes.
X		 */
X		if (msglen > R_MINRMSG + sizeof(long)) {
X			iov.iov_len = auio.uio_resid =
X				msglen - auio.uio_offset;
X			auio.uio_iov = &iov;
X			auio.uio_iovcnt = 1;
X			debug10("getmsg2: resid=%d... cc=%d\n",
X				auio.uio_resid, so->so_rcv.sb_cc);
X			if (error = rmt_uio(rp, &auio, soreceive)) {
X				debug11("2nd: err=%d, resid=%d, msglen=%d\n",	
X					error, auio.uio_resid, msglen);
X				break;
X			}
X		}
X
X		/*
X		 * Now find the right recipient.
X		 */
X		rp->r_received = TRUE;
X		rp->r_recver = rp->r_msg.m_pid;
X		if (rp->r_recver == u.u_procp->p_pid)
X			break;
X		if (rp->r_recver >= 0 && (p = pfind(rp->r_recver))) {
X			debug11("%d: msg for %d@%x\n",
X				u.u_procp->p_pid, rp->r_recver, p->p_wchan);
X			if (p->p_wchan == (caddr_t)&rp->r_recver)
X				setrun(p);
X			continue;
X		}
X		else
X			debug11("proc %d?\n", rp->r_recver);
X		flushmsg(rp, rp->r_msg.m_totlen - rp->r_msg.m_hdlen, TRUE);
X	}
X
X	/*
X	 * Wrap up and decide if everything is still kosher...
X	 */
X	if (rp->r_close || error || auio.uio_resid) {
X		debug11("%d: getmsg: close=%s,err=%d,resid=%d\n",
X			u.u_procp->p_pid, rp->r_close ? "true" : "false",
X			error, auio.uio_resid);
X		rp->r_close = TRUE;
X		rmt_shutdown(system);
X		error = ECONNABORTED;
X	}
X	return(error);
X}
X
Xflushmsg(rp, len, input)
X	register struct remoteinfo	*rp;
X	register long	len, input;
X{
X	register struct socket *so = rp->r_sock;
X	register long	error = 0, need;
X	struct uio	auio;
X	struct iovec	iov;
X	char	buf[ MLEN ];
X	extern long	sosend(), soreceive();
X	func		ioroutine = (input ? soreceive : sosend);
X
X	debug11("flush %d %s bytes\n", len, input ? "input" : "output");
X	auio.uio_segflg = 1;	/* kernel bcopy */
X	while (len > 0 && ! error) {
X		need = iov.iov_len = auio.uio_resid = MIN(len, MLEN);
X		auio.uio_iov = &iov;
X		auio.uio_iovcnt = 1;
X		iov.iov_base = (caddr_t)buf;
X		debug11("flush: resid=%d... cc=%d\n",
X			auio.uio_resid, so->so_rcv.sb_cc);
X		error = rmt_uio(rp, &auio, ioroutine);
X		len -= need - auio.uio_resid;
X	}
X	if (error)
X		rp->r_close = TRUE;
X	if (input) {
X		rp->r_recver = -1;
X		rp->r_received = FALSE;
X		wakeup((caddr_t)&rp->r_recver);
X	}
X	else {
X		rp->r_sender = -1;
X		ioroutine = sosend;
X		wakeup((caddr_t)&rp->r_sender);
X	}
X	debug11("flush: error=%d\n", error);
X}
X
Xrmt_shutdown(system)
X	register int	system;
X{
X	register struct remoteinfo *rp = remote_info + system;
X	register struct proc	*p;
X
X	wakeup((caddr_t)&rp->r_sender);
X	wakeup((caddr_t)&rp->r_recver);
X	if (rp->r_recver >= 0 && (p = pfind(rp->r_recver)) && p->p_wchan) {
X		debug12("wake rder %d\n", p->p_pid);
X		wakeup((caddr_t)p->p_wchan);
X	}
X	if (rp->r_sender >= 0 && (p = pfind(rp->r_sender)) && p->p_wchan) {
X		debug12("wake wrter %d\n", p->p_pid);
X		wakeup((caddr_t)p->p_wchan);
X	}
X	debug12("shtdwn: ref=%d, reason=", rp->r_refcnt);
X	if (rp->r_close || (rp->r_sock->so_state & SS_CANTRCVMORE))
X		debug12("%s\n",
X			(rp->r_sock->so_state & SS_CANTRCVMORE)
X			? "no more" : "closed");
X	else {
X		debug12("?, not done\n");
X		return(EBUSY);
X	}
X	rp->r_close = TRUE;
X	if (rp->r_refcnt || rp->r_users)
X		return(EBUSY);
X	rmt_closehost(rp);
X	return(0);
X}
X
X/*
X * Close a host connection.
X */
Xrmt_closehost(rp)
X	register struct remoteinfo	*rp;
X{
X	struct socket	*so;
X
X	so = rp->r_sock;
X	rp->r_recver = rp->r_sender = -1;
X	rp->r_sock = NULL;
X	rp->r_age = time.tv_sec;
X	rp->r_close = 0;
X	if (so)
X		soclose(so);
X	else
X		debug12("rmt_closehost: so == 0, rp=%x\n", rp);
X}
X
Xsendrsig(system)
X	register int	system;
X{
X	debug11("would have sent sig to system %d\n", system);
X}
SHAREOF
chmod 444 remote/usr.sys.remote/rmt_io.c
#
# remote/usr.sys.remote/rmt_subr.c
#
if [ -f remote/usr.sys.remote/rmt_subr.c ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.remote/rmt_subr.c or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.remote/rmt_subr.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.remote/rmt_subr.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 * $Header: rmt_subr.c,v 2.0 85/12/07 18:19:10 toddb Rel $
X *
X * $Log:	rmt_subr.c,v $
X * Revision 2.0  85/12/07  18:19:10  toddb
X * First public release.
X * 
X */
X#include	"../h/param.h"
X#ifndef pyr	/* Pyramid */
X#include	"../machine/pte.h"
X#endif
X#include	"../h/systm.h"
X#include	"../h/map.h"
X#include	"../h/dir.h"
X#include	"../h/user.h"
X#include	"../h/proc.h"
X#ifdef BSD4_3
X#include	"../h/namei.h"
X#else BSD4_3
X#include	"../h/nami.h"
X#endif BSD4_3
X#include	"../h/inode.h"
X#include	"../h/mbuf.h"
X#include	"../h/socket.h"
X#include	"../remote/remotefs.h"
X#include	"../h/errno.h"
X#include	"../netinet/in.h"
X#include	"../h/file.h"
X
Xextern struct remoteinfo remote_info[];
Xextern struct remoteinfo *remote_generic;
Xextern struct nameserver	remote_ns;
X
X/*
X * A fast routine for determining whether an inode is in the list of
X * remote hosts, and returning a pointer into that list.
X * Failure returns NULL.
X */
Xstruct remoteinfo *rmt_host(ip, asysnum)
X	register struct inode	*ip;
X	register long		*asysnum;
X{
X	register struct remoteinfo	*rp = remote_info;
X	register long			i;
X	
X	if (ip == NULL)
X		printf("rmt_host: ip=0\n");
X	else for(i=0; i < R_MAXSYS; i++, rp++)
X		if (rp->r_mntpt == ip) {
X			*asysnum = i;
X			return(rp);
X		}
X	return(NULL);
X}
X
X/*
X * This is an extension to rmt_host() in that if rmt_host() returns a
X * pointer to a generic mount point, we return the pointer to the entry
X * that describes where we have our current working directory.
X */
Xstruct remoteinfo *rmt_hostdir(ip, asysnum)
X	register struct inode	*ip;
X	register long		*asysnum;
X{
X	register struct remoteinfo *rp;
X
X	rp = rmt_host(ip, asysnum);
X	if (rp == NULL)
X		return(NULL);
X	if (rp->r_name == NULL)
X		if (u.u_rmtcdir < 0)
X			return(rp);
X		else
X			return(remote_info + (*asysnum = u.u_rmtcdir));
X	return(rp);
X}
X
X/*
X * called by isremote() to figure out if there is a host implied by
X * 'path'.  Note that a user process must have ``registered'' with
X * the kernel as being willing to provide name service.
X */
Xstruct remoteinfo *rmt_findhost(apath, asysnum)
X	char	**apath;
X	register long	*asysnum;
X{
X	label_t				qsave;
X	register struct remoteinfo	*rp;
X	char				savec;
X	struct remoteinfo		*rmt_findaddr(),
X					*rmt_findslot();
X	register struct proc		*p;
X	register char			*path = *apath, *cp;
X	register struct mbuf		*m = NULL;
X	register long			error = 0,
X					i;
X
X	/*
X	 * If the path is relative, then it must be because we have done
X	 * a remote chdir()... take the directory from there.
X	 */
X	if (*path != '/' && u.u_rmtcdir >= 0) {
X		debug13("path %s==>cwd=#%d\n", path, u.u_rmtcdir);
X		*asysnum = u.u_rmtcdir;
X		return (remote_info + u.u_rmtcdir);
X	}
X
X	/*
X	 * First try to satisfy the name from the existing table... there
X	 * may have been a mount done explicitly that has the form
X	 * "/hostname", or there may have been an implicit mount.  Check
X	 * for both.
X	 */
X	rp = remote_info;
X	for(i=0; i < R_MAXSYS; i++, rp++)
X		if (rp->r_name && rmt_pathimplies(rp, apath)) {
X			debug13("%s==>mntpt=%s(#%d)\n",
X				*apath, rp->r_mntpath, i);
X			*asysnum = i;
X			return(rp);
X		}
X
X	/*
X	 * If that fails, then give the name server a crack at it.  Note that
X	 * we don't check to see if we found an open slot, because the address
X	 * that we get back may match an existing address.
X	 * If the nameserver is around, send him a signal.  Then wait
X	 * patiently for the response.
X	 */
X	while (remote_ns.rn_path) /* Lock out all other nameserver action */
X		sleep((caddr_t)&remote_ns.rn_path, PZERO+1);
X
X	bcopy(&u.u_qsave, &qsave, sizeof(label_t));
X	if (setjmp(&u.u_qsave)) {
X		error = EINTR;
X		goto out;
X	}
X
X	/*
X	 * The nameserver only needs the first component.
X	 */
X	cp = path;
X	while (*cp == '/')
X		cp++;
X	while (*cp && *cp != '/')
X		cp++;
X	savec = *cp;
X	*cp = '\0';
X	remote_ns.rn_pathlen = cp - path + 1;
X	remote_ns.rn_path = path;
X	p = remote_ns.rn_proc;
X	if (server_alive(p)) {
X		psignal(p, SIGURG);
X		sleep((caddr_t)&remote_ns.rn_name, PZERO+1);
X	}
X	*cp = savec;
X
X	/*
X	 * Ok, now see what the server had to say...
X	 */
X	m = remote_ns.rn_name;
X	remote_ns.rn_name = NULL;
X	if (m == NULL)
X		error = EADDRNOTAVAIL;
X	else {
X		rp = rmt_findaddr(m, asysnum);
X		*apath = cp;
X	}
X	if (rp || m == NULL)
X		goto out;
X
X	if ((rp = rmt_findslot(asysnum)) == NULL)
X		error = ETOOMANYREMOTE;
X	else {
X		if (rp->r_name) {
X			debug13("findhost: reusing %d, %s\n",
X				asysnum, rp->r_mntpath);
X			(void) m_free(rp->r_name);
X		}
X		rp->r_name = m;
X		bcopy (mtod(m, caddr_t) + m->m_len, rp->r_mntpath,
X			MIN(R_MNTPATHLEN, MLEN - m->m_len));
X		m = NULL;
X	}
X
Xout:
X	if (remote_ns.rn_name)
X		(void) m_free(remote_ns.rn_name);
X	else if (m)
X		(void) m_free(m);
X	remote_ns.rn_name = NULL;
X	remote_ns.rn_path = NULL;
X	wakeup((caddr_t)&remote_ns.rn_path);
X	if (error) {
X		rp = NULL;
X		u.u_error = error;
X	}
X
X	/*
X	 * Since we are returning and may sleep again, we must restore the
X	 * setjmp info so that we don't kill ourselves.
X	 */
X	bcopy(&qsave, &u.u_qsave, sizeof(label_t));
X	return (rp);
X}
X
X/*
X * if (index >= 0) i.e. valid remote host
X *	Set the working directory to the mount point for system 'index'.
X *	This, along with what the server does, will effect a chdir("remotedir");
X * if (index < 0)
X *	then simply decrement the number of chdir's on the current remote
X *	host, if any.
X */
Xremotechdir(index)
X	long	index;
X{
X	register struct inode *ip = NULL, *oip;
X	register struct remoteinfo	*rp;
X	register long			error = 0;
X	long				i;
X	struct remoteinfo		*rmt_host();
X
X	debug14("cd #%d\n", index);
X	if (index >= R_MAXSYS)
X		return(ENOENT);
X	/*
X	 * If we are currently cd'ed to another remote host, decrement its'
X	 * reference count.
X	 */
X	oip = u.u_cdir;
X	if (rp = rmt_hostdir(oip, &i)) {
X		debug14("uncd #%d, ip=%x\n", i, oip);
X		rp->r_nchdir--;
X	}
X	rp = remote_info + index;
X	if (index >= 0) {
X		/*
X		 * If this is an implied mount point, find the inode for the
X		 * generic mount pt.
X		 */
X		if (rp->r_mntpt == NULL) {
X			if (remote_generic)
X				ip = remote_generic->r_mntpt; 
X			debug14("cd is generic, ip=%x\n", ip);
X			if (ip == NULL)
X				return(ENOENT);
X		}
X		else
X			ip = rp->r_mntpt;
X		rp->r_nchdir++;		/* bump the reference count */
X		u.u_rmtcdir = index;
X		irele(oip);
X		ip->i_count++;
X		u.u_cdir = ip;
X	}
X
X	return(error);
X}
X
X/*
X * See if a host is implied in a remote_info entry from the path name 'path'.
X */
Xrmt_pathimplies(rp, path)
X	register struct remoteinfo	*rp;
X	register char			**path;
X{
X	register char	*p1, *p2, *pend;
X
X	p1 = rp->r_mntpath;
X	while(*p1 == '/')
X		p1++;
X	p2 = *path;
X	while(*p2 == '/')
X		p2++;
X
X	/*
X	 * Compare against the mount point.
X	 */
X	pend = rp->r_mntpath + R_MNTPATHLEN;
X	while (*p1 == *p2 && *p1 && p1 < pend)
X		p1++, p2++;
X	if (*p1 == *p2 || (*p1 == '\0' && *p2 == '/')) {
X		*path = p2;
X		return(TRUE);
X	}
X
X	return (FALSE);
X}
X
X/*
X * See if any remote entry already had address 'addr'.
X */
Xstruct remoteinfo *rmt_findaddr(m, asysnum)
X	register struct mbuf	*m;
X	register long		*asysnum;
X{
X	register struct remoteinfo	*rp;
X	register caddr_t		addr;
X	register int			i, len;
X
X	addr = mtod(m, caddr_t);
X	len = m->m_len;
X	for (i=0, rp = remote_info; i < R_MAXSYS; i++, rp++)
X		if (rp->r_name
X		&& len == rp->r_name->m_len
X		&& bcmp(rp->r_name, addr, len) == 0) {
X			*asysnum = i;
X			debug13("%s: same as mnt %d\n", addr+len, i);
X			return(rp);
X		}
X	return(NULL);
X}
X
X/*
X * Find an open slot in the remote info.
X */
Xstruct remoteinfo *rmt_findslot(asysnum)
X	register long	*asysnum;
X{
X	register struct remoteinfo	*rp,
X					*frp = NULL;
X	register int			i, fi;
X
X	for (i=0, rp = remote_info; i < R_MAXSYS; i++, rp++) {
X		if (rp->r_mntpt || rp ->r_sock) /* active connections */
X			continue;
X		if (rp->r_name == NULL) {
X			frp = rp;
X			fi = i;
X			break;
X		}
X		if (frp == NULL || rp->r_age < frp->r_age) {
X			frp = rp;
X			fi = i;
X		}
X	}
X	if (frp) {
X		debug13("slt: %d\n", fi);
X		*asysnum = fi;
X		return(frp);
X	}
X
X	/*
X	 * No slot... do garbage collection.
X	 */
X	for (i=0, rp = remote_info; i < R_MAXSYS; i++, rp++)
X		if (rp->r_mntpt == NULL
X		 && rp->r_nchdir == 0 && rp->r_nfile == 0) {
X			debug13("fndslt: usurp %d=%s\n",
X				rp - remote_info, rp->r_mntpath);
X			*asysnum = i;
X			rmt_closehost(rp);
X			(void) m_free(rp->r_name);
X			rp->r_name = NULL;
X			return(rp);
X		}
X
X	return(NULL);
X}
SHAREOF
chmod 444 remote/usr.sys.remote/rmt_subr.c
#
# remote/usr.sys.remote/rmt_syscall1.c
#
if [ -f remote/usr.sys.remote/rmt_syscall1.c ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.remote/rmt_syscall1.c or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.remote/rmt_syscall1.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.remote/rmt_syscall1.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 * $Header: rmt_syscall1.c,v 2.0 85/12/07 18:19:21 toddb Rel $
X *
X * $Log:	rmt_syscall1.c,v $
X * Revision 2.0  85/12/07  18:19:21  toddb
X * First public release.
X * 
X */
X#include	"../h/param.h"
X#ifndef pyr	/* Pyramid */
X#include	"../machine/pte.h"
X#endif
X#include	"../h/systm.h"
X#include	"../h/map.h"
X#include	"../h/dir.h"
X#include	"../h/user.h"
X#include	"../h/kernel.h"
X#include	"../h/proc.h"
X#include	"../h/mbuf.h"
X#include	"../h/socket.h"
X#include	"../h/file.h"
X#include	"../remote/remotefs.h"
X#include	"../h/stat.h"
X#include	"../h/errno.h"
X#include	"../netinet/in.h"
X
Xextern struct remoteinfo	remote_info[];
X
X/*
X * Remote access()
X */
Xrmt_access (sysindex, m)
X	int	sysindex;
X	struct mbuf	*m;
X{
X	struct message	*msg = mtod(m, struct message *);
X	struct a {
X		char	*path;
X		long	mode;
X	} *uap = (struct a *)u.u_ap;
X
X	msg->m_args[ 0 ] = htonl(uap->mode);
X	
X	/*
X	 * Now send it.
X	 */
X	return( rmt_msgfin(sysindex, m, 0) );
X}
X
X/*
X * Remote chdir()
X */
Xrmt_chdir (sysindex, m)
X	int	sysindex;
X	struct mbuf	*m;
X{
X	int	error;
X
X	/*
X	 * Now send it.
X	 */
X	if ((error = rmt_msgfin(sysindex, m, 0)) == 0)
X		error = remotechdir(sysindex);
X
X	return( error );
X}
X
X/*
X * Remote chmod() and fchmod()
X */
Xrmt_chmod (sysindex, m)
X	int	sysindex;
X	struct mbuf	*m;
X{
X	int	i = 0;
X	struct message *msg = mtod(m, struct message *);
X	struct a {
X		long	path_or_fd;
X		long	mode;
X	} *uap = (struct a *)u.u_ap;
X
X	if (htons(msg->m_syscall) == RSYS_fchmod)
X		i++;
X	msg->m_args[ i ] = htonl(uap->mode);
X	/*
X	 * Now send it.
X	 */
X	return( rmt_msgfin(sysindex, m, 0) );
X}
X
X/*
X * Remote chown() and fchown()
X */
Xrmt_chown (sysindex, m)
X	int	sysindex;
X	struct mbuf	*m;
X{
X	int	i = 0;
X	struct message *msg = mtod(m, struct message *);
X	struct a {
X		long	path_or_fd;
X		long	owner, group;
X	} *uap = (struct a *)u.u_ap;
X
X	if (htons(msg->m_syscall) == RSYS_fchown)
X		i++, m->m_len = R_MINRMSG + 3*sizeof(long);
X	msg->m_args[ i++ ] = htonl(uap->owner);
X	msg->m_args[ i ] = htonl(uap->group);
X	/*
X	 * Now send it.
X	 */
X	return( rmt_msgfin(sysindex, m, 0) );
X}
X
X/*
X * Remote dup()
X */
Xrmt_dup (sysindex, m)
X	long	sysindex;
X	struct mbuf	*m;
X{
X	int	fd, error;
X	struct message *msg = mtod(m, struct message *);
X	struct file	*fp;
X	struct a {
X		long	fd;
X	} *uap = (struct a *)u.u_ap;
X
X	fp = u.u_ofile[ uap->fd ];
X	fd = ufalloc(0);
X	if (fd < 0)
X		return(-1);
X	remote_info[ (int)fp->f_data ].r_nfile++;
X	dupit(fd, fp, u.u_pofile[uap->fd]);
X	msg->m_args[ 1 ] = htonl(fd);
X
X	/*
X	 * Now send it.
X	 */
X	error = rmt_msgfin(sysindex, m, 0);
X	if (error)
X		rmt_deallocfd(fd);
X	return(error);
X}
X
X/*
X * Remote dup2()
X */
Xrmt_dup2 (sysindex, m)
X	long	sysindex;
X	struct mbuf	*m;
X{
X	struct message *msg = mtod(m, struct message *);
X	struct file	*oldfp, *newfp;
X	struct a {
X		long	oldfd,
X			newfd;
X	} *uap = (struct a *)u.u_ap;
X	long	oldfd = uap->oldfd,
X		newfd = uap->newfd,
X		error;
X
X	oldfp = u.u_ofile[ oldfd ];
X	if (newfd >= NOFILE)
X		return(EBADF);
X	if (oldfd == newfd)
X		return(newfd);
X	if (newfp = u.u_ofile[ newfd ]) {
X		/*
X		 * If the new file descriptor (which must be closed) is
X		 * remote on system 'n', then we may have to send a close
X		 * message to system 'n', but only if
X		 *	1. the file descriptor being duped is non-remote
X		 *		or
X		 *	2. the file descriptor being duped is on a different
X		 *	   remote system.
X		 * Note that case number 1 implies that there is no more
X		 * remote work to be done.
X		 */
X		if (newfp->f_flag & FREMOTE) {
X			if ((oldfp->f_flag & FREMOTE) == 0
X			 || newfp->f_data != oldfp->f_data) {
X				if ((oldfp->f_flag & FREMOTE) == 0)
X					sysindex = -1;
X				uap->oldfd = uap->newfd;
X				remote_fd(RSYS_close);
X			}
X			else
X				closef(newfp);
X		}
X		else
X			closef(newfp);
X	}
X	dupit(newfd, oldfp, u.u_pofile[ oldfd ]);
X
X	/*
X	 * We may already be done.
X	 */
X	if (sysindex < 0)
X		return(0);
X	
X	/*
X	 * Now send it.
X	 */
X	remote_info[ sysindex ].r_nfile++;
X	msg->m_args[ 1 ] = htonl(newfd);
X	error = rmt_msgfin(sysindex, m, 0);
X	if (error)
X		rmt_deallocfd(newfd);
X
X	return(error);
X}
X
X/*
X * routine for handling an error.  We should never get here... but if we
X * do.....
X */
Xrmt_error(sysnum)
X	int	sysnum;
X{
X	debug1("error reached\n");
X	return(EINVAL);
X}
SHAREOF
chmod 444 remote/usr.sys.remote/rmt_syscall1.c
#
# remote/usr.sys.remote/rmt_syscall2.c
#
if [ -f remote/usr.sys.remote/rmt_syscall2.c ]; then 
	echo -n 'Hit <return> to overwrite remote/usr.sys.remote/rmt_syscall2.c or ^C to quit' 
	read ans 
	rm -f remote/usr.sys.remote/rmt_syscall2.c 
fi 
 
sed -e 's/^.//' << \SHAREOF > remote/usr.sys.remote/rmt_syscall2.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 * $Header: rmt_syscall2.c,v 2.0 85/12/07 18:19:28 toddb Rel $
X *
X * $Log:	rmt_syscall2.c,v $
X * Revision 2.0  85/12/07  18:19:28  toddb
X * First public release.
X * 
X */
X#include	"../h/param.h"
X#ifndef pyr	/* Pyramid */
X#include	"../machine/pte.h"
X#endif
X#include	"../h/systm.h"
X#include	"../h/map.h"
X#include	"../h/dir.h"
X#include	"../h/user.h"
X#include	"../h/kernel.h"
X#include	"../h/proc.h"
X#include	"../h/mbuf.h"
X#include	"../h/socket.h"
X#include	"../remote/remotefs.h"
X#include	"../h/file.h"
X#include	"../h/stat.h"
X#include	"../h/errno.h"
X#include	"../netinet/in.h"
X#include	"../h/uio.h"
X
Xextern struct remoteinfo	remote_info[];
Xextern syscalls			remote_syscall[];
X
X/*
X * Remote fcntl()
X */
X
Xrmt_fcntl (sysindex, m)
X	int	sysindex;
X	struct mbuf	*m;
X{
X	register long		fd,
X				error;
X	register struct message *msg = mtod(m, struct message *);
X	register struct a {
X		long	fd,
X			command,
X			arg;
X	} *uap = (struct a *)u.u_ap;
X	register struct file	*fp;
X
X	if (uap->command == F_DUPFD) {
X		fp = u.u_ofile[ uap->fd ];
X		fd = ufalloc(uap->arg);
X		if (fd < 0)
X			return(-1);
X		remote_info[ (int)fp->f_data ].r_nfile++;
X		dupit(fd, fp, u.u_pofile[uap->fd]);
X		msg->m_args[ 1 ] = htonl(fd);
X		msg->m_syscall = htons(RSYS_dup);
X	}
X	else {
X		msg->m_args[ 1 ] = htonl(uap->command);
X		msg->m_args[ 2 ] = htonl(uap->arg);
X		m->m_len += sizeof(long);
X	}
X
X	/*
X	 * Now send it
X	 */
X	error = rmt_msgfin(sysindex, m, 0);
X	if (error && uap->command == F_DUPFD)
X		rmt_deallocfd(fd);
X
X	return(error);
X}
X
X/*
X * Remote flock()
X */
Xrmt_flock (sysindex, m)
X	int	sysindex;
X	struct mbuf	*m;
X{
X	struct message *msg = mtod(m, struct message *);
X	struct a {
X		long	fd;
X		long	operation;
X	} *uap = (struct a *)u.u_ap;
X
X	msg->m_args[ 1 ] = htonl(uap->operation);
X	/*
X	 * Now send it.
X	 */
X	return( rmt_msgfin(sysindex, m, 0) );
X}
X
X/*
X * Remote ioctl()
X */
X
Xrmt_ioctl (sysindex, m, request, argp)
X	int	sysindex,
X		request;
X	struct mbuf	*m;
X	char	*argp;
X{
X
X	/*
X	 * for now always fail.
X	 */
X	return(EINVAL);
X}
X
X/*
X * Remote lseek()
X */
Xrmt_lseek (sysindex, m)
X	long	sysindex;
X	struct mbuf	*m;
X{
X	struct message	*msg = mtod(m, struct message *);
X	struct a {
X		long	fd,
X			offset,
X			whence;
X	} *uap = (struct a *)u.u_ap;
X	register long	flags = RFLG_INFO;
X	register long	twhence = uap->whence;
X	register long	error;
X	register struct file	*fp = u.u_ofile[ uap->fd ];
X
X	/*
X	 * As a special case for the sake of speed, L_INCR and L_SET can be
X	 * done locally and then the message can be sent as
X	 * info only (no reply).
X	 */
X	switch (twhence) {
X	case L_INCR:
X		/*
X		 * Very special case: lseek(fd, 0, L_INCR) is a noop.
X		 */
X		if (uap->offset == 0) {
X			m_free(m);
X			u.u_r.r_off = fp->f_offset;
X			return(0);
X		}
X		fp->f_offset += uap->offset;
X		break;
X	case L_XTND:
X		flags = 0;
X		break;
X	case L_SET:
X		fp->f_offset = uap->offset;
X		break;
X	default:
X		m_free(m);
X		u.u_error = EINVAL;
X		return(0);
X	}
X	msg->m_args[ 1 ] = htonl(uap->offset);
X	msg->m_args[ 2 ] = htonl(twhence);
X	m->m_len += sizeof(long);
X	if (flags == RFLG_INFO)
X		msg->m_syscall = htons(RSYS_qlseek);
X
X	/*
X	 * Now send it.
X	 */
X	error = rmt_msgfin(sysindex, m, flags);
X	if (flags != RFLG_INFO)
X		fp->f_offset = u.u_r.r_val1;
X	else
X		u.u_r.r_off = fp->f_offset;
X	return( error );
X}
X
X/*
X * Remote mknod()
X */
Xrmt_mknod (sysindex, m, mode, dev)
X	long	sysindex,
X		mode, dev;
X	struct mbuf	*m;
X{
X	struct message	*msg = mtod(m, struct message *);
X	struct a {
X		char	*path;
X		long	mode,
X			dev;
X	} *uap = (struct a *)u.u_ap;
X
X	msg->m_args[ 0 ] = htonl(uap->mode);
X	msg->m_args[ 1 ] = htonl(uap->dev);
X	msg->m_args[ 2 ] = htonl(u.u_cmask);
X
X	/*
X	 * Now send it.
X	 */
X	return( rmt_msgfin(sysindex, m, 0) );
X}
X
Xrmt_noop() {	return;	}
X
X/*
X * Remote mkdir() and rmdir() and unlink() and fsync() and close()
X */
Xrmt_onearg (sysindex, m)
X	int	sysindex;
X	struct mbuf	*m;
X{
X	struct message	*msg = mtod(m, struct message *);
X	short	syscall = ntohs(msg->m_syscall);
X	long	error;
X
X	if (syscall == RSYS_close) {
X		struct a {
X			long	fd;
X		} *uap = (struct a *)u.u_ap;
X		rmt_deallocfd(uap->fd);
X		m->m_len = R_MINRMSG + sizeof(long);
X	}
X	else if (syscall == RSYS_fsync)
X		m->m_len = R_MINRMSG + sizeof(long);
X	else
X		msg->m_args[ 0 ] = htonl(u.u_cmask);
X
X	error = rmt_msgfin(sysindex, m, remote_syscall[ syscall ].sys_flag);
X	return(error);
X}
SHAREOF
chmod 444 remote/usr.sys.remote/rmt_syscall2.c