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