RFS: remote file system (part 3 of 7)

sources-request at panda.UUCP sources-request at panda.UUCP
Thu Jan 9 07:45:16 AEST 1986


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



More information about the Mod.sources mailing list