sources-request@panda.UUCP (01/08/86)
Mod.sources: Volume 3, Issue 77 Submitted by: genrad!masscomp!tektronix!tekcrl!toddb Subject: RFS: a Kernel-resident remote file system RFS release 2.0+ (plus more fixes, easy installation w/ patch, etc.) These seven shar files contain the software and documentation for installation, maintenance and adjustment of RFS, a public domain, kernel-resident distributed file system, written at Tektronix Computer Research Laboratories* by me for partial fulfillment of the master's degree program at the University of Denver. It was designed to provide complete transparency with respect to file access and protections for all programs whether they use local or remote files and directories. It has been installed on VAX BSD 4.2 and 4.3 UNIX, Pyramid 4.2/5.0 UNIX, version 2.5, and on a Tektronix internal proprietary workstation, called Magnolia. The instructions are designed in a way that keeps all changes separate from your standard sources, in hope that it will encourage sites to try the installation. Todd Brunhoff toddb%crl@tektronix.csnet decvax!tektronix!crl!toddb * RFS should not be confused with another completely different (but excellent) implementation from Tektronix available on the 6000 series workstation, called DFS, and done by a separate product group. The work on RFS was designed and written strictly by the author of this paper at about the same time as DFS, and draws none of its implementation details from DFS. RFS is public domain, while DFS is proprietary. #!/bin/sh # # RFS, a kernel-resident remote file system. Shar 1 of 7 # # # This is a shell archive, meaning: # 1. Remove everything above the #!/bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # remote/README # remote/byteorder.c # remote/change.c # remote/debug.c # remote/doc # remote/doc/install.ms # remote/doc/paper # remote/doc/paper/Makefile # remote/doc/paper/appendixB # remote/doc/paper/fig1 # remote/doc/paper/fig1.mag # remote/doc/paper/fig4 # remote/doc/paper/fig5 # remote/doc/paper/fig6 mkdir remote # # remote/README # if [ -f remote/README ]; then echo -n 'Hit <return> to overwrite remote/README or ^C to quit' read ans rm -f remote/README fi sed -e 's/^.//' << \SHAREOF > remote/README XStart with running off the following documents in the doc directory: X X install.ms (standard Berkeley ms macros) X remotename.2 \ X remoteon.2 \ (standard Berkeley man macros) X rfs_server.8 / X rmtmnt.8 / X XThe directory doc/paper, contains a paper that contains most of the early Xdesign considerations for RFS, but is written using some TEK-internal Xms macros. X XRead the install.ms document first. SHAREOF chmod 664 remote/README # # remote/byteorder.c # if [ -f remote/byteorder.c ]; then echo -n 'Hit <return> to overwrite remote/byteorder.c or ^C to quit' read ans rm -f remote/byteorder.c fi sed -e 's/^.//' << \SHAREOF > remote/byteorder.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: byteorder.c,v $ X * Revision 2.0 85/12/07 18:20:50 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: byteorder.c,v 2.0 85/12/07 18:20:50 toddb Rel $"; Xlong data = 0x03020100; X Xmain() X{ X char *p = (char *)&data; X X printf("bytes order=%d,%d,%d,%d\n", p[0],p[1],p[2],p[3]); X} SHAREOF chmod 444 remote/byteorder.c # # remote/change.c # if [ -f remote/change.c ]; then echo -n 'Hit <return> to overwrite remote/change.c or ^C to quit' read ans rm -f remote/change.c fi sed -e 's/^.//' << \SHAREOF > remote/change.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: change.c,v $ X * Revision 2.0 85/12/07 18:20:57 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: change.c,v 2.0 85/12/07 18:20:57 toddb Rel $"; X#include "server.h" X#include <stdio.h> X#include <sys/time.h> X Xextern short current_uid; Xextern short current_pid; Xextern short current_umask; Xextern short current_server; Xextern short gateway_server; Xextern long fds_in_use; Xextern long to_gateway; Xextern long from_servers; Xextern boolean i_am_gateway; Xextern boolean i_have_control; Xextern process *wildcard; Xextern syscallmap smap[]; Xextern hosts *host; X X/* X * Given the user id # and the process id # in the message, we look up the X * process (or allocate a new one). If there are things to be accomplished X * before the system call is performed, do them here. X */ Xprocess *change_to_proc(msg) X register struct message *msg; X{ X register rusers *ruser; X register process *proc = NULL; X register char *p; X register long syscall = msg->m_syscall, X syscalltype = smap[ syscall ].s_type; X X /* X * First, we check to see that the file is not really a local file X * for the client. A simple example of this is a pathname of '..' X * while sitting in our root directory. If it is local, islocal() X * will compose a message and send it. We simply return. X * X * Even if this is handled by another server, we may be able to serve X * the request; but only if: X * 1. it is a system call using a path (NEED_CWD). X * 2. The path is starts with a '/'. X * 3. The system call does not generate a new file descriptor X * (like open). X * 4. This is not chdir(). X * The system calls that fall in this category, are stat, lstat, X * rename, unlink, symlink, readlink, etc. X * If the system call does not match these criterion, then we must X * reroute it. X */ X X proc = findprocess(msg->m_pid, msg->m_uid); X if (syscalltype & NEED_CWD) { X if (proc X && proc->p_handler == current_pid X && islocal(msg, syscalltype)) X return(NULL); X if ((syscalltype & NEED_MYSERVER) == 0) X { X if (syscalltype & NEED_2PATH) X p = twopath2addr(msg); X else X p = path1addr(msg); X if (*p == '/') X { X setup_proc(proc = wildcard, X msg->m_uid, msg->m_pid); X debug0("using wildcard proc... "); X } X } X } X X /* X * A fork() (but not vfork()) generates two messages, one X * from parent, one from the child. If we know about it (no X * matter if we are the server for the parent, the child or if X * we are the gateway), then we already have received the X * first notification. Don't do a reroute for that, just X * handle it locally (its redundant info). If we don't know X * about it, then this is the first anyone has heard of it, X * so we use args[1] which is the parent pid of X * the fork (in both messages). X */ X if (proc == NULL && (syscall == RSYS_fork || syscall == RSYS_vfork)) X proc = findprocess(msg->m_args[ 1 ], msg->m_uid); X X if (proc == NULL) X { X /* X * If we are the gateway, and don't know about this process, X * and it is an exit() call, then just ignore it; cause if we X * don't know this guy, nobody does. Otherwise, X * allocate a new slot for it. X */ X if (i_am_gateway) X { X if (syscall == RSYS_exit) X { X debug0("discard exit call for pid %d\n", X msg->m_pid); X return(NULL); X } X else X proc = add_new_process(msg->m_uid, msg->m_pid); X } X /* X * If we are'nt the gateway, then hand this request back to X * the gateway. Maybe he will know where to send the request. X */ X else X { X reroute(gateway_server, msg); X return(NULL); X } X } X /* X * And if we just happen to know about this process (whether we X * are the gateway or not), then just reroute it. X */ X else if (proc->p_handler != current_pid) X { X reroute(proc->p_handler, msg); X if (syscall == RSYS_exit && !i_am_gateway) X { X deletelist(&host->h_proclist, proc); X freeproc(proc); X } X return(NULL); X } X X /* X * At this point, the request is for us, and there is definitely X * no mistake. X */ X if ((syscalltype & NEED_FD) || syscall == RSYS_chdir) X { X debug3("%d current file descriptors\n", fds_in_use); X /* X * Here is where we reroute the opening of a file X * or a chdir() to another server. X */ X if (need_to_fork()) X if (! become_server(msg)) X return(NULL); X } X X if (syscalltype & NEED_PERM) X change_to_user( proc->p_ruser->r_user ); X X debug1("pid %d: ", proc->p_pid); X return(proc); X} X X/* X * change the current user id to 'uid'. X * This is done with simply a setreuid X */ Xchange_to_user(user) X register users *user; X{ X#ifdef RFSDEBUG X long gids[ NGROUPS ], ngids, i; X#endif RFSDEBUG X X if (current_uid != user->u_local_uid) X { X debug2("set uid to %s(%d)\n", X user->u_name, user->u_local_uid); X change_to_uid(0); X if (setgroups(user->u_numgroups, user->u_local_groups) < 0) X { X register long i; X X log("cannot set gids\n"); X for (i=1; i<user->u_numgroups; i++) X log(",%d", user->u_local_groups[i]); X return(FALSE); X } X change_to_uid(user->u_local_uid); X } X else X debug2("already at uid %d (uid=%d/%d)\n", X current_uid, getuid(), geteuid()); X#ifdef RFSDEBUG X if (remote_debug & 0x4) X { X log("%d gids should be", user->u_numgroups); X for (i=0; i<user->u_numgroups; i++) X log(" %d", user->u_local_groups[i]); X ngids = getgroups(NGROUPS, gids); X log("\n%d gids are=", ngids); X for (i=0; i<ngids; i++) X log(" %d", gids[i]); X log("\n"); X } X#endif RFSDEBUG X return (TRUE); X} X X/* X * Change to uid 'uid'. X */ Xchange_to_uid(uid) X register long uid; X{ X if (current_uid != uid) X if (setreuid(0, uid) < 0) X log("cannot set uid to %d\n", uid); X else X { X current_uid = uid; X debug2("uid now %d/%d\n", getuid(), geteuid()); X } X} X X/* X * Change to umask 'mask'. X */ Xchange_to_umask(mask) X register long mask; X{ X register long oldmask; X X if (mask != current_umask) X { X oldmask = umask(current_umask = mask); X debug2("umask now 0%o, was 0%o\n", current_umask, oldmask); X } X} X X/* X * check to see if we need to fork. We do this for two reasons: X * 1. we are the gateway server. X * 2. we are currently handling other processes (a chdir might mess X * them up). X * Note that we only have to ask ourselves "do we need to fork" when we are X * opening a new file, accepting a new process (the client is doing a fork() X * or vfork()), or changing directory. X */ Xneed_to_fork() X{ X register char *fds; X register process *proc; X register long myprocs = 0; X X if (i_am_gateway) X return(TRUE); X for (proc = host->h_proclist; proc; proc = proc->p_next) X if(proc->p_handler == current_pid) X myprocs++; X return(myprocs > 1); X} SHAREOF chmod 444 remote/change.c # # remote/debug.c # if [ -f remote/debug.c ]; then echo -n 'Hit <return> to overwrite remote/debug.c or ^C to quit' read ans rm -f remote/debug.c fi sed -e 's/^.//' << \SHAREOF > remote/debug.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: debug.c,v $ X * Revision 2.0 85/12/07 18:21:07 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: debug.c,v 2.0 85/12/07 18:21:07 toddb Rel $"; X#include "server.h" X Xmain(argc, argv) X char **argv; X int argc; X{ X int dbg; X X dbg = atox(argv[1]); X printf("set debug to %x\n", dbg); X printf("remotename()=%d\n", remotename(NM_DEBUG, dbg)); X perror("debug"); X} X X/* X * ascii to hex X */ Xatox(buf) X char *buf; X{ X register char *p; X register unsigned num, nibble; X X /* X * now, take it out checking to make sure that the number is X * valid. X */ X if (! buf) X return(0); X for(num=0, p = buf; *p; p++) X { X nibble = *p; X if (nibble >= 'A' && nibble <= 'F') X nibble -= 'A' - 10; X else if (nibble >= 'a' && nibble <= 'f') X nibble -= 'a' - 10; X else if (nibble >= '0' && nibble <= '9') X nibble -= '0'; X else X return(0); X num = (num << 4) | nibble; X } X return(num); X} SHAREOF chmod 444 remote/debug.c # # remote/doc # mkdir remote/doc chmod 775 remote/doc # # remote/doc/install.ms # if [ -f remote/doc/install.ms ]; then echo -n 'Hit <return> to overwrite remote/doc/install.ms or ^C to quit' read ans rm -f remote/doc/install.ms fi sed -e 's/^.//' << \SHAREOF > remote/doc/install.ms X.ds Fi \\u\\s-4\\n+*\\s+4\\d X.TL XInstalling and Operating RFS X.AU XT. Brunhoff Xtoddb%crl@tektronix.csnet Xdecvax!tektronix!crl!toddb X.AI XUniversity of Denver X.AB XThis document describes Xthe installation, maintenance and adjustment Xof RFS, a public domain, kernel\-resident distributed file system, Xwritten at XTektronix Computer Research Laboratories* for partial Xfulfillment of the master's degree program at the University of Denver. XIt was designed to provide complete transparency with Xrespect to file access and protections for all programs Xwhether they use local or remote files and directories. XIt has been installed on VAX BSD 4.2 and 4.3 UNIX, XPyramid 4.2/5.0 UNIX, version 2.5, Xand on a Tektronix internal proprietary workstation, Xcalled Magnolia. XThe instructions are designed in a way that keeps all changes Xseparate from your standard sources, in hope that Xit will encourage sites to try the installation. X.AE X.nr * 0 1 X.FS * XRFS should not be confused with another completely different (but excellent) Ximplementation Xfrom Tektronix available on the 6000 series workstation, called DFS, Xand done by a separate product group. XThe work on RFS was designed and written Xstrictly by the author of this paper at about the same Xtime as DFS, and draws none of its implementation details from DFS. XRFS is public domain, while DFS is proprietary. X.FE X.NH 1 XInstalling and Compiling X.PP XThese instructions assume that you are familiar with Xthe C compiler, the commands \fImake(1)\fP, \fIvi\fP, Xthe structure of the kernel source files, Xhow to build a new kernel[1], Xthe structure of \fI/etc/passwd, /etc/hosts, /etc/services, /etc/rc.local\fP. XInstalling and compiling the software should take about two to four hours Xwithout interruption and on a lightly loaded 11/750. X.PP XThe best way to install this at first, is to make everything in someone's Xlogin directory, keeping all changes from being anywhere near permanent. XIn this way Xyou can gain confidence comfortably that the software really Xworks. XAll compiles can be done by an unprivilaged user that has read access Xto the kernel source. X.PP XTo do this, Xyou need the \fIremote\fP directory X(this document came from \fIremote/doc/install.ms\fP) Xwith all of its original contents. XLet us say that you have allocated this project to a user named \fIrfs\fP, Xand that he will be installing everything beneath his login directory, X\fI~rfs\fP. XIf you are reading this document, Xthen you probably now have the following directories Xunder \fI~rfs\fP: X.DS Xremote Xremote/RCS Xremote/doc Xremote/doc/paper Xremote/usr.include.{VAX4.2,VAX4.3,PYR2.5} Xremote/usr.src.lib.libc Xremote/usr.src.lib.libc/gen Xremote/usr.src.lib.libc/{vax,pyr} Xremote/usr.src.lib.libc/{vax,pyr}/sys Xremote/usr.sys.VAX4.2/{conf,h,machine,sys} Xremote/usr.sys.VAX4.3/{conf,h,machine,sys} Xremote/usr.sys.PYR2.5/{conf,h,sys} Xremote/usr.sys.remote X.DE X.PP XIf not, Xthey are easily obtained by mounting the tape (if that is the medium of this Xrelease) or by placing the \fIshar\fP file in, say, X\fI/tmp/rfs.shar\fP. XTo extract them, you would type, respectively, X.DS X% cd ~rfs; tar x X or X% cd ~rfs; sh < /tmp/rfs.shar X.DE X.NH 2 XBuilding the Kernel X.PP XA new kernel must be installed on the machine that is to have the Xdistributed file system capability. XThe machines that will be accessed through RFS Xdo not need to have a new kernel if they are running XBSD 4.3; Xhowever, BSD 4.2 sites have a serious bug in sys_socket.c that Xcauses infinite loops if there is any activity on a socket being Xread using the \fIrecv(2)\fP system call. XThe server uses this system call. X.PP XFirst, Xyou must set up a local copy of the kernel sources Xin \fI~rfs/sys\fP Xusing symbolic links for most, Xand copying and changing others (note that \fI~rfs/sys\fP does not Xexist yet, so be patient). XThe files new to the kernel are: X.DS X~rfs/sys/remote/remotefs.h X~rfs/sys/remote/rmt_data_template (used to build rmt_data.c) X~rfs/sys/remote/remote_mkdata (used to build rmt_data.c) X~rfs/sys/remote/rmt_exec.c X~rfs/sys/remote/rmt_final.c X~rfs/sys/remote/rmt_general.c X~rfs/sys/remote/rmt_generic.c X~rfs/sys/remote/rmt_io.c X~rfs/sys/remote/rmt_subr.c X~rfs/sys/remote/rmt_syscall1.c X~rfs/sys/remote/rmt_syscall2.c X~rfs/sys/remote/rmt_syscall3.c X.DE XThe files that must be changed in the kernel are: X.DS X~rfs/sys/h/errno.h X~rfs/sys/h/param.h X~rfs/sys/h/user.h X~rfs/sys/machine/trap.c X~rfs/sys/sys/init_sysent.c X~rfs/sys/sys/kern_exec.c X~rfs/sys/sys/kern_exit.c X~rfs/sys/sys/sys_inode.c (a semantic bug; fixed in 4.3) X~rfs/sys/sys/ufs_nami.c (ufs_namei.c in 4.3) X~rfs/sys/sys/ufs_syscalls.c X~rfs/sys/sys/uipc_socket.c (the \fIrecv(2)\fP bug; fixed in 4.3) X.DE XFor configuration, there are a few files which must be changed Xslightly: X.DS X~rfs/sys/conf/files X~rfs/sys/conf/makefile.vax (Makefile.vax in 4.3) X.DE XFinally, Xthe source files for building the new system calls (see X\fBBuilding the User Programs\fP) Xmust know about the new system call numbers. XThis requires a X(local) change to a file normally found in \fI/usr/include\fP: X.DS X~rfs/usr.include/syscalls.h X.DE X.NH 3 XEditing in the Changes (about 15 minutes) X.PP XAll of these files, or the changes that need to be made to them Xare found in files of the same name (plus a \fI.diff\fP for the Xpatch files) under \fI~rfs/remote/usr.*\fP. XA shell program named \fI~rfs/remote/shells/rfs_setup\fP Xhas been provided for setting up the symbolic links, Xcopying files, Xand patching in all the changes to the kernel using the \fBpatch\fP Xutility which has been posted publicly to newsgroups such as \fInet.sources\fP Xby Larry Wall\*(Fi. XSome of the added kernel Xsoftware contains \fIifdef\fPs for 4.3 BSD differences Xwhich only clutter the code and cause problems Xwhen you run \fImake depend\fP on BSD 4.2. X\fI~Rfs_setup\fP will remove these. X.FS XIf you have never heard of the \fBpatch\fP program, I don't know how you ever Xfound out about RFS. XSend me a note and I will mail the source to you. X.FE XRunning \fIremote/shells/rfs_setup\fP will work for 4.2 and 4.3 BSD Vax systems, Xand for Pyramid 90x systems running 2.5, Xbut for other systems, you must examine the shell Xscript to infer what it accomplishes. XLet me emphasize again that you are not (and should not be) Xediting the standard kernel sources. X.DS X% cd ~rfs X% ./remote/shells/rfs_setup # several questions will be asked X.DE X.NH 3 XEnsuring that RFS Software Does Not Interfere with the Kernel X.PP XThere are four variables defined in \fI~rfs/sys/remote/remotefs.h\fP Xwhich must be examined to be sure that they fit in correctly with Xthe rest of the kernel. XTheir values in the distributed software have been chosen Xso as not to conflict Xwith VAX BSD 4.2 or 4.3, and Pyramid 2.5 software. XIt will have to be changed for other Unix versions. X.IP FREMOTE Xis a flag that must not conflict with any other flags associated Xwith the kernel \fIfile\fP structure. XCheck in \fI/usr/sys/h/file.h\fP. X.IP DTYPE_REMOTE Xshould not conflict with DTYPE_INODE or DTYPE_SOCKET in X\fI/usr/sys/h/file.h\fP. XThis new file descriptor type means the Xfix to \fIino_close()\fP in \fI~rfs/sys/sys/sys_inode.c\fP must be installed. X.IP SREMOTE Xmarks a process as having used a remote file system at some time. XIt must be a unique bit for the \fIproc\fP structure element \fIp_flag\fP Xas defined in \fI/usr/sys/h/proc.h\fP. X.IP SNOREMOTE Xmust also be a unique bit for the \fIproc\fP structure element \fIp_flag\fP. XThis flag bit prevents any processes having it from using any remote Xfile system. XIt is used primarily by \fIrfs_server\fP to prevent ``hopping'' Xacross more than one machine with the remote file system. X.NH 3 XSetting up VAX\*(Fi Configuration (about 10 minutes) X.PP X.FS XPyramid software does not have a configuration file. Xconfiguration is done with command\-line shell script arguments. X.FE XThe configuration file for VAX machines should now be in \fI~/rfs/sys/conf\fP, Xbut it is a symbolic link to the real one in \fI/usr/sys/conf\fP, Xlet us say, FOOVAX. XYou should remove the link and copy it to this directory so Xthat you can add three lines to it\*(Fi: X.FS XThe RFSDEBUG option gives you the ability to Xenable selective portions of the RFS kernel to give out Xinformation about activity and problems. XSee the section on debugging. XCompiling it in has a negligible performance impact (<< %1) Xif it is not used. XYou can compile it out later by removing \fIrmt*.o\fP, Xremoving the RFSDEBUG option line from the config file, Xrunning config again, and recompiling. X.FE X.DS Xoptions REMOTEFS # to compile in REMOTEFS changes Xoptions RFSDEBUG # to compile in debug software (optional) Xpseudo-device remotefs # to include the rfs software in the makefile X X so X X% cd ~rfs/sys/conf X% rm FOOVAX X% cp /usr/sys/conf/FOOVAX . X% vi FOOVAX X< add in the three new lines > X% mkdir ../FOOVAX # for the config directory X% config FOOVAX X.DE X.NH 3 XCompiling the RFS Kernel (about 90-120 minutes) X.PP XIf you have installed everything correctly Xand if I have told you all that I should, Xthen you should now be able to compile the kernel. XNote that compilation is different for VAX and Pyramid. X.DS X VAX X% cd ~rfs/sys/FOOVAX X% make depend X% make X X PYRAMID X% mkdir ~rfs/sys/FOOVAX # not made yet X% cd ~rfs/sys/FOOVAX X% cp ../conf/* . # copy in configuration scripts and makefiles X% makesys 64 VER=01 N # you better check with your pyramid rep. X.DE XYou should boot the kernel to assure yourself that Xit won't crash and to prepare for the remaining software. X.NH 2 XBuilding the User Programs X.PP X\fIRmtmnt\fP is to a remote file system what \fI/etc/mount\fP is Xto a disk file system. XIn addition, Xit provides statistics on currently active remote file systems. X\fIRfs_server\fP Xprovides name translation to the kernel for pathnames Xbelow a generic mount point, e.g. \fI/net/foovax/etc/passwd\fP, Xand it is the system call server which a client talks to. X.PP XThere are three new system calls added to the kernel, Xand there are three new error numbers defined in \fI<errno.h>\fP. XThe system calls X\fIremoteon(2)\fP and \fIremoteoff(2)\fP turn on and Xoff the remote file system, Xand \fIremotename(2)\fP allows the Xserver and kernel to talk to each other. XHence, you must first make a new libc, Xso that \fIrfs_server\fP and \fIrmtmnt\fP compile and link Xwithout any undefined symbols, Xand any new programs that get relinked will be able to print Xa reasonable message using the standard library call, \fIperror(3)\fP. X.NH 3 XBuilding a new \fIlibc.a\fP (about 10 minutes) X.PP XThe new system calls and the new error messages for \fI/lib/libc.a\fP are: X.DS X~rfs/remote/usr.src.lib.libc/gen/errlst.c.diff X~rfs/remote/usr.src.lib.libc/{vax,pyr}/sys/remoteon.c X~rfs/remote/usr.src.lib.libc/{vax,pyr}/sys/remoteoff.c X~rfs/remote/usr.src.lib.libc/{vax,pyr}/sys/remotename.c X.DE XThe contents of \fIerrlst.c.diff\fP is a patch file for X\fI/usr/src/lib/libc/gen/errlst.c\fP\*(Fi. X.FS XThe \fIMakefile\fP assumes that general source is in \fI/usr/src\fP. XThis can be overridden with an assignment on the command line: X.sp 1 X # make vax SRC=/usr/othersrcdir X.sp 1 X.FE XThe file \fI~rfs/remote/usr.src.lib.libc/Makefile\fP Xknows how to build a C\-library from the sources and patch files provided. XBy default, the \fIMakefile\fP will install the new libc in X\fI/lib/libc.a\fP\*(Fi so you must be root. X.FS XYou can install it in \fI~rfs/remote\fP Xby changing the \fIMakefile\fP variable LIBDIR, Xor by assigning it on the command line X.sp 1 X # make vax LIBDIR=.. X.sp 1 Xbut then you must remember to change the \fIMakefile\fP Xin ~rfs/remote Xafter it is generated by \fI~rfs/remote/shells/makemake\fP. X.FE X.DS X% su root XPassword: X# cd ~rfs/remote/usr.src.lib.libc X# make vax # for VAX BSD 4.2 or 4.3 X or X# make pyr # for Pyramid 2.5 X.DE X.NH 3 XBuilding a Makefile for \fIRfs_server\fP, and \fIRmtmnt\fP (about 5 minutes) X.PP XThere are a variety of makefiles for building the server, \fIrfs_server\fP, Xand each is built with a command called \fIshells/makemake\fP. XCurrently there is support for a makefile Xon a Vax that will run the RFS kernel, for Xa Pyramid that will run the RFS kernel and Xfor a Vax that will only be a server (running an ordinary kernel). XEach is created\*(Fi X.FS XThe last command run will leave that kind of makefile in \fI./remote\fP. X.FE Xwith one of the following commands\*(Fi: X.FS XIf none of these fit your needs, Xyou must design your own from the files \fImake.base*\fP. XAn important part of the makefile is the byte\-ordering Xfor the machine on which the server will run. XIf your architecture is neither Vax nor Pyramid, Xyou should compile the program \fI~rfs/remote/byteorder.c\fP Xand run it to get its opinion. X.FE X.DS X% cd ~rfs/remote X% shells/makemake vax # Vax with RFS kernel X or X% shells/makemake vaxnorfs # Vax without RFS kernel X or X% shells/makemake pyramid # Pyramid with RFS kernel X.DE X.NH 3 XCompiling \fIRmtmnt\fP and \fIRfs_server\fP (about 30 minutes) X.PP XNow, compile the server and \fIrmtmnt\fP program\*(Fi, Xinstalling the binaries as root: X.FS XIf you put the new libc.a in ~rfs/remote, instead Xof following the reccomended procedure, Xyou should edit the makefile at this point. X.FE X.DS X% cd ~rfs/remote X% make X% su root XPassword: X# make install X.DE X.NH 2 XOther Chores X.PP XAt this point, Xyou should have an RFS kernel running on one or more machines, Xcall them \fIclient\fPs, and the Xpotential to run the RFS server on one or more machines, Xcall them \fIserver\fPs\*(Fi. X.FS XAny machine can be both client and server, Xeven with respect to itself. X.FE XBefore starting up any connections, Xthere are a few extra items that should be tended to. X.IP \(bu .125i XAdd the service \fIremotefs\fP to \fI/etc/services\fP, Xon all server and client machines. XIt should be a privileged port number, i.e. less than 1024, Xbecause the server runs as root and does a \fIseteuid(2)\fP Xto whatever user it thinks it should be. XI have used port 556 on the machines where I installed RFS. X.IP \(bu .125i XAdd the user \fIguest\fP to \fI/etc/passwd\fP on Xeach server machine. XThe default permissions for any access to a server machine Xare mapped to guest (so it shouldn't have wide access). XThe server process will refuse to run without this user id installed. X.IP \(bu .125i XIf you are on a Pyramid, Xthere is no easy way to turn on the debugging software in the kernel, Xso there is a program provided; Xyou should compile it now hand have it ready. XMore on debugging later. X.DS X% cd ~rfs/remote X% make debug X.DE X.NH 2 XStarting up the software X.PP XThe server should be started as root. XFor now, you start it by hand, Xand then arrange for it to be started automatically. XThis should be done on all machines that will be servers or Xclients. XRemember that \fI/etc/rfs_server\fP is slightly different for Xa machine running the RFS kernel; see section \fB1.2.2\fP. X.DS X% su root XPassword: X# /etc/rfs_server X# vi /etc/rc.local X< insert at an appropriate place, the lines... > X if [ -f /etc/rfs_server ]; then X /etc/rfs_server & echo -n ' rfs_server' >/dev/console X fi X.DE X.PP XNext we should set up for loop\-back RFS access just to make Xsure that everything works. XNote that the mount point is a file, Xnot a directory. XThis is very important. XThe design decisions are discussed in a separate paper Xunder \fI~rfs/remote/doc/paper\fP. XIn a nutshell, Xusing a file for a mount point Xallows the natural syntax for file access X.DS X% cp /foovax/etc/passwd /feevax/tmp/x X.DE Xbut prevents programs like X.DS X% find / -print X.DE Xfrom finding every file on every remote host. X.PP XIf your host name is foovax, then create the file /foovax and Xmount your host. XThe use of the file /foovax is not required, Xbut only suggested as a convention\*(Fi. XFoovax must be defined in \fI/etc/hosts\fP and \fIrfs_server\fP Xshould be running. X.FS XIt has been pointed out to me that this convention Xis slightly restrictive for machines whose owners choose Xinteresting names such as bin and tmp. X.FE X.DS X% touch /foovax X% /etc/rmtmnt foovax /foovax X.DE XIn all likelyhood, Xyou should not have crashed by this time, Xbut if there are any problems with the way you installed the software, Xthey will be encountered now. XTry the commands X.DS X% ls -ld /foovax/ X% ls -ld /foovax/etc X% ls -l /foovax/etc X% cd /foovax/etc X% pwd X% ls X.DE XIf the machine crashes Xor the result is not what you expected, Xyou should pull out the stops and start debugging. XSee the section on debugging. XIf all goes well, Xthen try mounting another host, say foo2vax: X.DS X% touch /foo2vax X% /etc/rmtmnt foo2vax /foo2vax X% ls -l /foo2vax/etc X% .... X.DE XTry a generic mount point: X.DS X% touch /net X% /etc/rmtmnt -g /net X% more /net/anotherhost/etc/passwd X.DE X.PP XFinally, Xwhen you are satisfied that everything is working, Xyou should install the mount commands in \fI/etc/rc.local\fP. XNote that you don't really need the generic mount point Xunless you have many workstations that you don't want to explicitly Xmount. X.DS X% su root XPassword: X# /etc/rfs_server X# vi /etc/rc.local X< insert at an appropriate place, the lines... > X if [ -f /foovax ]; then X /etc/rmtmnt foovax /foovax X fi X if [ -f /foo2vax ]; then X /etc/rmtmnt foovax /foovax X fi X if [ -f /net ]; then X /etc/rmtmnt -v /net X fi X.DE X.NH 1 XGeneral Portability X.PP XI consider RFS to be ``installable'', not necessarily portable. X.PP XRFS's server, \fIrfs_server\fP, Xdepends very heavily on the BSD signal mechanism, Xinheirited file descriptors (sockets to the client), Xand the \fIrecv(2)\fP system call using the MSG_PEEK flag. X.PP XThe RFS kernel depends very heavily on mbuf structures, and the BSD Xsocket paradigm. X.NH 1 XAccess Permissions over RFS X.PP XFor a greater understanding of this discussion, Xand the terms ``sentry server'', ``gateway server'', XI suggest that the reader familiarize himself Xwith the \fIrfs_server(8)\fP man page. XThe terms ``client'' and ``server'' are described in section \fI1.3\fP. X.PP XA permission map is compiled by \fIrfs_server\fP Xwhen it starts up Xbased on \fI/etc/hosts\fP, \fI/etc/passwd\fP and \fI.rhosts\fP files Xunder every user's login directory. XIn addition, Xwhenever a client does a \fIrmtmnt\fP command, Xthat command sends its \fI/etc/passwd\fP file to the sentry server. XSimilarly, Xif a server receives a call from a client, Xbut has not received an \fI/etc/passwd\fP file, Xthe server calls the client's server, Xand asks for it\*(Fi. X.FS XIf this fails, Xthen the server will return EIO Xon all \fIread(2)\fP calls where the file descriptor Xis to a directory, Xbecause it doesn't know the client architecture's byte order. X.FE X.PP XWhen a server receives a message from a client process Xwhose uid number is \fIn\fP, Xit consults the client's \fI/etc/passwd\fP file. XIf it finds a matching uid number, Xthen it checks\*(Fi to see if Xthat uid name is allowed login privileges in some Xuser's \fI.rhosts\fP file on the server. XIf a user allows it, Xthen the server for that process sets Xthe effective user id Xto that user's uid number (with \fIseteuid(2)\fP) Xand sets the groups associated with that Xuser (with \fIsetgroups(2)\fP). X.FS XMost of this checking is done when \fIrfs_server\fP first starts up, Xand is kept in LRU lists for fast access. XMappings from client uid to server uid are already done Xby the time a client makes a connection. X.FE X.PP XIf more than one user on the server host Xallows login access to that client's user, Xthen the last user in the server's \fI/etc/passwd\fP takes precedence. XHowever, Xif the one of the users on the server hosts has the same uid name Xas that on the client, Xthat mapping takes precedence over all other mappings. XNote that this means the user \fIx\fP on may have remote Xlogin privileges for users \fIy\fP and \fIz\fP, Xbut his access permissions over RFS will be for one or the other, Xnever both. X.PP XIf a user changes his \fI.rhosts\fP file on a server, Xthat change is not noticed until the server is restarted. XFortunately, Xrestarting the server is simple: Xjust run \fIrfs_server\fP again. XAs long as the primary log \fI/usr/tmp/rfs_log\fP Xstill exists which contains the process id number of the running server, Xit is intelligent enough to shutdown the old server. X.PP XIf the server host on which the user wanted to change his \fI.rhosts\fP file Xis currently connected to the client, Xthat connection must be severed and a new one started. XThis can be done by killing all processes Xhaving the SREMOTE bit set\(*Fi on the client machine. XThe \fI/etc/rmtmnt\fP command with no arguments will tell Xyou how many processes are connected to each server. X.FS XThe command \fIps axl\fP will show all commands and their per\-process Xflag bits. Xsimply examine the left\-most field of the \fIps\fP output Xlooking for the SREMOTE bit. XUnfortunately, Xmultiple remote systems may be open, Xand \fIps\fP output does not show which process is using which remote hosts Xor even if it is using multiple hosts. X.FE X.PP XSimilarly, Xif a new user is added to a client's \fI/etc/passwd\fP file, Xor an existing user's uid number changes on a client, Xthe \fIrfs_server\fP must be started again on each of the server machines, Xor the remote file systems can be unmounted and mounted again using X\fI/etc/rmtmnt\fP. XAgain, however, Xif the client host where the change was made is currently connected Xto a server, Xthen that connection must be severed and a new one started Xas described above. X.NH 1 XDebugging X.PP XAll kernel debugging is accomplished by setting the Xglobal variable \fIremote_debug\fP. XThe bit definitions are briefly explained in the Xfile \fI~rfs/sys/remote/remotefs.h\fP. X.PP XDebugging on the server is explained briefly in the Xman page for \fIrfs_server(8)\fP. X.NH 2 XPlaces to Look if RFS Does Not Work X.PP XIf the kernel gets hung in startup or does not seem to do Xsome of the system calls correctly Xcheck the code inserted into \fI~rfs/sys/machine/trap.c\fP for Xone of the following problems: X.IP \(bu .125i XOn the Vax, Xthe declarations at the top of the routine are very position Xdependent. XRFS has some register declarations that must appear last Xor the register allocation that the code depends on will be Xmessed up. X.IP \(bu .125i XOn the Pyramid, Xsystem calls are made by passing the arguments as arguments X(the Vax copies them to an array). XCheck to make sure that the code inserted is doing this right, Xbecause I only tested it for a week. X.PP XOn the Pyramid, Xdeclarations of variables inside of local blocks Xsometimes causes the value of other local variables in outer blocks to Xbe corrupted. XFor example: X.DS X routinex(arg1, ...) X { X register long a, b, c, ...; /* lots of variables */ X ... X x = y; X X { /* start a local block */ X register long z; X X z = 1; X } X } X.DE XThe declaration and use of z Xwill probably clobber one of the earlier variables \fIa, b, c, ...\fP. XThis is a pretty bad compiler bug, but I think they are aware of it. XThis kind of code was completely removed at one time from the XRFS source code, but may have crept back in; Xbe sure that you don't add any. X.PP XIf you \fIcd\fP to a remote directory, Xbut it always appears as if you are still in the root directory for Xthat machine, Xit almost certainly has to do with \fIfork(2)\fP or \fIvfork(2)\fP Xsystem calls not being sent to the server. XCheck the generated table at the end of X\fI~rfs/sys/remote/rmt_data.c\fP to ensure that there is a \fIRFS_\fP Xentry for both \fIfork(2)\fP and \fIvfork(2)\fP. XIf there isn't, change it by hand or try to fix the shell file Xthat generates it in \fI~rfs/sys/remote/remote_mkdata\fP. X.NH 1 XMaking the Software Permanent X.PP XFirst, Xread in the distribution tape again, this Xtime putting it in \fI/usr/src/etc\fP; Xthis will be the proper resting place for the software that Xlives in the directory immediately below the first\-level directory, X\fIremote\fP, Xbecause the two commands \fI/etc/rfs_server\fP and \fI/etc/rmtmnt\fP Xreside there. X.PP XSecond, Xrerun the installation procedure, Xthis time instructing \fIrfs_setup\fP to make the installation permanent, Xinstead of in the current directory. XThe only exception is that the software in \fI~rfs/remote/usr.src.lib.libc\fP Xmust be copied by hand to /usr/src/lib/libc and placed in Xthe proper directories there, modifying the \fImakefile\fP accordingly. X.NH 1 XCurrent Bugs and Needed Extensions X.PP XThe bugs listed have only proved irritating for our environment, Xbut worthy of note, none the less. X.IP \(bu .125i XWhen a client fails to connect to a server, Xthe internal count of how many processes there are sometimes Xgoes awry, Xand the kernel (as seen by \fIrmtmnt\fP) Xwill insist that it is still closing Xwaiting for processes to die that aren't there. XThe bug is almost certainly in \fIremote_getconnection()\fP. X.IP \(bu .125i XWhenever a connection goes down, Xthere may be processes still up ``using'' that connection. XHowever, Xif there are no open files or remote \fIchdir(2)\fP's, Xthe kernel could just as well restart the connection Xwithout waiting for those processes to die. XThis fix would go into \fIremote_getconnection()\fP. X.IP \(bu .125i XThe server has the beginnings of capability to Xdo an asynchronous system call (like reading 10k of data), Xbut it has not been fully implemented. XA much better solution would be to implement an Xatomic \fIwrite(2)\fP system call where Xthe writer is guarenteed that no one else Xwill be able to write on the same file descriptor (socket, Xin this case) Xuntil he is done. XThis would allow servers to perform system calls Xat their own pace sending the results back at any time. X.IP \(bu .125i XAlong the same lines, Ximplementing an atomic message reader system call Xthat would allow all servers to be blocked on a read Xof the single socket connected to the client. XThe reading server would provide a list of process id's Xthat he is handling as input arguments along with Xfile descriptor, buffer and size. XThe kernel would slice up all the messages, handing Xeach out to the server that is serving that process. XThe only reason it wasn't implemented so far, was to keep the Xserver standard. X.IP \(bu .125i XThe server maps two user id names with the same Xnumber on a client to one user id on a server. XThe reason is that only the uid number is sent in the messages Xto the server. XThere is no real fix for this. X.IP \(bu .125i XThe sentry server has the information about every host in Xits memory and hands all this information off to each \fIgateway\fP Xserver and its children even though it is never used. XIf this was freed when each \fIgateway\fP Xserver starts up, the servers would consume fewer memory Xand swap resources. X.IP \(bu .125i XThe server currently does not handle \fI.rhosts\fP Xfiles that have entries uttering only a host name. XIt also ignores \fI/etc/hosts.equiv\fP. X.IP \(bu .125i XThis implementation ignores the possibility that the kernel COMPAT Xoption may have been used. XOld system calls should just fail. X.IP \(bu .125i XThe \fIpwd\fP command (and library call) does not work Xwhile your current directory is under \fI/net/host/somedirectory\fP. XBasically, the \fIpwd\fP command discovers that its current directory Xis \fI/net/somedirectory\fP Xbecause the \fIhost\fP is really only a virtual pathname component. XBut when it tries to do Xa \fIchdir(2)\fP back to it, it fails. XThis is an irritating problem, Xbut the only easy solution is for a change in the implementation, Xsuch that \fI/net\fP becomes a directory, and the nameserver Xcreates files and Xdoes an explicit mount for any hosts that the kernel asks about. XSo far I have resisted this because it requires another change Xto the kernel routine \fInamei()\fP, Xand because \fIpwd\fP works just fine if a host explicitly mounted. X.IP \(bu .125i XI think that RFS may be responsible for dropping an mbuf when a connection Xfails, but this is apparently infrequent. X.IP \(bu .125i X\fIChroot(2)\fP system call is only partially implemented. Xand should not be used with a remote directory as an argument. X.IP \(bu .125i XThe \fIselect(2)\fP and \fIioctl(2)\fP system calls are not yet implemented. XThe latter means that the \fItip\fP command won't work with remote Xpointers to tty dialers. X.IP \(bu .125i XThe server allows any unknown user on a client to see Xits file system through the guest Xaccount. XThis is a good default. XBut an appropriate extension Xwould be a table describing a restricted domain of access, Xso that if machines \fIx\fP and \fIy\fP appear in the table, Xthey are allowed access through the normal permission scheme Xdescribed above. XHowever, any machine not in the table would be denied access in general, Xso that only users on the client that have been allowed remote logins Xvia \fI.rhosts\fP files can have access. X.IP \(bu .125i XNo fixes have been provided for \fImv(1)\fP or \fIcp(1)\fP Xto distinguish the triple device/inode/host for uniqueness. XThe information is available: Xfor a local file, Xthe \fIstat(2)\fP, \fIfstat(2)\fP and \fIlstat(2)\fP Xsystem calls return a stat structure whose X\fIst_spare1\fP element is 0. XIf the file is remote, Xthe \fIst_spare1\fP element contains the value \fIn\fP+1 Xwhere \fIn\fP is the number of the remote host mount point, Xas shown by \fI/etc/rmtmnt\fP. X.IP \(bu .125i XThe server, \fIrfs_server\fP, does not correctly handle situations where Xa host has more than one internet address. XWhat happens is that all of the user access privileges X(distilled from all the .rhosts files) Xgets attached to one address, and when a call is made using the Xother address, everyone only has the access of the \fIguest\fP user. X.IP \(bu .125i XSome user commands, Xlike \fIchgrp(1)\fP and \fIrn(1)\fP Xtry to guess ahead of time whether the kernel will allow you write Xpermission on a file. XHence, they will fail sometimes where they should not. XFor example, Xif your user id number on one host is 5 and on Xanother host it is 6, X\fIchgrp(1)\fP on one host Xwill tell you that you cannot change the group of a file that resides on Xanother host, even though RFS would allow it. X.NH 1 XConclusions and Plans for the Future X.PP XRFS is not production quality, Xbut is very useful, Xproviding reasonably fast file access: XI consider rcp unreasonable. XI have made this software publicly available in hopes that other Xinterested parties might contribute some of the fixes to it. XI have other responsibilities and cannot afford to spend the Xmany hours necessary to get that last 5 or 10% of quality, Xbut perhaps you can help. X.PP XThe only hope for this software is that it is free and easy Xto install and debug. XI am more than willing to accept bug reports and fixes for it Xuntil this or something else becomes part of the Berkeley Software XDistribution. SHAREOF chmod 664 remote/doc/install.ms # # remote/doc/paper # mkdir remote/doc/paper chmod 775 remote/doc/paper # # remote/doc/paper/Makefile # if [ -f remote/doc/paper/Makefile ]; then echo -n 'Hit <return> to overwrite remote/doc/paper/Makefile or ^C to quit' read ans rm -f remote/doc/paper/Makefile fi sed -e 's/^.//' << \SHAREOF > remote/doc/paper/Makefile XRFS = remotefs fig1.mag fig2.mag fig3.mag fig4.mag fig5.mag fig6.mag \ X appendixB.out X Xrfs: $(RFS) X troff $(ONLY) -Tmag -mstek remotefs > image X @sh -c "echo -n Waiting... ; read x" X dmag -w$(WIND) < image Xlgp: $(RFS) X ltroff -mstek $(ONLY) remotefs X X# X# run off figure 1 or 2 or 3 X# Xf1: fig1.mag X troff -Tmag -mstek fig1.mag > image X @sh -c "echo -n Waiting... ; read x" X dmag -w$(WIND) < image Xf2: fig2.mag X troff -Tmag -mstek fig2.mag > image X @sh -c "echo -n Waiting... ; read x" X dmag -w$(WIND) < image Xf3: fig3.mag X troff -Tmag -mstek fig3.mag > image X @sh -c "echo -n Waiting... ; read x" X dmag -w$(WIND) < image Xf4: fig4.mag X troff -Tmag -mstek fig4.mag > image X @sh -c "echo -n Waiting... ; read x" X dmag -w$(WIND) < image Xf5: fig5.mag X troff -Tmag -mstek fig5.mag > image X @sh -c "echo -n Waiting... ; read x" X dmag -w$(WIND) < image Xf5: fig5.mag X troff -Tmag -mstek fig5.mag > image X @sh -c "echo -n Waiting... ; read x" X dmag -w$(WIND) < image Xf6: fig6.mag X troff -Tmag -mstek fig6.mag > image X @sh -c "echo -n Waiting... ; read x" X dmag -w$(WIND) < image XA: appendixA.out X troff -Tmag -mstek appendixA.out > image X @sh -c "echo -n Waiting... ; read x" X dmag -w$(WIND) < image XB: appendixB.out X troff -Tmag -mstek appendixB.out > image X @sh -c "echo -n Waiting... ; read x" X dmag -w$(WIND) < image X X# X# generate figure 1 X# Xfig1.mag: fig1 X /lib/cpp -Dfigure1 fig1 | sed -e '/^#/d' | pic -T100 > fig1.mag Xfig1.lgp: fig1 X /lib/cpp -Dfigure1 fig1 | sed -e '/^#/d' | pic > fig1.lgp X X# X# generate figure 2 X# Xfig2.mag: fig1 X /lib/cpp -Dfigure2 fig1 | sed -e '/^#/d' | pic -T100 > fig2.mag Xfig2.lgp: fig1 X /lib/cpp -Dfigure2 fig1 | sed -e '/^#/d' | pic > fig2.lgp X X# X# generate figure 3 X# Xfig3.mag: fig1 X /lib/cpp -Dfigure3 fig1 | sed -e '/^#/d' | pic -T100 > fig3.mag Xfig3.lgp: fig1 X /lib/cpp -Dfigure3 fig1 | sed -e '/^#/d' | pic > fig3.lgp X X# X# generate figure 4 X# Xfig4.mag: fig4 X pic -T100 fig4 > fig4.mag Xfig4.lgp: fig4 X pic fig4 > fig4.lgp X X# X# generate figure 5 X# Xfig5.mag: fig5 X pic -T100 fig5 > fig5.mag Xfig5.lgp: fig5 X pic fig5 > fig5.lgp X X# X# generate figure 6 X# Xfig6.mag: fig6 X pic -T100 fig6 > fig6.mag Xfig6.lgp: fig6 X pic fig6 > fig6.lgp X X# X# generate appendix A X# XappendixA.out: appendixA X tbl appendixA > appendixA.out X X# X# generate appendix B X# XappendixB.out: appendixB X tbl appendixB > appendixB.out SHAREOF chmod 664 remote/doc/paper/Makefile # # remote/doc/paper/appendixB # if [ -f remote/doc/paper/appendixB ]; then echo -n 'Hit <return> to overwrite remote/doc/paper/appendixB or ^C to quit' read ans rm -f remote/doc/paper/appendixB fi sed -e 's/^.//' << \SHAREOF > remote/doc/paper/appendixB X.if "\*(.T"mag" \{\ X. nr PS 12 X. nr VS 14 X. ps \n(PS X. vs \n(VS X. pl 9.5i X.\} X.ds LH \fBAppendix B\fP X.BP X.NH 1 XAppendix B X.PP XThese two tables contain the functions that must be ``changed'' for a remote Xor distributed file system to work. XThe column headings have the same meaning for both tables, Xbut since some system calls have no before and after necessities (column 4), Xit is clearer to put them by themselves in \fITable 1\fP. X\fITable 2\fP has the rest of the system calls. XThe first column, \fBSystem Call\fP, is the name of the system call Xas found in section 2 of the UNIX User's Manual. X.PP XThe second column, X\fBInteresting Arguments\fP, Xlists the arguments that we are particularly interested in. XFor example, \fIaccess()\fP, has two arguments, one a flag and one is Xa path. XThe path is noteworthy because we must find out what portion of the path Xis on a remote host, and what remote host it is on. XOther interesting arguments are those with two path names and those Xhaving file descriptors. XSome may not have any arguments worth considering, Xbut are included because of important side effects. X.PP X\fBFollow Symlinks\fP shows whether \fInamei()\fP must follow Xsymbolic links when determining ``remoteness'' (and is not applicable Xto system calls that do not deal with path names). XThis is an important point, Xbut only for an implementation like \fBRemotefs\fP. X\fBRemotefs\fP uses another system call, \fIisremote()\fP, Xwhen determining what remote host a file is on and what portion Xof the path is on that host. XNow, the authors of 4.2 Xdecided when \fInamei()\fP may or may not follow a symbolic link, Xand \fIisremote()\fP must do the same for whatever system call is Xin operation. X.PP XThe last column, \fBSpecial Considerations Before & After the Syscall\fP, Xshows what preparation Xthe local host must do before Xsending the system call to a remote host, Xsuch as doing a local open to allocate a file descriptor Xfor a \fIdup()\fP system call. XThe fourth column shows the followup steps that should be taken Xafter a successful remote system call. X.PP XThese descriptions assume that the system call has already been identified Xas one that needs to be sent to a remote host. XThat is, Xat least one of the path names (for those system calls that deal with paths) Xis remote, Xor that the file descriptor passed as an argument to a system call is Xto a remote file, Xor even that there has been one or more remote system call requests Xof some kind X(\fIfork()\fP, \fIvfork()\fP, \fIumask()\fP, \fIexit()\fP). X.BP X.TS Xtab(+) center box; Xc | c | c Xc | c | c Xl | l | c. X\fBSystem+Interesting+Follow\fR X\fBCall+Arguments+Symlinks\fR X= X\fIaccess()\fP+One Path Name+yes+ X\fIstat()\fP+\^+\^ X\fIutimes()\fP+\^+\^ X\fItruncate()\fP+\^+\^ X_ X\fIchmod()\fP+One Path Name+no X\fIchown()\fP+\^+\^ X\fIlstat()\fP+\^+\^ X\fImkdir()\fP+\^+\^ X\fImknod()\fP+\^+\^ X\fIrmdir()\fP+\^+\^ X\fIunlink()\fP+\^+\^ X_ X\fIfchmod()\fP+File Descriptor+n/a+ X\fIfchown()\fP+\^+\^ X\fIfcntl()\fP+\^+\^ X\fIflock()\fP+\^+\^ X\fIfstat()\fP+\^+\^ X\fIfsync()\fP+\^+\^ X\fIftruncate()\fP+\^+\^ X\fIioctl()\fP+\^+\^ X\fIlseek()\fP+\^+\^ X_ X.TE X.ce 1 X\fITable 1\fP X.BP X.TS Xtab(+) center box expand; Xc | c | c | cw(3.5i) Xc | c | c | cw(3.5i) Xl | l | c | lw(3.5i). X\fBSystem+Interesting+Follow+Special Considerations\fR X\fBCall+Arguments+Symlinks+Before & After the Syscall\fR X= X\fIchdir()\fP+One Path Name+yes+T{ X\fBAfter:\fP XMake note of the system and path name of the \fIchdir()\fP argument. XT} X_ X\fIclose()\fP+File Descriptor+n/a+T{ X\fBAfter:\fP XClose the local file descriptor XT} X_ X\fIcreat()\fP+One Path Name+yes+T{ X\fBBefore:\fP XAllocate a local file descriptor as a place\-holder. X\fIDup2()\fP always closes the file descriptor in Xits second argument in anticipation Xof putting the new file descriptor at that ordinate value. XThat file descriptor must be closed locally before sending Xthe request to the remote host. X.sp 1 X\fBAfter:\fP XIf the system call was not successful, close the local one. XAlso, Xthere may need to be some mapping of file descriptors. XFor instance, Xthe local file descriptor may be 5 while the remote may be 6. XHence, every request on fd 5 must be mapped to 6. XAlternatively, Xthe server may take care of the mapping if the local host sends Xthe local file descriptor number to the remote host. XT} X\fIopen()\fP+One Path Name+\^+\^ X\fIdup()\fP+File Descriptor+\^+\^ X\fIdup2()\fP+File Descriptor+\^+\^ X_ X\fIexecv()\fP+One Path Name+yes+T{ X\fBAfter:\fP XThe text for the program to be run must be copied Xto the local swap space and executed from there. XIf it is just a shell file, then it could be run normally, Xwith the shell causing a remote open. XT} X\fIexecve()\fP+\^+\^+\^ X_ X\fIexit()\fP+None+n/a+T{ X\fBAfter:\fP XThe \fIexit()\fP must be also run locally. XT} X_ X\fIfork()\fP+None+n/a+T{ X\fBBefore:\fP XThe \fIfork()\fP or \fIvfork()\fP should be run locally first Xto determine if the resources are available. XT} X\fIvfork()\fP+\^+\^+\^ X_ X\fIlink()\fP+Two Path Names+no+T{ X\fBBefore:\fP XBoth path names must be on the same remote (or local) host. XIf not, we can simulate failure locally. XT} X_ X\fIread()\fP+File Descriptor++T{ X\fBAfter:\fP XThe data that was actually read by the system call Xmust be gotten from the remote host. XT} X\fIreadlink()\fP+One Path Name+no+\^ X\fIreadv()\fP+File Descriptor++\^ X_ X\fIrename()\fP+Two Path Names+yes+T{ X\fBBefore:\fP XThe two path names must both be on the same remote (or local) Xhost. XT} X_ X\fIsymlink()\fP+Two Path Names+yes+T{ X\fBBefore:\fP XOnly the second path name should be checked for ``remoteness''. XT} X_ X\fIumask()\fP+None+n/a+T{ X\fBAfter:\fP X\fIumask()\fP must also be run locally. XT} X_ X\fIwrite()\fP+File Descriptor+n/a+T{ X\fBBefore:\fP XThe data to be written must be sent to the remote host. XT} X\fIwritev()\fP+\^+\^+\^ X.TE X.ce 1 X\fITable 2\fP SHAREOF chmod 664 remote/doc/paper/appendixB # # remote/doc/paper/fig1 # if [ -f remote/doc/paper/fig1 ]; then echo -n 'Hit <return> to overwrite remote/doc/paper/fig1 or ^C to quit' read ans rm -f remote/doc/paper/fig1 fi sed -e 's/^.//' << \SHAREOF > remote/doc/paper/fig1 X.KF X.if "\*(.T"mag" \{\ X. nr PS 12 X. nr VS 14 X. ps \n(PS X. vs \n(VS X.\} X.PP X.PS X#ifdef figure1 Xboxht = .3i Xboxwid = .8i Xmovewid = .2i XSyscalls: [ X A: box "read()"; move X B: box "open()"; move X C: box "stat()"; move X D: box "..." X] X Xboxht = last [].ht+1.2i Xboxwid = last [].wid+.1i XUserlevel: box dashed with .n at last [].n + (0i, .3i) Xline from Syscalls.A.s to Userlevel.s Xline from Syscalls.B.s to Userlevel.s Xline from Syscalls.C.s to Userlevel.s Xline from Syscalls.D.s to Userlevel.s X"\s+4A User's Program\s-4" at Userlevel.se + (0, .075i) rjust X#endif X X#ifdef figure1 Xboxwid = boxwid + 1.5i Xboxht = boxht + 1i XSystem: box dashed with .n at last box.s - (0, .3i) X X#else Xboxwid = 5.5i Xboxht = 2i XSystem: box dashed X#endif X"\s+4UNIX Kernel\s-4" at System.se + (0, .075i) rjust X X#ifdef figure1 Xarrow from Userlevel.s to System.n X#else Xarrow from System.n + (0, .3i) to System.n X#endif Xboxht = .3i Xboxwid = 1.5i XSysinterface: box "Syscall Interface" dashed .02i with .n at System.n X Xboxht = .3i Xboxwid = .8i Xmovewid = .2i XRwuio: box "rwuio()" with .w at System.w + (.1i, 0); move XCopen: box "copen()" X Xmovewid = (-.2i) XEtc: box "..." with .e at System.e - (.1i, 0) XStat1: box "stat1()" with .e at Etc.w - (.2i, 0) X Xarrow from Sysinterface.s to Copen.n X#ifdef figure1 Xarrow from Sysinterface.s to Rwuio.n Xarrow from Sysinterface.s to Etc.n Xarrow from Sysinterface.s to Stat1.n X#endif X X#ifdef figure1 XNamei: box "namei()" at System.c - (0, .4i) X#endif X#ifdef figure2 XNamei: box "namei()" at System.c - (0, .4i) X#endif X#ifdef figure3 XNamei: box wid 1.8*boxwid ht 2.5*boxht at System.c - (0, .5i) X"namei()" at Namei above XRemotecheck: box wid 1.15*boxwid ht 1.3*boxht with .se at Namei.se X"check for" at Remotecheck above X"``remoteness''" at Remotecheck below X#endif X Xspline -> right .4i from Copen.e then to Namei.n - (.1i, 0) X#ifdef figure1 Xspline -> left .4i from Stat1.w then to Namei.n + (.1i, 0) Xspline -> down .2i from Etc.s + (.025i, 0) then to Namei.e X#endif Xboxht = 1i Xboxwid = 3i X XDevices: box dashed with .n at System.s - (0, .3i) X"\s+4Device Drivers\s-4" at Devices.se + (0, .075i) rjust Xboxht = .5i Xboxwid = 1i X X#ifdef figure1 XDisk: box dashed .02i with .n at Devices.n X#endif X X#ifdef figure2 XDisk: box dashed .02i with .ne at Devices.ne - (.2i, 0) XPseudo: box dashed .02i with .nw at Devices.nw + (.2i, 0) X"Pseudo\-Disk" at Pseudo above X"Interface" at Pseudo below X#endif X X#ifdef figure3 XDisk: box dashed .02i with .ne at Devices.ne - (.2i, 0) XNet: box dashed .02i with .nw at Devices.nw + (.2i, 0) X"Network" at Net above X"Connection" at Net below X#endif X X"Disk" at Disk above X"Interface" at Disk below X X#ifdef figure1 Xarrow from Rwuio.s to Disk.n - (.025, 0) Xarrow from Namei.s to Disk.n + (.025, 0) X#endif X#ifdef figure2 Xarrow from Rwuio.s to Pseudo.n - (.025, 0) Xarrow from Namei.s to Pseudo.n + (.025, 0) X#endif X#ifdef figure3 Xarrow from Rwuio.s to Net.n - (.033, 0) Xarrow from Copen.s to Net.n Xarrow from Namei.s to Disk.n + (.025, 0) X#endif X.PE X.ce X#ifdef figure1 X\fIFigure 1\fP X#endif X#ifdef figure2 X\fIFigure 2\fP X#endif X#ifdef figure3 X\fIFigure 3\fP X#endif X.SP X.KE SHAREOF chmod 664 remote/doc/paper/fig1 # # remote/doc/paper/fig1.mag # if [ -f remote/doc/paper/fig1.mag ]; then echo -n 'Hit <return> to overwrite remote/doc/paper/fig1.mag or ^C to quit' read ans rm -f remote/doc/paper/fig1.mag fi sed -e 's/^.//' << \SHAREOF > remote/doc/paper/fig1.mag SHAREOF chmod 644 remote/doc/paper/fig1.mag # # remote/doc/paper/fig4 # if [ -f remote/doc/paper/fig4 ]; then echo -n 'Hit <return> to overwrite remote/doc/paper/fig4 or ^C to quit' read ans rm -f remote/doc/paper/fig4 fi sed -e 's/^.//' << \SHAREOF > remote/doc/paper/fig4 X.KF X.if "\*(.T"mag" \{\ X. nr PS 12 X. nr VS 14 X. ps \n(PS X. vs \n(VS X.\} X.PP X.PS Xboxht = .3i Xboxwid = .8i Xmovewid = .2i XSyscalls: [ X A: box "read()"; move X B: box "open()"; move X C: box "stat()"; move X D: box "..." X] Xboxwid = last [].wid XRemotecheck: box with .nw at Syscalls.A.sw - (0, .15i) X"check for ``remoteness''" at Remotecheck X Xboxht = last [].ht+1.2i Xboxwid = last [].wid+.1i XUserlevel: box dashed with .n at last [].n + (0i, .3i) Xarrow from Syscalls.A.s to (Syscalls.A.s.x, Remotecheck.n.y) Xarrow from Syscalls.B.s to (Syscalls.B.s.x, Remotecheck.n.y) Xarrow from Syscalls.C.s to (Syscalls.C.s.x, Remotecheck.n.y) Xarrow from Syscalls.D.s to (Syscalls.D.s.x, Remotecheck.n.y) Xarrow from Remotecheck.s to Userlevel.s - (0, .3i) X"\s+4A User's Program\s-4" at Userlevel.se + (0, .075i) rjust X.PE X.ce X\fIFigure 4\fP X.SP X.KE SHAREOF chmod 664 remote/doc/paper/fig4 # # remote/doc/paper/fig5 # if [ -f remote/doc/paper/fig5 ]; then echo -n 'Hit <return> to overwrite remote/doc/paper/fig5 or ^C to quit' read ans rm -f remote/doc/paper/fig5 fi sed -e 's/^.//' << \SHAREOF > remote/doc/paper/fig5 X.DS X.if "\*(.T"mag" \{\ X. nr PS 12 X. nr VS 14 X. ps \n(PS X. vs \n(VS X.\} X.PS Xboxht = boxht/2 Xboxwid = boxwid*2 XProto: [ X A: box "request" X B: box "response" with .n at last box.s - (0, .1) X C: box "request" with .n at last box.s - (0, .1) X D: box "response" with .n at last box.s - (0, .1) X E: box "..." with .n at last box.s - (0, .1) X] XLocal: box "Local Host" with .e at last [].w - (1i, 0) XRemote: box "Remote Host" with .w at last [].e + (1i, 0) Xarrow from Local.e to Proto.A.w Xarrow from Local.e to Proto.C.w Xarrow from Local.e to Proto.E.w Xarrow from Remote.w to Proto.B.e Xarrow from Remote.w to Proto.D.e X.PE X.DE SHAREOF chmod 664 remote/doc/paper/fig5 # # remote/doc/paper/fig6 # if [ -f remote/doc/paper/fig6 ]; then echo -n 'Hit <return> to overwrite remote/doc/paper/fig6 or ^C to quit' read ans rm -f remote/doc/paper/fig6 fi sed -e 's/^.//' << \SHAREOF > remote/doc/paper/fig6 X.DS X.if "\*(.T"mag" \{\ X. nr PS 12 X. nr VS 14 X. ps \n(PS X. vs \n(VS X.\} X.PS Xboxht = boxht/2 Xboxwid = boxwid*2 XProto: [ X A: box "read request" X B: box "read response" with .n at last box.s - (0, .1) X C: box "read request" with .n at last box.s - (0, .1) X D: box "read response" with .n at last box.s - (0, .1) X E: box "continue" with .n at last box.s - (0, .1) X F: box "read response" with .n at last box.s - (0, .1) X G: box "read response" with .n at last box.s - (0, .1) X H: box "..." invis with .n at last box.s - (0, .1) X I: box "stop \fIn\fP" with .n at last box.s - (0, .1) X J: box "read response" with .n at last box.s - (0, .1) X K: box "read response" with .n at last box.s - (0, .1) X L: box "..." invis with .n at last box.s - (0, .1) X M: box "acknowledge" with .n at last box.s - (0, .1) X] XLocal: box "Local Host" with .e at last [].w - (1i, 0) XRemote: box "Remote Host" with .w at last [].e + (1i, 0) Xarrow from Local.e to Proto.A.w Xarrow from Local.e to Proto.C.w Xarrow from Local.e to Proto.E.w Xarrow from Local.e to Proto.I.w Xarrow from Remote.w to Proto.B.e Xarrow from Remote.w to Proto.D.e Xarrow from Remote.w to Proto.F.e Xarrow from Remote.w to Proto.G.e Xarrow from Remote.w to Proto.J.e Xarrow from Remote.w to Proto.K.e Xarrow from Remote.w to Proto.M.e X.PE X.DE SHAREOF chmod 664 remote/doc/paper/fig6
sources-request@panda.UUCP (01/09/86)
Mod.sources: Volume 3, Issue 78 Submitted by: tektronix!tekcrl!toddb #!/bin/sh # # RFS, a kernel-resident remote file system. Shar 2 of 7 # # # This is a shell archive, meaning: # 1. Remove everything above the #!/bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # remote/doc/paper/remotefs # remote/doc/remotename.2 # remote/doc/remoteon.2 # remote/doc/rfs_server.8 # remote/doc/rmtmnt.8 # remote/file.c # remote/fileserver.c # remote/find.c # remote/info.c # remote/init.c # # remote/doc/paper/remotefs # if [ -f remote/doc/paper/remotefs ]; then echo -n 'Hit <return> to overwrite remote/doc/paper/remotefs or ^C to quit' read ans rm -f remote/doc/paper/remotefs fi sed -e 's/^.//' << \SHAREOF > remote/doc/paper/remotefs X.HS I X.if "\*(.T"mag" \{\ X. nr PS 12 X. nr VS 14 X.\} X.pl 9.75i X.TR X.DR X.de CN X.. X.TL XDesign Considerations for Remote File Systems X(Extended Abstract) X.AU XT. Brunhoff X.AI XComputer Environments Group XApplied Research Group XTektronix, inc. X.AB XThere have been several remote file systems written, Xincluding one written by the author called \fBRemotefs\fR. XThis paper covers the design choices Xthat can be made at several software levels, Xfrom where the hooks for a remote file system Xlie in the operating system, Xon up to the user interface, Xand reveals those made by \fBRemotefs\fP. XThe reader should have a strong familiarity Xwith the 4.2 BSD kernel function \fInamei()\fP, Xthe concept of mount points, Xthe system call interface and Xthe 4.2 BSD socket paradigm. X.AE X.SH XHistory X.PP XThe Computer Research Labs within the Applied Research Group Xhas approximately forty-five internally\-designed workstations, Xcalled X.I Magnolias, Xtwenty newly announced Tektronix 4404 AI workstations, Xcalled \fIPegasus\fP, a X.I VAX 11/780 Xand a X.I VAX 11/750. XThe Computer Environments Group, Xwithin the Computer Research Labs Xcares for most of these machines and the software that runs on them. X.PP XAfter porting 4.2 BSD Unix to the X.I Magnolia, Xthe amount of software available quickly outgrew Xthe capacity of its 35-megabyte winchester drives. XTo alleviate this, Xthe author designed and began in December of 1984 to write a Xremote file system based on a implementation paradigm used Xby K. McKusick in his implementation of the 4.2 BSD file system; Xi.e., "write it in user-mode to fit in the kernel". XThis paper is in part Xabout that implementation, Xand about design and Ximplementation in general to achieve a remote (or distributed) file system. XAt this writing, Xthe design still lies mostly in the user level, Xlinked in by the \fBld(1)\fP flag X\fI\-lremote\fP, Xwith a few new system calls.\(dg X.FS \(dg XThis remote file system, Xknown simply as \fBRemotefs\fP, Xshould not be confused with another, Xmore complete remote file system, Xcalled \fBDFS\fR. XThe latter is available on the Tektronix 6000 series workstations. X.FE X.NH 1 XChoosing a Springboard for the Software X.PP XThe focus of I/O activity on X.B UNIX Xis the inode; Xeach time a file is open, read, written, locked, closed, etc., Xthe inode is referred to. XThese system calls Xconverge on the system call interface which dispatches calls to Xthe appropriate internal routine. XAny system calls that involve a path name must call \fInamei()\fP Xfor the inode information, and similarly, any system calls that Xdeal with file descriptors must refer to the inode information Xgenerated by an \fIopen()\fP or \fIcreate()\fR. XOnly then can the data on the disks be accessed. X.so fig1.\*(.T X.PP XFor example, in Figure 1, X\fIopen()\fP makes a request to the system call interface; Xthe system call interface determines that the \fIopen()\fP system call must Xbe executed (the kernel \fIopen()\fP is just a call to \fIcopen()\fP). X\fICopen()\fP then calls \fInamei()\fP to get the inode information Xwhich in turn calls the appropriate disk device driver to get the inode Xfrom the correct disk. XSubsequent \fIread()\fP Xor \fIwrite()\fP calls use this information to access the disk. XIt makes sense to make \fInamei()\fP the focal point for the remote Xfile system implementation Xbecause of its critical role. XBut there are other approaches. X.NH 2 X\&\.\.\. From the Device Driver X.PP XSince \fInamei()\fP gets its information from the Xdisk via the disk driver, Xwe have only to Xreplace the disk driver with a \fIremote\fP disk driver. XThis remote disk driver would be designed to send requests for disk Xblocks directly to a remote host to be satisfied Xfrom a single partition on its own disk. X.so fig2.\*(.T X.PP XNow, following the previous example in Figure 2, X\fInamei()\fP may instead encounter a mount point while Xtrying to find an inode for a file, Xand will get its inode information from the remote disk driver. XSimilarly, Xreads and writes Xrequest blocks from the \fIremote\fP disk driver Xusing this inode information. X.PP XThis is where early implementations put remote file systems. XIt offers speed and a good deal of portability with Xthe kernel changes limited to the device driver, Xbut it limits usefulness because each partition Xon every remote system must be mounted, Xand access can only be read\-only. X.NH 2 X\&\.\.\. In \fInamei()\fP X.PP XThere are two ways of checking for ``remoteness'' Xin \fInamei()\fP, Xbut the key change to \fInamei()\fP is that it must fail in Xits inode lookup when it encounters a path name component Xon a remote machine; then it must return with a special error. XThis \fInamei()\fP failure mechanism will be alluded to later. X.PP XOne method, depicted in Figure 3, Xis to catch any reference to a special Xsyntax of path name, Xsuch as \fI/\.\.\|/host/pathname\fP, X\fI/net/host/pathname\fP Xor \fI//host/pathname\fP. XThis is a cue to \fInamei()\fP Xto return a special error code to the invoking system call. XIt is then Xthe responsibility of that system call to send Xa request to a server on the remote host. XThis special syntax is very convenient because the X\fIhost\fP component of the path Xneed not correspond to some existing ``mount point''. XHence, hosts can be mounted and unmounted on demand Xif the implementor cares to take the trouble. X.so fig3.\*(.T X.PP XA second strategy is very similar Xexcept that it uses a more natural Xsyntax of \fI/host/pathname\fP X(without needing symbolic links). XAn important point is that the host cannot be ``mounted'' Xon a directory, Xbut rather on a special mount point, Xor even a plain file. XThe reason for this is a bit obscure, Xbut will be clarified shortly. X.PP XThe special path names like \fI/\.\.\|/host/pathname\fP Xor mount points like \fI/host\fP are needed partly because no XUNIX program should ever find these gateways through normal perusal of Xa file system. XImagine how long the command ``\fIfind / -print\fP'' would take Xif it traversed every remote host as well as itself! XFor this reason, using a directory for a mount point would Xnot be appropriate. X.PP X\fBRemotefs\fP uses a plain file as a mount point because of some extra Xbenefits: Xthe simplicity of the code changes to \fInamei()\fP, Xand not having to add another file type for \fBUNIX\fP utilities to learn. XThe path name \fI/host\fP remains a valid local filename, Xbut \fI/host/\fP or anything longer results in Xa special case, which \fInamei\fP labels with the error X\fBENOTDIR\fP X(See Appendix A). XIt is this place in the \fBUNIX\fP kernel Xthat \fBRemotefs\fP detects all remote file references. X.NH 3 XAn Aside: When to Follow a Symbolic Link in \fINamei()\fP. X.NH 2 X\&\.\.\. At the User Level. X.PP XA slight variation of the above, Xshown in Figure 4, Xis to simply place the check for ``remoteness'' in Xappropriate system calls with in the C runtime library, X\fIlibc.a\fP. X(see Appendix B for this list). XUnfortunately, Xthis requires the user level software to duplicate Xwhat \fInamei()\fP does Xwhenever a system call involving a path name returns the Xerror \fBENOENT\fR or \fBENOTDIR\fR. XThis implementation approach is typically slower, Xbut very portable. X.so fig4.\*(.T X.NH 1 XFile Descriptors X.PP XOnce an \fIopen()\fP or \fIcreat()\fP has succeeded Xon the remote host and returned a file descriptor, say \fIi\fP, Xwe must allocate a real file descriptor, \fIj\fP, on the local machine. XThis may be done in the kernel or user level code, Xbut it is most important that the user's idea of the ordinate Xvalue of \fIj\fP remain inviolate. X.NH 2 XFile Descriptors Handled at User Level X.NH 2 XFile Descriptors Handled at Kernel Level X.NH 2 XInheriting File Descriptors Across a \fIfork()\fP or \fIexec()\fP X.NH 2 XReading Directories on a Remote Host X.NH 1 XChanging Directories X.PP XImplementing the ability to change Xdirectories is a big win for any implementation Xbecause interactive shells will then allow you to Xperuse directories on remote hosts. XHowever, inheritance of file descriptors must Xbe implemented, Xas explained in section 2.3. XThe \fIchdir()\fP executing on the remote host Xdoes nothing special. XIf it succeeds, all is well. XBut on the local side, Xthe software cannot change state (the current Xworking directory) Xto match what has occurred on the remote machine. XInstead, Xit must simply be remembered it in some way. X.NH 2 XInterpreting Pathnames X.PP XIf the remote file system software lies entirely in user\-level code, Xthen the only solution is for the software Xto remember \fIchdir()\fP's path name argument Xand that the current directory is on a remote host. XThen when a new path name is passed to a system call, Xthe software need only to check to see if it is absolute Xor relative (with or without a leading '/' character, respectively). XIf it is relative, Xthen the request must be sent to the remote host. X.PP XOn the other hand if the software uses a special Xmount point like \fI/host\fP, Xthe kernel can arrange Xto make the process's working directory inode Xto be the mount point's inode. XThis is very convenient because no absolute vs. relative Xchecks are necessary Xand nothing need be added to \fInamei()\fP. XFor example, Xabsolute path names in a system call will still cause the mechanism Xto function normally. XAnd relative path names will immediately fail in \fInamei()\fP X(remember our key change in section 1.2). XSee Appendix A. X.NH 2 XPwd(1) and Changing to ``/\.\.'' on the Remote Host X.NH 1 XSpecial Problems X.NH 2 X\fIExec()\fP X.NH 2 X\fIFork()\fP and \fIvfork()\fP X.NH 2 X\fISelect()\fP X.NH 2 XUniqueness of Files Across Hosts X.NH 1 XPermissions Across Hosts X.NH 2 XDatabase Model X.NH 2 XDynamic Model X.NH 1 XServer Design X.NH 2 XWhen to \fIfork()\fP X.NH 2 XHow to Change Uid/Gid permissions X.NH 2 XFile Descriptor Overload X.NH 2 XCommunication Model X.NH 3 XProtocol X.NH 3 XWho Answers the Phone? X.NH 3 XSpeed Improvements X.PP XImagine Xa very loose view of the protocol (moving downward): X.so fig5.\*(.T XA remote file system implementation Xhas a decidedly synchronous flavor to it, Xand for most system calls, Xnothing else is appropriate. XBut \fIRead()\fP and \fIwrite()\fP system calls Xlend themselves very well to optimization, Xspecifically, lookahead. X.PP XA change in the protocol could be made Xbased on expected requests. XAfter, Xsay, two consecutive \fIread()\fP requests Xon the same file descriptor for the same number of bytes, Xthe local host could ask the server to continue servicing Xthe same request until further notice. XThe response would contain the same information Xthat would be expected on a normal request, Xand would, of course, Xterminate on an error or end\-of\-file. XThe remote host, could easily detect and recover from a termination Xof this kind, too. XThe difficult part would be for the local host to try to stop Xthe servicing before end\-of\-file. XSo, Xour protocol now would be X.so fig6.\*(.T XNotice that the responses may continue on beyond Xthe request to stop, Xbut the acknowledgment of the request to stop would put Xthe hosts back in sync. XThe remote host has only to reset its read pointer Xback to the point where it had serviced X\fIn\fP requests, Xand the local host must read the responses up to and including Xthe acknowledgment. X.PP XThe protocol also may Xhave to refuse continuation service for file descriptors Xthat read from devices. X.PP X\fIWrite()\fP is similar, Xbut recovery when the remote host Xreaches an end\-of\-file or encounters an error Xwould be much more complicated, and in some cases impossible. XThe local host, Xon receipt of a request to stop from the remote host, Xwould have to not only reset its idea of the write pointer, Xbut perhaps the read pointer from which the data was gathered Xto do the write. XConsidering that the reading may have been done from multiple Xfiles or the data was transformed in some way, Xthe remote file system software may not be able to accomplish the task. XIt appears to be only feasible if the implementor is willing to sacrifice Xidentical behavior of user\-level software on remote vs. local file Xsystems. X.NH 1 XStatus of \fBRemotefs\fP X.NH 1 XAppendix A X.so appendixB.out X.NH 1 XAppendix C SHAREOF chmod 664 remote/doc/paper/remotefs # # remote/doc/remotename.2 # if [ -f remote/doc/remotename.2 ]; then echo -n 'Hit <return> to overwrite remote/doc/remotename.2 or ^C to quit' read ans rm -f remote/doc/remotename.2 fi sed -e 's/^.//' << \SHAREOF > remote/doc/remotename.2 X.TH REMOTENAME 2 "27 July 1983" X.UC 4 X.SH NAME Xremotename \- provide name information to the kernel X.SH SYNOPSIS X.nf X.ft B X#include <remote/remotefs.h> X Xremotename(action, name, namelen, path) Xlong action; Xcaddr_t name; Xlong namelen; Xchar *path; X.fi X.SH DESCRIPTION X.I Remotename Xis an interface for an exchange of information with Xthe kernel about remote hosts. XThe value of X.I action, Xdefined by NM_* symbolic constants in remote/remotefs.h, Xdetermines what exchange takes place: X.PP XNM_SERVER X.br XThe current process is registered as the name server for the kernel. XWhenever the kernel needs a path name translated into Xan internet address, Xthe current process will receive the SIGIO signal. XArguments besides X.I action Xare ignored. XIf there is already a process registered as the name server, X.I remotename Xwill fail. X.PP XNM_WHATNAME X.br XAfter receiving the SIGIO signal, Xthe registered name server should Xsupply this action to X.I remotename Xalong with a valid Xcharacter pointer Xin X.I name Xand its length in X.I namelen. XThe kernel will copy into that pointer Xa null\-terminated string of the form "/single-component". XIt is the name server's job to translate "single-component" Xinto a valid internet address. X.PP XThe kernel obtains the single component from the second component Xof a path name used in a system call by some user process. XThe first component of that path name would have been a generic mount Xpoint. X.PP XNM_NAMEIS X.br XAfter obtaining a valid internet address, Xthe registered name server should Xsupply this action to X.I remotename Xalong with a valid X.I name Xand X.I namelen Xcontaining the internet address the way that X.I connect(2) Xwould expect it, Xand a X.I path Xcontaining the nameserver's opion of what the null-terminated Xmount point should Xhave been. X.PP XNM_DEBUG X.br XTurns on debug level to the value in X.I system. X.SH "RETURN VALUE X.I Remotename Xreturns 0 if the action occurred, \-1 if X.I name Xor X.I path Xis an invalid address (when a valid one was expected), Xor the user is not the super user. X.SH ERRORS X.TP 15 X[EPERM] XThe caller is not the super-user Xor the calling process is not the registered nameserver. X.TP 15 X[EINVAL] X.I Name Xor X.I path Xare not valid addresses (if expected), X.I namelen Xis too long or Xthe X.I action Xwas not recognized. X.TP 15 X[ENOREMOTEFS] XOn X.I NM_WHATNAME Xthere was no pathname for which the kernel needed a internet address. X.TP 15 X[EBUSY] XThe calling process is trying to register as the nameserver, Xbut one already exists. X.SH "SEE ALSO" Xremoteon(2), remoteoff(2), rmtmnt(8), rfs_server(8) X.SH BUGS X.I NM_DEBUG Xwill not be recognized unless the kernel is has the debug software Xcompiled in. SHAREOF chmod 664 remote/doc/remotename.2 # # remote/doc/remoteon.2 # if [ -f remote/doc/remoteon.2 ]; then echo -n 'Hit <return> to overwrite remote/doc/remoteon.2 or ^C to quit' read ans rm -f remote/doc/remoteon.2 fi sed -e 's/^.//' << \SHAREOF > remote/doc/remoteon.2 X.TH REMOTEON 2 "27 July 1983" X.UC 4 X.SH NAME Xremoteon, remoteoff \- turn on and off remote file system X.SH SYNOPSIS X.nf X.ft B Xremoteon(path, pathlen, name, namelen) Xchar *path; Xint pathlen; Xstruct sockaddr *name; Xint namelen; X.PP X.ft B Xremoteoff(path) Xchar *path; X.fi X.SH DESCRIPTION X.I Remoteon Xannounces to the system that the file system Xstarting with the root, aka "/", on the internet host X.I name Xhas been mounted on Xthe plain file X.I path; Xfrom then on, references to any files below X.I path Xwill refer to Xfiles below the root file system on the remote host, X.I name. X.I Path Xis a pointer to a null-terminated string Xcontaining the appropriate path name, Xbut for storage purposes in the kernel, X.I pathlen Xmust also be provided. X.I name Xcan only be a valid internet address (this may be extended later), Xand X.I namelen Xshould be the correct length, Xnormally X.I sizeof(struct sockaddr_in). X.PP X.I Path Xmust exist already and be Xa plain file. XIts old contents Xare still accessible while the remote file system Xis mounted, Xbut the file cannot be removed. X.PP XA special case for X.I remoteon Xand X.I remoteoff Xis when X.I path Xis a null pointer. XThis tells the kernel to disallow X.I (remoteoff) Xor allow X.I (remoteon) Xremote access for the current Xprocess, Xand is intended primarily for use with a remote file server Xto prevent remote file system loops. XBy default, Xall processes are allowed remote access. XNote that while only the super-user may turn on or off the remote Xfile system, Xany user may turn on and off remote access for himself. X.PP X.I Remoteoff Xannounces to the system that the X.I path Xfile is no longer to be a remote mount point. XCurrently, Xeven if X.I remoteoff Xfails, Xthe remote file system is marked for closing and Xno more usage is allowed. XSystem calls that must be run on the remote system after Xthis point will fail (return \-1). X.SH "RETURN VALUE X.I Remoteon Xreturns 0 if the action occurred, \-1 if X.I path Xis inaccessible, Xalready a remote mount point, not an appropriate file, if X.I path Xdoes not exist, Xor if there are already too many remote file systems mounted. X.PP X.I Remoteoff Xreturns 0 if the action occurred; \-1 if Xif the file is inaccessible or Xdoes not point to a remote file system, Xor if there are active processes using the remote Xfile system. X.SH ERRORS X.I Remoteon Xwill fail when one of the following occurs: X.TP 15 X[EPERM] XThe caller is not the super-user. X.TP 15 X[ENOENT] X.I Special Xdoes not exist. X.TP 15 X[EISDIR] X.I Path Xis not a plain file. X.TP 15 X[EINVAL] X.I Namelen Xis too long. X.TP 15 X[ENOBUFS] Xthe system is out of mbuf structures. X.TP 15 X[EFAULT] X.I Name Xpoints to a bad address. X.TP 15 X[ETOOMANYREMOTE] XThe action would overflow internal tables. X.TP 15 X[EBUSY] X.I Path Xis already a remote mount point. X.PP X.I Remoteoff Xmay fail with one of the following errors: X.TP 15 X[EPERM] XThe caller is not the super-user. X.TP 15 X[ENOENT] X.I Path Xdoes not exist. X.TP 15 X[EBUSY] XA process is holding a reference to the remote file system. X.SH "SEE ALSO" Xrmtmnt(8), rfs_server(8) SHAREOF chmod 664 remote/doc/remoteon.2 # # remote/doc/rfs_server.8 # if [ -f remote/doc/rfs_server.8 ]; then echo -n 'Hit <return> to overwrite remote/doc/rfs_server.8 or ^C to quit' read ans rm -f remote/doc/rfs_server.8 fi sed -e 's/^.//' << \SHAREOF > remote/doc/rfs_server.8 X.TH RFS_SERVER 8 "18 October 1985" X.UC 4 X.SH NAME Xrfs_server \- remote file system server and kernel name server X.SH SYNOPSIS X.B /etc/rfs_server X[ -s internet-service ] X[ -v debug-level ] X.SH DESCRIPTION XThis is a server for the remote file system and Xis intended to be started up in /etc/rc. X.PP X.PP XThe optional flag X.I \-s Xand its argument, X.I internet-service, Xtells the server to accept calls on the named service Xport described in /etc/services. XWithout this argument, X.I rfs_server Xuses the service X.I remotefs. X.PP XThe optional flag X.I \-v Xand its argument, X.I debug-level, Xstarts up the server with the given initial debug level. XThe argument should be a hexadecimal number containing one bit Xfor each class of debug output desired. X.PP XThe server maintains three identities, Xand each can be determined by the current command line using the X.I ps(1) Xcommand. X.PP XThe first identity is the X.I sentry Xof which there can only be one at any time. XThe command line for this remains unaltered from the way it was started. XThe function of the X.I sentry Xserver is to build a database of all hosts in /etc/hosts, Xall users and groups in /etc/passwd and /etc/group, Xand of all users' .rhost files. XAfter this database has been built, Xit waits Xfor connections from remote hosts. X.PP XThe second identity is a X.I "gateway server" Xand changes its command line Xto tell which host it is a X.I "gateway server" Xfor. XThis identity is the child of the X.I sentry Xafter the latter receives a connection from a remote host; Xthere can only be one X.I "gateway server" Xfor each remote host. XThe responsibilities of the X.I "gateway server" Xare to service context-free system calls for the remote host, Xcreate other servers to handle context-sensitive system calls, Xmaintain complete information about all remote processes being served, Xand ensure at all times Xthat only one server has control of the socket file Xdescriptor to the remote machine being served. X.PP XThe third identity is that of a plain X.I server, Xand changes its command line to be similar to that Xof the X.I "gateway server" Xexcept that the word X.I gateway Xis missing and it identifies its parent process. XIts responsibilities Xare to service context-free system calls for the remote host and Xcreate other servers for remote processes that must inherit Xcertain context information (e.g. remote current working directories, Xand open file descriptors). X.SH "DEBUG LEVELS" XIt should be noted that the debug option is only useful with Xa copy of the source code in hand and a server that has been Xcompiled with the debug software turned on. XThe current selection of the bits are: X.PP X.ta 1i 2.5i 4i X 0x00000001 process switching X.br X 0x00000002 system calls X.br X 0x00000004 setuid/setgid, umask X.br X 0x00000008 file descriptor allocation X.br X 0x00000010 connections X.br X 0x00000020 server switching X.br X 0x00000040 nameserver X.br X 0x00000080 directory nuxi X.br X 0x00000100 message in and out X.br X 0x00000200 don't fork child for gateway (good for adb) X.br X 0x00000400 local/remote file decisions X.br X 0x00000800 don't remove log file on exit (except exit on error) X.br X 0x00001000 exec information X.br X 0x00002000 auto debug for 0x20 (server switching) X.br X 0x00004000 parsing messages to gateway X.PP XAnother method of setting the debug level in any identity of the X.I rfs_server Xis to place the desired hexidecimal level in the file /usr/tmp/rfs_debug Xand to send the appropiate server signal number 5, aka X.I SIGTRAP. XThis method can be used with X.I sentry Xservers, any X.I gateway Xservers, and any other servers that are marked active. XIt should not be used on sleeping servers. X.PP XIf any server receives SIGILL, SIGSEGV or SIGBUS, Xit will arrange for its core file to be dumped in /usr/tmp. X.SH "RESTARTING THE SERVER" XThe best way to restart the X.I sentry Xserver (e.g. installing a new X.I rfs_server), Xis to simply run the new server. XThe new server knows how to examine the previous log file Xto discover the pid number of the previous server, and kill it. X.PP XIf you know that that will fail, then the second best way Xis to send it the signal X.I SIGTERM X.PP XSending X.I SIGTERM Xsignal to a X.I "gateway server" Xwill cause it and all of its children to gracefully go away. X.SH "SEE ALSO" Xremotename(2), Xrmtmnt(8). X.SH BUGS XProbably. SHAREOF chmod 664 remote/doc/rfs_server.8 # # remote/doc/rmtmnt.8 # if [ -f remote/doc/rmtmnt.8 ]; then echo -n 'Hit <return> to overwrite remote/doc/rmtmnt.8 or ^C to quit' read ans rm -f remote/doc/rmtmnt.8 fi sed -e 's/^.//' << \SHAREOF > remote/doc/rmtmnt.8 X.TH RMTMNT 8 "18 October 1985" X.UC 4 X.SH NAME Xrmtmnt \- mount and dismount remote file systems X.SH SYNOPSIS X.B /etc/rmtmnt X[ -s internet-service ] host path X.PP X.B /etc/rmtmnt X-g path X.PP X.B /etc/rmtmnt X-u path X.PP X.B /etc/rmtmnt X.SH DESCRIPTION XIn the first usage, X.I rmtmnt Xannounces to the system that the file system Xstarting with the root, aka "/", on the internet host named X.I host Xhas been mounted on Xthe plain file X.I path; Xfrom now on, references to any files below X.I path Xwill refer to Xfiles below the root file system on the remote host, X.I host. XThe file X.I path Xmust exist already; it must be a file. XIt becomes the name of the newly mounted root. X.PP XThe optional flag X.I \-s Xand argument X.I internet-service Xindicates that the kernel should use Xthe named internet service (defined in /etc/services) Xwhen connecting to that remote host. X.PP XThe second usage with the X.I -g Xflag indicates that the mount point is to be "generic". XBy convention, Xthe name of this path ought to be X.I /net, Xbut may be any valid path name. XNo specific host is associated with the Xpath name. XInstead, Xthe component following X.I /net Xis handed to the nameserver, usually X.I rfs_server(8), Xfor translation to an internet address. XWhen the kernel receives the new address, Xan implicit mount is made by the kernel. X.PP XThe third usage with the X.I -u Xflag informs the kernel that the internet host Xmounted on X.I path Xshould be unmounted. X.PP XThe last usage, Xhaving no arguments or flags Xwill print out a complete status of all current mount points. X.SH "SEE ALSO" Xremoteon(2), Xrfs_server(8). X.SH BUGS XImlicit mount points cannot be unmounted. X.PP XIf a command which has a current working directory Xon a remote machine through an X.I implicit Xmount point Xattempts to find the current working directory, Xit will produce a pathname missing the second component, Xand, hence, will fail. XExplicit mount points work fine. SHAREOF chmod 664 remote/doc/rmtmnt.8 # # remote/file.c # if [ -f remote/file.c ]; then echo -n 'Hit <return> to overwrite remote/file.c or ^C to quit' read ans rm -f remote/file.c fi sed -e 's/^.//' << \SHAREOF > remote/file.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: file.c,v $ X * Revision 2.0 85/12/07 18:21:11 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: file.c,v 2.0 85/12/07 18:21:11 toddb Rel $"; X#include "server.h" X#include <errno.h> X Xextern int fds_in_use; Xextern int errno; X X/* X * here we allocate a file descriptor to a process and make note of our X * total number of open file descriptors. 'fd' is the file descriptor X * that the server itself got back, and remotefd is the file descriptor X * that the remote process is expecting. X */ Xallocate_fd(fd, proc, remotefd) X register int fd, X remotefd; X register process *proc; X{ X if (fd != -1) X { X proc->p_fds[ remotefd ] = fd; X debug3("allocate local fd %d, remote fd %d\n", X fd, remotefd); X fds_in_use++; X checkfiletype(fd); X } X else X remotefd = -1; X return(remotefd); X} X Xdeallocate_fd(proc, remotefd) X register process *proc; X register long remotefd; X{ X register char fd; X register long retval; X X if ((unsigned)remotefd >= NOFILE) X { X errno = EBADF; X return(-1); X } X fd = proc->p_fds[ remotefd ]; X proc->p_fds[ remotefd ] = -1; X retval = close(fd); X fds_in_use--; X return(retval); X} SHAREOF chmod 444 remote/file.c # # remote/fileserver.c # if [ -f remote/fileserver.c ]; then echo -n 'Hit <return> to overwrite remote/fileserver.c or ^C to quit' read ans rm -f remote/fileserver.c fi sed -e 's/^.//' << \SHAREOF > remote/fileserver.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: fileserver.c,v $ X * Revision 2.0 85/12/07 18:21:14 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: fileserver.c,v 2.0 85/12/07 18:21:14 toddb Rel $"; X#include <errno.h> X#include <stdio.h> X#include <ctype.h> X#include <signal.h> X#include "server.h" X#include <sys/file.h> X Xextern long errno; Xextern long from_servers; Xextern long to_gateway; Xextern long so_listen; Xextern long blocking_servers; Xextern short gateway_server; Xextern short current_ppid; Xextern short current_pid; Xextern short current_uid; Xextern short current_server; Xextern char mntpt[ MAXPATHLEN ]; Xextern char *program; Xextern char *last_argaddr; Xextern char *logfile; Xextern char *service; Xextern char *syscallnames[]; Xextern boolean i_am_gateway; Xextern boolean i_am_asleep; Xextern boolean i_have_control; Xextern boolean route_to_gateway; Xextern boolean watch_for_lock; Xextern boolean gateway_needs_control; Xextern syscallmap smap[]; Xextern process *wildcard; Xextern hosts *host; X Xmain(argc, argv) X int argc; X char **argv; X{ X register hosts *h; X X setopts(argc, argv); X if ((remote_debug & 0x200) == 0 && fork()) X exit(0); X current_pid = getpid(); X setlogfile(); X if ((so_listen = tcppassive()) < 0) X log_fatal("cannot open socket\n"); X init(); X for (;;) X { X if ((h = tcpaccept(so_listen)) == NULL) X break; X debug4("call on fd %d, portno %d, from host \"%s\"\n", X h->h_cmdfd, h->h_portnum, h->h_names[0]); X dumphost(h); X if (server(h)) X exit(0); X } X} X X/* X * This is the top lexical level for the server. We decide here X * when to call for a next request and whether we are running the X * new format remote fs or not. X * X * We also decide whether this is a connection from the mount program X * on a remote host or not. If it is, then we just want to assemble the X * info that it gives us and not become a child server. X */ X Xserver(h) X register hosts *h; X{ X long pipefd[ 2 ]; X struct message msgbuf, X *getmsg(); X register struct message *msg = &msgbuf; X register process *proc; X register long cmd, len; X X /* X * Get the first message from this connection. X */ X alarm(5); X if (! (msg = getmsg(h->h_cmdfd))) X { X log("connection initiation lost to \"%s\"\n", h->h_names[0]); X close(h->h_cmdfd); X h->h_cmdfd = -1; X alarm(0); X return(FALSE); X } X alarm(0); X X /* X * may be a special command X */ X len = msg->m_hdlen; X if (msg->m_syscall == RSYS_nosys) X { X cmd = msg->m_args[0]; X debug5("new client; cmd=%d\n", cmd); X switch(cmd) { X case CMD_SERVICE: X break; X case CMD_MOUNT: X gobble_last_msg(h->h_cmdfd, msg); X getbyteorder(h); X getrusers(h); X return(FALSE); X case CMD_NEEDMOUNT: X sendmount(h); X dont_gobble_msg(msg); X return(FALSE); X default: X log_fatal("unknown server directive = %d\n", cmd); X } X } X else X { X debug5("new client, not mounted by rmtmnt\n"); X dont_gobble_msg(msg); X if (!h->h_mounted) X getmount(h); X } X X /* X * If we reach this point, then we are to be the gateway server. X * There may ba a server still running. Kill it. X */ X if (h->h_serverpid) X sendsig(h->h_serverpid, SIGTERM); X X if ((remote_debug & 0x200) == 0 && vfork()) X { X wait(0); X /* X * we are the parent... just return. X */ X close(h->h_cmdfd); X h->h_cmdfd = -1; X return(FALSE); X } X else if ((remote_debug & 0x200) == 0 && (h->h_serverpid = fork())) X exit(0); X host = h; X wildcard->p_handler = gateway_server = current_pid = getpid(); X set_label("active"); X if ((remote_debug & 0x200) == 0) X { X setlogfile(); X close(so_listen); X } X if (pipe(pipefd) < 0) X log_fatal("Can't open pipe\n"); X from_servers = pipefd[ 0 ]; X to_gateway = pipefd[ 1 ]; X X /* X * Ok, now be a server! X */ X for(;;) X { X if (i_am_gateway && ! i_have_control) X { X gateway_listen(); X continue; X } X /* X * The gateway may be waiting for control. Let's see. X */ X if (watch_for_lock) X if (gateway_needs_control X || flock(2, LOCK_NB | LOCK_SH) < 0) X { X debug5("gateway wants control\n"); X reroute(gateway_server, msg); X continue; X } X else X flock(2, LOCK_UN); X X if ((msg = getmsg(host->h_cmdfd)) == NULL) X break; X proc = change_to_proc(msg); X if (proc == NULL) X continue; X X errno = 0; X (*smap[ msg->m_syscall ].s_server)(msg, proc); X } X debug5("done.\n"); X if (i_am_gateway) X for (proc = host->h_proclist; proc; proc=proc->p_next) X { X /* X * just hand it to the other server... he'll get eof X */ X if (proc->p_handler != current_pid) X sendsig(proc->p_handler, SIGIO); X } X else X say_something(S_EOF, 0); X if ((remote_debug & 0x800) == 0) X unlink(logfile); X return(TRUE); X} X Xsetopts(argc, argv) X register int argc; X register char **argv; X{ X register int error = FALSE; X register char **p; X extern char **environ; X X program = argv[0]; X last_argaddr = argv[argc-1]; X for (argv++, argc--; argc; argv++, argc--) X { X if (**argv != '-') X { X log("arg \"%s\" is unknown\n", X *argv); X error = TRUE; X } X switch(argv[0][1]) { X case 'v': X if (argv[0][2]) X remote_debug = atox(argv[0] + 2); X else if (isdigit(argv[1][0])) X argc--, remote_debug = atox(*(++argv)); X break; X case 's': X if (argv[0][2]) X service = argv[0] + 2; X else X argc--, service = *(++argv); X break; X default: X log("unknown flag = %s\n", *argv); X error = TRUE; X } X } X /* X * Make sure that last_argaddr points to the last possible address X */ X p = environ; X while (*p) X p++; X if (p != environ) X p--; X if (*p) X last_argaddr = *p; X last_argaddr = (char *)ctob(btoc(last_argaddr)) - 1; X debug5("program addr=%x, last_argaddr=%x\n", program, last_argaddr); X X if (error) X exit(1); X} X X/* X * ascii to hex X */ Xatox(buf) X char *buf; X{ X register char *p; X register unsigned num, nibble; X X /* X * now, take it out checking to make sure that the number is X * valid. X */ X if (! buf) X return(0); X for(num=0, p = buf; *p; p++) X { X nibble = *p; X if (nibble >= 'A' && nibble <= 'F') X nibble -= 'A' - 10; X else if (nibble >= 'a' && nibble <= 'f') X nibble -= 'a' - 10; X else if (nibble >= '0' && nibble <= '9') X nibble -= '0'; X else X return(0); X num = (num << 4) | nibble; X } X return(num); X} X X/* X * fork() and give the process on the top of the list to the child. X */ Xbecome_server(msg) X register struct message *msg; X{ X register long pid, i; X register char *fds; X register process *proc = host->h_proclist; X X /* X * Have to change to uid 0 or we may be refused a fork X */ X change_to_uid(0); X i_am_asleep = TRUE; X if (pid = fork()) /* the parent loses control */ X { X if (pid < 0) X log_fatal("cannot fork\n"); X debug5("new server: pid=%d,mine=%d give him (%d)\n", X pid, current_pid, host->h_proclist->p_pid); X proc->p_handler = pid; X dont_gobble_msg(msg); X slumber(TRUE); X if (i_am_gateway) X current_server = pid; X return(FALSE); X } X X /* X * If we got this far, then we are no longer the gateway. So set X * our pid, etc. Also, try to dup stderr so that flock will work. X * If we can't do it, we are in big trouble. X */ X current_ppid = current_pid; X current_pid = getpid(); X if (i_am_gateway) X { X close(from_servers); X if (blocking_servers) X { X watch_for_lock = TRUE; X route_to_gateway = TRUE; X } X } X else X say_something(S_NEWSERVER, proc->p_pid); X i_am_gateway = FALSE; X set_label("active"); X wildcard->p_handler = current_pid; X proc->p_handler = current_pid; X if ((i = dup(2)) < 0) X log_fatal("cannot dup(2)\n"); X dup2(i, 2); X close(i); X debug5("new server: pid=%d, ppid=%d\n", current_pid, getppid()); X X return(TRUE); X} X X#ifdef RFSDEBUG Xdumphost(h) X register hosts *h; X{ X register rusers *ruser; X X if ((remote_debug & 0x10) == 0) X return; X log("host %s, local user = %s, ruser@%x\n", X *h->h_names, X h->h_default_user ? h->h_default_user->u_name : "default", X ruser = h->h_default_ruser); X log("\tr %s(%d)-->%s(%d)\n", X ruser->r_name, ruser->r_uid, X ruser->r_user->u_name, ruser->r_user->u_local_uid); X for(ruser = h->h_rusers; ruser; ruser=ruser->r_next) X log("\tr %s(%d)-->%s(%d)\n", X ruser->r_name, ruser->r_uid, X ruser->r_user->u_name, ruser->r_user->u_local_uid); X} X#endif RFSDEBUG X Xset_label(string) X register char *string; X{ X char process_label[ 100 ]; X static char *pend; X static short pid; X register char *pfrom, *pto; X register long i; X X if (pid != current_pid) X { X if (i_am_gateway) X sprintf(process_label, "%s gateway server: ", X host->h_names[0]); X else X sprintf(process_label, "%s server via %d: ", X host->h_names[0], pid); X pid = current_pid; X pend = program + strlen(process_label); X strncpy(program, process_label, last_argaddr - program); X pto = pend; X while (pto < last_argaddr) X *pto++ = ' '; X } X pto = pend; X pfrom = string; X while (pto < last_argaddr && *pfrom) X *pto++ = *pfrom++; X for (i=0; pto < last_argaddr && i<10; i++) X *pto++ = ' '; X if (pto <= last_argaddr) X *pto = '\0'; X} SHAREOF chmod 444 remote/fileserver.c # # remote/find.c # if [ -f remote/find.c ]; then echo -n 'Hit <return> to overwrite remote/find.c or ^C to quit' read ans rm -f remote/find.c fi sed -e 's/^.//' << \SHAREOF > remote/find.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: find.c,v $ X * Revision 2.0 85/12/07 18:21:23 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: find.c,v 2.0 85/12/07 18:21:23 toddb Rel $"; X#include "server.h" X#include <stdio.h> X#include <signal.h> X Xextern hosts *hostlist; Xextern hosts *host; Xextern users *userlist; Xextern boolean i_am_gateway; Xextern short current_pid; X Xprocess *findprocess(pid, uid) X register short pid; X register short uid; X{ X register process *p; X register rusers *ruser; X X debug0("findproc: ", dumpprocs(host->h_proclist)); X for(p = host->h_proclist; p; p=p->p_next) X if (p->p_pid == pid) X { X debug0("found pid %d\n", pid); X /* X * If the user changes uid, then change with him. X */ X if (uid >= 0 && uid != p->p_uid) X { X debug2("pid %d changes uid %d->%d\n", X pid, p->p_uid, uid); X p->p_uid = uid; X if (ruser = findremuid(&host->h_rusers, uid)) X p->p_ruser = ruser; X else X p->p_ruser = host->h_default_ruser; X debug2(" locally mapped to %s(%d)\n", X p->p_ruser->r_user->u_name, X p->p_ruser->r_user->u_local_uid); X } X toplist(&host->h_proclist, p); X return(p); X } X return(NULL); X} X X/* X * find the user structure whose name is 'name'. X */ Xusers *findusername(name) X register char *name; X{ X register users *user; X X for(user=userlist; user; user=user->u_next) X if (strcmp(user->u_name, name) == 0) X { X toplist(&userlist, user); X return(user); X } X return(NULL); X} X Xhosts *findhostname(name) X register char *name; X{ X register hosts *h; X register int i; X register char **hnames; X X for(h=hostlist; h; h=h->h_next) X for (i=0, hnames=h->h_names; hnames[ i ]; i++) X if (strcmp(hnames[ i ], name) == 0) X { X toplist(&hostlist, h); X return(h); X } X return(NULL); X} X Xhosts *findhostaddr(addr) X register struct in_addr *addr; X{ X register hosts *h; X X debug4("find %s...\n", inet_ntoa(*addr)); X for(h=hostlist; h; h=h->h_next) X if (bcmp(addr, &h->h_addr, sizeof(struct in_addr)) == 0) X { X toplist(&hostlist, h); X debug4("\tis %s (%s)\n", X h->h_names[0], inet_ntoa(h->h_addr)); X return(h); X } X else X debug4("\tnot %s (%s)\n", X h->h_names[0], inet_ntoa(h->h_addr)); X log("no host entry for %s, continuing anyway.\n", inet_ntoa(*addr)); X /* X * Kludge up a hosts structure for this guy X */ X h = newhost(); X h->h_names = newname(NULL, BOGUSHOST); X bcopy(addr, &h->h_addr, sizeof(struct in_addr)); X addlist(&hostlist, h); X return(h); X} X Xrusers *findremuid(list, uid) X register rusers **list; X register int uid; X{ X register rusers *ruser; X X for (ruser = *list; ruser; ruser=ruser->r_next) X if (ruser->r_uid == uid) X { X toplist(list, ruser); X return(ruser); X } X return(NULL); X} X X/* X * find the ruser structure whose name is 'name'. X */ Xrusers *findrusername(list, name) X register rusers **list; X register char *name; X{ X register rusers *ruser; X X for(ruser = *list; ruser; ruser=ruser->r_next) X if (strcmp(ruser->r_name, name) == 0) X { X toplist(list, ruser); X return(ruser); X } X return(NULL); X} X X#ifdef RFSDEBUG Xdumpprocs(p) X register process *p; X{ X register long i, fd; X X while(p) X { X log("proc@%x,pid=%d,uid=%d,next@%x,prev@%x,handler=%d\n", X p, p->p_pid, p->p_uid, p->p_next, p->p_prev, X p->p_handler); X log("\t%s(%d)->%s(%d),fds=", X p->p_ruser->r_name, p->p_ruser->r_uid, X p->p_ruser->r_user->u_name, X p->p_ruser->r_user->u_local_uid); X for (i=0; i<NOFILE; i++) X if ((fd = p->p_fds[ i ]) >= 0) X log("%d->%d ", i, fd); X log("\n"); X p=p->p_next; X } X} X#endif RFSDEBUG SHAREOF chmod 444 remote/find.c # # remote/info.c # if [ -f remote/info.c ]; then echo -n 'Hit <return> to overwrite remote/info.c or ^C to quit' read ans rm -f remote/info.c fi sed -e 's/^.//' << \SHAREOF > remote/info.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: info.c,v $ X * Revision 2.0 85/12/07 18:21:28 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: info.c,v 2.0 85/12/07 18:21:28 toddb Rel $"; X#include "server.h" X#include <stdio.h> X#include <sys/wait.h> X#include <sys/file.h> X#include <sys/stat.h> X#include <netdb.h> X#include <errno.h> X Xextern users *default_user; Xextern hosts *host; Xextern hosts *thishost; Xextern char byteorder[]; Xextern char *logfile; Xextern long serviceport; Xextern long errno; Xextern short current_pid; Xextern process *wildcard; Xextern boolean in_root_directory; Xextern boolean i_am_asleep; X Xgetbyteorder(h) X register hosts *h; X{ X register char *p; X X /* X * Read the byte order info. X */ X alarm(5); X p = (char *)h->h_byteorder; X if (read(h->h_cmdfd, p, 4) != 4) X { X log("can't read mount info from \"%s\"\n", h->h_names[0]); X alarm(0); X bzero(p, 4); X close(h->h_cmdfd); X h->h_cmdfd = -1; X return; X } X alarm(0); X if (bcmp(p, byteorder, 4) == 0) X h->h_byteorderok = TRUE; X else X h->h_byteorderok = FALSE; X debug4("byteorder=%d,%d,%d,%d: %s ours\n", X p[0], p[1], p[2], p[3], X h->h_byteorderok ? "same as" : "different than"); X} X Xgetrusers(h) X register hosts *h; X{ X char buf[ BUFSIZ ]; X register rusers *ruser; X register FILE *input; X register char *p; X register int uid; X X errno = 0; X /* X * Read in the users from the remote host and squirrel them away. X * Actually it is the actual password file from the remote X * host, and we ignore most of the info, and save the user name and X * uid. X */ X if ((input = fdopen(h->h_cmdfd, "r")) == NULL) X log_fatal("getrusers: cannot fdopen\n"); X X alarm(30); X while (fgets(buf, BUFSIZ, input)) X { X /* X * First, the user name. X */ X for(p=buf; *p && *p != ':'; p++) ; X *p = '\0'; X X /* X * now the user id number X */ X for(p++; *p && *p != ':'; p++) ; X uid = atoi(p+1); X X /* X * Now we need to add the info to our database on this remote X * host. If the user is already present, just update the uid X * number. If the user is not present, and there is a default X * local user for this remote host, use that. If not, then X * use the default user entry for this host (where the server X * runs). X */ X if (ruser = findrusername(&h->h_rusers, buf)) X { X debug2("(existing) "); X ruser->r_uid = uid; X } X else X { X debug2("(new, "); X ruser = newruser(); X ruser->r_name = copy(buf); X ruser->r_uid = uid; X if (h->h_default_user) X { X debug2("%s default)", *h->h_names); X ruser->r_user = h->h_default_user; X } X else X { X ruser->r_user = default_user; X debug2("host default)"); X } X addlist(&h->h_rusers, ruser); X } X debug2("host %s: user %s (%d) -> local user %s (%d)\n", X h->h_names[ 0 ], ruser->r_name, ruser->r_uid, X ruser->r_user->u_name, ruser->r_user->u_local_uid); X } X fclose(input); X h->h_cmdfd = -1; X alarm(0); X if (errno == EINTR) X log("can't get remote users from \"%s\"\n", h->h_names[0]); X} X X/* X * Try to obtain mount information for host 'h'. X */ Xgetmount(h) X register hosts *h; X{ X long savefd = h->h_cmdfd; X struct message msgbuf; X register struct message *msg = &msgbuf; X register long len; X X if (thishost == h) /* our own machine */ X { X log("we are talking to ourselves\n"); X h->h_cmdfd = open("/etc/passwd", O_RDONLY); X bcopy(byteorder, h->h_byteorder, 4); X h->h_byteorderok = TRUE; X } X else X { X if ((h->h_cmdfd = tcpconnect(h)) < 0) X goto done; X len = R_MINRMSG + sizeof(long); X msg->m_hdlen = htons(len); X msg->m_totlen = htonl(len); X msg->m_syscall = htons(RSYS_nosys); X msg->m_args[ 0 ] = htonl(CMD_NEEDMOUNT); X if (!sndmsg(h->h_cmdfd, msg, len, 0, 0)) X { X log("can't ask for mount info\n"); X close(h->h_cmdfd); X goto done; X } X getbyteorder(h); X } X getrusers(h); /* getrusers() closes the file descriptor */ Xdone: X h->h_cmdfd = savefd; X} X X/* X * Send mount information. This includes a 4-byte header containing the X * byte order for our machine, followed by /etc/passwd. X */ Xsendmount(h) X register hosts *h; X{ X char buf[ BUFSIZ ]; X register long fd = open("/etc/passwd", O_RDONLY), X cnt; X register char *p = buf; X X write(h->h_cmdfd, byteorder, 4); X while ((cnt = read(fd, p, BUFSIZ)) > 0) X _rmtio(write, h->h_cmdfd, p, cnt); X close(h->h_cmdfd); X h->h_cmdfd = -1; X close(fd); X} X X/* X * Mourne the death of any children. X */ Xmourne() X{ X union wait status; X char buf[ BUFSIZ ]; X register char *p = buf; X register long pid; X X while ((pid = wait3(&status, WNOHANG, 0)) > 0) X { X sprintf(p, "server %d found dead", pid); X p += strlen(p); X if (status.w_termsig) X sprintf(p, " by sig #%d", status.w_termsig); X p += strlen(p); X if (status.w_coredump) X sprintf(p, " with core dump", status.w_termsig); X p += strlen(p); X sprintf(p, " exit=%d\n", status.w_retcode); X debug5("%s", buf); X p = buf; X } X} X X/* X * Catch signals and only report. X */ Xcatch(sig, code, scp) X register long sig, X code; X register struct sigcontext *scp; X{ X log("caught signal #%d...", sig); X if (sig == SIGILL || sig == SIGSEGV || sig == SIGBUS) X { X change_to_uid(0); X chdir("/usr/tmp"); X log("aborting: code=%d, scp=%x, sp=%x, pc=%x, end of scp=%x\n", X code, scp, scp->sc_sp, scp->sc_pc, scp+1); X sendsig(current_pid, SIGEMT); X log_fatal("could not abort\n"); X } X else if (sig == SIGTERM) /* quietly go away */ X { X /* X * unlink the file only if we are allowed to and if it is X * not the sentry server's logfile. X */ X if ((remote_debug & 0x800) == 0 && host != NULL) X unlink(logfile); X cleanup(); X log("goodbye.\n"); X exit(0); X } X else X log_fatal("exiting\n"); X} X X/* X * Receive a wakeup call. X */ Xwakeup_call() X{ X if (! i_am_asleep) X { X log("recieved spurious wakeup call!\n"); X return; X } X i_am_asleep = FALSE; X} X X/* X * Provide name server function for kernel. At this point we have just X * recieved a SIGURG signal because the kernel wants us to translate a X * name. X */ Xnameserver() X{ X#ifdef CANREMOTE X char path[ BUFSIZ ], X hostname[ BUFSIZ ]; X struct sockaddr_in sinbuf; X register char *p1, *p2, *name; X register hosts *h = NULL; X register struct sockaddr_in *sin; X X if (remotename(NM_WHATNAME, 0, BUFSIZ, path) < 0) X return; X /* X * Find the end of the '/' prefix and copy up to the next '/' or X * null character. X */ X p1 = path; X while (*p1 == '/') X p1++; X p2 = hostname; X *p2++ = '/'; X while (*p1 && *p1 != '/') X *p2++ = *p1++; X *p2 = '\0'; X X /* X * Now look it up. X */ X if (hostname[1]) X h = findhostname(hostname+1); X if (h == NULL) X { X debug6("cannot find host for path \"%s\"\n", path); X sin = NULL; X } X else X { X sin = &sinbuf; X debug6("path %s mapped to host %s\n", path, h->h_names[0]); X bzero((char *)sin, sizeof (struct sockaddr_in)); X bcopy(&h->h_addr, (char *)&sin->sin_addr, X sizeof(struct in_addr)); X sin->sin_family = AF_INET; X sin->sin_port = serviceport; X } X remotename(NM_NAMEIS, sin, sizeof(struct sockaddr_in), hostname); X#endif CANREMOTE X} X X/* X * Decide if a file is really a local file to the client or not. We only X * look for explicit references like X * name1/name2/../name3 ... X * And we then check to see whether name2 is the root directory. If it is X * then we send the request back to the client. X */ Xislocal(msg, type) X register struct message *msg; X{ X register char *p; X register boolean checktwopaths; X register short syscall = msg->m_syscall; X register long offset1, X offset2 = -1, X localcnt = 0; X register process *proc; X char buf[ BUFSIZ ]; X X debug10("cwd=%s\n", getwd(buf)); X checktwopaths = (type & NEED_2REMOTE); X X if (checktwopaths) X p = twopath1addr(msg); X else X p = path1addr(msg); X if ((offset1 = find_dotdot(p)) >= 0) X localcnt++; X if (checktwopaths) X if ((offset2 = find_dotdot(twopath2addr(msg))) >= 0) X localcnt++; X if (localcnt) X { X debug10("%d paths are remote: \"%s\" @ %d, \"%s\" @ %d\n", X localcnt, X checktwopaths ? twopath1addr(msg) : path1addr(msg), X offset1, checktwopaths ? twopath2addr(msg) : "", X offset2); X setup_proc(proc = wildcard, msg->m_uid, msg->m_pid); X proc->p_errno = -1; X proc->p_returnval = offset1; X sendreturn(proc, host->h_cmdfd, NULL, 1, offset2); X } X return(localcnt); X} X X/* X * kernel code stolen for speed. X */ Xmyaccess(st, user, perm) X register struct stat *st; X register long perm; X register users *user; X{ X register long *gp, i; X X perm <<= 6; X if (user->u_local_uid != st->st_uid) { X perm >>= 3; X gp = user->u_local_groups; X for (i=0; i < user->u_numgroups; i++, gp++) X if (st->st_gid == *gp) X goto found; X perm >>= 3; Xfound: X ; X } X if ((st->st_mode & perm) != 0) X return (TRUE); X return(FALSE); X} X X/* X * look for a component of ".." terminated by a '/' or a null character. X * If we find one, examine the previous component to see if it is our X * root directory. X */ Xfind_dotdot(path) X register char *path; X{ X struct stat statb; X register char *p; X register struct stat *statp = &statb; X register long retval; X extern struct stat root; X X for (p = path; *p;) X { X while (*p == '/') X p++; X if (p[0] == '.' && p[1] == '.' X && (p[2] == '\0' || p[2] == '/')) X { X if (p == path) X if (in_root_directory) X return(0); X else X goto next_component; X *p = '\0'; /* we know it is a '.' */ X retval = lstat(path, statp); X *p = '.'; X if (retval < 0) X return(retval); X if (isroot(statp)) X return(p - path + 1); X } Xnext_component: X while (*p && *p != '/') X p++; X } X return(-1); X} SHAREOF chmod 444 remote/info.c # # remote/init.c # if [ -f remote/init.c ]; then echo -n 'Hit <return> to overwrite remote/init.c or ^C to quit' read ans rm -f remote/init.c fi sed -e 's/^.//' << \SHAREOF > remote/init.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: init.c,v $ X * Revision 2.1 86/01/05 18:13:54 toddb X * Added include for sys/stat.h because pyramid machines get upset. X * X * Revision 2.0 85/12/07 18:21:37 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: init.c,v 2.1 86/01/05 18:13:54 toddb Exp $"; X#include "server.h" X#include <stdio.h> X#include <pwd.h> X#include <grp.h> X#include <netdb.h> X#include <fcntl.h> X#include <sys/dir.h> X#include <sys/user.h> X#include <sys/signal.h> X#include <sys/ioctl.h> X#include <sys/stat.h> X Xextern hosts *hostlist; Xextern hosts *thishost; Xextern users *userlist; Xextern users *default_user; Xextern char hostname[]; Xextern char *service; Xextern short current_uid; Xextern short current_pid; Xextern process *wildcard; Xextern struct sigvec sig_vec; Xextern struct sigvec sig_name; Xextern struct sigvec sig_alarm; Xextern struct sigvec sig_ignore; Xextern struct sigvec sig_continue; X#ifdef RFSDEBUG Xextern struct sigvec sig_debug; X#endif Xextern struct stat root; X X/* X * Initialize the host tables and user tables. X */ Xinit() X{ X long tt; X struct hostent *gethostent(); X struct passwd *getpwent(); X struct group *getgrent(); X X /* X * catch signals. X */ X sigvec(SIGHUP, &sig_ignore, (struct sigvec *)0); X sigvec(SIGINT, &sig_vec, (struct sigvec *)0); X sigvec(SIGQUIT, &sig_vec, (struct sigvec *)0); X sigvec(SIGILL, &sig_vec, (struct sigvec *)0); X#ifdef RFSDEBUG X sigvec(SIGTRAP, &sig_debug, (struct sigvec *)0); X#endif RFSDEBUG X /* SIGIOT */ X /* SIGEMT */ X /* SIGFPE */ X /* SIGKILL */ X sigvec(SIGBUS, &sig_vec, (struct sigvec *)0); X sigvec(SIGSEGV, &sig_vec, (struct sigvec *)0); X sigvec(SIGSYS, &sig_vec, (struct sigvec *)0); X sigvec(SIGPIPE, &sig_vec, (struct sigvec *)0); X sigvec(SIGALRM, &sig_alarm, (struct sigvec *)0); X sigvec(SIGTERM, &sig_vec, (struct sigvec *)0); X sigvec(SIGURG, &sig_name, (struct sigvec *)0); X /* SIGSTOP */ X /* SIGTSTP */ X /* SIGCONT */ X /* SIGCHLD */ X sigvec(SIGTTIN, &sig_vec, (struct sigvec *)0); X sigvec(SIGTTOU, &sig_vec, (struct sigvec *)0); X sigvec(SIGIO, &sig_continue, (struct sigvec *)0); X sigvec(SIGXCPU, &sig_vec, (struct sigvec *)0); X sigvec(SIGXFSZ, &sig_vec, (struct sigvec *)0); X sigvec(SIGVTALRM, &sig_vec, (struct sigvec *)0); X /* SIGPROF */ X X /* X * set up some important global values, including uid, pid, X * the pipe file descriptors for messages to and from the gateway X * server. Register as the nameserver. Get host name. Get service. X * Get root stat info. X */ X if (chdir("/") == -1) X log_fatal("cannot chdir(\"/\")\n"); X wildcard = newprocess(); X fcntl(2, F_SETFL, FAPPEND); X close(0); X close(1); X change_to_uid(0); X if (gethostname(hostname, HOSTNAMELEN) < 0 || *hostname == '\0') X log_fatal("host name not set!\n"); X if (stat("/", &root) < 0) X log_fatal("cannot stat /\n"); X#ifdef CANREMOTE X if (remotename(NM_SERVER, 0, 0, 0) < 0) X log("cannot register as nameserver\n"); X /* X * Turn off remote access, if we have any. X */ X remoteoff(NULL); X#endif X tt = open("/dev/tty", 2); X X if (tt >= 0) X { X ioctl(tt, TIOCNOTTY, 0); X close(tt); X } X setpgrp(0,0); X X initusers(); X initgroups(); X inithosts(); X initrhosts(); X} X X/* X * build the list of users on this host (where the server runs). X */ Xinitusers() X{ X register struct passwd *pw; X register users *user; X char buf[ BUFSIZ ]; X register char *pbuf = buf; X X while(pw = getpwent()) X { X if (*pw->pw_dir == '\0' || *pw->pw_name == '\0') X { X log("login \"%s\" has problems, dir=\"%s\"\n", X pw->pw_name, pw->pw_dir); X continue; X } X user = newuser(); X user->u_local_uid = pw->pw_uid; X user->u_name = copy( pw->pw_name ); X addgroup(user, pw->pw_gid); X user->u_dir = copy( pw->pw_dir ); X sprintf(pbuf, "%s/.rhosts", pw->pw_dir); X user->u_rhosts = copy( pbuf ); X addlist(&userlist, user); X } X endpwent(); X if (user = findusername(DEFAULTUSER)) X default_user = user; X else X log_fatal("The user \"%s\" must be in /etc/passwd (%s)\n", X DEFAULTUSER, "for default permissions"); X} X X/* X * Build the list of groups that each user belongs to. X */ Xinitgroups() X{ X register struct group *gr; X register users *user; X register char **p; X X X while(gr = getgrent()) X { X for (p = gr->gr_mem; *p; p++) X if (user = findusername(*p)) X addgroup(user, gr->gr_gid); X else X log("group %s: bad user=%s\n", X gr->gr_name, *p); X } X endgrent(); X} X X/* X * Then build the list of all hosts. X */ Xinithosts() X{ X register struct hostent *h; X register rusers *ruser; X register hosts *hst; X register users *user; X register long i; X X while (h = gethostent()) X { X hst = newhost(); X hst->h_names = newname(hst->h_names, h->h_name); X for (i=0; h->h_aliases[ i ]; i++) X hst->h_names = newname(hst->h_names, X h->h_aliases[ i ]); X X hst->h_addr = *((struct in_addr *)(h->h_addr)); X addlist(&hostlist, hst); X X /* X * now if there exists a user on this machine having X * the same name as the name of this host (NOT AN X * ALIAS!), then that will be our defaut local user X * to map to. Be sure that we don't allow a machine X * to be mapped onto a user if the uid is real small: X * e.g. a machine named root, where all its user ids X * become root using the remote fs! X */ X user = findusername(hst->h_names[ 0 ]); X if (user && user->u_local_uid <= UID_TOO_LOW) X { X log("host/user %s: uid %d too low for alias\n", X hst->h_names[ 0 ], user->u_local_uid); X user = NULL; X } X else if (user) X { X hst->h_default_user = user; X debug2("default user for host %s (%s) is %s\n", X hst->h_names[ 0 ], X inet_ntoa(hst->h_addr), user->u_name); X } X ruser = hst->h_default_ruser = newruser(); X if (user) X ruser->r_user = user; X else X ruser->r_user = default_user; X ruser->r_uid = -1; X ruser->r_name = copy(BOGUSUSER); X } X endhostent(); X if ((thishost = findhostname(hostname)) == NULL) X log_fatal("this host (\"%s\") is not in host file\n", X hostname); X} X X/* X * Now for each user that has a .rhosts file, assemble the X * references and attach them to the appropriate host. X */ Xinitrhosts() X{ X register hosts *hst; X register rhost *rh; X register users *user; X char buf[ BUFSIZ ]; X register char *pbuf = buf; X X for (user=userlist; user; user=user->u_next) X { X setrhost(user->u_rhosts); X while (rh = getrhostent(pbuf)) X if (hst = findhostname(rh->rh_host)) X addremoteuser(hst, user, rh->rh_user); X endrhost(); X } X} X Xchar *copy(string) X register char *string; X{ X register char *ret = malloc( strlen(string)+1 ); X X if (ret == NULL) X log_fatal("cannot allocate space\n"); X strcpy(ret, string); X return(ret); X} X X/* X * Add a remote user to those recognized on a certain host. X */ Xaddremoteuser(h, user, remoteuser) X register hosts *h; X register users *user; X register char *remoteuser; X{ X register rusers *ruser; X register long old = FALSE; X X debug2("\t%s!%s --> %s ", *h->h_names, remoteuser, user->u_name); X if ((ruser = findrusername(&h->h_rusers, remoteuser)) == NULL) X { X debug2("\n"); X ruser = newruser(); X } X else X { X old = TRUE; X if (strcmp(remoteuser, user->u_name) != 0) X { X debug2("(old, ignored)\n"); X return; X } X else X debug2("(old)\n"); X } X ruser->r_name = copy(remoteuser); X ruser->r_uid = -1; X ruser->r_user = user; X if (! old) X addlist(&h->h_rusers, ruser); X} SHAREOF chmod 444 remote/init.c
sources-request@panda.UUCP (01/09/86)
Mod.sources: Volume 3, Issue 79 Submitted by: tektronix!tekcrl!toddb #!/bin/sh # # RFS, a kernel-resident remote file system. Shar 3 of 7 # # # This is a shell archive, meaning: # 1. Remove everything above the #!/bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # remote/list.c # remote/make.base # remote/make.base.M68 # remote/make.base.magnolia # remote/make.base.pyramid # remote/make.base.vax # remote/make.base.vaxnorfs # remote/new.c # remote/newinit.c # remote/rhost.c # remote/rmtmnt.c # remote/route.c # remote/server.h # remote/serverdata.c # remote/serverdir.c # # remote/list.c # if [ -f remote/list.c ]; then echo -n 'Hit <return> to overwrite remote/list.c or ^C to quit' read ans rm -f remote/list.c fi sed -e 's/^.//' << \SHAREOF > remote/list.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: list.c,v $ X * Revision 2.0 85/12/07 18:21:44 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: list.c,v 2.0 85/12/07 18:21:44 toddb Rel $"; X#include "server.h" X#include <stdio.h> X X/* X * Stick a new item of any type on top of the list. X */ Xl_list *addlist(list, item) X register l_list **list; X register l_list *item; X{ X item->l_next = *list; X if (*list) X { X item->l_prev = (*list)->l_prev; X (*list)->l_prev = item; X } X else X item->l_prev = item; X *list = item; X return(item); X} X X/* X * delete an item from a list. The item itself is left intact. It is X * the responsibility of the caller to deal with the deleted item. X */ Xl_list *deletelist(list, item) X register l_list **list; X register l_list *item; X{ X if (item == *list) X { X if (item->l_next == NULL) X *list = NULL; X else X { X *list = item->l_next; X item->l_next->l_prev = item->l_next; X } X } X else X { X item->l_prev->l_next = item->l_next; X if (item->l_next != NULL) X item->l_next->l_prev = item->l_prev; X } X return (*list); X} X X/* X * stick 'item' at the top of the 'list' ( if it isn't there X * already. X */ Xl_list *toplist(list, item) X register l_list **list; X register l_list *item; X{ X if (item == *list) X return; X item->l_prev->l_next = item->l_next; X if (item->l_next) X item->l_next->l_prev = item->l_prev; X item->l_next = (*list); X /* X * if our target is the last on the list, then X * be careful that we don't make a cycle. Since X * we want the head of the list's l_prev pointer X * to point to the last in the list, we don't X * have to do anything. X */ X if (item != (*list)->l_prev) /* NOT last on list */ X item->l_prev = (*list)->l_prev; X (*list)->l_prev = item; X *list = item; X} SHAREOF chmod 444 remote/list.c # # remote/make.base # if [ -f remote/make.base ]; then echo -n 'Hit <return> to overwrite remote/make.base or ^C to quit' read ans rm -f remote/make.base fi sed -e 's/^.//' << \SHAREOF > remote/make.base XSOBJS = change.$O file.$O fileserver.$O find.$O \ X info.$O init.$O list.$O new.$O \ X rhost.$O route.$O serverdata.$O serverdir.$O serverio.$O \ X serversyscall.$O XCFILES = change.c file.c fileserver.c find.c \ X info.c init.c list.c new.c \ X rhost.c route.c serverdata.c serverdir.c serverio.c \ X serversyscall.c X Xall: $(ALL) X X$(RFS_SERVER): $(SOBJS) X $(CC) -o $@ $(SOBJS) $(LDFLAGS) X $(XINU) $(RFS_SERVER) X$(RMTMNT): rmtmnt.$O X $(CC) -o $@ rmtmnt.$O $(LDFLAGS) X $(XINU) $(RMTMNT) X$(DEBUG): debug.$O X $(CC) -o $@ debug.$O $(LDFLAGS) X $(XINU) $(DEBUG) Xtags: $(CFILES) X ctags $(CFILES) $(INCLUDE) X$(SOBJS): $(INCLUDE) X Xinstall: all X $(INSTALL) -c -m 755 $(RFS_SERVER) $(DEST)/etc/rfs_server X $(INSTALL_RMTMNT) -c -m 0755 $(RMTMNT) $(DEST)/etc/rmtmnt SHAREOF chmod 664 remote/make.base # # remote/make.base.M68 # if [ -f remote/make.base.M68 ]; then echo -n 'Hit <return> to overwrite remote/make.base.M68 or ^C to quit' read ans rm -f remote/make.base.M68 fi sed -e 's/^.//' << \SHAREOF > remote/make.base.M68 XDEST = /usr3/mag XHOST = XINCLUDE = $(DEST)/usr/include/remote/remotefs.h server.h XCFLAGS = -G$(HOST) -O -DRFSDEBUG -DCANREMOTE -DBYTEORDER=3,2,1,0 -DREMOTEFS -DMACHTYPE=magnolia XLDFLAGS = -z XCC = cc68 XO = b XRFS_SERVER = rfs_server.x XRMTMNT = rmtmnt.x XDEBUG = debug.x XINSTALL_RMTMNT = install68 XINSTALL = install68 XALL = $(RFS_SERVER) $(RMTMNT) XXINU = xinu68 X X.SUFFIXES: X.SUFFIXES: .b .c X X.c.b: X $(CC) $(CFLAGS) $< -c SHAREOF chmod 664 remote/make.base.M68 # # remote/make.base.magnolia # if [ -f remote/make.base.magnolia ]; then echo -n 'Hit <return> to overwrite remote/make.base.magnolia or ^C to quit' read ans rm -f remote/make.base.magnolia fi sed -e 's/^.//' << \SHAREOF > remote/make.base.magnolia XHOST = tekcrl XINCLUDE = /usr/include/remote/remotefs.h server.h XO = o XCFLAGS = -G$(HOST) -O -DRFSDEBUG -DCANREMOTE -DBYTEORDER=3,2,1,0 -DREMOTEFS XLDFLAGS = -z XRFS_SERVER = rfs_server XRMTMNT = rmtmnt XDEBUG = debug XINSTALL = install68 XINSTALL_RMTMNT = install68 XDEST = XCC = cc XALL = $(RFS_SERVER) $(RMTMNT) XXINU = : SHAREOF chmod 664 remote/make.base.magnolia # # remote/make.base.pyramid # if [ -f remote/make.base.pyramid ]; then echo -n 'Hit <return> to overwrite remote/make.base.pyramid or ^C to quit' read ans rm -f remote/make.base.pyramid fi sed -e 's/^.//' << \SHAREOF > remote/make.base.pyramid XINCLUDE = ../usr.include/remote/remotefs.h server.h XO = o XLDFLAGS = -z XRFS_SERVER = rfs_server XINS_RFS_SERVER = rfs_server XRMTMNT = rmtmnt XDEBUG = debug XINSTALL_RMTMNT = install XINSTALL = install XDEST = XCC = cc XALL = $(RFS_SERVER) $(RMTMNT) XXINU = : XDEFINES = -DRFSDEBUG -DCANREMOTE -DBYTEORDER=3,2,1,0 -DREMOTEFS -I/usr/include/sys XCFLAGS = -O ${DEFINES} -I../usr.include SHAREOF chmod 644 remote/make.base.pyramid # # remote/make.base.vax # if [ -f remote/make.base.vax ]; then echo -n 'Hit <return> to overwrite remote/make.base.vax or ^C to quit' read ans rm -f remote/make.base.vax fi sed -e 's/^.//' << \SHAREOF > remote/make.base.vax XINCLUDE = ../usr.include/remote/remotefs.h server.h XO = o XLDFLAGS = -z XRFS_SERVER = rfs_server XINS_RFS_SERVER = rfs_server XRMTMNT = rmtmnt XDEBUG = debug XINSTALL_RMTMNT = install XINSTALL = install XDEST = XCC = cc XALL = $(RFS_SERVER) $(RMTMNT) XXINU = : XDEFINES = -DRFSDEBUG -DCANREMOTE -DBYTEORDER=0,1,2,3 -DREMOTEFS XCFLAGS = -O ${DEFINES} -I../usr.include SHAREOF chmod 664 remote/make.base.vax # # remote/make.base.vaxnorfs # if [ -f remote/make.base.vaxnorfs ]; then echo -n 'Hit <return> to overwrite remote/make.base.vaxnorfs or ^C to quit' read ans rm -f remote/make.base.vaxnorfs fi sed -e 's/^.//' << \SHAREOF > remote/make.base.vaxnorfs XINCLUDE = ../usr.include/remote/remotefs.h server.h XO = o XLDFLAGS = -z XRFS_SERVER = rfs_server XINS_RFS_SERVER = rfs_server XRMTMNT = rmtmnt XDEBUG = debug XINSTALL_RMTMNT = : XINSTALL = install XDEST = XCC = cc XALL = $(RFS_SERVER) XXINU = : XCFLAGS = -O -DRFSDEBUG -DBYTEORDER=0,1,2,3 -DNREMOTE=1 -I../usr.include SHAREOF chmod 664 remote/make.base.vaxnorfs # # remote/new.c # if [ -f remote/new.c ]; then echo -n 'Hit <return> to overwrite remote/new.c or ^C to quit' read ans rm -f remote/new.c fi sed -e 's/^.//' << \SHAREOF > remote/new.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: new.c,v $ X * Revision 2.0 85/12/07 18:21:48 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: new.c,v 2.0 85/12/07 18:21:48 toddb Rel $"; X#include "server.h" X#include <stdio.h> X Xextern short current_pid; Xextern hosts *host; X Xusers *newuser() X{ X register users *user; X X user = (users *)malloc(sizeof(users)); X if (user == NULL) X log_fatal("cannot allocate space\n"); X bzero(user, sizeof(users)); X return(user); X} X Xhosts *newhost() X{ X register hosts *h; X X h = (hosts *)malloc(sizeof(hosts)); X if (h == NULL) X log_fatal("cannot allocate space\n"); X bzero(h, sizeof(hosts)); X h->h_cmdfd = -1; X return(h); X} X Xrusers *newruser() X{ X register rusers *ruser; X X ruser = (rusers *)malloc(sizeof(rusers)); X if (ruser == NULL) X log_fatal("cannot allocate space\n"); X bzero(ruser, sizeof(rusers)); X return(ruser); X} X Xprocess *newprocess() X{ X register process *p; X X p = (process *)malloc(sizeof(process)); X if (p == NULL) X log_fatal("cannot allocate space\n"); X bzero(p, sizeof(process)); X return(p); X} X Xfreeproc(p) X register process *p; X{ X if (p->p_execfd >= 0) X close(p->p_execfd); X free(p); X} X Xchar **newname(namelist, name) X register char **namelist; X register char *name; X{ X register long i = 0; X X if (namelist == NULL) X namelist = (char **)malloc(sizeof(char *) * 2); X else X { X /* X * count the elements in the list now. X */ X for (i=0; namelist && namelist[i]; i++) ; X X namelist = (char **)realloc(namelist, sizeof(char *) * (i+2)); X } X namelist[ i++ ] = copy(name); X namelist[ i ] = NULL; X return(namelist); X} X X/* X * Add a group to 'user' unless he has exceeded the limit or the group X * is already in his domain. X */ Xaddgroup(user, gid) X register users *user; X register short gid; X{ X register long i = 0, X *gr = user->u_local_groups; X X for (i=0; i < user->u_numgroups; i++) X if (gr[ i ] == gid) X return; X if (i >= NGROUPS) X return; X gr[ user->u_numgroups++ ] = gid; X} X Xprocess *add_new_process(uid, pid) X register short uid, pid; X{ X register process *p; X register long i; X X debug0("allocate new proc: pid=%d uid=%d host=%s\n", X pid, uid, host->h_names[0]); X setup_proc(p = newprocess(), uid, pid); X addlist(&host->h_proclist, p); X X /* X * Initialize the file descriptors for this process. X */ X for(i=0; i<NOFILE; i++) X p->p_fds[ i ] = 0x80; /* -128 */ X X return(p); X} X Xsetup_proc(proc, uid, pid) X register process *proc; X register short uid, pid; X{ X register rusers *ruser; X X proc->p_pid = pid; X proc->p_uid = uid; X proc->p_handler = current_pid; X proc->p_returnval = 0; X proc->p_execfd = -1; X if (ruser = findremuid(&host->h_rusers, uid)) X proc->p_ruser = ruser; X else X proc->p_ruser = host->h_default_ruser; X} SHAREOF chmod 444 remote/new.c # # remote/newinit.c # if [ -f remote/newinit.c ]; then echo -n 'Hit <return> to overwrite remote/newinit.c or ^C to quit' read ans rm -f remote/newinit.c fi sed -e 's/^.//' << \SHAREOF > remote/newinit.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: init.c,v $ X * Revision 2.0 85/12/07 18:21:37 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: init.c,v 2.0 85/12/07 18:21:37 toddb Rel $"; X#include "server.h" X#include <stdio.h> X#include <pwd.h> X#include <grp.h> X#include <netdb.h> X#include <fcntl.h> X#include <sys/dir.h> X#include <sys/user.h> X#include <sys/signal.h> X#include <sys/ioctl.h> X Xextern hosts *hostlist; Xextern hosts *thishost; Xextern users *userlist; Xextern users *default_user; Xextern char hostname[]; Xextern char *service; Xextern short current_uid; Xextern short current_pid; Xextern process *wildcard; Xextern struct sigvec sig_vec; Xextern struct sigvec sig_name; Xextern struct sigvec sig_alarm; Xextern struct sigvec sig_ignore; Xextern struct sigvec sig_continue; X#ifdef RFSDEBUG Xextern struct sigvec sig_debug; X#endif Xextern struct stat root; X X/* X * Initialize the host tables and user tables. X */ Xinit() X{ X long tt; X struct hostent *gethostent(); X struct passwd *getpwent(); X struct group *getgrent(); X X /* X * catch signals. X */ X sigvec(SIGHUP, &sig_ignore, (struct sigvec *)0); X sigvec(SIGINT, &sig_vec, (struct sigvec *)0); X sigvec(SIGQUIT, &sig_vec, (struct sigvec *)0); X sigvec(SIGILL, &sig_vec, (struct sigvec *)0); X#ifdef RFSDEBUG X sigvec(SIGTRAP, &sig_debug, (struct sigvec *)0); X#endif RFSDEBUG X /* SIGIOT */ X /* SIGEMT */ X /* SIGFPE */ X /* SIGKILL */ X sigvec(SIGBUS, &sig_vec, (struct sigvec *)0); X sigvec(SIGSEGV, &sig_vec, (struct sigvec *)0); X sigvec(SIGSYS, &sig_vec, (struct sigvec *)0); X sigvec(SIGPIPE, &sig_vec, (struct sigvec *)0); X sigvec(SIGALRM, &sig_alarm, (struct sigvec *)0); X sigvec(SIGTERM, &sig_vec, (struct sigvec *)0); X sigvec(SIGURG, &sig_name, (struct sigvec *)0); X /* SIGSTOP */ X /* SIGTSTP */ X /* SIGCONT */ X /* SIGCHLD */ X sigvec(SIGTTIN, &sig_vec, (struct sigvec *)0); X sigvec(SIGTTOU, &sig_vec, (struct sigvec *)0); X sigvec(SIGIO, &sig_continue, (struct sigvec *)0); X sigvec(SIGXCPU, &sig_vec, (struct sigvec *)0); X sigvec(SIGXFSZ, &sig_vec, (struct sigvec *)0); X sigvec(SIGVTALRM, &sig_vec, (struct sigvec *)0); X /* SIGPROF */ X X /* X * set up some important global values, including uid, pid, X * the pipe file descriptors for messages to and from the gateway X * server. Register as the nameserver. Get host name. Get service. X * Get root stat info. X */ X if (chdir("/") == -1) X log_fatal("cannot chdir(\"/\")\n"); X wildcard = newprocess(); X fcntl(2, F_SETFL, FAPPEND); X close(0); X close(1); X change_to_uid(0); X if (gethostname(hostname, HOSTNAMELEN) < 0 || *hostname == '\0') X log_fatal("host name not set!\n"); X if (stat("/", &root) < 0) X log_fatal("cannot stat /\n"); X#ifdef CANREMOTE X if (remotename(NM_SERVER, 0, 0, 0) < 0) X log("cannot register as nameserver\n"); X /* X * Turn off remote access, if we have any. X */ X remoteoff(NULL); X#endif X tt = open("/dev/tty", 2); X X if (tt >= 0) X { X ioctl(tt, TIOCNOTTY, 0); X close(tt); X } X setpgrp(0,0); X X initusers(); X initgroups(); X inithosts(); X initrhosts(); X} X X/* X * build the list of users on this host (where the server runs). X */ Xinitusers() X{ X register struct passwd *pw; X register users *user; X char buf[ BUFSIZ ]; X register char *pbuf = buf; X X while(pw = getpwent()) X { X if (*pw->pw_dir == '\0' || *pw->pw_name == '\0') X { X log("login \"%s\" has problems, dir=\"%s\"\n", X pw->pw_name, pw->pw_dir); X continue; X } X user = newuser(); X user->u_local_uid = pw->pw_uid; X user->u_name = copy( pw->pw_name ); X addgroup(user, pw->pw_gid); X user->u_dir = copy( pw->pw_dir ); X sprintf(pbuf, "%s/.rhosts", pw->pw_dir); X user->u_rhosts = copy( pbuf ); X addlist(&userlist, user); X } X endpwent(); X if (user = findusername(DEFAULTUSER)) X default_user = user; X else X log_fatal("The user \"%s\" must be in /etc/passwd (%s)\n", X DEFAULTUSER, "for default permissions"); X} X X/* X * Build the list of groups that each user belongs to. X */ Xinitgroups() X{ X register struct group *gr; X register users *user; X register char **p; X X X while(gr = getgrent()) X { X for (p = gr->gr_mem; *p; p++) X if (user = findusername(*p)) X addgroup(user, gr->gr_gid); X else X log("group %s: bad user=%s\n", X gr->gr_name, *p); X } X endgrent(); X} X X/* X * Then build the list of all hosts. X */ Xinithosts() X{ X register struct hostent *h; X register rusers *ruser; X register hosts *hst; X register users *user; X register long i; X boolean duplicate; X X while (h = gethostent()) X { X /* X * One physical host may have more than one physical X * address each having a unique host name associated X * with it. If we find any entry having one of its aliases X * match a previous alias, then simply fold all aliases X * into it, and continue. X */ X duplicate = FALSE; X for (i = -1; i < 0 || h->h_aliases[ i ]; i++) X { X if (i < 0) X hst = findhost(h->h_name); X else X hst = findhost(h->h_aliases[i]); X if (hst) X { X duplicate = TRUE; X break; X } X } X X /* X * If we have a redundant host... add all the names X * in; newname will remove redundant copies. X */ X if (!duplicate) X hst = newhost(); X hst->h_names = newname(hst->h_names, h->h_name); X for (i=0; h->h_aliases[ i ]; i++) X hst->h_names = newname(hst->h_names, X h->h_aliases[ i ]); X if (duplicate) X X hst->h_addr = *((struct in_addr *)(h->h_addr)); X addlist(&hostlist, hst); X X /* X * now if there exists a user on this machine having X * the same name as the name of this host (NOT AN X * ALIAS!), then that will be our defaut local user X * to map to. Be sure that we don't allow a machine X * to be mapped onto a user if the uid is real small: X * e.g. a machine named root, where all its user ids X * become root using the remote fs! X */ X user = findusername(hst->h_names[ 0 ]); X if (user && user->u_local_uid <= UID_TOO_LOW) X { X log("host/user %s: uid %d too low for alias\n", X hst->h_names[ 0 ], user->u_local_uid); X user = NULL; X } X else if (user) X { X hst->h_default_user = user; X debug2("default user for host %s (%s) is %s\n", X hst->h_names[ 0 ], X inet_ntoa(hst->h_addr), user->u_name); X } X ruser = hst->h_default_ruser = newruser(); X if (user) X ruser->r_user = user; X else X ruser->r_user = default_user; X ruser->r_uid = -1; X ruser->r_name = copy(BOGUSUSER); X } X endhostent(); X if ((thishost = findhostname(hostname)) == NULL) X log_fatal("this host (\"%s\") is not in host file\n", X hostname); X} X X/* X * Now for each user that has a .rhosts file, assemble the X * references and attach them to the appropriate host. X */ Xinitrhosts() X{ X register hosts *hst; X register rhost *rh; X register users *user; X char buf[ BUFSIZ ]; X register char *pbuf = buf; X X for (user=userlist; user; user=user->u_next) X { X setrhost(user->u_rhosts); X while (rh = getrhostent(pbuf)) X if (hst = findhostname(rh->rh_host)) X addremoteuser(hst, user, rh->rh_user); X endrhost(); X } X} X Xchar *copy(string) X register char *string; X{ X register char *ret = malloc( strlen(string)+1 ); X X if (ret == NULL) X log_fatal("cannot allocate space\n"); X strcpy(ret, string); X return(ret); X} X X/* X * Add a remote user to those recognized on a certain host. X */ Xaddremoteuser(h, user, remoteuser) X register hosts *h; X register users *user; X register char *remoteuser; X{ X register rusers *ruser; X register long old = FALSE; X X debug2("\t%s!%s --> %s ", *h->h_names, remoteuser, user->u_name); X if ((ruser = findrusername(&h->h_rusers, remoteuser)) == NULL) X { X debug2("\n"); X ruser = newruser(); X } X else X { X old = TRUE; X if (strcmp(remoteuser, user->u_name) != 0) X { X debug2("(old, ignored)\n"); X return; X } X else X debug2("(old)\n"); X } X ruser->r_name = copy(remoteuser); X ruser->r_uid = -1; X ruser->r_user = user; X if (! old) X addlist(&h->h_rusers, ruser); X} SHAREOF chmod 664 remote/newinit.c # # remote/rhost.c # if [ -f remote/rhost.c ]; then echo -n 'Hit <return> to overwrite remote/rhost.c or ^C to quit' read ans rm -f remote/rhost.c fi sed -e 's/^.//' << \SHAREOF > remote/rhost.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: rhost.c,v $ X * Revision 2.0 85/12/07 18:21:52 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: rhost.c,v 2.0 85/12/07 18:21:52 toddb Rel $"; X#include <stdio.h> X#include "server.h" X Xstatic char *rhostpath; Xstatic FILE *fd; Xstatic rhost rh; X Xsetrhost(path) X register char *path; X{ X extern int errno; X X if ((fd = fopen(path, "r")) != 0) X debug2("rhost %s\n", path); X errno = 0; X} X Xrhost *getrhostent(buf) X register char *buf; X{ X register char *p; X X while (1) X { X if (fd == NULL || fgets(buf, BUFSIZ, fd) == NULL) X return(NULL); X X /* X * assign the first token to rh_host and then look for the X * second token on the line. If there is none, then X * don't return this entry because we can never map X * a remote user id name of "" to anything meaningful. X */ X rh.rh_host = buf; X for (p=buf; *p && *p != ' ' && *p != '\n'; p++) ; X if (*p == '\n' || *p == '\0') X continue; X X /* X * remove the newline on the end X */ X rh.rh_user = p+1; X *p = '\0'; X for (p++; *p && *p != ' ' && *p != '\n'; p++) ; X *p = '\0'; X break; X } X return(&rh); X} X Xendrhost() X{ X if (fd) X { X fclose(fd); X fd = NULL; X } X} SHAREOF chmod 444 remote/rhost.c # # remote/rmtmnt.c # if [ -f remote/rmtmnt.c ]; then echo -n 'Hit <return> to overwrite remote/rmtmnt.c or ^C to quit' read ans rm -f remote/rmtmnt.c fi sed -e 's/^.//' << \SHAREOF > remote/rmtmnt.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: rmtmnt.c,v $ X * Revision 2.0 85/12/07 18:21:56 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: rmtmnt.c,v 2.0 85/12/07 18:21:56 toddb Rel $"; X#include "server.h" X#include <stdio.h> X#include <sys/file.h> X#include <netdb.h> X#include <signal.h> X#include <setjmp.h> X#include <nlist.h> X Xextern int errno; /* for errors */ Xchar *service; /* service name */ Xchar byteorder[4] = { BYTEORDER }; X X/* X * for slow or dead remote hosts, we catch alarms. X */ Xint onalrm(); Xstruct sigvec vec = { onalrm, 0, 0 }; X X/* X * Displaying current mount points requires that we read kernel space. X */ Xstruct nlist nl[] = { X#ifdef magnolia X { "remote_info" }, X#else X { "_remote_info" }, X#endif X { "" }, X}; X#ifdef magnolia Xchar *kernel = "/magix"; X#else Xchar *kernel = "/vmunix"; X#endif X Xmain(argc, argv) X int argc; X char **argv; X{ X long generic = FALSE, X unmount = FALSE; X char *mntpt = NULL, X *host = NULL; X X /* X * Parse the args. X */ X for (argv++, argc--; argc; argv++, argc--) X { X if (**argv != '-') X break; X switch(argv[0][1]) { X case 's': /* service name */ X if (argv[0][2]) X service = argv[0]+2; X else X argv++, argc--, service = argv[0]; X break; X case 'g': /* Make this a generic mount point */ X generic = TRUE; X break; X case 'u': /* unmount this mount point */ X unmount = TRUE; X break; X default: X fprintf(stderr, "unknown option = %s\n", *argv); X usage(); X exit(1); X } X } X X if (! generic && ! unmount && argc-- > 0) X host = *argv++; X if (argc-- > 0) X { X mntpt = *argv++; X if (*mntpt != '/') X { X fprintf(stderr, "mount point must begin with '/'\n"); X mntpt = NULL; X } X } X else X { X show(); X exit(0); X } X X if (argc > 0 X || (generic && unmount) X || (mntpt == NULL)) X usage(); X X if (unmount) X turnoff(mntpt); X else X turnon(mntpt, host); X} X X/* X * Display the current mount points in the kernal. X */ Xshow() X{ X long index = 0, X diff, X now, X kfd; X char buf[BUFSIZ], X *p; X struct sockaddr_in hostaddr; X struct sockaddr_in *sys; X struct servent *servp; X struct hostent *hostent; X struct remoteinfo rinfo[ R_MAXSYS ], X *rp; X struct mbuf bufs[ R_MAXSYS ], X *m; X X servp = getservbyname(REMOTE_FS_SERVER, "tcp"); X /* X * Get the address of the remote mount point information X * and read kernel memory. X */ X nlist(kernel, nl); X if(nl[0].n_type == 0) X log_fatal("no %s for namelist\n", kernel); X kfd = open("/dev/kmem", 0); X if(kfd < 0) X log_fatal("cannot open /dev/kmem\n"); X lseek(kfd, (long)nl[0].n_value, 0); X read(kfd, rinfo, sizeof(struct remoteinfo) * R_MAXSYS); X X /* X * Now get the mbufs on each mount point. X */ X m = bufs; X time(&now); X for (index=0, rp = rinfo; rp < rinfo+R_MAXSYS; rp++, index++) X { X buf[0] = '\0'; X if (rp->r_name || rp->r_mntpt) X printf("%d: ", index); X else X continue; X if (rp->r_name) X { X lseek(kfd, (long)rp->r_name, 0); X read(kfd, m, sizeof(struct mbuf)); X rp->r_name = m++; X sys = mtod(rp->r_name, struct sockaddr_in *); X hostent = gethostbyaddr(&sys->sin_addr, X sizeof (struct in_addr), sys->sin_family); X if (hostent == NULL) X { X log("no host entry for %s\n", X inet_ntoa(sys->sin_addr)); X continue; X } X bprintf(buf, "%s(%s) on ", X hostent->h_name, inet_ntoa(sys->sin_addr)); X } X else X bprintf(buf, "generic mount point "); X bprintf(buf, "%s", rp->r_mntpath); X if (rp->r_mntpt == NULL) X bprintf(buf, ", implied"); X if (rp->r_name && sys->sin_port != servp->s_port) X bprintf(buf, ", port %d", sys->sin_port); X if (rp->r_sock) X bprintf(buf, ", connected"); X if (rp->r_close) X bprintf(buf, ", closing"); X if (rp->r_users) X bprintf(buf, ", %d process%s", X rp->r_users, rp->r_users > 1 ? "es" : ""); X if (rp->r_nfile) X bprintf(buf, ", %d open file%s", X rp->r_nfile, rp->r_nfile > 1 ? "s" : ""); X if (rp->r_nchdir) X bprintf(buf, ", %d chdir%s", X rp->r_nchdir, rp->r_nchdir > 1 ? "'s" : ""); X if (rp->r_opening) X bprintf(buf, ", opening"); X if (rp->r_failed) X { X bprintf(buf, ", connect failed, retry "); X diff = rp->r_age - now; X if (diff <= 0) X bprintf(buf, "time reached"); X else X { X bprintf(buf, "in "); X if (diff / 60) X bprintf(buf, "%d minute%s", diff/60, X (diff/60) > 1 ? "s" : ""); X if (diff / 60 && diff % 60) X bprintf(buf, " and "); X if (diff % 60) X bprintf(buf, "%d second%s", diff%60, X (diff%60) > 1 ? "s" : ""); X } X } X else if(rp->r_sock == NULL && rp->r_age) X { X bprintf(buf, ", last closed %s", X ctime(&rp->r_age)); X buf[ strlen(buf)-1 ] = '\0'; /* remove newline */ X } X printf("%s\n", buf); X } X} X X/* X * buffer printf. i.e. do a printf into a buffer, appending to whatever X * is there. Split long lines. X */ Xbprintf(buf, x0,x1,x2,x3,x4,x5,x6,x7,x8,x9) X char *buf; X{ X char xbuf[ BUFSIZ ], X *pfrom, *pto, c; X long col; X X sprintf(xbuf, x0,x1,x2,x3,x4,x5,x6,x7,x8,x9); X for (pto = buf; *pto; pto++) ; X for (pfrom = xbuf, col=0; *pfrom; pfrom++, col++) X { X c = *pfrom; X *pto++ = c; X if (c == '\n') X col = -1; X else if (c == ' ' && col > 50) X { X *pto++ = '\n'; X *pto++ = '\t'; X col = 7; X } X } X *pto = '\0'; X} X X/* X * Do a mount. X */ Xturnon(mntpt, host) X char *mntpt, *host; X{ X int index, ret, fdout, fdin; X struct message msgbuf, *msg = &msgbuf; X struct sockaddr_in sys; X char buf[ BUFSIZ ]; X X if (strlen(mntpt) >= R_MNTPATHLEN) X log_fatal("mount point must be < %d chars\n", R_MNTPATHLEN); X X /* X * Connect to the machine and send it our byte order and X * password file. X */ X if (host) X { X if ((fdout = tcpname(&sys, host)) < 0) X log("system unreachable now..."); X index = remoteon(mntpt, strlen(mntpt)+1, X &sys, sizeof(struct sockaddr_in)); X } X else X index = remoteon(mntpt, strlen(mntpt), 0, 0); X if (index == -1) X log_fatal("cant mount remote fs\n"); X else if (host && fdout < 0) X log(" system mounted anyway\n"); X if (host == NULL) X return; X if ((fdin = open("/etc/passwd", O_RDONLY)) == -1) X log_fatal("can't open /etc/passwd\n"); X msg->m_syscall = htons(RSYS_nosys); X msg->m_hdlen = htons(R_MINRMSG + sizeof(long)); X msg->m_totlen = htonl(R_MINRMSG + sizeof(long)); X msg->m_args[0] = htonl(CMD_MOUNT); X write(fdout, msg, R_MINRMSG + sizeof(long)); X write(fdout, byteorder, 4); X while ((ret = read(fdin, buf, BUFSIZ)) > 0) X write(fdout, buf, ret); X close(fdout); X close(fdin); X return; X} X Xturnoff(mntpt) X char *mntpt; X{ X int index, fd; X X index = remoteoff(mntpt); X if (index == -1) X log_fatal("can't unmount remote fs\n"); X close(fd); X} X Xusage() X{ X fprintf(stderr, "Usage:\t%s\n\t%s\n\t%s\n", X "rmtmnt [-sservicename] -g path", X "rmtmnt [-sservicename] host path", X "rmtmnt"); X exit(1); X} X Xtcpname(sin, host) X struct sockaddr_in *sin; X char *host; X{ X struct servent *servp; X struct hostent *hostp; X int s; X X servp = getservbyname(service ? service : REMOTE_FS_SERVER, "tcp"); X X if (servp == NULL) { X fprintf(stderr, "%s: unknown service\n", REMOTE_FS_SERVER); X exit(1); X } X X hostp = gethostbyname(host); X if (hostp == NULL) { X fprintf(stderr, "%s: unknown host\en", host); X exit(1); X } X bzero((char *)sin, sizeof (struct sockaddr_in)); X bcopy(hostp->h_addr, (char *)&sin->sin_addr, hostp->h_length); X sin->sin_family = hostp->h_addrtype; X sin->sin_port = servp->s_port; X X /* X * Ok, now make sure that the connection will work X */ X if (sigvec(SIGALRM, &vec, (struct sigvec *)0) == -1) { X perror("signals"); X return(-1); X } X s = socket(AF_INET, SOCK_STREAM, 0); X if (s < 0) X return(-1); X alarm(5); X if(connect(s, sin, sizeof(struct sockaddr_in)) < 0) { X alarm(0); X return(-1); X } X alarm(0); X return(s); X} X Xonalrm(sig) X{ X fprintf(stderr, "timeout: "); X} X Xlog_fatal(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9) X{ X log(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9); X exit(1); X} X Xlog(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9) X{ X if (errno) X perror("rmtmnt"); X errno = 0; X fprintf(stderr, x0,x1,x2,x3,x4,x5,x6,x7,x8,x9); X} SHAREOF chmod 444 remote/rmtmnt.c # # remote/route.c # if [ -f remote/route.c ]; then echo -n 'Hit <return> to overwrite remote/route.c or ^C to quit' read ans rm -f remote/route.c fi sed -e 's/^.//' << \SHAREOF > remote/route.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: route.c,v $ X * Revision 2.2 86/01/05 18:14:47 toddb X * Added a forgotten case to gateway_listen(): S_CORRUPTED. X * X * Revision 2.1 85/12/19 15:53:23 toddb X * Changed declaration of a local variable (sigmask) because it conflicts X * with a 4.3 define. X * X * Revision 2.0 85/12/07 18:22:04 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: route.c,v 2.2 86/01/05 18:14:47 toddb Exp $"; X#include "server.h" X#include <sys/file.h> X#include <sys/time.h> X#include <setjmp.h> X#include <errno.h> X Xextern short current_pid; Xextern short current_ppid; Xextern short gateway_server; Xextern short current_server; Xextern long blocking_servers; Xextern long to_gateway; Xextern long from_servers; Xextern long errno; Xextern boolean i_am_gateway; Xextern boolean i_have_control; Xextern boolean gateway_needs_control; Xextern boolean route_to_gateway; Xextern boolean watch_for_lock; Xextern boolean i_am_asleep; Xextern hosts *host; X X/* X * Reroute to the server whose pid is 'pid'. X */ Xreroute(pid, msg) X register short pid; X register struct message *msg; X{ X if (route_to_gateway) X { X debug5("routing changed from server %d to gateway\n", pid); X route_to_gateway = FALSE; X pid = gateway_server; X } X watch_for_lock = gateway_needs_control = FALSE; X dont_gobble_msg(msg); X X if (pid == current_pid) X log_fatal("reroute myself???\n"); X debug5("%d waking up %d\n", current_pid, pid); X X /* X * If we are the gateway, there may be some servers that are blocking X * on a request. If so, then we lock file descriptor 2 with an X * shared lock. This tells the server to always check to see if X * the lock goes up to an exclusive lock. If so, then the server X * must then return control to the gateway. X */ X if (i_am_gateway) X { X set_label("reading messages"); X i_have_control = FALSE; X if (blocking_servers) X if (flock(2, LOCK_NB | LOCK_SH) < 0) X log_fatal("cannot lock fd 2\n"); X } X X i_am_asleep = TRUE; X if (pid == gateway_server) X say_something(S_THIS_IS_YOURS, gateway_server); X else X wake_up(pid); X slumber(FALSE); X if (! i_am_gateway) X { X /* X * Check for the lock on fd 2. But even if the gateway wants X * control, go ahead an serve this request. X */ X if (flock(2, LOCK_NB | LOCK_EX) < 0) X if (flock(2, LOCK_NB | LOCK_SH) >= 0) X { X debug5("watch for lock on each request\n"); X watch_for_lock = TRUE; X flock(2, LOCK_UN); X } X else X { X debug5("Gateway wants control\n"); X gateway_needs_control = TRUE; X } X else X flock(2, LOCK_UN); X } X} X X X/* X * Tell the gateway something. X */ Xsay_something(cmd, arg) X register long cmd, arg; X{ X gtmsgs gmsg[2]; X register gtmsgs *g = gmsg; X register long len = sizeof(gtmsgs); X X X if (cmd == S_NEWSERVER) /* actually 2 messages */ X { X g->g_server = current_ppid; X g->g_cmd = cmd; X g->g_pid = current_pid; X cmd = S_NEWPROCESS; X g++; X len += sizeof(gtmsgs); X } X g->g_server = current_pid; X g->g_cmd = cmd; X g->g_pid = arg; X X debug5("say: cmd=%d, arg=%d\n", cmd, arg); X if (write(to_gateway, gmsg, len) != len) X log_fatal("pid %d: can't write to gateway!!\n", X current_pid); X} X X/* X * Read message from servers. We do the allocation of space and maintain it. X */ Xgtmsgs *read_gtmsgs() X{ X static gtmsgs *msgs; X static long current_len, X len_needed = 10; X register long red; X register gtmsgs *g; X X /* X * Allocate space for the current read. X */ X if (current_len < len_needed) X { X if (msgs) X msgs = (gtmsgs *)realloc(msgs, X len_needed * sizeof(gtmsgs)); X else X msgs = (gtmsgs *)malloc(len_needed * sizeof(gtmsgs)); X current_len = len_needed; X } X X /* X * Now read the messages. X */ X red = read(from_servers, msgs, (current_len-1) * sizeof(gtmsgs)); X if (red % sizeof(gtmsgs) != 0) X log_fatal("partial message on read = %d\n", red); X red /= sizeof(gtmsgs); X if (red == current_len-1) X len_needed++; X msgs[ red ].g_server = 0; X#ifdef RFSDEBUG X for (g=msgs; g->g_server; g++) X debug14("red: server %d, cmd %d, pid=%d\n", X g->g_server, g->g_cmd, g->g_pid); X#endif RFSDEBUG X return(msgs); X} X X/* X * This process is called to gather incomming messages from servers out X * there with something interesting to say. We return TRUE if we have X * read a message from a process that is relinquishing control, FALSE X * otherwise. X */ Xgateway_listen() X{ X register process *proc; X register gtmsgs *msgs, *g; X short dequeue(); X register short cmd, i, pid, server; X X msgs = read_gtmsgs(); X X errno = 0; X for (g=msgs; g->g_server; g++) X { X pid = g->g_pid; X server = g->g_server; X cmd = g->g_cmd; X X switch(cmd) { X case S_NEWSERVER: /* a new server forked by another server */ X debug5("hear: %d forks new server %d\n", server, pid); X break; X case S_NEWPROCESS: /* a new process is being served */ X proc = add_new_process(0, pid); X proc->p_handler = server; X debug5("hear: pid %d serving pid %d\n", server, pid); X break; X case S_PROCEXIT: /* some server's client did an exit() call */ X debug5("hear: proc exit from server %d: pid=%d\n", X server, pid); X if ((proc = findprocess(pid, -1)) == NULL) X log("can't find pid %d!\n", pid); X else X { X deletelist(&host->h_proclist, proc); X freeproc(proc); X } X break; X case S_I_WOULD_BLOCK: /* server will block on I/O */ X debug5("hear: server %d blocks\n", server); X blocking_servers++; X goto gateway_control; X case S_ALLDONE: /* an existing server is ready to die */ X case S_EOF: /* a server got eof on command socket */ X mourne(); X debug5("hear: server %d %s... ", server, X cmd == S_ALLDONE ? "dead" : "got eof"); X for (proc=host->h_proclist; proc; proc=proc->p_next) X if (proc->p_handler == server) X { X debug5("free proc %d...", proc->p_pid); X deletelist(&host->h_proclist, proc); X freeproc(proc); X } X debug5("\n"); X /* fall through */ X case S_THIS_IS_YOURS: /* just relinquish control */ X gateway_control: X /* X * Always unlock when we have control. X */ X flock(2, LOCK_UN); X if (cmd == S_THIS_IS_YOURS) X debug5("hear: server %d gives us control\n", X server); X /* X * Now that we have control, see about dequeing X * a server that is ready to go. If there is one, X * Then change this message so that it looks like X * a message from ourself saying to reroute to X * 'server'. X */ X server = dequeue(); X if (server > 0) X { X debug5("server %d ready to go\n", server); X wake_up(server); X } X else X { X debug5("gateway pid %d continuing\n", X current_pid); X set_label("active"); X i_have_control = TRUE; X } X break; X case S_I_AM_READY: X debug5("hear: server %d ready\n", server); X blocking_servers--; X if (flock(2, LOCK_EX) < 0) X log_fatal("cannot lock fd 2\n"); X queue(server); X break; X case S_CORRUPTED: X log_fatal("corrupted input stream\n"); X break; X default: X log("unknown message from %d = %d\n", server, cmd); X break; X } X } X X return(FALSE); X} X Xwake_up(pid) X long pid; X{ X sendsig(pid, SIGIO); X} X Xsendsig(pid, sig) X long pid, X sig; X{ X register func logger; X extern long log(), log_fatal(); X X change_to_uid(0); X if (kill(pid, sig) < 0) X { X if (errno == ESRCH) X logger = log; X else X logger = log_fatal; X logger("couldn't signal %d w/ sig=%d\n", pid, sig); X return(FALSE); X } X return(TRUE); X} X Xstatic short *server_queue; Xstatic short server_len; Xstatic short last_server; X/* X * Put a server on a queue to be run again. Fifo queue. X */ Xqueue(pid) X register short pid; X{ X if (++last_server > server_len) X { X server_len++; X if (server_queue == NULL) X server_queue = (short *)malloc(sizeof(short)); X else X server_queue = (short *)realloc(server_queue, X server_len*sizeof(short)); X } X server_queue[ last_server - 1 ] = pid; X} X X/* X * Get the first server off the queue. Blech! We have to copy all the X * queue back one. X */ Xshort dequeue() X{ X register short retval, i; X X if (last_server == 0) X return(0); X retval = server_queue[ 0 ]; X for (i=1; i<last_server; i++) X server_queue[ i-1 ] = server_queue[ i ]; X last_server--; X return( retval ); X} X X/* X * Go to sleep awaiting a wakup call. Do not return until we receive it. X * However, if we are the gateway, we, of course MUST return and go X * on reading messages. X * X * Since there is a window between testing the i_am_asleep flag and doing X * the pause, in which we could be awakened, we must always jump around X * this loop using longjmp() from the interrupt routine. X */ Xslumber(forked) X boolean forked; X{ X register long signalmask; X X if (i_am_gateway) X { X set_label("reading messages"); X i_have_control = FALSE; X return; X } X set_label("asleep"); X signalmask = sigblock(1<<(SIGIO-1)); X while (i_am_asleep) X sigpause(signalmask); X sigsetmask(signalmask); X X debug5("pid %d continuing%s\n", X current_pid, forked ? "after fork" : ""); X set_label("active"); X mourne(); X} SHAREOF chmod 444 remote/route.c # # remote/server.h # if [ -f remote/server.h ]; then echo -n 'Hit <return> to overwrite remote/server.h or ^C to quit' read ans rm -f remote/server.h fi sed -e 's/^.//' << \SHAREOF > remote/server.h X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Header: server.h,v 2.0 85/12/07 18:22:12 toddb Rel $ X * X * $Log: server.h,v $ X * Revision 2.0 85/12/07 18:22:12 toddb X * First public release. X * X */ X#include <sys/param.h> X#include <sys/mbuf.h> X#include <sys/socket.h> X#include <netinet/in.h> X#include <remote/remotefs.h> X Xtypedef unsigned char boolean; X X/* X * The maximum number of longs in a message that we accept X */ X#define MAXMSGS ((R_MAXMBUFS*MLEN)/sizeof(long)) X/* X * The name of a host for which we have no record. And the name of the user X * to use if we don't recognize the user on the remote host. X */ X#define BOGUSHOST "unknown host" X#define BOGUSUSER "unknown user" X#define DEFAULTUSER "guest" X X/* X * The uid number below which we reserve for privilaged users. X */ X#define UID_TOO_LOW 20 X X/* X * This is to make the debug? macro work for the server. X * X * The bits and what they turn on are as follows X * 0x00000001 process switching X * 0x00000002 system calls X * 0x00000004 setuid/setgid, umask X * 0x00000008 file descriptor allocation X * 0x00000010 connections X * 0x00000020 server switching X * 0x00000040 nameserver X * 0x00000080 directory nuxi X * 0x00000100 message in and out X * 0x00000200 don't fork child for gateway (good for adb) X * 0x00000400 local/remote file decisions X * 0x00000800 don't remove log file on exit (except exit on error) X * 0x00001000 exec information X * 0x00002000 auto debug for 0x20 (server switching) X * 0x00004000 parsing messages to gateway X */ X#define rmt_debug log X#ifndef RFSDEBUG X#define dumphost() X#endif RFSDEBUG X X/* X * The size of the initial allocation for internal io buffers. X */ X#define BIGBUF (8*1024) X X/* X * other Manifest constants... X */ X#define HOSTNAMELEN 255 X X/* X * Map a file descriptor from the user's fd to our own internal fd. X */ X#define MAPFD(fd, proc) \ X (((unsigned)fd > NOFILE) ? -1 : (proc)->p_fds[ fd ] ) X/* X * requirements for different system calls. X */ X#define NEED_ZIP 0x000 /* don't need anything special */ X#define NEED_CWD 0x001 /* need the current working directory set */ X#define NEED_PERM 0x002 /* need the user and group ids set */ X#define NEED_FD 0x004 /* need a file descriptor allocated */ X#define NEED_2PATH 0x010 /* uses two paths */ X#define NEED_MYSERVER 0x020 /* must be run by the assigned server */ X#define NEED_2REMOTE 0x040 /* both paths must be remote */ X X/* X * Commands to the server sent by external programs (like rmtmnt, to mount X * a remote system. X */ X#define CMD_SERVICE 1 X#define CMD_MOUNT 2 /* here is mount information */ X#define CMD_NEEDMOUNT 3 /* give me mount information */ X#define CMD_WHOAMI 4 /* what uid am I on your host */ X X/* X * Finally, some commands that are sent to the gateway server by other X * servers. X */ X#define S_NEWSERVER 0 X#define S_NEWPROCESS 1 X#define S_ALLDONE 2 X#define S_THIS_IS_YOURS 3 X#define S_PROCEXIT 4 X#define S_EOF 5 X#define S_I_WOULD_BLOCK 6 X#define S_I_AM_READY 7 X#define S_CORRUPTED 8 X X/* X * Macros for getting the address of the paths out of the incomming message. X * Note that path1addr is for system calls that deal with only one path, X * and twopath1addr() and twopath2addr() are for system calls that have X * two paths (in the latter cases, path2 appears in the same position X * as path1 does for single path system calls). X */ X#define path1addr(msg) ((char *)&(msg)->m_args[R_PATHSTART]) X#define twopath1addr(msg) ((char *)(msg) + (msg)->m_args[R_PATHOFF]) X#define twopath2addr(msg) ((char *)&(msg)->m_args[R_PATHSTART]) X X/* X * Macro for preventing getmsg(), and thereby gobble_last_msg() from X * reading the last message. This is used when control is being passed X * from one server to another. X */ X#define dont_gobble_msg(msg) (msg)->m_totlen = 0 X X/* X * Macro for determining whether a stat structure reflects the root inode X * of our machine or not. X */ X#define isroot(p) (p->st_ino == root.st_ino && p->st_dev == root.st_dev) X X/* X * This structure is one-to-one with each local user where the server runs. X * Note that the u_next and u_prev pointers must be located X * in the first and second spots of the structure, respectively so that X * they can be modified by the linked-list routines. X */ Xtypedef struct users_type users; Xstruct users_type { X users *u_next; /* pointers for linked list, both forward... */ X users *u_prev; /* ... and back. */ X char *u_name; /* The ascii name of same. */ X char *u_dir; /* login directory for same */ X char *u_rhosts; /* path of the user's rhost file */ X short u_local_uid; /* A user id number on the local host */ X long u_local_groups[NGROUPS];/* The groups this user belongs to */ X char u_numgroups; /* The number of groups in u_local_groups */ X}; X X/* X * Remote user specification. X */ Xtypedef struct ruser_type rusers; Xstruct ruser_type { X rusers *r_next; X rusers *r_prev; X short r_uid; /* Uid number on remote host ... */ X char *r_name; /* Uid name on remote host ... */ X users *r_user; /* corresponding local user */ X}; X X/* X * This is the important stuff. There is one of these structures for X * each pid that we are providing service to. X */ Xtypedef struct process_type process; Xstruct process_type { X process *p_next; X process *p_prev; X long p_returnval; /* return value from last syscall */ X rusers *p_ruser; /* info about the owner of this pid */ X short p_pid; /* process id number on remote host */ X short p_uid; /* remote uid that was last known */ X short p_handler; /* the handler for this process */ X short p_errno; /* errno for the system call */ X char p_execfd; /* file descriptor of exec file */ X boolean p_execstarted; /* whether we have done first read */ X char p_fds[ NOFILE ];/* fd's assoc. with this pid */ X}; X X/* X * This structure keeps track of the possible hosts that may make a connection X * the the remote fs server. Note that the h_next and hprev pointers must be X * located in the first and second spots of the structure, respectively, X * so that they can be modified by the linked-list routines. X */ Xtypedef struct hosts_type hosts; Xstruct hosts_type { X hosts *h_next; X hosts *h_prev; X char **h_names; /* name (and aliases) of a host */ X rusers *h_rusers; /* the user list for this host */ X users *h_default_user;/* default local user (if defined */ X rusers *h_default_ruser;/* default when the remote user is unknown */ X long h_portnum; /* port number that we connected on */ X char *h_mntpt; /* mount point for this machine */ X process *h_proclist; /* processes we know about on this host */ X struct in_addr h_addr; /* network address */ X union h_bytes { X long hu_mounted; /* non-zero if host has been mounted */ X u_char hu_byteorder[4]; /* byte order for this host */ X } h_bytes; X#define h_mounted h_bytes.hu_mounted X#define h_byteorder h_bytes.hu_byteorder X char h_cmdfd; /* file descriptor for commands */ X boolean h_byteorderok; /* true if byte order same as ours */ X short h_serverpid; /* gateway server for this host */ X}; X X/* X * This structure is the mask structure that the linked list routines use X * to modify any linked-list type of structure. Note that l_next and l_prev X * must be in the first and second spots. X */ Xtypedef struct l_list_type l_list; Xstruct l_list_type { X l_list *l_next; X l_list *l_prev; X long l_data; /* never used */ X}; X X/* X * This structure is for convenience: it simply defines an easy way of X * storing the host/user line found in a .rhost file. X */ Xtypedef struct rhost_type rhost; Xstruct rhost_type { X char *rh_host; X char *rh_user; X}; X X/* X * Each message from the servers to the gateway, is placed into this X * structure, the "gateway message". X */ Xtypedef struct gtmsg_type gtmsgs; Xstruct gtmsg_type { X short g_server; /* server that sent the message. */ X short g_pid; /* pid of whom this message is about */ X short g_cmd; /* what this message is about */ X}; X X/* X * Finally, this is the way we keep database info on the system calls X * themselves. X */ Xtypedef struct syscallmap syscallmap; Xstruct syscallmap { X func s_server; X func s_syscall; X char s_type; X}; X Xrhost *getrhostent(); Xhosts *tcpaccept(); Xhosts *findhostaddr(); Xhosts *findhostname(); Xhosts *newhost(); Xl_list *toplist(); Xl_list *bottomlist(); Xl_list *addlist(); Xl_list *deletelist(); Xprocess *newprocess(); Xprocess *findprocess(); Xprocess *change_to_proc(); Xprocess *add_new_process(); Xusers *finduid(); Xusers *findusername(); Xusers *newuser(); Xrusers *findremuid(); Xrusers *findrusername(); Xrusers *newruser(); Xchar **newname(); Xchar *copy(); Xchar *malloc(); Xchar *realloc(); Xchar *get_data_buf(); Xshort *newshortlist(); SHAREOF chmod 444 remote/server.h # # remote/serverdata.c # if [ -f remote/serverdata.c ]; then echo -n 'Hit <return> to overwrite remote/serverdata.c or ^C to quit' read ans rm -f remote/serverdata.c fi sed -e 's/^.//' << \SHAREOF > remote/serverdata.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: serverdata.c,v $ X * Revision 2.0 85/12/07 18:22:20 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: serverdata.c,v 2.0 85/12/07 18:22:20 toddb Rel $"; X#include "server.h" X#include <nlist.h> X#include <signal.h> X#include <netdb.h> X#include <sys/stat.h> X X/* X * system calls. X */ Xlong access(), chdir(), chmod(), chown(), close(), dup(), execve(), X fchmod(), fchown(), fcntl(), flock(), fork(), fstat(), fsync(), X ftruncate(), ioctl(), link(), lseek(), lstat(), mkdir(), X mknod(), open(), read(), readlink(), rename(), rmdir(), X stat(), symlink(), truncate(), unlink(), utimes(), X write(), X/* X * ...and our own routines to set up for the system calls. X */ X noop(), s_access(), s_dup(), s_execinfo(), s_execread(), s_exit(), X s_fcntl(), s_fd1(), s_fd1_plus(), s_fork(), s_ioctl(), s_lseek(), X s_open(), s_path1(), s_path1_plus(), s_path2(), s_read(), X s_readlink(), s_stat(), s_utimes(), s_write(); X Xsyscallmap smap[] = { X s_fork, noop, NEED_ZIP, /* RSYS_fork */ X s_read, read, NEED_ZIP, /* RSYS_read */ X s_write, write, NEED_ZIP, /* RSYS_write */ X s_open, open, NEED_CWD X |NEED_MYSERVER X |NEED_PERM X |NEED_FD, /* RSYS_open */ X s_fd1, close, NEED_ZIP, /* RSYS_close */ X noop, noop, NEED_CWD X |NEED_PERM X |NEED_FD, /* RSYS_creat */ X s_path2, link, NEED_CWD X |NEED_MYSERVER X |NEED_2PATH X |NEED_2REMOTE X |NEED_PERM, /* RSYS_link */ X s_path1, unlink, NEED_CWD|NEED_PERM, /* RSYS_unlink */ X s_path1, chdir, NEED_MYSERVER X |NEED_CWD X |NEED_PERM X |NEED_MYSERVER, /* RSYS_chdir */ X s_path1_plus, mknod, NEED_CWD|NEED_PERM, /* RSYS_mknod */ X s_path1_plus, chmod, NEED_CWD|NEED_PERM, /* RSYS_chmod */ X s_path1_plus, chown, NEED_CWD|NEED_PERM, /* RSYS_chown */ X s_stat, stat, NEED_CWD|NEED_PERM, /* RSYS_stat */ X s_lseek, lseek, NEED_ZIP, /* RSYS_lseek */ X s_access, access, NEED_CWD|NEED_PERM, /* RSYS_access */ X s_stat, lstat, NEED_CWD|NEED_PERM, /* RSYS_lstat */ X s_dup, dup, NEED_FD, /* RSYS_dup */ X s_ioctl, ioctl, NEED_ZIP, /* RSYS_ioctl */ X s_path2, symlink, NEED_CWD X |NEED_2PATH X |NEED_PERM, /* RSYS_symlink */ X s_readlink, readlink, NEED_CWD|NEED_PERM, /* RSYS_readlink */ X s_stat, fstat, NEED_ZIP, /* RSYS_fstat */ X s_dup, dup, NEED_FD, /* RSYS_dup2 */ X s_fd1_plus, fcntl, NEED_ZIP, /* RSYS_fcntl */ X s_fd1, fsync, NEED_ZIP, /* RSYS_fsync */ X noop, noop, NEED_ZIP, /* RSYS_readv */ X noop, noop, NEED_ZIP, /* RSYS_writev */ X s_fd1_plus, fchown, NEED_PERM, /* RSYS_fchown */ X s_fd1_plus, fchmod, NEED_PERM, /* RSYS_fchmod */ X s_path2, rename, NEED_MYSERVER X |NEED_2REMOTE X |NEED_CWD X |NEED_2PATH X |NEED_PERM, /* RSYS_rename */ X s_path1_plus, truncate, NEED_CWD|NEED_PERM, /* RSYS_truncate */ X s_fd1_plus, ftruncate,NEED_ZIP, /* RSYS_ftruncate */ X s_fd1_plus, flock, NEED_ZIP, /* RSYS_flock */ X s_path1_plus, mkdir, NEED_CWD|NEED_PERM, /* RSYS_mkdir */ X s_path1, rmdir, NEED_CWD|NEED_PERM, /* RSYS_rmdir */ X s_utimes, utimes, NEED_CWD|NEED_PERM, /* RSYS_utimes */ X s_exit, noop, NEED_ZIP, /* RSYS_exit */ X s_fork, noop, NEED_ZIP, /* RSYS_Vfork */ X s_execinfo, noop, NEED_MYSERVER X |NEED_CWD X |NEED_PERM, /* RSYS_execinfo */ X s_execread, noop, NEED_PERM, /* RSYS_execread */ X noop, noop, NEED_ZIP, /* RSYS_execve */ X noop, noop, NEED_ZIP, /* RSYS_nosys */ X s_lseek, lseek, NEED_ZIP, /* RSYS_qlseek */ X}; X Xchar *syscallnames[] = { X "fork", X "read", X "write", X "open", X "close", X "creat", X "link", X "unlink", X "chdir", X "mknod", X "chmod", X "chown", X "stat", X "lseek", X "access", X "lstat", X "dup", X "ioctl", X "symlink", X "readlink", X "fstat", X "dup2", X "fcntl", X "fsync", X "readv", X "writev", X "fchown", X "fchmod", X "rename", X "truncate", X "ftruncate", X "flock", X "mkdir", X "rmdir", X "utimes", X "exit", X "vfork", X "execinfo", X "execread", X "execve", X "nosys", X "quick lseek" X}; X Xchar hostname[ HOSTNAMELEN ];/* our host name */ Xchar mntpt[ MAXPATHLEN ]; /* mount point for client */ Xchar *program; /* name of this program */ Xchar *last_argaddr; /* last address that we can scribble on */ Xchar *service = REMOTE_FS_SERVER; /* name of alternate internet service */ Xchar *stdlogfile = "/usr/tmp/rfs_log"; /* log file for server */ Xchar *logfile; Xlong serviceport; /* port number for service */ Xlong remote_debug; /* level of debug output */ Xshort current_uid; /* whatever uid we are, right now */ Xshort current_pid; /* whatever pid we are, right now */ Xshort current_ppid; /* our parent server */ Xshort current_umask; /* whatever umask we have, right now */ Xshort current_server; /* server that has control right now */ Xshort gateway_server; /* pid of our gateway */ Xshort last_sentry; /* previous sentry server (if non-zero) */ Xlong fds_in_use; /* number of total file descriptors open */ Xlong to_gateway; /* file descriptor for messages to gateway */ Xlong so_listen; /* socket for listening for connections */ Xlong from_servers; /* file descriptor for messages from servers */ Xlong blocking_servers; /* number of servers waiting for I/O */ Xhosts *hostlist; /* all the hosts we know of */ Xhosts *host; /* the current host that we talk to */ Xhosts *thishost; /* host pointer for this machine */ Xusers *userlist; /* all the users on this host we know of */ Xusers *default_user; /* default user to map unknown clients to */ Xprocess *wildcard; /* wildcard process for easy requests */ Xboolean i_am_gateway = TRUE; /* whether we are the gateway server */ Xboolean i_have_control = TRUE; /* whether the gateway server has control of */ X /* the command socket */ Xboolean i_am_asleep; /* whether we are sleeping or not */ Xboolean gateway_needs_control; /* True if gateway wants control back */ Xboolean watch_for_lock; /* True if we need to watch for lock on fd 2 */ Xboolean route_to_gateway; /* True if we should route to gateway */ Xboolean in_root_directory = TRUE;/* whether we are at root directory or not */ Xstruct stat filetypes[ NOFILE ]; /* file types for open files */ X Xchar byteorder[4] = { BYTEORDER }; Xlong catch(), X nameserver(), X wakeup_call(), X alarmsig(); X Xstruct sigvec sig_continue = { X wakeup_call, X 1<<(SIGIO -1), X 0 X}; X Xstruct sigvec sig_ignore = { X (int (*)())SIG_IGN, X 1<<(SIGHUP -1), X 0 X}; X Xstruct sigvec sig_alarm = { X alarmsig, X 1<<(SIGALRM -1), X 0 X}; X Xstruct sigvec sig_name = { X nameserver, X 1<<(SIGURG -1), X 0 X}; X Xstruct sigvec sig_vec = { X catch, X (1<<(SIGINT -1)) X |(1<<(SIGQUIT-1)) X |(1<<(SIGBUS-1)) X |(1<<(SIGILL-1)) X |(1<<(SIGSEGV-1)) X |(1<<(SIGPIPE-1)) X |(1<<(SIGSYS-1)) X |(1<<(SIGTERM-1)) X |(1<<(SIGTTIN-1)) X |(1<<(SIGTTOU-1)) X |(1<<(SIGXCPU-1)) X |(1<<(SIGXFSZ-1)) X |(1<<(SIGVTALRM-1)), X 0 X}; X X#ifdef RFSDEBUG X Xlong newdebug(); X Xstruct sigvec sig_debug = { X newdebug, X (1<<(SIGTRAP -1)), X 0 X}; X#endif RFSDEBUG X Xstruct stat root; /* stat info for root directory */ SHAREOF chmod 444 remote/serverdata.c # # remote/serverdir.c # if [ -f remote/serverdir.c ]; then echo -n 'Hit <return> to overwrite remote/serverdir.c or ^C to quit' read ans rm -f remote/serverdir.c fi sed -e 's/^.//' << \SHAREOF > remote/serverdir.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: serverdir.c,v $ X * Revision 2.0 85/12/07 18:22:28 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: serverdir.c,v 2.0 85/12/07 18:22:28 toddb Rel $"; X#include "server.h" X#include <sys/dir.h> X#include <sys/stat.h> X#include <errno.h> X Xextern hosts *host; Xextern long errno; Xextern char byteorder[]; Xextern struct stat filetypes[]; X X/* X * Check to see type open file type... we may have to massage input X * it if the user wants to read this file descriptor and it is a directory. X */ Xcheckfiletype(fd) X register int fd; X{ X struct stat statb, *statp = &statb; X X if (fd < 0) X return; X fstat(fd, statp); X filetypes[ fd ] = statb; X} X X/* X * If byte-ordering is different between this machine and our client, X * the directories must be massaged into the right byte order. X */ Xfixdir(fd, buf, size) X register long size, X fd; X register char *buf; X{ X register struct direct *dirp; X register char *next, *last; X register u_char *clientorder = host->h_byteorder; X short fixshort(); X X if (size < 0) X return(errno); X if (fd >= NOFILE || (filetypes[fd].st_mode & S_IFDIR) == 0) X return(0); X X /* X * we don't know this client's byteorder... can't do it right X */ X if (!host->h_mounted) X return(EIO); X dirp = (struct direct *)buf; X last = buf; X debug7("nuxi directory entry buf=0%x, size=%d, end @%x\n", X buf, size, buf+size); X while(last < buf + size && dirp->d_reclen) X { X dirp = (struct direct *)last; X next = last + dirp->d_reclen; X X debug7("dir @0x%x (next+%d @0x%x): %x %x %x %s -->", X last, dirp->d_reclen, next, X dirp->d_ino, X (unsigned)dirp->d_reclen, X (unsigned)dirp->d_namlen, X dirp->d_name); X dirp->d_ino = fixlong(clientorder, &dirp->d_ino); X dirp->d_reclen = fixshort(clientorder, &dirp->d_reclen); X dirp->d_namlen = fixshort(clientorder, &dirp->d_namlen); X debug7(" %x %x %x %s\n", X dirp->d_ino, X (unsigned)dirp->d_reclen, X (unsigned)dirp->d_namlen, X dirp->d_name); X last = next; X } X return(0); X} X Xfixlong(clto, from) X register char *clto, /* clients byte order */ X *from; /* data to be fixed */ X{ X register char *srvo, /* server's byte order */ X *to; X long result; X X to = (char *)&result; X srvo = byteorder; X to[ clto[0] ] = from[ srvo[0] ]; X to[ clto[1] ] = from[ srvo[1] ]; X to[ clto[2] ] = from[ srvo[2] ]; X to[ clto[3] ] = from[ srvo[3] ]; X return(result); X} X Xshort fixshort(clto, from) X register char *clto, /* clients byte order */ X *from; /* data to be fixed */ X{ X register char *srvo, /* server's byte order */ X *to; X short result; X X to = (char *)&result; X srvo = byteorder; X to[ clto[0]&0x1 ] = from[ srvo[0]&0x1 ]; X to[ clto[1]&0x1 ] = from[ srvo[1]&0x1 ]; X return(result); X} SHAREOF chmod 444 remote/serverdir.c
sources-request@panda.UUCP (01/09/86)
Mod.sources: Volume 3, Issue 80 Submitted by: tektronix!tekcrl!toddb #!/bin/sh # # RFS, a kernel-resident remote file system. Shar 4 of 7 # # # This is a shell archive, meaning: # 1. Remove everything above the #!/bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # remote/serverio.c # remote/serversyscall.c # remote/shells # remote/shells/makemake # remote/shells/mkdist # remote/shells/mkdist.shar # remote/shells/rfs_clean # remote/shells/rfs_kerninstall # remote/shells/rfs_kernpatch # remote/shells/rfs_setup # remote/shells/rfs_userpatch # remote/usr.include.PYR2.5 # remote/usr.include.PYR2.5/syscall.h.diff # remote/usr.include.VAX4.3 # remote/usr.include.VAX4.2 # remote/usr.include.VAX4.2/syscall.h.diff # remote/usr.src.lib.libc # remote/usr.src.lib.libc/Makefile # remote/usr.src.lib.libc/gen # remote/usr.src.lib.libc/gen/pyr.errlst.c.diff # remote/usr.src.lib.libc/gen/vax.errlst.c.diff # remote/usr.src.lib.libc/pyr # remote/usr.src.lib.libc/pyr/sys # remote/usr.src.lib.libc/pyr/sys/remotename.s # remote/usr.src.lib.libc/pyr/sys/remoteoff.s # remote/usr.src.lib.libc/pyr/sys/remoteon.s # remote/usr.src.lib.libc/vax # remote/usr.src.lib.libc/vax/sys # remote/usr.src.lib.libc/vax/sys/remotename.c # remote/usr.src.lib.libc/vax/sys/remoteoff.c # remote/usr.src.lib.libc/vax/sys/remoteon.c # remote/usr.sys.PYR2.5 # remote/usr.sys.PYR2.5/conf # remote/usr.sys.PYR2.5/conf/makefromsource.diff # remote/usr.sys.PYR2.5/h # # remote/serverio.c # if [ -f remote/serverio.c ]; then echo -n 'Hit <return> to overwrite remote/serverio.c or ^C to quit' read ans rm -f remote/serverio.c fi sed -e 's/^.//' << \SHAREOF > remote/serverio.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: serverio.c,v $ X * Revision 2.0 85/12/07 18:22:33 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: serverio.c,v 2.0 85/12/07 18:22:33 toddb Rel $"; X#include <errno.h> X#include <stdio.h> X#include "server.h" X#include <sys/uio.h> X#include <sys/file.h> X#include <netdb.h> X#include <signal.h> X X/* X * This routine prepares to recieve a connection from another process. X * To be any good it must be followed by a call to tcpaccept(). X */ Xextern long errno; Xextern short current_pid; Xextern char *sys_errlist[], X *service, X *logfile, X *stdlogfile, X *getbuf(); Xextern boolean i_am_gateway; Xextern hosts *host; Xextern long serviceport, X errno; Xextern short last_sentry; X Xint read(), X write(); X X/* X * Get ready to accept connections. X */ Xtcppassive() X{ X int f; X struct sockaddr_in sin; X struct servent *servp; X X if ((servp = getservbyname(service, "tcp")) == NULL) X log_fatal("%s: unknown service\n", service); X serviceport = servp->s_port; X X sin.sin_port = serviceport; X sin.sin_addr.s_addr = INADDR_ANY; X sin.sin_family = AF_INET; X X f = socket(AF_INET, SOCK_STREAM, 0); X setsockopt(f, SOL_SOCKET, SO_KEEPALIVE, 0, 0); X setsockopt(f, SOL_SOCKET, SO_REUSEADDR, 0, 0); X X while (bind(f, (caddr_t)&sin, sizeof (sin)) < 0) { X if (last_sentry && errno == EADDRINUSE) X { X log("shutting down old sentry (pid %d)\n", X last_sentry); X if (! sendsig(last_sentry, SIGTERM)) X last_sentry = 0; X sleep(2); /* give it time to die */ X continue; X } X log("cannot bind %s\n", service); X return(-1); X } X X listen(f, 5); X return(f); X} X X/* X * Here we passively accept a connection from another process. X * We return a pointer to the hosts structure. If there is no X * corresponding host for a given connection, we make up a new one X * and return that. X */ Xhosts *tcpaccept(f) X int f; X{ X hosts *h = NULL; X struct sockaddr_in sin; X int g, X i, X len = sizeof (struct sockaddr_in); X X for (i = 0, g = -1; g < 0 && i < 10; i++) { X g = accept(f, &sin, &len); X if (g < 0) X { X log("accept failed\n"); X continue; X } X X /* X * Ok, we have recieved a connection. Find out what we X * know about this fella, and save the command file descriptor X * and the port number. X */ X h = findhostaddr(&sin.sin_addr); X h->h_cmdfd = g; X h->h_portnum = htons((u_short)sin.sin_port); X } X X return(h); X} X X/* X * Call another host's server. We assume that he is using the same service X * as we. X */ Xtcpconnect(h) X register hosts *h; X{ X struct sockaddr_in sin; X register long s; X X bzero((char *)&sin, sizeof (sin)); X bcopy(&h->h_addr, (char *)&sin.sin_addr, sizeof(struct in_addr)); X sin.sin_family = AF_INET; X sin.sin_port = serviceport; X s = socket(AF_INET, SOCK_STREAM, 0); X if (s < 0) X { X log("can't get socket to remote server\n"); X return(-1); X } X X /* X * time out on connection rather quickly. X */ X alarm(5); X if (connect(s, (char *)&sin, sizeof (sin)) < 0) { X alarm(0); X log("can't connect to server\n"); X close(s); X return(-1); X } X alarm(0); X return(s); X} X Xalarmsig() X{ X log("timeout\n"); X errno = EINTR; X} X Xlog(x1, x2, x3, x4, x5, x6, x7, x8, x9) X{ X char buf[ BUFSIZ ]; X register char *p = buf; X static boolean printpid = TRUE; X X *p = '\0'; X if (printpid) X { X sprintf(p, "(%d)", current_pid); X p += strlen(p); X if (errno) X { X sprintf(p, "%s: ", sys_errlist[ errno ]); X p += strlen(p); X errno = 0; X } X } X sprintf(p, x1, x2, x3, x4, x5, x6, x7, x8, x9); X p += strlen(p); X if (*(p-1) == '\n') X printpid = TRUE; X else X printpid = FALSE; X write(2, buf, p-buf); X} X Xlog_fatal(x1, x2, x3, x4, x5, x6, x7, x8, x9) X{ X static boolean entered = FALSE; X X if (! entered) X { X entered = TRUE; X log ("fileserver: FATAL ERROR: "); X log (x1, x2, x3, x4, x5, x6, x7, x8, x9); X cleanup(); X } X exit (1); X} X X/* X * Set up the log file for the current process. If there is no current X * host defined, then we are the sentry server and simply use the X * standard logfile: this should be done once only. If 'host' is defined, X * then set up a logfile for this particular connection. X * X * The sentry server always puts his signature at the top of the file X * (pid number). So as a side effect, the global variable last_sentry X * is set to this signature (if there exists one). X */ Xsetlogfile() X{ X char buf[ BUFSIZ ]; X register char *pbuf = buf; X register long newstderr; X boolean sentry = FALSE; X FILE *fd; X X if (logfile) X free (logfile); X if (host == NULL) X { X sentry = TRUE; X strcpy(pbuf, stdlogfile); X } X else X sprintf(pbuf, "%s.%s.%d", X stdlogfile, host->h_names[0], current_pid); X logfile = malloc(strlen(pbuf)+1); X strcpy(logfile, pbuf); X X /* X * Get the previous signature. X */ X if (sentry) X { X if ((fd = fopen(logfile, "r")) != NULL) X { X *pbuf = '\0'; X fgets(pbuf, BUFSIZ, fd); X last_sentry = atoi(pbuf+1); X fclose(fd); X } X } X X newstderr = open(logfile, O_RDWR|O_APPEND|O_CREAT|O_TRUNC, 0444); X if (newstderr < 0) X log_fatal("cannot reopen stderr\n"); X dup2(newstderr, 2); X close(newstderr); X log("startup.\n"); /* put down our signature. */ X} X Xcleanup() X{ X register process *proc; X X if (i_am_gateway && host) X for (proc=host->h_proclist; proc; proc=proc->p_next) X if (proc->p_handler != current_pid) X sendsig(proc->p_handler, SIGKILL); X mourne(); X} X Xsndmsg(fd, msg, msglen, data, len) X register struct message *msg; X register char *data; X register int fd, msglen, len; X{ X register int num; X struct iovec iov[2]; X X X showmsg(msg, TRUE); X /* X * set up for the write and if there is any data to send, try to send X * a bunch of it. X */ X if (len > 0 && data) X { X iov[0].iov_base = (char *)msg; X iov[0].iov_len = msglen; X iov[1].iov_base = data; X iov[1].iov_len = len; X if ((num = writev(fd, iov, 2)) == len + msglen) X { X debug8("wrote data and msg (%d)!!\n", len + msglen); X return(TRUE); X } X debug8("wrote %d of %d msg + data\n", num, len+msglen); X if (num < 0) X return(FALSE); X if (_rmtio(write, fd, data+num, len-num) <= 0) X return(FALSE); X } X else if (_rmtio(write, fd, msg, msglen) <= 0) X return(FALSE); X return(TRUE); X} X X/* X * Read the next message. Its format is null-separated hex-ascii strings. X * In order, they are: X * total_length length of this request X * header_length length of the message request (minus length of data) X * pid Process id on requesting machine X * uid user id of process on requesting machine X * syscall our internal syscall number X * args... between 0 and ? X * X * Followed by actual data (if any). We grab the first two fields, and X * use them for making sure we read all that is necessary. The remainder X * are returned in a array of character pointers. It there is any data X * in this request, then it is pointed to by the last character pointer. X * X * The way that we read messages is as follows: X * X * last message length = 0 X * while no more messages X * do X * if last message length > 0 X * gobbleup last message length bytes X * peek at next message X * if this message is for another process X * then X * wake up the other process X * last message length = 0 X * go to sleep X * continue X * endif X * if data in this message X * then X * read the message X * last message length = 0 X * else X * last message length = length of this message X * endif X * service request X * done X */ X Xstruct message *getmsg(fd) X register long fd; X{ X register long cnt, X lastcnt = 0, X len; X register struct message *msg; X X msg = (struct message *)getbuf(BIGBUF); X /* X * Check to see if there is a message still in the queue, that has X * been processed, but not yet read. X */ X gobble_last_msg(fd, msg); X for (;;) X { X debug8("peek at fd %d... ", fd); X cnt = recv(fd, (char *)msg, BIGBUF, MSG_PEEK); X if (cnt < R_MINRMSG) X { X if (cnt < 0 && errno == EINTR) X continue; X debug8("eof, cnt=%d\n", cnt); X return(NULL); X } X debug8("got %d from peek\n", cnt); X X /* X * Now find out how long the request is (excluding data) X * and make sure that we have at least that amount. X */ X#ifdef magnolia X len = msg->m_hdlen; X#else /* magnolias don't need to do this garbage (MC68000) */ X msg->m_totlen = ntohl(msg->m_totlen); X len = msg->m_hdlen = ntohs(msg->m_hdlen); X msg->m_pid = ntohs(msg->m_pid); X msg->m_uid = ntohs(msg->m_uid); X msg->m_syscall = ntohs(msg->m_syscall); X msg->m_args[0] = ntohl(msg->m_args[0]); X msg->m_args[1] = ntohl(msg->m_args[1]); X msg->m_args[2] = ntohl(msg->m_args[2]); X msg->m_args[3] = ntohl(msg->m_args[3]); X#endif X if (len > cnt) X { X if (cnt == lastcnt) X { X log("most but not all of message is in\n"); X dumpmsg(msg, cnt); X return(NULL); X } X else X debug8("didn't get all of message headder\n"); X lastcnt = cnt; X sleep(5); X } X else if (len < R_MINRMSG) X { X log("bad soft msg len=%d, got %d\n", len, cnt); X dumpmsg(msg, cnt); X if (i_am_gateway) X log_fatal(""); X say_something(S_CORRUPTED, 0); X sendsig(current_pid, SIGSTOP); X } X else X break; X } X showmsg(msg, FALSE); X return(msg); X} X X/* X * Here we format the response to be sent to the client. Note that X * the client can never tolerate a message shorter than X * R_MINRMSG + sizeof(long). The declaration of x0-xf is for the X * sake of stupid Pyramid argument conventions. X */ Xsendreturn(proc, fd, data, cnt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,xa,xb,xc,xd,xe,xf) X process *proc; X register long cnt; X register char *data; X long fd; X{ X char buf[ BUFSIZ ]; X struct message msgbuf; X register struct message *msg = &msgbuf; X register *argp = &x0, msglen, i; X X msg->m_errno = htons(proc->p_errno); X msg->m_pid = htons(proc->p_pid); X msg->m_uid = htons(proc->p_uid); X if (proc->p_errno > 0) /* -1 is valid errno: says its a local file */ X { X msglen = R_MINRMSG + sizeof(long); X msg->m_totlen = htonl(msglen); X proc->p_returnval = -1; X } X else X { X msglen = R_MINRMSG + (cnt+1)*sizeof(long); X if (data) X msg->m_totlen = htonl(msglen + proc->p_returnval); X else X msg->m_totlen = htonl(msglen); X#ifdef pyr /* Pyramid */ X msg->m_args[ R_RETVAL+1 ] = htonl(x0); X msg->m_args[ R_RETVAL+2 ] = htonl(x1); X msg->m_args[ R_RETVAL+3 ] = htonl(x2); X msg->m_args[ R_RETVAL+4 ] = htonl(x3); X msg->m_args[ R_RETVAL+5 ] = htonl(x4); X msg->m_args[ R_RETVAL+6 ] = htonl(x5); X msg->m_args[ R_RETVAL+7 ] = htonl(x6); X msg->m_args[ R_RETVAL+8 ] = htonl(x7); X msg->m_args[ R_RETVAL+9 ] = htonl(x8); X msg->m_args[ R_RETVAL+10 ] = htonl(x9); X msg->m_args[ R_RETVAL+11 ] = htonl(xa); X msg->m_args[ R_RETVAL+12 ] = htonl(xb); X msg->m_args[ R_RETVAL+13 ] = htonl(xc); X msg->m_args[ R_RETVAL+14 ] = htonl(xd); X msg->m_args[ R_RETVAL+15 ] = htonl(xe); X msg->m_args[ R_RETVAL+16 ] = htonl(xf); X#else pyr X for (i=0; i<cnt; i++) X msg->m_args[ R_RETVAL+1+i ] = htonl(argp[ i ]); X#endif X } X msg->m_args[ R_RETVAL ] = htonl(proc->p_returnval); X msg->m_hdlen = htons(msglen); X sndmsg(fd, msg, msglen, data, proc->p_returnval); X errno = 0; X} X X_shutdown(fd) X int fd; X{ X log("shutdown fd %d\n", fd); X close(fd); X} X Xchar *getbuf(size) X{ X static char *buf, *calloc(), *realloc(); X static int cursize; X static int highwater; X X if (size > highwater) X { X if (buf == NULL) X buf = calloc(cursize = size, sizeof(char)); X else X { X buf = realloc(buf, highwater = size); X debug8("resize buffer to %d\n", size); X } X highwater = size; X if (buf == NULL) X log_fatal("cannot allocate buffer space\n"); X } X return(buf); X} X Xchar *get_data_buf(size) X{ X static char *buf, *malloc(), *realloc(); X static int cursize; X static int highwater; X X if (size > highwater) X { X if (buf == NULL) X buf = malloc(cursize = size); X else X { X buf = realloc(buf, highwater = size); X debug8("resize data buffer to %d\n", size); X } X highwater = size; X if (buf == NULL) X log_fatal("cannot allocate data buffer space\n"); X } X return(buf); X} X Xgobble_last_msg(fd, msg) X register long fd; X register struct message *msg; X{ X if (msg->m_totlen) X { X debug8("gobble up last %d byte message... ", msg->m_totlen); X _rmtio(read, fd, msg, msg->m_totlen); X msg->m_totlen = 0; X } X} X X_rmtio(iofunc, fd, buf, len) X register func iofunc; X register int fd, len; X register char *buf; X{ X register int cnt, need = len; X X debug8("io %d bytes, fd=%d...", len, fd); X while(need) X { X if ((cnt = (*iofunc)(fd, buf+len-need, need)) <= 0) X { X _shutdown(fd); X return(cnt); X } X need -= cnt; X } X debug8("did %d.\n", len - need); X return(len); X} X X_rmtiov(iofunc, fd, iovec, len) X register func iofunc; X register int fd, len; X register struct iovec *iovec; X{ X X debug8("io %d vectors, fd=%d...", len, fd); X if ((len = (*iofunc)(fd, iovec, len)) <= 0) X _shutdown(fd); X debug8("did %d.\n", len); X return(len); X} X X/* X * Show the message in characters and hex. X */ Xdumpmsg(msg, len) X char *msg; X long len; X{ X char string[ 100 ], *pstring = string, X words[ 100 ], *pwords = words, X dwords[ 100 ], *pdwords = dwords, X longs[ 100 ], *plongs = longs, X *p; X long cnt = 0; X X for(p = msg; cnt<len; cnt++, p++) X { X /* character */ X if (*p >= ' ') X sprintf(pstring, "%c ", *p > '~' ? '?' : *p); X else X sprintf(pstring, "^%c ", *p | 0x40); X pstring += 3; X if ((cnt & 0x1) == 0) X { X sprintf(pwords, "%-4.4x ", X *((unsigned short *)p)); X sprintf(pdwords, "%-5.5d ", X *((unsigned short *)p)); X pwords += 6; X pdwords += 6; X } X if ((cnt & 0x3) == 0) X { X sprintf(plongs, "%-8.8x ", *((long *)p)); X plongs += 12; X } X if (pstring >= string+72) X { X log("%s\n", pstring = string); X log("%s\n", pwords = words); X log("%s\n", pdwords = dwords); X log("%s\n\n", plongs = longs); X } X } X log("%s\n", string); X log("%s\n", words); X log("%s\n", dwords); X log("%s\n", longs); X} X X#ifdef RFSDEBUG X Xshowmsg(msg, fromserver) X register struct message *msg; X long fromserver; X{ X register long end, len, pid, uid, totlen; X X if ((remote_debug & 0x100) == 0) X return; X if (fromserver) X len = ntohs(msg->m_hdlen), X totlen = ntohl(msg->m_totlen), X pid = ntohs(msg->m_pid), X uid = ntohs(msg->m_uid); X else X len = msg->m_hdlen, X totlen = msg->m_totlen, X pid = msg->m_pid, X uid = msg->m_uid; X log("%s server: len=%d,tot=%d,pid=%d,uid=%d", X fromserver ? "from" : "to", len, totlen, pid, uid); X X /* round up into long words */ X len = (len - R_MINRMSG + 3) >> 2; X if (fromserver) X { X log(",errno=%d,retval=%d", X htons(msg->m_errno), htonl(msg->m_args[ R_RETVAL ])); X end = R_RETVAL+1; X } X else X { X log(",syscall=%d", msg->m_syscall); X end = 0; X } X for (; end<len; end++) X log(",0x%x", ntohl(msg->m_args[ end ])); X log("\n"); X} X X/* X * Set new debug levels. X */ Xnewdebug() X{ X register long fd, cnt; X char *dbfile = "/usr/tmp/rfs_debug", X buf[ BUFSIZ ]; X register char *p = buf; X X fd = open(dbfile, O_RDONLY); X if (fd < 0) { X log("can't open %s\n", dbfile); X goto out; X } X X cnt = read(fd, buf, BUFSIZ); X close(fd); X if (cnt <= 0) { X log("can't read %s\n", dbfile); X goto out; X } X X while ((*p >= 'a' && *p <= 'f') X || (*p >= 'A' && *p <= 'F') X || (*p >= '0' && *p <= '9')) X p++; X *p = '\0'; X remote_debug = atox(buf); Xout: X log("debug=%x\n", remote_debug); X} X#endif RFSDEBUG SHAREOF chmod 444 remote/serverio.c # # remote/serversyscall.c # if [ -f remote/serversyscall.c ]; then echo -n 'Hit <return> to overwrite remote/serversyscall.c or ^C to quit' read ans rm -f remote/serversyscall.c fi sed -e 's/^.//' << \SHAREOF > remote/serversyscall.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Log: serversyscall.c,v $ X * Revision 2.0 85/12/07 18:22:44 toddb X * First public release. X * X */ Xstatic char *rcsid = "$Header: serversyscall.c,v 2.0 85/12/07 18:22:44 toddb Rel $"; X#include "server.h" X#include <sys/stat.h> X#include <sys/dir.h> X#include <sys/file.h> X#include <sys/user.h> X#include <errno.h> X Xextern char *syscallnames[]; Xextern short current_pid; Xextern short gateway_server; Xextern boolean i_am_gateway; Xextern boolean in_root_directory; Xextern syscallmap smap[]; Xextern struct stat filetypes[]; Xextern hosts *host; Xextern long errno; X Xs_fork(msg, proc) X register struct message *msg; X register process *proc; X{ X register process *newproc; X register long newpid = msg->m_args[ 0 ], X i, fd; X register short syscall = msg->m_syscall; X boolean needtofork = FALSE; X X if (newproc = findprocess(newpid, msg->m_uid)) X debug1("%d = %sfork(%d), redundant\n", X newpid, syscall == RSYS_vfork ? "v" : "", X msg->m_args[ 1 ]); X else X { X debug1("%d = %sfork(%d)\n", X newpid, syscall == RSYS_vfork ? "v" : "", X proc->p_pid); X newproc = add_new_process(msg->m_uid, newpid); X for (i=0; i<NOFILE; i++) X if ((fd = proc->p_fds[ i ]) >= 0) X newproc->p_fds[ i ] = fd, needtofork = TRUE; X X if (needtofork) X become_server(msg); X else if (! i_am_gateway) X say_something(S_NEWPROCESS, newpid); X } X /* X * No return message is sent! X */ X} X Xs_read(msg, proc) X register struct message *msg; X register process *proc; X{ X register long clientfd = msg->m_args[0], X fd, X size = msg->m_args[1]; X register char *buf = get_data_buf(size); X X fd = MAPFD(clientfd, proc); X proc->p_returnval = read(fd, buf, size); X proc->p_errno = fixdir(fd, buf, proc->p_returnval); X debug1("%d = read(%d->%d, 0x%x, %d);\n", X proc->p_returnval, clientfd, fd, buf, size); X sendreturn(proc, host->h_cmdfd, buf, 0); X} X Xs_write(msg, proc) X register struct message *msg; X register process *proc; X{ X register long clientfd = msg->m_args[0], X fd, X size = msg->m_args[1], X totlen = msg->m_totlen; X register char *buf; X X if (totlen > BIGBUF) X msg = (struct message *)getbuf(totlen); X buf = (char *)&msg->m_args[R_DATA]; X gobble_last_msg(host->h_cmdfd, msg); X fd = MAPFD(clientfd, proc); X proc->p_returnval = write(fd, buf, size); X proc->p_errno = errno; X debug1("%d = write(%d->%d, 0x%x, %d);\n", X proc->p_returnval, clientfd, fd, buf, size); X sendreturn(proc, host->h_cmdfd, NULL, 0); X} X X/* X * Open a file. Also interface for creat(). Note that we pass back X * the current file offset. X */ Xs_open(msg, proc) X struct message *msg; X register process *proc; X{ X#define mask args[ 3 ] X#define clientfd args[ 2 ] X#define mode args[ 1 ] X#define flags args[ 0 ] X X register long ourfd, X *args = msg->m_args; X register char *path = path1addr(msg); X X change_to_umask(mask); X ourfd = open(path, flags, mode); X proc->p_errno = errno; X proc->p_returnval = allocate_fd(ourfd, proc, clientfd); X debug1("%d = open(\"%s\", 0%o, %d)\n", X proc->p_returnval, path, flags, mode); X sendreturn(proc, host->h_cmdfd, NULL, 1, lseek(ourfd, 0, L_INCR)); X X#undef mask X#undef clientfd X#undef mode X#undef flags X} X Xs_fd1(msg, proc) X register struct message *msg; X register process *proc; X{ X register long clientfd = msg->m_args[0], X fd, X syscall = msg->m_syscall; X X fd = MAPFD(clientfd, proc); X /* X * No return sent for close or fsync! X */ X if (syscall == RSYS_close || syscall == RSYS_fsync) X proc->p_returnval = deallocate_fd(proc, msg->m_args[0]); X else X { X proc->p_returnval = (*smap[ syscall ].s_syscall)(fd); X proc->p_errno = errno; X if (syscall != RSYS_fsync) X sendreturn(proc, host->h_cmdfd, NULL, 0); X } X debug1("%d = %s(%d->%d)\n", X proc->p_returnval, syscallnames[ syscall ], clientfd, fd); X} X Xs_fd1_plus(msg, proc) X register struct message *msg; X register process *proc; X{ X#define arg1 msg->m_args[1] X#define arg2 msg->m_args[2] X register long clientfd = msg->m_args[0], X fd; X X fd = MAPFD(clientfd, proc); X proc->p_returnval = (*smap[ msg->m_syscall ].s_syscall)(fd, arg1, arg2); X proc->p_errno = errno; X debug1("%d = %s(%d->%d, %d(0%o), %d(0%o))\n", X proc->p_returnval, syscallnames[ msg->m_syscall ], X clientfd, fd, arg1, arg1, arg2, arg2); X sendreturn(proc, host->h_cmdfd, NULL, 0); X#undef arg1 X#undef arg2 X} X X/* X * link, symlink and rename X */ Xs_path2(msg, proc) X register struct message *msg; X register process *proc; X{ X#define mask msg->m_args[0] X register char *path1, *path2; X register short syscall = msg->m_syscall; X X change_to_umask(mask); X path2 = twopath2addr(msg); X path1 = twopath1addr(msg); X proc->p_returnval = (*smap[ syscall ].s_syscall)(path1, path2); X proc->p_errno = errno; X debug1("%d = %s(\"%s\", \"%s\")\n", syscallnames[ syscall ], X proc->p_returnval, path1, path2); X sendreturn(proc, host->h_cmdfd, NULL, 0); X#undef mask X} X Xs_path1(msg, proc) X register struct message *msg; X register process *proc; X{ X register char *path; X register short syscall = msg->m_syscall; X register long mask = msg->m_args[0]; X struct stat statb; X extern struct stat root; X register struct stat *statp = &statb; X X change_to_umask(mask); X path = path1addr(msg); X proc->p_returnval = (*smap[ syscall ].s_syscall)(path); X proc->p_errno = errno; X debug1("%d = %s(\"%s\")\n", X proc->p_returnval, syscallnames[ syscall ], path); X if (syscall == RSYS_chdir) X if (proc->p_returnval == -1) X debug1("can't chdir to %s\n", path); X else X { X if (stat(".", statp) == 0 && isroot(statp)) X in_root_directory = TRUE; X else X in_root_directory = FALSE; X debug10("Now I'm %sin root\n", X !in_root_directory ? "not " : ""); X } X sendreturn(proc, host->h_cmdfd, NULL, 0); X} X Xs_access(msg, proc) X register struct message *msg; X register process *proc; X{ X register char *path; X register long perm = msg->m_args[0]; X X path = path1addr(msg); X X /* X * The kernel access is strange: it first sets the effective uid X * and gid to be the real uid/gid and THEN it does the access. X * Well, our real uid is always 0 (so we can change our effective X * uid at will), so the effect is different than a normal user X * would expect. i.e. access always succeeds no matter what X * the arguments. This is clearly not what we want, so we apply X * an awful kludge here; change our real uid to be the user we X * are pretending to be, and then call access. X */ X change_to_uid(0); X setreuid(proc->p_ruser->r_user->u_local_uid, 0); X proc->p_returnval = access(path, perm); X proc->p_errno = errno; X debug1("%d = access(\"%s\", 0%o\n", proc->p_returnval, path, perm); X setreuid(0, 0); X sendreturn(proc, host->h_cmdfd, NULL, 0); X} X Xs_path1_plus(msg, proc) X register struct message *msg; X register process *proc; X{ X register char *path; X register long syscall = msg->m_syscall, X arg1 = msg->m_args[0], X arg2 = msg->m_args[1], X mask = msg->m_args[2]; X X path = path1addr(msg); X change_to_umask(mask); X X proc->p_returnval = (*smap[ syscall ].s_syscall)(path, arg1, arg2); X proc->p_errno = errno; X debug1("%d = %s(\"%s\", %d(0%o), %d(%o))\n", X proc->p_returnval, X syscallnames[ syscall ], path, arg1, arg1, arg2, arg2); X sendreturn(proc, host->h_cmdfd, NULL, 0); X} X Xs_stat(msg, proc) X register struct message *msg; X register process *proc; X{ X union a { X char *path; X long fd; X } arg; X register short syscall = msg->m_syscall; X register long clientfd = msg->m_args[0]; X struct stat statbuf; X register struct stat *statp = &statbuf; X X if (syscall == RSYS_fstat) X arg.fd = MAPFD(clientfd, proc); X else X arg.path = path1addr(msg); X proc->p_returnval = (*smap[ syscall ].s_syscall)(arg.path, statp); X proc->p_errno = errno; X#ifdef RFSDEBUG X if (syscall == RSYS_fstat) X debug1("%d = fstat(%d->%d, 0x%x)\n", X proc->p_returnval, clientfd, arg.fd, &statbuf); X else X debug1("%d = %s(\"%s\", 0x%x)\n", proc->p_returnval, X syscallnames[ syscall ], arg.path, &statbuf); X#endif RFSDEBUG X if (proc->p_returnval == -1) X sendreturn(proc, host->h_cmdfd, NULL, 0); X else X sendreturn(proc, host->h_cmdfd, NULL, 14, X statp->st_dev, X statp->st_ino, X statp->st_mode, X statp->st_nlink, X statp->st_uid, X statp->st_gid, X statp->st_rdev, X statp->st_size, X statp->st_atime, X statp->st_mtime, X statp->st_ctime, X statp->st_blksize, X statp->st_blocks, X isroot(statp)); X} X Xs_lseek(msg, proc) X register struct message *msg; X register process *proc; X{ X register long clientfd = msg->m_args[0], fd; X X fd = MAPFD(clientfd, proc); X proc->p_returnval = lseek(fd, msg->m_args[1], msg->m_args[2]); X proc->p_errno = errno; X debug1("%d = lseek(%d->%d, %d, %d)\n", proc->p_returnval, X clientfd, fd, msg->m_args[1], msg->m_args[2]); X if (msg->m_syscall == RSYS_lseek) X sendreturn(proc, host->h_cmdfd, NULL, 0); X} X Xs_dup(msg, proc) X register struct message *msg; X register process *proc; X{ X register long clientfd = msg->m_args[0], fd, X newclientfd = msg->m_args[1], X ourfd, X newfd; X X fd = MAPFD(clientfd, proc); X if (msg->m_syscall == RSYS_dup2) X { X newfd = MAPFD(newclientfd, proc); X if (newfd >= 0) X { X proc->p_returnval = deallocate_fd(proc, newclientfd, 0); X debug1("%d = (dup2)close(%d->%d)... ", X proc->p_returnval, newclientfd, newfd); X } X } X if (fd >= 0) X { X ourfd = dup(fd); X proc->p_returnval = allocate_fd(ourfd, proc, newclientfd); X proc->p_errno = errno; X } X else if (msg->m_syscall == RSYS_dup2 && newfd >= 0) X proc->p_returnval = newclientfd; X else X { X proc->p_returnval = -1; X proc->p_errno = EINVAL; X } X debug1("%d = dup(%d->%d)\n", proc->p_returnval, clientfd, fd); X sendreturn(proc, host->h_cmdfd, NULL, 0); X} X Xs_ioctl(msg, proc) X struct message *msg; X process *proc; X{ X long fd = msg->m_args[0]; X} X Xs_readlink(msg, proc) X register struct message *msg; X register process *proc; X{ X register long size = msg->m_args[0]; X register char *buf = get_data_buf(size), X *path = path1addr(msg); X X proc->p_returnval = readlink(path, buf, size); X proc->p_errno = errno; X debug1("%d = readlink(\"%s\", 0x%x, %d);\n", X proc->p_returnval, path, buf, size); X sendreturn(proc, host->h_cmdfd, buf, 0); X} X X/* X * Send exec information the remote host. X */ Xs_execinfo(msg, proc) X register struct message *msg; X register process *proc; X{ X register long hdrsize = msg->m_args[ 0 ], X red, X err = 0, X msglen = R_MINRMSG + sizeof(long)*R_EXECDATA; X register char *path = path1addr(msg), X *p; X struct stat st; X struct message msgbuf; X X errno = 0; X if (hdrsize > (R_MAXARGS - R_EXECDATA)*sizeof(long)) X { X log("exec: hdrsize = %d!!\n", hdrsize); X err = EINVAL; X goto done; X } X /* X * Start building the outgoing message... get header, X * check permissions and open file. X */ X msg = &msgbuf; X if ((proc->p_execfd = open(path, O_RDONLY)) == -1) X goto done; X fstat(proc->p_execfd, &st); X if ((st.st_mode & S_IFMT) != S_IFREG X || ! myaccess(&st, proc->p_ruser->r_user, X_OK)) X { X err = ENOEXEC; X debug12("%s mode=0%o %sreg file, %sexecutable\n", X path, st.st_mode, X (st.st_mode & S_IFMT) != S_IFREG ? "not " : "", X myaccess(&st, proc->p_ruser->r_user, X_OK) ? X "" : "not "); X goto done; X } X msg->m_args[ R_EXECREADONLY ] = X (myaccess(&st, proc->p_ruser->r_user, W_OK) == FALSE); X msg->m_args[R_EXECDATA] = 0; /* for zero-length files */ X red = read(proc->p_execfd, msg->m_args + R_EXECDATA, hdrsize); X if (red <= 0) X { X debug12("read on exec fd %d=%d\n", proc->p_execfd, red); X err = EINVAL; X goto done; X } X msglen += red; X X X /* X * Check setuid/setgid info X */ X if (st.st_mode & S_ISUID) X msg->m_args[ R_EXECUID ] = htonl(st.st_uid); X else X msg->m_args[ R_EXECUID ] = htonl(-1); X if (st.st_mode & S_ISGID) X msg->m_args[ R_EXECGID ] = htonl(st.st_gid); X else X msg->m_args[ R_EXECGID ] = htonl(-1); X Xdone: X proc->p_execstarted = FALSE; X msg->m_hdlen = htons(msglen); X msg->m_totlen = htonl(msglen); X if (errno) X err = errno; X if (err) X { X debug12("execinfo: err=%d\n", err); X close(proc->p_execfd); X proc->p_execfd = -1; X } X debug1("%d = execve(\"%s\");\n", proc->p_returnval, path); X if (msg->m_errno = htons(err)) X msg->m_args[ R_RETVAL ] = htonl(-1); X else X msg->m_args[ R_RETVAL ] = htonl(st.st_size); X msg->m_pid = htons(proc->p_pid); X msg->m_uid = htons(proc->p_uid); X sndmsg(host->h_cmdfd, msg, msglen, 0, 0); X} X X/* X * Send exec text and data to remote host. X */ Xs_execread(msg, proc) X struct message *msg; X process *proc; X{ X register long fd = proc->p_execfd, X hdrsize = msg->m_args[0], X size = msg->m_args[1], X red; X register char *buf = get_data_buf(size); X X if (!proc->p_execstarted) X { X if (lseek(fd, hdrsize, 0) != hdrsize) X { X log("can't seek to %d on fd %d for exec\n", X hdrsize, fd); X proc->p_errno = EINVAL; X } X proc->p_execstarted = TRUE; X } X if (size) X { X proc->p_returnval = read(fd, buf, size); X proc->p_errno = errno; X debug1("%d = execread(%d)\n", proc->p_returnval, size); X } X else /* all done; send no return */ X { X proc->p_returnval = close(proc->p_execfd); X proc->p_execfd = -1; X debug1("%d = execread(%d)\n", proc->p_returnval, size); X return; X } X X sendreturn(proc, host->h_cmdfd, buf, 0); X} X Xs_utimes(msg, proc) X struct message *msg; X process *proc; X{ X char *path; X struct timeval tv[2]; X X path = path1addr(msg); X tv[0].tv_sec = msg->m_args[0]; X tv[0].tv_usec = msg->m_args[1]; X tv[1].tv_sec = msg->m_args[2]; X tv[1].tv_usec = msg->m_args[3]; X X X proc->p_returnval = utimes(path, tv); X proc->p_errno = errno; X debug1("%d = utimes(\"%s\", 0x%x\n", proc->p_returnval, path, tv); X sendreturn(proc, host->h_cmdfd, NULL, 0); X} X X/* X * Let a process exit. X */ Xs_exit(msg, proc) X struct message *msg; X process *proc; X{ X long otherprocs = 0; X process *p2; X X /* X * No return message sent! X */ X debug1("exit()\n"); X deletelist(&host->h_proclist, proc); X freeproc(proc); X if (! i_am_gateway) X { X for (proc=host->h_proclist; proc; proc=proc->p_next) X if (proc->p_handler == current_pid) X otherprocs++; X if (otherprocs == 0) X { X gobble_last_msg(host->h_cmdfd, msg); X say_something(S_ALLDONE, 0); X mourne(); X exit(0); X } X else X say_something(S_PROCEXIT, msg->m_pid); X } X} X Xnoop(msg, proc) X struct message *msg; X process *proc; X{ X extern long errno; X X log("*** FUNCTION IGNORED ***\n", proc->p_pid); X proc->p_returnval = -1; X proc->p_errno = EINVAL; X sendreturn(proc, host->h_cmdfd, NULL, 0); X} SHAREOF chmod 444 remote/serversyscall.c # # remote/shells # mkdir remote/shells chmod 775 remote/shells # # remote/shells/makemake # if [ -f remote/shells/makemake ]; then echo -n 'Hit <return> to overwrite remote/shells/makemake or ^C to quit' read ans rm -f remote/shells/makemake fi sed -e 's/^.//' << \SHAREOF > remote/shells/makemake X#!/bin/sh XMAKEFILE=Makefile X Xcase "$1" in X"") X echo "Usage: $0 <machinetype>" X exit 1 X ;; XM68) X MAKEFILE=M68 X ;; Xesac X Xif [ ! -f make.base.$1 ] Xthen X echo No machine type $1 supported. X exit 1 Xfi X Xcat make.base.$1 make.base > $MAKEFILE SHAREOF chmod 755 remote/shells/makemake # # remote/shells/mkdist # if [ -f remote/shells/mkdist ]; then echo -n 'Hit <return> to overwrite remote/shells/mkdist or ^C to quit' read ans rm -f remote/shells/mkdist fi sed -e 's/^.//' << \SHAREOF > remote/shells/mkdist X#!/bin/sh X XFILES=' X remote/README X remote/*.[ch] X remote/doc X remote/make.* X remote/shells X remote/usr.*' X XFILES=`echo $FILES` Xcd .. Xtar cvhf - $FILES > remote/remotefs.tar SHAREOF chmod 755 remote/shells/mkdist # # remote/shells/mkdist.shar # if [ -f remote/shells/mkdist.shar ]; then echo -n 'Hit <return> to overwrite remote/shells/mkdist.shar or ^C to quit' read ans rm -f remote/shells/mkdist.shar fi sed -e 's/^.//' << \SHAREOF > remote/shells/mkdist.shar X#!/bin/sh X XFILES=' X remote/README X remote/*.[ch] X remote/doc X remote/make.* X remote/shells X remote/usr.*' X Xset -x Xcd .. Xshar $FILES Xmv shar.? remote X X# X# put in the count X# XCOUNT=`ls remote/shar.? | grep -c .` Xcnt=1 Xwhile [ $cnt -le $COUNT ] Xdo X Xed remote/shar.$cnt << EOF X1a X# X# RFS, a kernel-resident remote file system. Shar $cnt of $COUNT X# X. Xw Xq XEOF X cnt=`expr $cnt + 1` Xdone X X# X# add in the intro X# Xed remote/shar.1 << \EOF X1i XThese seven shar files contain the software and documentatino for Xinstallation, maintenance and adjustment of RFS, a public domain, Xkernel-resident distributed file system, written at Tektronix Computer XResearch Laboratories* by me for partial fulfillment of the master's Xdegree program at the University of Denver. It was designed to provide Xcomplete transparency with respect to file access and protections for Xall programs whether they use local or remote files and directories. XIt has been installed on VAX BSD 4.2 and 4.3 UNIX, Pyramid 4.2/5.0 XUNIX, version 2.5, and on a Tektronix internal proprietary workstation, Xcalled Magnolia. The instructions are designed in a way that keeps all Xchanges separate from your standard sources, in hope that it will Xencourage sites to try the installation. X X Todd Brunhoff X toddb%crl@tektronix.csnet X decvax!tektronix!crl!toddb X X* RFS should not be confused with another completely different (but X excellent) implementation from Tektronix available on the 6000 series X workstation, called DFS, and done by a separate product group. The X work on RFS was designed and written strictly by the author of this X paper at about the same time as DFS, and draws none of its X implementation details from DFS. RFS is public domain, while DFS is X proprietary. X X. Xw Xq XEOF SHAREOF chmod 755 remote/shells/mkdist.shar # # remote/shells/rfs_clean # if [ -f remote/shells/rfs_clean ]; then echo -n 'Hit <return> to overwrite remote/shells/rfs_clean or ^C to quit' read ans rm -f remote/shells/rfs_clean fi sed -e 's/^.//' << \SHAREOF > remote/shells/rfs_clean X#!/bin/sh X Xcd /usr/tmp Xfor file in rfs_log.*.* Xdo X pid=`expr "$file" : '.*\.\(.*\)'` X result=`kill -19 $pid 2>&1` X case "$result" in X *"No such process") (set -x; rm -f $file);; X esac Xdone SHAREOF chmod 755 remote/shells/rfs_clean # # remote/shells/rfs_kerninstall # if [ -f remote/shells/rfs_kerninstall ]; then echo -n 'Hit <return> to overwrite remote/shells/rfs_kerninstall or ^C to quit' read ans rm -f remote/shells/rfs_kerninstall fi sed -e 's/^.//' << \SHAREOF > remote/shells/rfs_kerninstall X#!/bin/sh X X# X# Install script for added RFS kernel sources. X# X NL=' X' X SRC=$1 X DEST=$2 X VER=$3 X USAGE="${NL}Usage: $0 src-dir dest-dir VAX4.3|VAX4.2|PYR2.5" XRemove_start= X Remove_end= X Delete= X X# X# Figure out what software we are running... X# Xcase "$VER" in XVAX4.3) Remove_start='^#else[ ]BSD4_3' X Remove_end='^#endif[ ]BSD4_3' X Delete='^#ifdef[ ]BSD4_3' X ;; XVAX4.2) Remove_start='^#ifdef[ ]BSD4_3' X Remove_end='^#else[ ]BSD4_3' X Delete='^#endif[ ]BSD4_3' X ;; XPYR2.5) Remove_start='^#ifdef[ ]BSD4_3' X Remove_end='^#else[ ]BSD4_3' X Delete='^#endif[ ]BSD4_3' X ;; X*) echo "$0: Unknown type = $VER" \ X "$USAGE" X exit 1 X ;; Xesac Xif [ "$SRC" = "" -o ! -d "$SRC" \ X -o "$DEST" = "" -o ! -d "$DEST" ] Xthen X echo "Either \"$SRC\" or \"$DEST\" is not a directory!" \ X "$USAGE" X exit 1 Xfi X Xfor file in `ls $SRC` Xdo X echo -n "${NL}$file " X sed -e "/$Remove_start/,/$Remove_end/d" \ X -e "/$Delete/d" \ X < $SRC/$file > $DEST/$file Xdone Xchmod 0755 $DEST/remote_mkdata Xecho SHAREOF chmod 755 remote/shells/rfs_kerninstall # # remote/shells/rfs_kernpatch # if [ -f remote/shells/rfs_kernpatch ]; then echo -n 'Hit <return> to overwrite remote/shells/rfs_kernpatch or ^C to quit' read ans rm -f remote/shells/rfs_kernpatch fi sed -e 's/^.//' << \SHAREOF > remote/shells/rfs_kernpatch X#!/bin/sh X# X# Kernel level setup for compiling RFS. X# XCHANGELIST=' h/errno.h X h/param.h X h/user.h X sys/init_sysent.c X sys/kern_exec.c X sys/kern_exit.c X sys/ufs_syscalls.c' XCHANGE_42=' sys/sys_inode.c X sys/ufs_nami.c X sys/uipc_socket.c X machine/trap.c X conf/files' XCHANGE_43=' sys/ufs_namei.c X machine/trap.c X conf/files' XCHANGE_PYR=' sys/kern_trap.c' X PATCHES=$1 X SRC=$2 X DEST=$3 X VER=$4 X USAGE="Usage: $0 patch-dir src-dir dest-dir VAX4.3|VAX4.2|PYR2.5" X NL=' X' X Xif [ ! -d "$PATCHES" -o ! -d "$SRC" -o ! -d "$DEST" ] Xthen X echo "One of \"$PATCHES\", \"$SRC\" or \"$DEST\" is not a directory" \ X "$NL$USAGE" X exit 1 Xfi X Xcase "$VER" in XVAX4.3) CHANGELIST="$CHANGELIST $CHANGE_43" X if [ -f $SRC/conf/Makefile.vax ] X then X CHANGELIST="$CHANGELIST conf/Makefile.vax" X else X CHANGELIST="$CHANGELIST conf/makefile.vax" X fi X ;; XVAX4.2) CHANGELIST="$CHANGELIST $CHANGE_42 conf/makefile.vax" ;; XPYR2.5) CHANGELIST="$CHANGELIST $CHANGE_PYR conf/makefromsource" ;; X*) echo "Invalid version = \"$VER\"$NL$USAGE" X exit 1 X ;; Xesac X X# X# copy the target files for the patches. X# Xcase "$DEST" in X X$SRC) ;; # no need to copy X X*) echo "Copy in files that must be changed..." X (cd $DEST; rm -f $CHANGELIST) X for file in $CHANGELIST X do X (set -x; cp $SRC/$file $DEST/$file) X done X ;; Xesac X(cd $DEST; chmod 0644 $CHANGELIST) X X# X# do the patches X# Xfor file in $CHANGELIST Xdo X while : X do X echo -n "${NL}${NL}Hit <return> to patch" \ X "$file or 'n' to skip: " X read prompt X case "$prompt" in X "") (set -x; patch $DEST/$file $PATCHES/$file.diff) X ;; X n) ;; X *) echo "Enter <return> or the letter 'n' only!" X continue X ;; X esac X break X done Xdone SHAREOF chmod 755 remote/shells/rfs_kernpatch # # remote/shells/rfs_setup # if [ -f remote/shells/rfs_setup ]; then echo -n 'Hit <return> to overwrite remote/shells/rfs_setup or ^C to quit' read ans rm -f remote/shells/rfs_setup fi sed -e 's/^.//' << \SHAREOF > remote/shells/rfs_setup X#!/bin/sh X# X# Setup for compiling RFS. X# XPWD=`pwd` XKERNELDIRS=' conf X h X net X netimp X netinet X remote X sys' XKDIRS_42=' vax X vaxif X vaxmba X vaxuba X netpup' XKDIRS_43=' vax X vaxif X vaxmba X vaxuba X bbnnet X netns' XKDIRS_PYR=' ether X io X kernel X kernel_m X ml X netpup X vls' XINCLUDEFILE=syscall.h X NL=' X' XEXECDIR=`expr $0 : '\(.*\)\/.*'` X X# X# Figure out what software they are running... X# Xwhile : Xdo X echo -n "Are you running" \ X "${NL} 1. VAX 4.3 BSD" \ X "${NL} 2. VAX 4.2 BSD" \ X "${NL} 3. Pyramid 2.5 (4.2/5.0)" \ X "${NL}enter 1, 2 or 3: " X read ans X case "$ans" in X 1) VER=VAX4.3 X MACH=vax X KERNELDIRS="$KERNELDIRS $KDIRS_43" X ;; X 2) VER=VAX4.2 X MACH=vax X KERNELDIRS="$KERNELDIRS $KDIRS_42" X ;; X 3) VER=PYR2.5 X MACH=pyr X KERNELDIRS="$KERNELDIRS $KDIRS_PYR" X ;; X *) echo "only 1, 2 and 3 are supported..." X continue X ;; X esac X break; Xdone X X# X# Find out the sys directory X# XSYSDIR= Xwhile : Xdo X echo -n "${NL}${NL}What is the top-level path of your kernel source" \ X "${NL}directory (normally it is /usr/sys)? " X read ans X if [ "$ans" = "" -o ! -d "$ans" ] X then X echo "...but \"$ans\" is not a directory!" X continue X fi X X # X # Ensure that the path begins with / X # X case "$ans" in X /*) ;; X *) echo "\"$ans\" must begin with '/'" X continue X ;; X esac X X SYSDIR=$ans X break Xdone X X# X# ask if the changes are to be permanent X# Xwhile : Xdo X echo -n "${NL}${NL}Do you want these changes" \ X "$NL 1. installed in $SYSDIR and in /usr/include" \ X "$NL 2. installed in this directory (reccomended 1st pass)" \ X "${NL}enter 1 or 2: " X read ans X case "$ans" in X 1) DEST=$SYSDIR X INCLUDEDIR=/usr/include X ;; X 2) DEST=$PWD/sys X INCLUDEDIR=usr.include X ;; X *) echo "only 1 or 2 allowed." X continue X ;; X esac X break Xdone X X Xumask 022 Xcase "$DEST" in X X"$SYSDIR") # don't need to make local directories, 'cept one. X mkdir $SYSDIR/remote X ;; X X*) # X # make directories X # X echo "${NL}${NL}Make kernel source directories in `pwd` ..." X ERR= X mkdir sys X for dir in $KERNELDIRS X do X mkdir sys/$dir X X case "$dir" in X remote) continue;; # don't check its existence... X esac X X if [ ! -d $SYSDIR/$dir ] X then X echo "Kernel sources not in $SYSDIR/$dir ???" X ERR=true X fi X done X case "$ERR" in X "") ;; X *) exit 1;; X esac X X case "$VER" in X VAX4.2|VAX4.3) (cd sys; ln -s vax machine);; X esac X X # X # make the symbolic links X # X for dir in $KERNELDIRS X do X case "$dir" in X remote) continue;; X esac X X echo "Make symbolic links from $DEST/$dir/*" \ X "${NL}to $SYSDIR/$dir/*..." X (cd $DEST/$dir; ln -s $SYSDIR/$dir/* .) X done X ;; Xesac X X# X# move the remote kernel stuff into place... X# Xecho "${NL}${NL}Copy $PWD/remote/usr.sys.remote/* files" \ X "${NL}to $DEST/remote (and remove" \ X "${NL}#ifdef BSD4_3 at the same time)..." X$EXECDIR/rfs_kerninstall $PWD/remote/usr.sys.remote $DEST/remote $VER X X# X# Now run patch on each files to install X# the changes necessary. X# Xcat <<EOF X X XI will now install all the kernel changes for you in X$DEST with the 'patch' utility, so you must have that Xprogram to continue. You will be given an opportunity to either suspend Xthis program or kill it before each file is patched so that you may Xmake adjustments as you think of them. You may also skip the patches Xif you know that they are already installed (Better be sure, though). X XFor the C-source files with the exception of two bug fixes, all changes Xwill be installed between the control statements: X X#ifdef REMOTEFS X#endif REMOTEFS X XEOF X X$EXECDIR/rfs_kernpatch remote/usr.sys.$VER $SYSDIR $DEST $VER X$EXECDIR/rfs_userpatch remote/usr.include.$VER $INCLUDEDIR $DEST X Xcat <<EOF X X XRfs software is set up and ready for compilation. See the installation Xmanual. X XEOF SHAREOF chmod 755 remote/shells/rfs_setup # # remote/shells/rfs_userpatch # if [ -f remote/shells/rfs_userpatch ]; then echo -n 'Hit <return> to overwrite remote/shells/rfs_userpatch or ^C to quit' read ans rm -f remote/shells/rfs_userpatch fi sed -e 's/^.//' << \SHAREOF > remote/shells/rfs_userpatch X#!/bin/sh X# X# User-level software setup for compiling RFS. X# Xumask 02 X PATCHES=$1 XINCLUDEDIR=$2 X SYS=$3 X NL=' X' X Xecho "$NL" X Xif [ ! -d $PATCHES -o ! -d $SYS ] Xthen X echo "Either \"$PATCHES\" or \"$SYS\" is not a directory" X exit 1 Xfi X X# X# Make the proper include directories if they don't already exist. X# link in remotefs.h and param.h X# Xif [ ! -d $INCLUDEDIR ] Xthen X mkdir $INCLUDEDIR Xfi Xif [ ! -d $INCLUDEDIR/remote ] Xthen X mkdir $INCLUDEDIR/remote Xfi Xif [ ! -d $INCLUDEDIR/sys ] Xthen X mkdir $INCLUDEDIR/sys Xfi X Xrm -f $INCLUDEDIR/remote/remotefs.h $INCLUDEDIR/sys/param.h X Xln -s $SYS/remote/remotefs.h $INCLUDEDIR/remote/remotefs.h Xln -s $SYS/h/param.h $INCLUDEDIR/sys/param.h X X# X# Finally make the change to syscall.h. If the changes go in usr.include, X# then assume that we must copy it there first. Otherwise, we make the X# changes in place. X# Xcase "$INCLUDEDIR" in X X/usr/include) ;; X X*) rm -f $INCLUDEDIR/syscall.h X cat /usr/include/syscall.h > $INCLUDEDIR/syscall.h X ;; Xesac X Xwhile : Xdo X echo -n "${NL}${NL}Hit <return> to patch" \ X "$INCLUDEDIR/syscall.h or 'n' to skip: " X read prompt X case "$prompt" in X "") (set -x; patch $INCLUDEDIR/syscall.h $PATCHES/syscall.h.diff) X ;; X n) ;; X *) echo "Enter <return> or the letter 'n' only!" X continue X ;; X esac X break Xdone SHAREOF chmod 755 remote/shells/rfs_userpatch # # remote/usr.include.PYR2.5 # mkdir remote/usr.include.PYR2.5 chmod 775 remote/usr.include.PYR2.5 # # remote/usr.include.PYR2.5/syscall.h.diff # if [ -f remote/usr.include.PYR2.5/syscall.h.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.include.PYR2.5/syscall.h.diff or ^C to quit' read ans rm -f remote/usr.include.PYR2.5/syscall.h.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.include.PYR2.5/syscall.h.diff XIf the changes to sys/init_sysent.c succeeded, then this should be fine. XIf not, you should check that the system call numbers added coincide with Xthose in sys/init_sysent.c. X*************** X*** 154,159 X /* 152 thru 165 reserved */ X #define SYS_setprocesshost 166 X #define SYS_getprocesshost 167 X X /* X * BTL system call header table. X X--- 154,162 ----- X /* 152 thru 165 reserved */ X #define SYS_setprocesshost 166 X #define SYS_getprocesshost 167 X+ #define SYS_remoteon 168 X+ #define SYS_remoteoff 169 X+ #define SYS_remotename 170 X X /* X * BTL system call header table. SHAREOF chmod 664 remote/usr.include.PYR2.5/syscall.h.diff # # remote/usr.include.VAX4.2 # mkdir remote/usr.include.VAX4.2 chmod 775 remote/usr.include.VAX4.2 if [ -f remote/usr.include.VAX4.3 ]; then echo -n 'Hit <return> to overwrite remote/usr.include.VAX4.2 or ^C to quit' read ans rm -rf remote/usr.include.VAX4.3 fi ln -s remote/usr.include.VAX4.2 remote/usr.include.VAX4.3 # # remote/usr.include.VAX4.2/syscall.h.diff # if [ -f remote/usr.include.VAX4.2/syscall.h.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.include.VAX4.2/syscall.h.diff or ^C to quit' read ans rm -f remote/usr.include.VAX4.2/syscall.h.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.include.VAX4.2/syscall.h.diff XIf the changes to sys/init_sysent.c succeeded, then this should be fine. XIf not, you should check that the system call numbers added coincide with Xthose in sys/init_sysent.c. X*************** X*** 150,152 X #define SYS_setquota 148 X #define SYS_quota 149 X #define SYS_getsockname 150 X X--- 150,155 ----- X #define SYS_setquota 148 X #define SYS_quota 149 X #define SYS_getsockname 150 X+ #define SYS_remoteon 151 X+ #define SYS_remoteoff 152 X+ #define SYS_remotename 153 SHAREOF chmod 664 remote/usr.include.VAX4.2/syscall.h.diff # # remote/usr.src.lib.libc # mkdir remote/usr.src.lib.libc chmod 775 remote/usr.src.lib.libc # # remote/usr.src.lib.libc/Makefile # if [ -f remote/usr.src.lib.libc/Makefile ]; then echo -n 'Hit <return> to overwrite remote/usr.src.lib.libc/Makefile or ^C to quit' read ans rm -f remote/usr.src.lib.libc/Makefile fi sed -e 's/^.//' << \SHAREOF > remote/usr.src.lib.libc/Makefile X# X# This makefile is present only to build a temporary libc... until X# you decide that the files compiled here should be installed in the X# source directory. This makefile should not be installed anywhere. X# XOBJS= remotename.o remoteon.o remoteoff.o errlst.o XSRC=/usr/src XLIBSRC=${SRC}/lib/libc XUSR_INCLUDE=../../usr.include XLIBDIR=/lib X Xnothing: X echo "Nothing made!" X echo "You must type 'make vax' or 'make pyr'" X Xvax: /tmp X make INCLUDE="-I${LIBSRC}/vax/sys -I${USR_INCLUDE}" \ X MACHTYPE=vax \ X SUFFIX=c \ X LIBDIR=${LIBDIR} \ X SRC=${SRC} \ X install X Xpyr: /tmp X make INCLUDE="-I${USR_INCLUDE}" \ X MACHTYPE=pyr \ X SUFFIX=s \ X LIBDIR=${LIBDIR} \ X SRC=${SRC} \ X install X Xnewlibc.a: ${OBJS} libc.a X cp libc.a newlibc.a X ar cru newlibc.a ${OBJS} X Xinstall: newlibc.a libc.a X -cp ${LIBDIR}/libc.a ${LIBDIR}/libc.a.bak X cp newlibc.a ${LIBDIR}/libc.a X ranlib ${LIBDIR}/libc.a X Xlibc.a: /lib/libc.a X cp /lib/libc.a . X Xerrlst.o: errlst.c Xremotename.o remoteon.o remoteoff.o: Xremotename.o: ${MACHTYPE}/sys/remotename.${SUFFIX} X /lib/cpp ${INCLUDE} -E $? | ${AS} -o $@ X -ld -x -r $@ X mv a.out $@ Xremoteon.o: ${MACHTYPE}/sys/remoteon.${SUFFIX} X /lib/cpp ${INCLUDE} -E $? | ${AS} -o $@ X -ld -x -r $@ X mv a.out $@ Xremoteoff.o: ${MACHTYPE}/sys/remoteoff.${SUFFIX} X /lib/cpp ${INCLUDE} -E $? | ${AS} -o $@ X -ld -x -r $@ X mv a.out $@ X Xerrlst.c: ${LIBSRC}/gen/errlst.c X cp ${LIBSRC}/gen/errlst.c nerrlst.c X patch nerrlst.c gen/${MACHTYPE}.errlst.c.diff X mv nerrlst.c errlst.c SHAREOF chmod 664 remote/usr.src.lib.libc/Makefile # # remote/usr.src.lib.libc/gen # mkdir remote/usr.src.lib.libc/gen chmod 775 remote/usr.src.lib.libc/gen # # remote/usr.src.lib.libc/gen/pyr.errlst.c.diff # if [ -f remote/usr.src.lib.libc/gen/pyr.errlst.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.src.lib.libc/gen/pyr.errlst.c.diff or ^C to quit' read ans rm -f remote/usr.src.lib.libc/gen/pyr.errlst.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.src.lib.libc/gen/pyr.errlst.c.diff XThese changes being installed should be just fine if you were able to make Xthe earlier changes to h/errno.h. Otherwise, you must install these changes Xby hand. X*************** X*** 82,88 X "Too many processes", /* 67 - EPROCLIM */ X "Too many users", /* 68 - EUSERS */ X "Disc quota exceeded", /* 69 - EDQUOT */ X! "","","","","","","","","","", /* 70-79 - spare */ X "","","","","","","","","","", /* 80-89 - spare */ X "","","","","","","","","","", /* 90-99 - spare */ X X X--- 82,91 ----- X "Too many processes", /* 67 - EPROCLIM */ X "Too many users", /* 68 - EUSERS */ X "Disc quota exceeded", /* 69 - EDQUOT */ X! "File is on remote host", /* 70 - EISREMOTE */ X! "Too many remote hosts defined", /* 71 - ETOOMANYREMOTE */ X! "No remote file system", /* 72 - ENOREMOTEFS */ X! "","","","","","","", /* 73-79 - spare */ X "","","","","","","","","","", /* 80-89 - spare */ X "","","","","","","","","","", /* 90-99 - spare */ X SHAREOF chmod 664 remote/usr.src.lib.libc/gen/pyr.errlst.c.diff # # remote/usr.src.lib.libc/gen/vax.errlst.c.diff # if [ -f remote/usr.src.lib.libc/gen/vax.errlst.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.src.lib.libc/gen/vax.errlst.c.diff or ^C to quit' read ans rm -f remote/usr.src.lib.libc/gen/vax.errlst.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.src.lib.libc/gen/vax.errlst.c.diff XThese changes being installed should be just fine if you were able to make Xthe earlier changes to h/errno.h. Otherwise, you must install these changes Xby hand. X*************** X*** 81,85 X "Too many processes", /* 67 - EPROCLIM */ X "Too many users", /* 68 - EUSERS */ X "Disc quota exceeded", /* 69 - EDQUOT */ X }; X int sys_nerr = { sizeof sys_errlist/sizeof sys_errlist[0] }; X X--- 81,88 ----- X "Too many processes", /* 67 - EPROCLIM */ X "Too many users", /* 68 - EUSERS */ X "Disc quota exceeded", /* 69 - EDQUOT */ X+ "File is on remote host", /* 70 - EISREMOTE */ X+ "Too many remote hosts defined", /* 71 - ETOOMANYREMOTE */ X+ "No remote file system", /* 72 - ENOREMOTEFS */ X }; X int sys_nerr = { sizeof sys_errlist/sizeof sys_errlist[0] }; SHAREOF chmod 664 remote/usr.src.lib.libc/gen/vax.errlst.c.diff # # remote/usr.src.lib.libc/pyr # mkdir remote/usr.src.lib.libc/pyr chmod 775 remote/usr.src.lib.libc/pyr # # remote/usr.src.lib.libc/pyr/sys # mkdir remote/usr.src.lib.libc/pyr/sys chmod 775 remote/usr.src.lib.libc/pyr/sys # # remote/usr.src.lib.libc/pyr/sys/remotename.s # if [ -f remote/usr.src.lib.libc/pyr/sys/remotename.s ]; then echo -n 'Hit <return> to overwrite remote/usr.src.lib.libc/pyr/sys/remotename.s or ^C to quit' read ans rm -f remote/usr.src.lib.libc/pyr/sys/remotename.s fi sed -e 's/^.//' << \SHAREOF > remote/usr.src.lib.libc/pyr/sys/remotename.s X#include "syscall.h" X .globl cerror X .globl _remotename X .align 2 X_remotename: X ###entry### X movw pr0,tr1 X movw pr1,tr2 X movw pr2,tr3 X movw pr3,tr4 X movw pr4,tr5 X movw $/**/SYS_remotename, tr0 X callk $0 X cmpw $0,tr0 X bne err X movw tr1,pr0 X ret Xerr: X jump cerror SHAREOF chmod 644 remote/usr.src.lib.libc/pyr/sys/remotename.s # # remote/usr.src.lib.libc/pyr/sys/remoteoff.s # if [ -f remote/usr.src.lib.libc/pyr/sys/remoteoff.s ]; then echo -n 'Hit <return> to overwrite remote/usr.src.lib.libc/pyr/sys/remoteoff.s or ^C to quit' read ans rm -f remote/usr.src.lib.libc/pyr/sys/remoteoff.s fi sed -e 's/^.//' << \SHAREOF > remote/usr.src.lib.libc/pyr/sys/remoteoff.s X#include "syscall.h" X .globl cerror X .globl _remoteoff X .align 2 X_remoteoff: X ###entry### X movw pr0,tr1 X movw $/**/SYS_remoteoff, tr0 X callk $0 X cmpw $0,tr0 X bne err X movw tr1,pr0 X ret Xerr: X jump cerror SHAREOF chmod 644 remote/usr.src.lib.libc/pyr/sys/remoteoff.s # # remote/usr.src.lib.libc/pyr/sys/remoteon.s # if [ -f remote/usr.src.lib.libc/pyr/sys/remoteon.s ]; then echo -n 'Hit <return> to overwrite remote/usr.src.lib.libc/pyr/sys/remoteon.s or ^C to quit' read ans rm -f remote/usr.src.lib.libc/pyr/sys/remoteon.s fi sed -e 's/^.//' << \SHAREOF > remote/usr.src.lib.libc/pyr/sys/remoteon.s X#include "syscall.h" X .globl cerror X .globl _remoteon X .align 2 X_remoteon: X ###entry### X movw pr0,tr1 X movw pr1,tr2 X movw pr2,tr3 X movw pr3,tr4 X movw $/**/SYS_remoteon, tr0 X callk $0 X cmpw $0,tr0 X bne err X movw tr1,pr0 X ret Xerr: X jump cerror SHAREOF chmod 644 remote/usr.src.lib.libc/pyr/sys/remoteon.s # # remote/usr.src.lib.libc/vax # mkdir remote/usr.src.lib.libc/vax chmod 775 remote/usr.src.lib.libc/vax # # remote/usr.src.lib.libc/vax/sys # mkdir remote/usr.src.lib.libc/vax/sys chmod 775 remote/usr.src.lib.libc/vax/sys # # remote/usr.src.lib.libc/vax/sys/remotename.c # if [ -f remote/usr.src.lib.libc/vax/sys/remotename.c ]; then echo -n 'Hit <return> to overwrite remote/usr.src.lib.libc/vax/sys/remotename.c or ^C to quit' read ans rm -f remote/usr.src.lib.libc/vax/sys/remotename.c fi sed -e 's/^.//' << \SHAREOF > remote/usr.src.lib.libc/vax/sys/remotename.c X/* remotename.c 4.2 85/10/25 */ X X#include "SYS.h" X XSYSCALL(remotename) X ret SHAREOF chmod 644 remote/usr.src.lib.libc/vax/sys/remotename.c # # remote/usr.src.lib.libc/vax/sys/remoteoff.c # if [ -f remote/usr.src.lib.libc/vax/sys/remoteoff.c ]; then echo -n 'Hit <return> to overwrite remote/usr.src.lib.libc/vax/sys/remoteoff.c or ^C to quit' read ans rm -f remote/usr.src.lib.libc/vax/sys/remoteoff.c fi sed -e 's/^.//' << \SHAREOF > remote/usr.src.lib.libc/vax/sys/remoteoff.c X/* remoteoff.c 4.2 85/10/25 */ X X#include "SYS.h" X XSYSCALL(remoteoff) X ret SHAREOF chmod 644 remote/usr.src.lib.libc/vax/sys/remoteoff.c # # remote/usr.src.lib.libc/vax/sys/remoteon.c # if [ -f remote/usr.src.lib.libc/vax/sys/remoteon.c ]; then echo -n 'Hit <return> to overwrite remote/usr.src.lib.libc/vax/sys/remoteon.c or ^C to quit' read ans rm -f remote/usr.src.lib.libc/vax/sys/remoteon.c fi sed -e 's/^.//' << \SHAREOF > remote/usr.src.lib.libc/vax/sys/remoteon.c X/* remoteon.c 4.2 85/10/25 */ X X#include "SYS.h" X XSYSCALL(remoteon) X ret SHAREOF chmod 644 remote/usr.src.lib.libc/vax/sys/remoteon.c # # remote/usr.sys.PYR2.5 # mkdir remote/usr.sys.PYR2.5 chmod 775 remote/usr.sys.PYR2.5 # # remote/usr.sys.PYR2.5/conf # mkdir remote/usr.sys.PYR2.5/conf chmod 775 remote/usr.sys.PYR2.5/conf # # remote/usr.sys.PYR2.5/conf/makefromsource.diff # if [ -f remote/usr.sys.PYR2.5/conf/makefromsource.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/conf/makefromsource.diff or ^C to quit' read ans rm -f remote/usr.sys.PYR2.5/conf/makefromsource.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.PYR2.5/conf/makefromsource.diff X*** /usr/toddb/crl/pyr/conf/makefromsource Wed Sep 18 00:25:15 1985 X--- makefromsource Thu Jan 2 15:18:44 1986 X*************** X*** 31,37 X # Compile options that are passed to all other source files: X # do not change (other than adding new options) X # X! OPTIONS = -DKERNEL -DINET -DRcsIdent -DNITP=8 -DXT -DWATCH X X CFLAGS = ${PROFILE} -O $(OPTIONS) ${DUALCPU} X ENTRY = _initcpus X X--- 31,37 ----- X # Compile options that are passed to all other source files: X # do not change (other than adding new options) X # X! OPTIONS = -DKERNEL -DINET -DRcsIdent -DNITP=8 -DXT -DWATCH -DREMOTEFS X X CFLAGS = ${PROFILE} -O $(OPTIONS) ${DUALCPU} X ENTRY = _initcpus X*************** X*** 87,92 X -mv param.c oldparam.c X cp ../conf/param.c . X X FRC: X # MAKEFROMBINARY ENDS HERE -- Do not delete this line. X X X--- 87,99 ----- X -mv param.c oldparam.c X cp ../conf/param.c . X X+ ../remote/rmt_data.c: ../remote/rmt_data_template ../remote/remotefs.h \ X+ ../sys/init_sysent.c X+ cat ../remote/rmt_data_template > ../remote/nrmt_data.c X+ /lib/cpp ${CFLAGS} ../sys/init_sysent.c | sh ../remote/remote_mkdata \ X+ ../remote/remotefs.h >> ../remote/nrmt_data.c X+ mv ../remote/nrmt_data.c ../remote/rmt_data.c X+ X FRC: X # MAKEFROMBINARY ENDS HERE -- Do not delete this line. X X*************** X*** 101,107 X netimp debug X X LIBS = sys${LIB} io${LIB} net${LIB} ether${LIB} drw${LIB} \ X! imp${LIB} dbg${LIB} X X # The following lines are automatically generated; do not modify them manually. X # LISTS BEGIN HERE -- Do not delete this line: make lists uses it X X--- 108,114 ----- X netimp debug X X LIBS = sys${LIB} io${LIB} net${LIB} ether${LIB} drw${LIB} \ X! imp${LIB} dbg${LIB} remote${LIB} X X # The following lines are automatically generated; do not modify them manually. X # LISTS BEGIN HERE -- Do not delete this line: make lists uses it X*************** X*** 205,210 X debugOBJS= \ X debug1.o debug2.o debug3.o dis.o X X CFILES= \ X ${sysSRCS} ${ioSRCS} ${netSRCS} ${netinetSRCS} ${etherSRCS} \ X ${dr11wSRCS} ${netimpSRCS} ${debugSRCS} X X--- 212,227 ----- X debugOBJS= \ X debug1.o debug2.o debug3.o dis.o X X+ remoteSRCS= \ X+ ../remote/rmt_data.c ../remote/rmt_exec.c ../remote/rmt_final.c \ X+ ../remote/rmt_general.c ../remote/rmt_generic.c ../remote/rmt_io.c \ X+ ../remote/rmt_subr.c ../remote/rmt_syscall1.c ../remote/rmt_syscall2.c \ X+ ../remote/rmt_syscall3.c X+ X+ remoteOBJS= \ X+ rmt_data.o rmt_exec.o rmt_final.o rmt_general.o rmt_generic.o \ X+ rmt_io.o rmt_subr.o rmt_syscall1.o rmt_syscall2.o rmt_syscall3.o X+ X CFILES= \ X ${sysSRCS} ${ioSRCS} ${netSRCS} ${netinetSRCS} ${etherSRCS} \ X ${dr11wSRCS} ${netimpSRCS} ${debugSRCS} ${remoteSRCS} X*************** X*** 207,213 X X CFILES= \ X ${sysSRCS} ${ioSRCS} ${netSRCS} ${netinetSRCS} ${etherSRCS} \ X! ${dr11wSRCS} ${netimpSRCS} ${debugSRCS} X X MLFILES= \ X ../ml/asm.s ../ml/ml.s X X--- 224,230 ----- X X CFILES= \ X ${sysSRCS} ${ioSRCS} ${netSRCS} ${netinetSRCS} ${etherSRCS} \ X! ${dr11wSRCS} ${netimpSRCS} ${debugSRCS} ${remoteSRCS} X X MLFILES= \ X ../ml/asm.s ../ml/ml.s X*************** X*** 244,250 X ../netinet/ip_var.h ../netinet/tcp.h ../netinet/tcp_debug.h \ X ../netinet/tcp_fsm.h ../netinet/tcp_seq.h ../netinet/tcp_timer.h \ X ../netinet/tcp_var.h ../netinet/tcpip.h ../netinet/udp.h \ X! ../netinet/udp_var.h X # LISTS END HERE -- Do not delete this line: make lists uses it X X # Special treatment for these files (symbolic links) which are used to X X--- 261,267 ----- X ../netinet/ip_var.h ../netinet/tcp.h ../netinet/tcp_debug.h \ X ../netinet/tcp_fsm.h ../netinet/tcp_seq.h ../netinet/tcp_timer.h \ X ../netinet/tcp_var.h ../netinet/tcpip.h ../netinet/udp.h \ X! ../netinet/udp_var.h ../remote/remotefs.h X # LISTS END HERE -- Do not delete this line: make lists uses it X X # Special treatment for these files (symbolic links) which are used to X*************** X*** 308,313 X dbg${LIB}: $(debugOBJS) X ar cr $@ $? && ranlib $@ X X X ml.o: ${MLFILES} X rm -f mltemp.[cs] X X--- 325,332 ----- X dbg${LIB}: $(debugOBJS) X ar cr $@ $? && ranlib $@ X X+ remote${LIB}: $(remoteOBJS) X+ ar cr $@ $? && ranlib $@ X X ml.o: ${MLFILES} X rm -f mltemp.[cs] X*************** X*** 763,768 X ${LD} -x -r $@ && mv a.out $@ X dis.o: ../debug/dis.c X ${CC} -I. -c ${CFLAGS} ../debug/dis.c X ${LD} -x -r $@ && mv a.out $@ X # RULES END HERE -- Do not delete this line: make rules uses it X X X--- 782,817 ----- X ${LD} -x -r $@ && mv a.out $@ X dis.o: ../debug/dis.c X ${CC} -I. -c ${CFLAGS} ../debug/dis.c X+ ${LD} -x -r $@ && mv a.out $@ X+ rmt_data.o: ../remote/rmt_data.c X+ ${CC} -I. -c -DRFSDEBUG ${CFLAGS} ../remote/rmt_data.c X+ ${LD} -x -r $@ && mv a.out $@ X+ rmt_exec.o: ../remote/rmt_exec.c X+ ${CC} -I. -c -DRFSDEBUG ${CFLAGS} ../remote/rmt_exec.c X+ ${LD} -x -r $@ && mv a.out $@ X+ rmt_final.o: ../remote/rmt_final.c X+ ${CC} -I. -c -DRFSDEBUG ${CFLAGS} ../remote/rmt_final.c X+ ${LD} -x -r $@ && mv a.out $@ X+ rmt_general.o: ../remote/rmt_general.c X+ ${CC} -I. -c -DRFSDEBUG ${CFLAGS} ../remote/rmt_general.c X+ ${LD} -x -r $@ && mv a.out $@ X+ rmt_generic.o: ../remote/rmt_generic.c X+ ${CC} -I. -c -DRFSDEBUG ${CFLAGS} ../remote/rmt_generic.c X+ ${LD} -x -r $@ && mv a.out $@ X+ rmt_io.o: ../remote/rmt_io.c X+ ${CC} -I. -c -DRFSDEBUG ${CFLAGS} ../remote/rmt_io.c X+ ${LD} -x -r $@ && mv a.out $@ X+ rmt_subr.o: ../remote/rmt_subr.c X+ ${CC} -I. -c -DRFSDEBUG ${CFLAGS} ../remote/rmt_subr.c X+ ${LD} -x -r $@ && mv a.out $@ X+ rmt_syscall1.o: ../remote/rmt_syscall1.c X+ ${CC} -I. -c -DRFSDEBUG ${CFLAGS} ../remote/rmt_syscall1.c X+ ${LD} -x -r $@ && mv a.out $@ X+ rmt_syscall2.o: ../remote/rmt_syscall2.c X+ ${CC} -I. -c -DRFSDEBUG ${CFLAGS} ../remote/rmt_syscall2.c X+ ${LD} -x -r $@ && mv a.out $@ X+ rmt_syscall3.o: ../remote/rmt_syscall3.c X+ ${CC} -I. -c -DRFSDEBUG ${CFLAGS} ../remote/rmt_syscall3.c X ${LD} -x -r $@ && mv a.out $@ X # RULES END HERE -- Do not delete this line: make rules uses it X SHAREOF chmod 664 remote/usr.sys.PYR2.5/conf/makefromsource.diff # # remote/usr.sys.PYR2.5/h # mkdir remote/usr.sys.PYR2.5/h chmod 775 remote/usr.sys.PYR2.5/h
sources-request@panda.UUCP (01/09/86)
Mod.sources: Volume 3, Issue 81 Submitted by: tektronix!tekcrl!toddb #!/bin/sh # # RFS, a kernel-resident remote file system. Shar 5 of 7 # # # This is a shell archive, meaning: # 1. Remove everything above the #!/bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # remote/usr.sys.PYR2.5/h/errno.h.diff # remote/usr.sys.VAX4.2/h/param.h.diff # remote/usr.sys.VAX4.3/h/param.h.diff # remote/usr.sys.PYR2.5/h/param.h.diff # remote/usr.sys.PYR2.5/h/user.h.diff # remote/usr.sys.PYR2.5/sys # remote/usr.sys.PYR2.5/sys/init_sysent.c.diff # remote/usr.sys.PYR2.5/sys/kern_exec.c.diff # remote/usr.sys.PYR2.5/sys/kern_exit.c.diff # remote/usr.sys.PYR2.5/sys/kern_trap.c.diff # remote/usr.sys.PYR2.5/sys/sys_inode.c.diff # remote/usr.sys.PYR2.5/sys/ufs_nami.c.diff # remote/usr.sys.PYR2.5/sys/ufs_syscalls.c.diff # remote/usr.sys.PYR2.5/sys/uipc_socket.c.diff # remote/usr.sys.VAX4.2 # remote/usr.sys.VAX4.2/conf # remote/usr.sys.VAX4.3/conf/files.diff # remote/usr.sys.VAX4.2/conf/files.diff # remote/usr.sys.VAX4.2/conf/makefile.vax.diff # remote/usr.sys.VAX4.2/h # remote/usr.sys.VAX4.3/h/errno.h.diff # remote/usr.sys.VAX4.2/h/errno.h.diff # remote/usr.sys.VAX4.2/h/user.h.diff # remote/usr.sys.VAX4.2/machine # remote/usr.sys.VAX4.2/machine/trap.c.diff # remote/usr.sys.VAX4.2/sys # remote/usr.sys.VAX4.2/sys/init_sysent.c.diff # remote/usr.sys.VAX4.2/sys/kern_exec.c.diff # remote/usr.sys.VAX4.2/sys/kern_exit.c.diff # remote/usr.sys.VAX4.2/sys/sys_inode.c.diff # remote/usr.sys.VAX4.2/sys/ufs_nami.c.diff # remote/usr.sys.VAX4.2/sys/ufs_syscalls.c.diff # remote/usr.sys.VAX4.2/sys/uipc_socket.c.diff # remote/usr.sys.VAX4.3 # remote/usr.sys.VAX4.3/conf # remote/usr.sys.VAX4.3/conf/Makefile.vax.diff # remote/usr.sys.VAX4.3/conf/makefile.vax.diff # remote/usr.sys.VAX4.3/h # remote/usr.sys.VAX4.3/h/user.h.diff # remote/usr.sys.VAX4.3/machine # remote/usr.sys.VAX4.3/machine/trap.c.diff # remote/usr.sys.VAX4.3/sys # remote/usr.sys.VAX4.3/sys/init_sysent.c.diff # # remote/usr.sys.PYR2.5/sys # mkdir remote/usr.sys.PYR2.5/sys chmod 775 remote/usr.sys.PYR2.5/sys # # remote/usr.sys.VAX4.2 # mkdir remote/usr.sys.VAX4.2 chmod 775 remote/usr.sys.VAX4.2 # # remote/usr.sys.VAX4.2/conf # mkdir remote/usr.sys.VAX4.2/conf chmod 775 remote/usr.sys.VAX4.2/conf # # remote/usr.sys.VAX4.2/h # mkdir remote/usr.sys.VAX4.2/h chmod 775 remote/usr.sys.VAX4.2/h # # remote/usr.sys.VAX4.2/machine # mkdir remote/usr.sys.VAX4.2/machine chmod 775 remote/usr.sys.VAX4.2/machine # # remote/usr.sys.VAX4.2/sys # mkdir remote/usr.sys.VAX4.2/sys chmod 775 remote/usr.sys.VAX4.2/sys # # remote/usr.sys.VAX4.3 # mkdir remote/usr.sys.VAX4.3 chmod 775 remote/usr.sys.VAX4.3 # # remote/usr.sys.VAX4.3/conf # mkdir remote/usr.sys.VAX4.3/conf chmod 775 remote/usr.sys.VAX4.3/conf # # remote/usr.sys.VAX4.3/h # mkdir remote/usr.sys.VAX4.3/h chmod 775 remote/usr.sys.VAX4.3/h # # remote/usr.sys.VAX4.3/machine # mkdir remote/usr.sys.VAX4.3/machine chmod 775 remote/usr.sys.VAX4.3/machine # # remote/usr.sys.VAX4.3/sys # mkdir remote/usr.sys.VAX4.3/sys chmod 775 remote/usr.sys.VAX4.3/sys # # remote/usr.sys.PYR2.5/h/errno.h.diff # if [ -f remote/usr.sys.PYR2.5/h/errno.h.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/h/errno.h.diff or ^C to quit' read ans rm -f remote/usr.sys.PYR2.5/h/errno.h.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.PYR2.5/h/errno.h.diff XThese changes add three new error numbers for the sake of RFS. X*************** X*** 90,95 X #define EUSERS 68 /* Too many users */ X #define EDQUOT 69 /* Disc quota exceeded */ X X X /*-----------------System V unique errno's----------------------*/ X #define ENOMSG 100 /* No message of desired type */ X X--- 90,99 ----- X #define EUSERS 68 /* Too many users */ X #define EDQUOT 69 /* Disc quota exceeded */ X X+ /* remote fs stuff */ X+ #define EISREMOTE 70 /* file is on a remote system */ X+ #define ETOOMANYREMOTE 71 /* too many remote file systems */ X+ #define ENOREMOTEFS 72 /* no remote file system */ X X /*-----------------System V unique errno's----------------------*/ X #define ENOMSG 100 /* No message of desired type */ SHAREOF chmod 664 remote/usr.sys.PYR2.5/h/errno.h.diff # # remote/usr.sys.PYR2.5/h/param.h.diff # if [ -f remote/usr.sys.PYR2.5/h/param.h.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/h/param.h.diff or ^C to quit' read ans rm -f remote/usr.sys.PYR2.5/h/param.h.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.PYR2.5/h/param.h.diff XThis addition defines NREMOTE, the number of remote mount points. X*************** X*** 26,27 X * Machine-independent constants X */ X X--- 26,30 ----- X * Machine-independent constants X */ X+ #ifdef REMOTEFS X+ #define NREMOTE 8 /* number of remote file systems */ X+ #endif REMOTEFS SHAREOF chmod 664 remote/usr.sys.PYR2.5/h/param.h.diff if [ -f remote/usr.sys.VAX4.2/h/param.h.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/h/param.h.diff or ^C to quit' read ans rm -rf remote/usr.sys.VAX4.2/h/param.h.diff fi ln remote/usr.sys.PYR2.5/h/param.h.diff remote/usr.sys.VAX4.2/h/param.h.diff if [ -f remote/usr.sys.VAX4.3/h/param.h.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/h/param.h.diff or ^C to quit' read ans rm -rf remote/usr.sys.VAX4.3/h/param.h.diff fi ln remote/usr.sys.PYR2.5/h/param.h.diff remote/usr.sys.VAX4.3/h/param.h.diff # # remote/usr.sys.PYR2.5/h/user.h.diff # if [ -f remote/usr.sys.PYR2.5/h/user.h.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/h/user.h.diff or ^C to quit' read ans rm -f remote/usr.sys.PYR2.5/h/user.h.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.PYR2.5/h/user.h.diff XThese changes keep track of the per-process RFS information. X*************** X*** 169,174 X dev_t nc_dev; /* dev of cached directory */ X time_t nc_time; /* time stamp for cache entry */ X } u_ncache; X int u_stack[1]; X }; X X X--- 169,184 ----- X dev_t nc_dev; /* dev of cached directory */ X time_t nc_time; /* time stamp for cache entry */ X } u_ncache; X+ #ifdef REMOTEFS X+ short u_rmtoffset[2]; /* path offset for local segment */ X+ short u_rmtcdir; /* system # of remote current dir */ X+ long u_rmtsys; /* room for 32 systems */ X+ /* one bit for each remote system */ X+ #ifdef pyr /* Pyramid */ X+ int u_ap; X+ #define u_arg u_ap X+ #endif pyr X+ #endif REMOTEFS X int u_stack[1]; X }; X SHAREOF chmod 664 remote/usr.sys.PYR2.5/h/user.h.diff # # remote/usr.sys.PYR2.5/sys/init_sysent.c.diff # if [ -f remote/usr.sys.PYR2.5/sys/init_sysent.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/sys/init_sysent.c.diff or ^C to quit' read ans rm -f remote/usr.sys.PYR2.5/sys/init_sysent.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.PYR2.5/sys/init_sysent.c.diff XThese two changes add in the new RFS systems calls, remoteon(), remoteoff() Xand remotename(). If the second hunk fails, then you have some system Xcall numbers that are not in standard Pyramid 2.5. X*************** X*** 124,129 X */ X int setuniverse(), ugetcsbase(); X X /* BEGIN JUNK */ X int profil(); /* 'cuz sys calls are interruptible */ X int vhangup(); /* should just do in exit() */ X X--- 124,138 ----- X */ X int setuniverse(), ugetcsbase(); X X+ #ifdef REMOTEFS X+ /* X+ * remote file sys stuff (toddb@du) X+ */ X+ int remoteon(), X+ remoteoff(), X+ remotename(); X+ #endif REMOTEFS X+ X /* BEGIN JUNK */ X int profil(); /* 'cuz sys calls are interruptible */ X int vhangup(); /* should just do in exit() */ X*************** X*** 324,329 X #endif NSA X { setprocesshost, 1}, /* 166 = setprocesshost */ X { getprocesshost, 1}, /* 167 = getprocesshost */ X }; X int nsysent = sizeof (sysent) / sizeof (sysent[0]); X X X--- 333,347 ----- X #endif NSA X { setprocesshost, 1}, /* 166 = setprocesshost */ X { getprocesshost, 1}, /* 167 = getprocesshost */ X+ #ifdef REMOTEFS X+ { remoteon, 4 }, /* 168 = remoteon */ X+ { remoteoff, 1 }, /* 169 = remoteoff */ X+ { remotename, 5 }, /* 170 = remotename */ X+ #else REMOTEFS X+ { nosys, 0}, /* 168 = reserved for REMOTEFS */ X+ { nosys, 0}, /* 169 = reserved for REMOTEFS */ X+ { nosys, 0}, /* 170 = reserved for REMOTEFS */ X+ #endif REMOTEFS X }; X int nsysent = sizeof (sysent) / sizeof (sysent[0]); X SHAREOF chmod 664 remote/usr.sys.PYR2.5/sys/init_sysent.c.diff # # remote/usr.sys.PYR2.5/sys/kern_exec.c.diff # if [ -f remote/usr.sys.PYR2.5/sys/kern_exec.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/sys/kern_exec.c.diff or ^C to quit' read ans rm -f remote/usr.sys.PYR2.5/sys/kern_exec.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.PYR2.5/sys/kern_exec.c.diff XThe following changes implement local execution of an object file that Xlives on another host. X*************** X*** 58,63 X #include "../h/cmap.h" X #include "../h/vmmac.h" X #include "../h/debug.h" X X int *swapstack(); X X X--- 58,69 ----- X #include "../h/cmap.h" X #include "../h/vmmac.h" X #include "../h/debug.h" X+ #ifdef REMOTEFS X+ /* X+ * needed only if EISREMOTE isn't in /usr/include/errno.h X+ */ X+ #include "../h/errno.h" X+ #endif REMOTEFS X X int *swapstack(); X X*************** X*** 76,81 X register char *cp; X register struct buf *bp; X register int na, ne, ucp, ap, c, i; X register int indir, uid, gid; X register char *sharg; X register struct inode *ip; X X--- 82,93 ----- X register char *cp; X register struct buf *bp; X register int na, ne, ucp, ap, c, i; X+ #ifdef REMOTEFS X+ register int indir; X+ int uid, gid; /* have to take address */ X+ struct inode *ip; /* have to take address */ X+ int remote = -1; X+ #else REMOTEFS X register int indir, uid, gid; X register struct inode *ip; X #endif REMOTEFS X*************** X*** 77,83 X register struct buf *bp; X register int na, ne, ucp, ap, c, i; X register int indir, uid, gid; X- register char *sharg; X register struct inode *ip; X register swblk_t bno; X char cfname[MAXNAMLEN + 1]; X X--- 89,94 ----- X int remote = -1; X #else REMOTEFS X register int indir, uid, gid; X register struct inode *ip; X #endif REMOTEFS X register char *sharg; X*************** X*** 79,84 X register int indir, uid, gid; X register char *sharg; X register struct inode *ip; X register swblk_t bno; X char cfname[MAXNAMLEN + 1]; X char cfarg[SHSIZE]; X X--- 90,97 ----- X #else REMOTEFS X register int indir, uid, gid; X register struct inode *ip; X+ #endif REMOTEFS X+ register char *sharg; X register swblk_t bno; X char cfname[MAXNAMLEN + 1]; X char cfarg[SHSIZE]; X*************** X*** 105,110 X * (7) do a ret X */ X if ((ip = namei(uchar, LOOKUP, 1)) == NULL) X return; X sysVinfo.sV_sysexec++; X bno = 0; X X--- 118,128 ----- X * (7) do a ret X */ X if ((ip = namei(uchar, LOOKUP, 1)) == NULL) X+ #ifdef REMOTEFS X+ if (u.u_error == EISREMOTE) X+ remote = remote_execinfo(&ip, &uid, &gid, fname); X+ if (u.u_error) X+ #endif REMOTEFS X return; X sysVinfo.sV_sysexec++; X bno = 0; X*************** X*** 110,115 X bno = 0; X bp = 0; X indir = 0; X uid = u.u_uid; X gid = u.u_gid; X if (ip->i_mode & ISUID) X X--- 128,136 ----- X bno = 0; X bp = 0; X indir = 0; X+ #ifdef REMOTEFS X+ if (remote < 0) { X+ #endif REMOTEFS X uid = u.u_uid; X gid = u.u_gid; X if (ip->i_mode & ISUID) X*************** X*** 148,153 X if (u.u_error) X goto bad; X u.u_count = resid; X #ifndef lint X if (resid > sizeof(u.u_exdata) - sizeof(u.u_exdata.Ux_A) && X u.u_exdata.ux_shell[0] != '#') { X X--- 169,180 ----- X if (u.u_error) X goto bad; X u.u_count = resid; X+ #ifdef REMOTEFS X+ } X+ X+ remote_again: X+ X+ #endif REMOTEFS X #ifndef lint X if (resid > sizeof(u.u_exdata) - sizeof(u.u_exdata.Ux_A) && X u.u_exdata.ux_shell[0] != '#') { X*************** X*** 224,229 X (unsigned)(u.u_dent.d_namlen + 1)); X cfname[MAXCOMLEN] = 0; X indir = 1; X iput(ip); X /* Security hole fix: don't allow SUID-root exec'able X scripts whose name starts with '-'.... allows X X--- 251,259 ----- X (unsigned)(u.u_dent.d_namlen + 1)); X cfname[MAXCOMLEN] = 0; X indir = 1; X+ #ifdef REMOTEFS X+ if (remote < 0) X+ #endif REMOTEFS X iput(ip); X /* Security hole fix: don't allow SUID-root exec'able X scripts whose name starts with '-'.... allows X*************** X*** 233,238 X return; X } X ip = namei(schar, LOOKUP, 1); X if (ip == NULL) X return; X goto again; X X--- 263,280 ----- X return; X } X ip = namei(schar, LOOKUP, 1); X+ #ifdef REMOTEFS X+ if (ip == NULL) { X+ if (u.u_error == EISREMOTE) X+ remote = remote_execinfo(&ip, 0, 0, 0); X+ if (u.u_error) X+ return; X+ if (ip == NULL) X+ goto remote_again; X+ } X+ else X+ remote = -1; X+ #else REMOTEFS X if (ip == NULL) X return; X #endif REMOTEFS X*************** X*** 235,240 X ip = namei(schar, LOOKUP, 1); X if (ip == NULL) X return; X goto again; X } X X X--- 277,283 ----- X #else REMOTEFS X if (ip == NULL) X return; X+ #endif REMOTEFS X goto again; X } X X*************** X*** 332,337 X bcopy((caddr_t)cfname, (caddr_t)u.u_dent.d_name, X (unsigned)(u.u_dent.d_namlen + 1)); X } X getxfile(ip, (int)(nc + (na+4)*NBPW), uid, gid); X if (u.u_error) { X badarg: X X--- 375,383 ----- X bcopy((caddr_t)cfname, (caddr_t)u.u_dent.d_name, X (unsigned)(u.u_dent.d_namlen + 1)); X } X+ #ifdef REMOTEFS X+ getxfile(ip, (int)(nc + (na+4)*NBPW), uid, gid, remote); X+ #else REMOTEFS X getxfile(ip, (int)(nc + (na+4)*NBPW), uid, gid); X #endif REMOTEFS X if (u.u_error) { X*************** X*** 333,338 X (unsigned)(u.u_dent.d_namlen + 1)); X } X getxfile(ip, (int)(nc + (na+4)*NBPW), uid, gid); X if (u.u_error) { X badarg: X for (c = 0; c < nc; c += CLSIZE*PAGSIZ) { X X--- 379,385 ----- X getxfile(ip, (int)(nc + (na+4)*NBPW), uid, gid, remote); X #else REMOTEFS X getxfile(ip, (int)(nc + (na+4)*NBPW), uid, gid); X+ #endif REMOTEFS X if (u.u_error) { X badarg: X for (c = 0; c < nc; c += CLSIZE*PAGSIZ) { X*************** X*** 627,632 X * Set up page tables and other structures for the process to be X * executed, and read in from the file. X */ X getxfile(ip, nargc, uid, gid) X register struct inode *ip; X { X X--- 674,682 ----- X * Set up page tables and other structures for the process to be X * executed, and read in from the file. X */ X+ #ifdef REMOTEFS X+ getxfile(ip, nargc, uid, gid, remote) X+ #else REMOTEFS X getxfile(ip, nargc, uid, gid) X #endif REMOTEFS X register struct inode *ip; X*************** X*** 628,633 X * executed, and read in from the file. X */ X getxfile(ip, nargc, uid, gid) X register struct inode *ip; X { X register size_t ts, ds, uss, css; X X--- 678,684 ----- X getxfile(ip, nargc, uid, gid, remote) X #else REMOTEFS X getxfile(ip, nargc, uid, gid) X+ #endif REMOTEFS X register struct inode *ip; X { X register size_t ts, ds, uss, css; X*************** X*** 632,637 X { X register size_t ts, ds, uss, css; X register int pagi; X register struct proc *p; X register struct file *fp; X register int flag; /* used to keep proc flags */ X X--- 683,691 ----- X { X register size_t ts, ds, uss, css; X register int pagi; X+ #ifdef REMOTEFS X+ register int oldtextsize; X+ #endif REMOTEFS X register struct proc *p; X register struct file *fp; X register int flag; /* used to keep proc flags */ X*************** X*** 650,655 X pagi = SPAGI; X else X pagi = 0; X if (u.u_exdata.ux_tsize!=0 && (ip->i_xflag&ITEXTFILE)==0 && X ip->i_count!=1) { X SPINLOCK(&file_lock); X X--- 704,720 ----- X pagi = SPAGI; X else X pagi = 0; X+ #ifdef REMOTEFS X+ if (remote >= 0) { X+ /* X+ * Prevent xalloc() from making a shared or paged text. X+ */ X+ pagi = 0; X+ oldtextsize = u.u_exdata.ux_tsize; X+ u.u_exdata.ux_dsize += u.u_exdata.ux_tsize; X+ u.u_exdata.ux_tsize = 0; X+ } X+ #endif REMOTEFS X if (u.u_exdata.ux_tsize!=0 && (ip->i_xflag&ITEXTFILE)==0 && X ip->i_count!=1) { X SPINLOCK(&file_lock); X*************** X*** 802,807 X * Read in the data segment if we are not going to page in this X * process. X */ X if (pagi == 0) { X u.u_error = X rdwri(UIO_READ, ip, X X--- 867,877 ----- X * Read in the data segment if we are not going to page in this X * process. X */ X+ #ifdef REMOTEFS X+ if (remote >= 0) X+ u.u_error = remote_execread(remote, oldtextsize); X+ else X+ #endif REMOTEFS X if (pagi == 0) { X u.u_error = X rdwri(UIO_READ, ip, SHAREOF chmod 664 remote/usr.sys.PYR2.5/sys/kern_exec.c.diff # # remote/usr.sys.PYR2.5/sys/kern_exit.c.diff # if [ -f remote/usr.sys.PYR2.5/sys/kern_exit.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/sys/kern_exit.c.diff or ^C to quit' read ans rm -f remote/usr.sys.PYR2.5/sys/kern_exit.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.PYR2.5/sys/kern_exit.c.diff XThe following changes ensure that upon exit, a process notifies any remote Xservers that may know about him, that he is indeed dead. X*************** X*** 59,64 X #include "../h/quota.h" X #include "../h/cmap.h" X #include "../h/text.h" X X /* X * Exit system call: pass back caller's arg X X--- 59,67 ----- X #include "../h/quota.h" X #include "../h/cmap.h" X #include "../h/text.h" X+ #ifdef REMOTEFS X+ #include "../remote/remotefs.h" X+ #endif REMOTEFS X X /* X * Exit system call: pass back caller's arg X*************** X*** 99,104 X vmsizmon(); X #endif X p = u.u_procp; X X gpid = p->p_gpid; X /* X X--- 102,114 ----- X vmsizmon(); X #endif X p = u.u_procp; X+ #ifdef REMOTEFS X+ /* X+ * First, release our server. X+ */ X+ if (p->p_flag & SREMOTE) X+ remote_exit(); X+ #endif REMOTEFS X X gpid = p->p_gpid; X /* SHAREOF chmod 664 remote/usr.sys.PYR2.5/sys/kern_exit.c.diff # # remote/usr.sys.PYR2.5/sys/kern_trap.c.diff # if [ -f remote/usr.sys.PYR2.5/sys/kern_trap.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/sys/kern_trap.c.diff or ^C to quit' read ans rm -f remote/usr.sys.PYR2.5/sys/kern_trap.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.PYR2.5/sys/kern_trap.c.diff XThese changes enable syscall() to start up a remote version of a system Xcall if the normal system call fails with error == EISREMOTE. X*************** X*** 47,52 X #include "../h/vmmac.h" X #include "../h/vmmeter.h" X #include "../h/debug.h" X X extern int kernstrt; X #define USER 040 /* user-mode flag added to type */ X X--- 47,59 ----- X #include "../h/vmmac.h" X #include "../h/vmmeter.h" X #include "../h/debug.h" X+ #ifdef REMOTEFS X+ #include "../remote/remotefs.h" X+ /* X+ * needed only if EISREMOTE isn't in /usr/include/errno.h X+ */ X+ #include "../h/errno.h" X+ #endif REMOTEFS X X extern int kernstrt; X #define USER 040 /* user-mode flag added to type */ X*************** X*** 395,400 X register long syst_sec, syst_usec; X register int s; X register int onslave = 0; X X SETGR9(); /* for dual cpu, put mastercpu into gr9 */ X spl0(); /* move up to system base priority level */ X X--- 402,411 ----- X register long syst_sec, syst_usec; X register int s; X register int onslave = 0; X+ #ifdef REMOTEFS X+ extern u_char remote_sysmap[]; X+ register int rmt_syscall, runremote, rmtcalled, rmtcnt; X+ #endif REMOTEFS X X SETGR9(); /* for dual cpu, put mastercpu into gr9 */ X spl0(); /* move up to system base priority level */ X*************** X*** 418,424 X if (u.u_error == 0 && u.u_eosys == JUSTRETURN) X u.u_error = EINTR; X } else { X! (*(callproc->sy_call))(arg1, arg2, arg3, arg4, arg5, arg6); X } X X if (u.u_eosys != RESTARTSYS) X X--- 429,461 ----- X if (u.u_error == 0 && u.u_eosys == JUSTRETURN) X u.u_error = EINTR; X } else { X! #ifdef REMOTEFS X! if (index < 512) { X! rmt_syscall = remote_sysmap[ index ]; X! rmtcalled = FALSE; X! rmtcnt = 0; X! X! u.u_eosys = JUSTRETURN; X! while (! rmtcalled) { X! runremote = (rmt_syscall != RSYS_nosys X! && u.u_procp->p_flag & SREMOTE); X! if (runremote) X! rmtcalled = remote_startup(rmtcnt, X! rmt_syscall, arg1, arg2, arg3, X! arg4, arg5, arg6); X! if (! rmtcalled) { X! (*callproc->sy_call)(arg1, arg2, arg3, X! arg4, arg5, arg6); X! if (u.u_error != EISREMOTE) X! rmtcalled = TRUE; X! else X! rmtcnt++; X! } X! } X! } else X! #endif REMOTEFS X! (*(callproc->sy_call))(arg1, arg2, arg3, X! arg4, arg5, arg6); X } X X if (u.u_eosys != RESTARTSYS) SHAREOF chmod 664 remote/usr.sys.PYR2.5/sys/kern_trap.c.diff # # remote/usr.sys.PYR2.5/sys/sys_inode.c.diff # if [ -f remote/usr.sys.PYR2.5/sys/sys_inode.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/sys/sys_inode.c.diff or ^C to quit' read ans rm -f remote/usr.sys.PYR2.5/sys/sys_inode.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.PYR2.5/sys/sys_inode.c.diff XThis change repairs a semantic change in ino_close() that assumes Xthe only other file descriptor type is DTYPE_SOCKET. If patch tells Xyou X Reversed (or previously applied) patch detected! XThen you already have the fix and you must undo what patch does. X*************** X*** 516,522 X for (ffp = file; ffp < fileNFILE; ffp++) { X if (ffp == fp) X continue; X! if (ffp->f_type == DTYPE_SOCKET) /* XXX */ X continue; X if (ffp->f_count && (ip = (struct inode *)ffp->f_data) && X ip->i_rdev == dev && (ip->i_mode&IFMT) == mode) X X--- 516,522 ----- X for (ffp = file; ffp < fileNFILE; ffp++) { X if (ffp == fp) X continue; X! if (ffp->f_type != DTYPE_INODE) /* semantic fix (toddb@du) */ X continue; X if (ffp->f_count && (ip = (struct inode *)ffp->f_data) && X ip->i_rdev == dev && (ip->i_mode&IFMT) == mode) SHAREOF chmod 664 remote/usr.sys.PYR2.5/sys/sys_inode.c.diff # # remote/usr.sys.PYR2.5/sys/ufs_nami.c.diff # if [ -f remote/usr.sys.PYR2.5/sys/ufs_nami.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/sys/ufs_nami.c.diff or ^C to quit' read ans rm -f remote/usr.sys.PYR2.5/sys/ufs_nami.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.PYR2.5/sys/ufs_nami.c.diff XThese changes are the primary hook into the operating system for detecting Xa "remote" file. X*************** X*** 145,150 X unsigned hash; /* value of name hash for entry */ X union nchash *nhp; /* cache chain head for entry */ X int isdotdot; /* != 0 if current name is ".." */ X X sysVinfo.sV_namei++; X lockparent = flag & LOCKPARENT; X X--- 145,153 ----- X unsigned hash; /* value of name hash for entry */ X union nchash *nhp; /* cache chain head for entry */ X int isdotdot; /* != 0 if current name is ".." */ X+ #ifdef REMOTEFS X+ long remote; X+ #endif REMOTEFS X X sysVinfo.sV_namei++; X lockparent = flag & LOCKPARENT; X*************** X*** 189,194 X * Check accessiblity of directory. X */ X if ((dp->i_mode&IFMT) != IFDIR) { X u.u_error = ENOTDIR; X goto bad; X } X X--- 192,214 ----- X * Check accessiblity of directory. X */ X if ((dp->i_mode&IFMT) != IFDIR) { X+ #ifdef REMOTEFS X+ remote = isremote(dp, cp, nbp->b_un.b_addr); X+ X+ /* X+ * If it is really local, then start again at the root. X+ */ X+ if (remote < 0) { X+ iput(dp); X+ dp = rootdir; X+ ilockx(dp); X+ dp->i_count++; X+ fs = dp->i_fs; X+ cp = nbp->b_un.b_addr; X+ goto dirloop2; X+ } X+ else if (! remote) X+ #endif REMOTEFS X u.u_error = ENOTDIR; X goto bad; X } X*************** X*** 604,609 X u.u_error = EPERM; X goto bad; X } X } X } X #ifdef NSA X X--- 624,640 ----- X u.u_error = EPERM; X goto bad; X } X+ #ifdef REMOTEFS X+ /* X+ * don't allow anyone to remove a remote mount X+ * point. X+ */ X+ if (rmt_host(dp, &i)) { X+ iput(u.u_pdir); X+ u.u_error = EBUSY; X+ goto bad; X+ } X+ #endif REMOTEFS X } X } X #ifdef NSA X*************** X*** 786,791 X X if (len + pathlen >= MAXPATHLEN - 1 || X ++nlink > MAXSYMLINKS) { X u.u_error = ELOOP; X goto bad2; X } X X--- 817,824 ----- X X if (len + pathlen >= MAXPATHLEN - 1 || X ++nlink > MAXSYMLINKS) { X+ printf("nlink=%d,len=%d,pathlen=%d:LOOP\n", X+ nlink, len, pathlen); X u.u_error = ELOOP; X goto bad2; X } SHAREOF chmod 664 remote/usr.sys.PYR2.5/sys/ufs_nami.c.diff # # remote/usr.sys.PYR2.5/sys/ufs_syscalls.c.diff # if [ -f remote/usr.sys.PYR2.5/sys/ufs_syscalls.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/sys/ufs_syscalls.c.diff or ^C to quit' read ans rm -f remote/usr.sys.PYR2.5/sys/ufs_syscalls.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.PYR2.5/sys/ufs_syscalls.c.diff XThese changes modify chdirec(), which is called by chroot() and chdir(), Xso that you can be allowed to do a chdir() to a remote mount point. XIn addition, the changes ensure that we adjust internal pointers when doing Xa chdir() OUT of a remote mount point. X*************** X*** 104,109 X register struct inode **ipp; X { X register struct inode *ip; X X ip = namei(uchar, LOOKUP, 1); X if (ip == NULL) X X--- 104,112 ----- X register struct inode **ipp; X { X register struct inode *ip; X+ #ifdef REMOTEFS X+ int i; X+ #endif REMOTEFS X X ip = namei(uchar, LOOKUP, 1); X if (ip == NULL) X*************** X*** 109,114 X if (ip == NULL) X return; X if ((ip->i_mode&IFMT) != IFDIR) { X u.u_error = ENOTDIR; X goto bad; X } X X--- 112,123 ----- X if (ip == NULL) X return; X if ((ip->i_mode&IFMT) != IFDIR) { X+ #ifdef REMOTEFS X+ if (rmt_hostdir(ip, &i) != NULL) X+ u.u_error = remotechdir(i); X+ else X+ u.u_error = ENOTDIR; X+ #else REMOTEFS X u.u_error = ENOTDIR; X #endif REMOTEFS X goto bad; X*************** X*** 110,115 X return; X if ((ip->i_mode&IFMT) != IFDIR) { X u.u_error = ENOTDIR; X goto bad; X } X if (access(ip, IEXEC)) X X--- 119,125 ----- X u.u_error = ENOTDIR; X #else REMOTEFS X u.u_error = ENOTDIR; X+ #endif REMOTEFS X goto bad; X } X if (access(ip, IEXEC)) X*************** X*** 114,119 X } X if (access(ip, IEXEC)) X goto bad; X iunlock(ip); X if (*ipp) X irele(*ipp); X X--- 124,132 ----- X } X if (access(ip, IEXEC)) X goto bad; X+ #ifdef REMOTEFS X+ remotechdir(-1); X+ #endif REMOTEFS X iunlock(ip); X if (*ipp) X irele(*ipp); SHAREOF chmod 664 remote/usr.sys.PYR2.5/sys/ufs_syscalls.c.diff # # remote/usr.sys.PYR2.5/sys/uipc_socket.c.diff # if [ -f remote/usr.sys.PYR2.5/sys/uipc_socket.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.PYR2.5/sys/uipc_socket.c.diff or ^C to quit' read ans rm -f remote/usr.sys.PYR2.5/sys/uipc_socket.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.PYR2.5/sys/uipc_socket.c.diff XThese changes Fix a bug in soreceive() that caused infinite loop if a Xpacket was received while doing uiomove() and the MSG_PEEK flag was set. XIf you have this fix, then patch will tell you: X X Reversed (or previously applied) patch detected! X XIf it does, you should just reinstall your original uipc_socket.c. XIf you have a different version of the fix or another modification that Xaffects this code, then patch will tell you that "Hunk #1 failed"; you Xmust install the patch by hand. X*************** X*** 659,665 X error = X uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio); X s = splnet(); X! if (len == m->m_len) { X eor = (int)m->m_act; X if (flags & MSG_PEEK) X m = m->m_next; X X--- 659,665 ----- X error = X uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio); X s = splnet(); X! if (moff+len == m->m_len) { /* infinite loop fix (toddb@du) */ X eor = (int)m->m_act; X if (flags & MSG_PEEK) X m = m->m_next; SHAREOF chmod 664 remote/usr.sys.PYR2.5/sys/uipc_socket.c.diff # # remote/usr.sys.VAX4.2/conf/files.diff # if [ -f remote/usr.sys.VAX4.2/conf/files.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/conf/files.diff or ^C to quit' read ans rm -f remote/usr.sys.VAX4.2/conf/files.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.2/conf/files.diff XThe files added here identify the RFS source code. X*************** X*** 107,108 X sys/vm_swp.c standard X sys/vm_text.c standard X X--- 107,118 ----- X sys/vm_swp.c standard X sys/vm_text.c standard X+ remote/rmt_data.c optional remotefs X+ remote/rmt_exec.c optional remotefs X+ remote/rmt_final.c optional remotefs X+ remote/rmt_general.c optional remotefs X+ remote/rmt_generic.c optional remotefs X+ remote/rmt_io.c optional remotefs X+ remote/rmt_subr.c optional remotefs X+ remote/rmt_syscall1.c optional remotefs X+ remote/rmt_syscall2.c optional remotefs X+ remote/rmt_syscall3.c optional remotefs SHAREOF chmod 664 remote/usr.sys.VAX4.2/conf/files.diff if [ -f remote/usr.sys.VAX4.3/conf/files.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/conf/files.diff or ^C to quit' read ans rm -rf remote/usr.sys.VAX4.3/conf/files.diff fi ln remote/usr.sys.VAX4.2/conf/files.diff remote/usr.sys.VAX4.3/conf/files.diff # # remote/usr.sys.VAX4.2/conf/makefile.vax.diff # if [ -f remote/usr.sys.VAX4.2/conf/makefile.vax.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/conf/makefile.vax.diff or ^C to quit' read ans rm -f remote/usr.sys.VAX4.2/conf/makefile.vax.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.2/conf/makefile.vax.diff XThis change teaches the makefile how to make rmt_data.c from X../remote/remotefs.h, ../remote/rmt_data_template and ../sys/init_sysent.c. X*************** X*** 166,168 X X %RULES X X X--- 166,175 ----- X X+ ../remote/rmt_data.c: ../remote/rmt_data_template ../remote/remotefs.h \ X+ ../sys/init_sysent.c X+ cat ../remote/rmt_data_template > ../remote/nrmt_data.c X+ /lib/cpp ${CFLAGS} ../sys/init_sysent.c | sh ../remote/remote_mkdata \ X+ ../remote/remotefs.h >> ../remote/nrmt_data.c X+ mv ../remote/nrmt_data.c ../remote/rmt_data.c X+ X %RULES X SHAREOF chmod 664 remote/usr.sys.VAX4.2/conf/makefile.vax.diff # # remote/usr.sys.VAX4.2/h/errno.h.diff # if [ -f remote/usr.sys.VAX4.2/h/errno.h.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/h/errno.h.diff or ^C to quit' read ans rm -f remote/usr.sys.VAX4.2/h/errno.h.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.2/h/errno.h.diff XThese changes add three new error numbers for the sake of RFS. X*************** X*** 94,96 X #define EPROCLIM 67 /* Too many processes */ X #define EUSERS 68 /* Too many users */ X #define EDQUOT 69 /* Disc quota exceeded */ X X--- 94,101 ----- X #define EPROCLIM 67 /* Too many processes */ X #define EUSERS 68 /* Too many users */ X #define EDQUOT 69 /* Disc quota exceeded */ X+ X+ /* remote fs stuff */ X+ #define EISREMOTE 70 /* file is on a remote system */ X+ #define ETOOMANYREMOTE 71 /* too many remote file systems */ X+ #define ENOREMOTEFS 72 /* no remote file system */ SHAREOF chmod 664 remote/usr.sys.VAX4.2/h/errno.h.diff if [ -f remote/usr.sys.VAX4.3/h/errno.h.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/h/errno.h.diff or ^C to quit' read ans rm -rf remote/usr.sys.VAX4.3/h/errno.h.diff fi ln remote/usr.sys.VAX4.2/h/errno.h.diff remote/usr.sys.VAX4.3/h/errno.h.diff # # remote/usr.sys.VAX4.2/h/user.h.diff # if [ -f remote/usr.sys.VAX4.2/h/user.h.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/h/user.h.diff or ^C to quit' read ans rm -f remote/usr.sys.VAX4.2/h/user.h.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.2/h/user.h.diff XThese changes keep track of the per-process RFS information. X*************** X*** 140,145 X unsigned pr_off; /* pc offset */ X unsigned pr_scale; /* pc scaling */ X } u_prof; X int u_stack[1]; X }; X X X--- 140,155 ----- X unsigned pr_off; /* pc offset */ X unsigned pr_scale; /* pc scaling */ X } u_prof; X+ #ifdef REMOTEFS X+ short u_rmtoffset[2]; /* path offset for local segment */ X+ short u_rmtcdir; /* system # of remote current dir */ X+ long u_rmtsys; /* room for 32 systems */ X+ /* one bit for each remote system */ X+ #ifdef pyr /* Pyramid */ X+ int *u.u_ap; X+ #define u_arg u_ap X+ #endif pyr X+ #endif REMOTEFS X int u_stack[1]; X }; X SHAREOF chmod 664 remote/usr.sys.VAX4.2/h/user.h.diff # # remote/usr.sys.VAX4.2/machine/trap.c.diff # if [ -f remote/usr.sys.VAX4.2/machine/trap.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/machine/trap.c.diff or ^C to quit' read ans rm -f remote/usr.sys.VAX4.2/machine/trap.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.2/machine/trap.c.diff XThese changes enable syscall() to start up a remote version of a system Xcall if the normal system call fails with error == EISREMOTE. X*************** X*** 25,30 X #ifdef SYSCALLTRACE X #include "../sys/syscalls.c" X #endif X X #include "../vax/mtpr.h" X X X--- 25,37 ----- X #ifdef SYSCALLTRACE X #include "../sys/syscalls.c" X #endif X+ #ifdef REMOTEFS X+ #include "../remote/remotefs.h" X+ /* X+ * needed only if EISREMOTE isn't in /usr/include/errno.h X+ */ X+ #include "../h/errno.h" X+ #endif REMOTEFS X X #include "../vax/mtpr.h" X X*************** X*** 193,198 X register struct proc *p; X int opc; X struct timeval syst; X X syst = u.u_ru.ru_stime; X if (!USERMODE(locr0[PS])) X X--- 200,214 ----- X register struct proc *p; X int opc; X struct timeval syst; X+ #ifdef REMOTEFS X+ /* X+ * It is imperative that these declarations come after other register X+ * declarations, because the (standard) code below depends upon the X+ * order of allocation. X+ */ X+ extern u_char remote_sysmap[]; X+ register long rmt_syscall, runremote, rmt_called, rmt_cnt; X+ #endif REMOTEFS X X syst = u.u_ru.ru_stime; X if (!USERMODE(locr0[PS])) X*************** X*** 233,238 X if (u.u_error == 0 && u.u_eosys == JUSTRETURN) X u.u_error = EINTR; X } else { X u.u_eosys = JUSTRETURN; X #ifdef SYSCALLTRACE X if (syscalltrace) { X X--- 249,258 ----- X if (u.u_error == 0 && u.u_eosys == JUSTRETURN) X u.u_error = EINTR; X } else { X+ #ifdef REMOTEFS X+ rmt_syscall = remote_sysmap[ code ]; X+ rmt_called = FALSE; X+ rmt_cnt = 0; X u.u_eosys = JUSTRETURN; X while (! rmt_called) { X runremote = (rmt_syscall != RSYS_nosys X*************** X*** 234,239 X u.u_error = EINTR; X } else { X u.u_eosys = JUSTRETURN; X #ifdef SYSCALLTRACE X if (syscalltrace) { X register int i; X X--- 254,275 ----- X rmt_called = FALSE; X rmt_cnt = 0; X u.u_eosys = JUSTRETURN; X+ while (! rmt_called) { X+ runremote = (rmt_syscall != RSYS_nosys X+ && u.u_procp->p_flag & SREMOTE); X+ if (runremote) X+ rmt_called = remote_startup(rmt_cnt, X+ rmt_syscall); X+ if (! rmt_called) { X+ (*callp->sy_call)(); X+ if (u.u_error != EISREMOTE) X+ rmt_called = TRUE; X+ else X+ rmt_cnt++; X+ } X+ } X+ #else REMOTEFS X+ u.u_eosys = JUSTRETURN; X #ifdef SYSCALLTRACE X if (syscalltrace) { X register int i; X*************** X*** 254,259 X } X #endif X (*(callp->sy_call))(); X } X locr0[PS] &= ~PSL_C; X if (u.u_eosys == RESTARTSYS) X X--- 290,296 ----- X } X #endif X (*(callp->sy_call))(); X+ #endif REMOTEFS X } X locr0[PS] &= ~PSL_C; X if (u.u_eosys == RESTARTSYS) SHAREOF chmod 664 remote/usr.sys.VAX4.2/machine/trap.c.diff # # remote/usr.sys.VAX4.2/sys/init_sysent.c.diff # if [ -f remote/usr.sys.VAX4.2/sys/init_sysent.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/sys/init_sysent.c.diff or ^C to quit' read ans rm -f remote/usr.sys.VAX4.2/sys/init_sysent.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.2/sys/init_sysent.c.diff XThese two changes add in the new RFS systems calls, remoteon(), remoteoff() Xand remotename(). If the second hunk fails, then you have some system Xcall numbers that are not in standard 4.2BSD. X*************** X*** 99,99 X /* BEGIN JUNK */ X X--- 99,107 ----- X+ #ifdef REMOTEFS X+ /* X+ * remote file sys stuff (toddb@du) X+ */ X+ int remoteon(), /* remote file sys stuff */ X+ remoteoff(), X+ remotename(); X+ #endif REMOTEFS X /* BEGIN JUNK */ X*************** X*** 270,274 X 2, setquota, /* 148 = quota */ X 4, qquota, /* 149 = qquota */ X 3, getsockname, /* 150 = getsockname */ X }; X int nsysent = sizeof (sysent) / sizeof (sysent[0]); X X--- 278,291 ----- X 2, setquota, /* 148 = quota */ X 4, qquota, /* 149 = qquota */ X 3, getsockname, /* 150 = getsockname */ X+ #ifdef REMOTEFS X+ 4, remoteon, /* 151 = remoteon */ X+ 1, remoteoff, /* 152 = remoteoff */ X+ 4, remotename, /* 153 = remotename */ X+ #else REMOTEFS X+ 0, nosys, /* 151 = nosys */ X+ 0, nosys, /* 152 = nosys */ X+ 0, nosys, /* 153 = nosys */ X+ #endif REMOTEFS X }; X int nsysent = sizeof (sysent) / sizeof (sysent[0]); SHAREOF chmod 664 remote/usr.sys.VAX4.2/sys/init_sysent.c.diff # # remote/usr.sys.VAX4.2/sys/kern_exec.c.diff # if [ -f remote/usr.sys.VAX4.2/sys/kern_exec.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/sys/kern_exec.c.diff or ^C to quit' read ans rm -f remote/usr.sys.VAX4.2/sys/kern_exec.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.2/sys/kern_exec.c.diff XThe following changes implement local execution of an object file that Xlives on another host. X*************** X*** 28,33 X #include "../h/uio.h" X #include "../h/nami.h" X #include "../h/acct.h" X X #ifdef vax X #include "../vax/mtpr.h" X X--- 28,39 ----- X #include "../h/uio.h" X #include "../h/nami.h" X #include "../h/acct.h" X+ #ifdef REMOTEFS X+ /* X+ * needed only if EISREMOTE isn't in /usr/include/errno.h X+ */ X+ #include "../h/errno.h" X+ #endif REMOTEFS X X #ifdef vax X #include "../vax/mtpr.h" X*************** X*** 57,62 X int na, ne, ucp, ap, c; X int indir, uid, gid; X char *sharg; X struct inode *ip; X swblk_t bno; X char cfname[MAXCOMLEN + 1]; X X--- 63,72 ----- X int na, ne, ucp, ap, c; X int indir, uid, gid; X char *sharg; X+ #ifdef REMOTEFS X+ struct inode *ip; /* have to take address */ X+ int remote = -1; X+ #else REMOTEFS X struct inode *ip; X #endif REMOTEFS X swblk_t bno; X*************** X*** 58,63 X int indir, uid, gid; X char *sharg; X struct inode *ip; X swblk_t bno; X char cfname[MAXCOMLEN + 1]; X char cfarg[SHSIZE]; X X--- 68,74 ----- X int remote = -1; X #else REMOTEFS X struct inode *ip; X+ #endif REMOTEFS X swblk_t bno; X char cfname[MAXCOMLEN + 1]; X char cfarg[SHSIZE]; X*************** X*** 64,69 X int resid; X X if ((ip = namei(uchar, LOOKUP, 1)) == NULL) X return; X bno = 0; X bp = 0; X X--- 75,86 ----- X int resid; X X if ((ip = namei(uchar, LOOKUP, 1)) == NULL) X+ #ifdef REMOTEFS X+ if (u.u_error == EISREMOTE) X+ remote = remote_execinfo(&ip, &uid, &gid, X+ ((struct execa *)u.u_ap)->fname); X+ if (u.u_error) X+ #endif REMOTEFS X return; X bno = 0; X bp = 0; X*************** X*** 68,73 X bno = 0; X bp = 0; X indir = 0; X uid = u.u_uid; X gid = u.u_gid; X if (ip->i_mode & ISUID) X X--- 85,93 ----- X bno = 0; X bp = 0; X indir = 0; X+ #ifdef REMOTEFS X+ if (remote < 0) { X+ #endif REMOTEFS X uid = u.u_uid; X gid = u.u_gid; X if (ip->i_mode & ISUID) X*************** X*** 106,111 X if (u.u_error) X goto bad; X u.u_count = resid; X #ifndef lint X if (u.u_count > sizeof(u.u_exdata) - sizeof(u.u_exdata.Ux_A) && X u.u_exdata.ux_shell[0] != '#') { X X--- 126,137 ----- X if (u.u_error) X goto bad; X u.u_count = resid; X+ #ifdef REMOTEFS X+ } X+ X+ remote_again: X+ X+ #endif REMOTEFS X #ifndef lint X if (u.u_count > sizeof(u.u_exdata) - sizeof(u.u_exdata.Ux_A) && X u.u_exdata.ux_shell[0] != '#') { X*************** X*** 171,176 X (unsigned)(u.u_dent.d_namlen + 1)); X cfname[MAXCOMLEN] = 0; X indir = 1; X iput(ip); X ip = namei(schar, LOOKUP, 1); X if (ip == NULL) X X--- 197,205 ----- X (unsigned)(u.u_dent.d_namlen + 1)); X cfname[MAXCOMLEN] = 0; X indir = 1; X+ #ifdef REMOTEFS X+ if (remote < 0) X+ #endif REMOTEFS X iput(ip); X ip = namei(schar, LOOKUP, 1); X #ifdef REMOTEFS X*************** X*** 173,178 X indir = 1; X iput(ip); X ip = namei(schar, LOOKUP, 1); X if (ip == NULL) X return; X goto again; X X--- 202,219 ----- X #endif REMOTEFS X iput(ip); X ip = namei(schar, LOOKUP, 1); X+ #ifdef REMOTEFS X+ if (ip == NULL) { X+ if (u.u_error == EISREMOTE) X+ remote = remote_execinfo(&ip, 0, 0, 0); X+ if (u.u_error) X+ return; X+ if (ip == NULL) X+ goto remote_again; X+ } X+ else X+ remote = -1; X+ #else REMOTEFS X if (ip == NULL) X return; X #endif REMOTEFS X*************** X*** 175,180 X ip = namei(schar, LOOKUP, 1); X if (ip == NULL) X return; X goto again; X } X X X--- 216,222 ----- X #else REMOTEFS X if (ip == NULL) X return; X+ #endif REMOTEFS X goto again; X } X X*************** X*** 244,249 X bcopy((caddr_t)cfname, (caddr_t)u.u_dent.d_name, X (unsigned)(u.u_dent.d_namlen + 1)); X } X getxfile(ip, nc + (na+4)*NBPW, uid, gid); X if (u.u_error) { X badarg: X X--- 286,294 ----- X bcopy((caddr_t)cfname, (caddr_t)u.u_dent.d_name, X (unsigned)(u.u_dent.d_namlen + 1)); X } X+ #ifdef REMOTEFS X+ getxfile(ip, nc + (na+4)*NBPW, uid, gid, remote); X+ #else REMOTEFS X getxfile(ip, nc + (na+4)*NBPW, uid, gid); X #endif REMOTEFS X if (u.u_error) { X*************** X*** 245,250 X (unsigned)(u.u_dent.d_namlen + 1)); X } X getxfile(ip, nc + (na+4)*NBPW, uid, gid); X if (u.u_error) { X badarg: X for (c = 0; c < nc; c += CLSIZE*NBPG) { X X--- 290,296 ----- X getxfile(ip, nc + (na+4)*NBPW, uid, gid, remote); X #else REMOTEFS X getxfile(ip, nc + (na+4)*NBPW, uid, gid); X+ #endif REMOTEFS X if (u.u_error) { X badarg: X for (c = 0; c < nc; c += CLSIZE*NBPG) { X*************** X*** 303,308 X /* X * Read in and set up memory for executed file. X */ X getxfile(ip, nargc, uid, gid) X register struct inode *ip; X int nargc, uid, gid; X X--- 349,357 ----- X /* X * Read in and set up memory for executed file. X */ X+ #ifdef REMOTEFS X+ getxfile(ip, nargc, uid, gid, remote) X+ #else REMOTEFS X getxfile(ip, nargc, uid, gid) X #endif REMOTEFS X register struct inode *ip; X*************** X*** 304,309 X * Read in and set up memory for executed file. X */ X getxfile(ip, nargc, uid, gid) X register struct inode *ip; X int nargc, uid, gid; X { X X--- 353,359 ----- X getxfile(ip, nargc, uid, gid, remote) X #else REMOTEFS X getxfile(ip, nargc, uid, gid) X+ #endif REMOTEFS X register struct inode *ip; X int nargc, uid, gid; X { X*************** X*** 309,314 X { X register size_t ts, ds, ss; X int pagi; X X if (u.u_exdata.ux_mag == 0413) X pagi = SPAGI; X X--- 359,367 ----- X { X register size_t ts, ds, ss; X int pagi; X+ #ifdef REMOTEFS X+ int oldtextsize; X+ #endif REMOTEFS X X if (u.u_exdata.ux_mag == 0413) X pagi = SPAGI; X*************** X*** 314,319 X pagi = SPAGI; X else X pagi = 0; X if (u.u_exdata.ux_tsize!=0 && (ip->i_flag&ITEXT)==0 && X ip->i_count!=1) { X register struct file *fp; X X--- 367,383 ----- X pagi = SPAGI; X else X pagi = 0; X+ #ifdef REMOTEFS X+ if (remote >= 0) { X+ /* X+ * Prevent xalloc() from making a shared or paged text. X+ */ X+ pagi = 0; X+ oldtextsize = u.u_exdata.ux_tsize; X+ u.u_exdata.ux_dsize += u.u_exdata.ux_tsize; X+ u.u_exdata.ux_tsize = 0; X+ } X+ #endif REMOTEFS X if (u.u_exdata.ux_tsize!=0 && (ip->i_flag&ITEXT)==0 && X ip->i_count!=1) { X register struct file *fp; X*************** X*** 370,375 X u.u_smap = u.u_csmap; X vgetvm(ts, ds, ss); X X if (pagi == 0) X u.u_error = X rdwri(UIO_READ, ip, X X--- 434,444 ----- X u.u_smap = u.u_csmap; X vgetvm(ts, ds, ss); X X+ #ifdef REMOTEFS X+ if (remote >= 0) X+ u.u_error = remote_execread(remote, oldtextsize); X+ else X+ #endif REMOTEFS X if (pagi == 0) X u.u_error = X rdwri(UIO_READ, ip, SHAREOF chmod 664 remote/usr.sys.VAX4.2/sys/kern_exec.c.diff # # remote/usr.sys.VAX4.2/sys/kern_exit.c.diff # if [ -f remote/usr.sys.VAX4.2/sys/kern_exit.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/sys/kern_exit.c.diff or ^C to quit' read ans rm -f remote/usr.sys.VAX4.2/sys/kern_exit.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.2/sys/kern_exit.c.diff XThe following changes ensure that upon exit, a process notifies any remote Xservers that may know about him, that he is indeed dead. X*************** X*** 33,38 X #include "../h/file.h" X #include "../h/mbuf.h" X #include "../h/inode.h" X X /* X * Exit system call: pass back caller's arg X X--- 33,41 ----- X #include "../h/file.h" X #include "../h/mbuf.h" X #include "../h/inode.h" X+ #ifdef REMOTEFS X+ #include "../remote/remotefs.h" X+ #endif REMOTEFS X X /* X * Exit system call: pass back caller's arg X*************** X*** 66,71 X vmsizmon(); X #endif X p = u.u_procp; X p->p_flag &= ~(STRC|SULOCK); X p->p_flag |= SWEXIT; X p->p_sigignore = ~0; X X--- 69,81 ----- X vmsizmon(); X #endif X p = u.u_procp; X+ #ifdef REMOTEFS X+ /* X+ * First, release our server. X+ */ X+ if (p->p_flag & SREMOTE) X+ remote_exit(); X+ #endif REMOTEFS X p->p_flag &= ~(STRC|SULOCK); X p->p_flag |= SWEXIT; X p->p_sigignore = ~0; SHAREOF chmod 664 remote/usr.sys.VAX4.2/sys/kern_exit.c.diff # # remote/usr.sys.VAX4.2/sys/sys_inode.c.diff # if [ -f remote/usr.sys.VAX4.2/sys/sys_inode.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/sys/sys_inode.c.diff or ^C to quit' read ans rm -f remote/usr.sys.VAX4.2/sys/sys_inode.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.2/sys/sys_inode.c.diff XThis change repairs a semantic change in ino_close() that assumes Xthe only other file descriptor type is DTYPE_SOCKET. If patch tells Xyou X Reversed (or previously applied) patch detected! XThen you already have the fix and you must undo what patch does. X X*************** X*** 351,357 X * two different inodes. X */ X for (fp = file; fp < fileNFILE; fp++) { X! if (fp->f_type == DTYPE_SOCKET) /* XXX */ X continue; X if (fp->f_count && (ip = (struct inode *)fp->f_data) && X ip->i_rdev == dev && (ip->i_mode&IFMT) == mode) X X--- 351,357 ----- X * two different inodes. X */ X for (fp = file; fp < fileNFILE; fp++) { X! if (fp->f_type != DTYPE_INODE) /* XXX */ X continue; X if (fp->f_count && (ip = (struct inode *)fp->f_data) && X ip->i_rdev == dev && (ip->i_mode&IFMT) == mode) SHAREOF chmod 664 remote/usr.sys.VAX4.2/sys/sys_inode.c.diff # # remote/usr.sys.VAX4.2/sys/ufs_nami.c.diff # if [ -f remote/usr.sys.VAX4.2/sys/ufs_nami.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/sys/ufs_nami.c.diff or ^C to quit' read ans rm -f remote/usr.sys.VAX4.2/sys/ufs_nami.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.2/sys/ufs_nami.c.diff XThese changes are the primary hook into the operating system for detecting Xa "remote" file. X*************** X*** 97,102 X struct inode *pdp; /* saved dp during symlink work */ X int i; X int lockparent; X X lockparent = flag & LOCKPARENT; X flag &= ~LOCKPARENT; X X--- 97,105 ----- X struct inode *pdp; /* saved dp during symlink work */ X int i; X int lockparent; X+ #ifdef REMOTEFS X+ long remote; X+ #endif REMOTEFS X X lockparent = flag & LOCKPARENT; X flag &= ~LOCKPARENT; X*************** X*** 145,150 X * Check accessiblity of directory. X */ X if ((dp->i_mode&IFMT) != IFDIR) { X u.u_error = ENOTDIR; X goto bad; X } X X--- 148,169 ----- X * Check accessiblity of directory. X */ X if ((dp->i_mode&IFMT) != IFDIR) { X+ #ifdef REMOTEFS X+ remote = isremote(dp, cp, nbp->b_un.b_addr); X+ /* X+ * If it is really local, then start again at the root. X+ */ X+ if (remote < 0) { X+ iput(dp); X+ dp = rootdir; X+ ilock(dp); X+ dp->i_count++; X+ fs = dp->i_fs; X+ cp = nbp->b_un.b_addr; X+ goto dirloop2; X+ } X+ else if (! remote) X+ #endif REMOTEFS X u.u_error = ENOTDIR; X goto bad; X } X*************** X*** 382,387 X iput(u.u_pdir); X goto bad; X } X } X } X brelse(nbp); X X--- 401,417 ----- X iput(u.u_pdir); X goto bad; X } X+ #ifdef REMOTEFS X+ /* X+ * don't allow anyone to remove a remote mount X+ * point. X+ */ X+ if (rmt_host(dp, &i)) { X+ iput(u.u_pdir); X+ u.u_error = EBUSY; X+ goto bad; X+ } X+ #endif REMOTEFS X } X } X brelse(nbp); SHAREOF chmod 664 remote/usr.sys.VAX4.2/sys/ufs_nami.c.diff # # remote/usr.sys.VAX4.2/sys/ufs_syscalls.c.diff # if [ -f remote/usr.sys.VAX4.2/sys/ufs_syscalls.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/sys/ufs_syscalls.c.diff or ^C to quit' read ans rm -f remote/usr.sys.VAX4.2/sys/ufs_syscalls.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.2/sys/ufs_syscalls.c.diff XThese changes modify chdirec(), which is called by chroot() and chdir(), Xso that you can be allowed to do a chdir() to a remote mount point. XIn addition, the changes ensure that we adjust internal pointers when doing Xa chdir() OUT of a remote mount point. X X*************** X*** 67,72 X chdirec(ipp) X register struct inode **ipp; X { X register struct inode *ip; X struct a { X char *fname; X X--- 67,75 ----- X chdirec(ipp) X register struct inode **ipp; X { X+ #ifdef REMOTEFS X+ int i; X+ #endif REMOTEFS X register struct inode *ip; X struct a { X char *fname; X*************** X*** 76,81 X if (ip == NULL) X return; X if ((ip->i_mode&IFMT) != IFDIR) { X u.u_error = ENOTDIR; X goto bad; X } X X--- 79,89 ----- X if (ip == NULL) X return; X if ((ip->i_mode&IFMT) != IFDIR) { X+ #ifdef REMOTEFS X+ if (rmt_hostdir(ip, &i) != NULL) X+ u.u_error = remotechdir(i); X+ else X+ #endif REMOTEFS X u.u_error = ENOTDIR; X goto bad; X } X*************** X*** 81,86 X } X if (access(ip, IEXEC)) X goto bad; X iunlock(ip); X if (*ipp) X irele(*ipp); X X--- 89,97 ----- X } X if (access(ip, IEXEC)) X goto bad; X+ #ifdef REMOTEFS X+ remotechdir(-1); X+ #endif REMOTEFS X iunlock(ip); X if (*ipp) X irele(*ipp); SHAREOF chmod 664 remote/usr.sys.VAX4.2/sys/ufs_syscalls.c.diff # # remote/usr.sys.VAX4.2/sys/uipc_socket.c.diff # if [ -f remote/usr.sys.VAX4.2/sys/uipc_socket.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.2/sys/uipc_socket.c.diff or ^C to quit' read ans rm -f remote/usr.sys.VAX4.2/sys/uipc_socket.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.2/sys/uipc_socket.c.diff XThese changes Fix a bug in soreceive() that caused infinite loop if a Xpacket was received while doing uiomove() and the MSG_PEEK flag was set. XIf you have this fix, then patch will tell you: X X Reversed (or previously applied) patch detected! X XIf it does, you should just reinstall your original uipc_socket.c. XIf you have a different version of the fix or another modification that Xaffects this code, then patch will tell you that "Hunk #1 failed"; you Xmust install the patch by hand. X X*************** X*** 546,552 X error = X uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio); X s = splnet(); X! if (len == m->m_len) { X eor = (int)m->m_act; X if (flags & MSG_PEEK) X m = m->m_next; X X--- 550,556 ----- X error = X uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio); X s = splnet(); X! if (moff+len == m->m_len) { X eor = (int)m->m_act; X if (flags & MSG_PEEK) X m = m->m_next; SHAREOF chmod 664 remote/usr.sys.VAX4.2/sys/uipc_socket.c.diff # # remote/usr.sys.VAX4.3/conf/Makefile.vax.diff # if [ -f remote/usr.sys.VAX4.3/conf/Makefile.vax.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.3/conf/Makefile.vax.diff or ^C to quit' read ans rm -f remote/usr.sys.VAX4.3/conf/Makefile.vax.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.3/conf/Makefile.vax.diff XThis change teaches the Makefile how to make remote/rmt_data.c from Xsys/init_sysent.c and remote/rmt_data_template. X*************** X*** 145,150 X param.o: param.c Makefile X ${CC} -c ${CFLAGS} ${PARAM} param.c X X %RULES X X # DO NOT DELETE THIS LINE -- make depend uses it X X--- 145,157 ----- X param.o: param.c Makefile X ${CC} -c ${CFLAGS} ${PARAM} param.c X X+ ../remote/rmt_data.c: ../remote/rmt_data_template ../remote/remotefs.h \ X+ ../sys/init_sysent.c X+ cat ../remote/rmt_data_template > ../remote/nrmt_data.c X+ /lib/cpp ${CFLAGS} ../sys/init_sysent.c | sh ../remote/remote_mkdata \ X+ ../remote/remotefs.h >> ../remote/nrmt_data.c X+ mv ../remote/nrmt_data.c ../remote/rmt_data.c X+ X %RULES X X # DO NOT DELETE THIS LINE -- make depend uses it SHAREOF chmod 664 remote/usr.sys.VAX4.3/conf/Makefile.vax.diff # # remote/usr.sys.VAX4.3/conf/makefile.vax.diff # if [ -f remote/usr.sys.VAX4.3/conf/makefile.vax.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.3/conf/makefile.vax.diff or ^C to quit' read ans rm -f remote/usr.sys.VAX4.3/conf/makefile.vax.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.3/conf/makefile.vax.diff XThis change teaches the Makefile how to make remote/rmt_data.c from Xsys/init_sysent.c and remote/rmt_data_template. X*************** X*** 145,150 X param.o: param.c makefile X ${CC} -c ${CFLAGS} ${PARAM} param.c X X %RULES X X # DO NOT DELETE THIS LINE -- make depend uses it X X--- 145,157 ----- X param.o: param.c Makefile X ${CC} -c ${CFLAGS} ${PARAM} param.c X X+ ../remote/rmt_data.c: ../remote/rmt_data_template ../remote/remotefs.h \ X+ ../sys/init_sysent.c X+ cat ../remote/rmt_data_template > ../remote/nrmt_data.c X+ /lib/cpp ${CFLAGS} ../sys/init_sysent.c | sh ../remote/remote_mkdata \ X+ ../remote/remotefs.h >> ../remote/nrmt_data.c X+ mv ../remote/nrmt_data.c ../remote/rmt_data.c X+ X %RULES X X # DO NOT DELETE THIS LINE -- make depend uses it SHAREOF chmod 664 remote/usr.sys.VAX4.3/conf/makefile.vax.diff # # remote/usr.sys.VAX4.3/h/user.h.diff # if [ -f remote/usr.sys.VAX4.3/h/user.h.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.3/h/user.h.diff or ^C to quit' read ans rm -f remote/usr.sys.VAX4.3/h/user.h.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.3/h/user.h.diff XThese changes keep track of the per-process RFS information. X*************** X*** 121,126 X } u_ncache; X struct nameidata u_nd; X X int u_stack[1]; X }; X X X--- 121,137 ----- X } u_ncache; X struct nameidata u_nd; X X+ #ifdef REMOTEFS X+ short u_rmtoffset[2]; /* path offset for local segment */ X+ short u_rmtcdir; /* system # of remote current dir */ X+ long u_rmtsys; /* room for 32 systems */ X+ /* one bit for each remote system */ X+ #ifdef pyr /* Pyramid */ X+ int *u.u_ap; X+ #define u_arg u_ap X+ #endif pyr X+ #endif REMOTEFS X+ X int u_stack[1]; X }; X SHAREOF chmod 664 remote/usr.sys.VAX4.3/h/user.h.diff # # remote/usr.sys.VAX4.3/machine/trap.c.diff # if [ -f remote/usr.sys.VAX4.3/machine/trap.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.3/machine/trap.c.diff or ^C to quit' read ans rm -f remote/usr.sys.VAX4.3/machine/trap.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.3/machine/trap.c.diff XThese changes enable syscall() to start up a remote version of a system Xcall if the normal system call fails with error == EISREMOTE. X*************** X*** 23,28 X #ifdef SYSCALLTRACE X #include "../sys/syscalls.c" X #endif X X #include "mtpr.h" X X X--- 23,35 ----- X #ifdef SYSCALLTRACE X #include "../sys/syscalls.c" X #endif X+ #ifdef REMOTEFS X+ #include "../remote/remotefs.h" X+ /* X+ * needed only if EISREMOTE isn't in /usr/include/errno.h X+ */ X+ #include "../h/errno.h" X+ #endif REMOTEFS X X #include "mtpr.h" X X*************** X*** 191,196 X register struct proc *p; X int opc; X struct timeval syst; X X syst = u.u_ru.ru_stime; X if (!USERMODE(locr0[PS])) X X--- 198,212 ----- X register struct proc *p; X int opc; X struct timeval syst; X+ #ifdef REMOTEFS X+ /* X+ * It is imperative that these declarations come after other register X+ * declarations, because the (standard) code below depends upon the X+ * order of allocation. X+ */ X+ extern u_char remote_sysmap[]; X+ register long rmt_syscall, runremote, rmt_called, rmt_cnt; X+ #endif REMOTEFS X X syst = u.u_ru.ru_stime; X if (!USERMODE(locr0[PS])) X*************** X*** 223,228 X if (u.u_error == 0 && u.u_eosys != RESTARTSYS) X u.u_error = EINTR; X } else { X u.u_eosys = NORMALRETURN; X #ifdef SYSCALLTRACE X if (syscalltrace) { X X--- 239,248 ----- X if (u.u_error == 0 && u.u_eosys != RESTARTSYS) X u.u_error = EINTR; X } else { X+ #ifdef REMOTEFS X+ rmt_syscall = remote_sysmap[ code ]; X+ rmt_called = FALSE; X+ rmt_cnt = 0; X u.u_eosys = NORMALRETURN; X while (! rmt_called) { X runremote = (rmt_syscall != RSYS_nosys X*************** X*** 224,229 X u.u_error = EINTR; X } else { X u.u_eosys = NORMALRETURN; X #ifdef SYSCALLTRACE X if (syscalltrace) { X register int i; X X--- 244,265 ----- X rmt_called = FALSE; X rmt_cnt = 0; X u.u_eosys = NORMALRETURN; X+ while (! rmt_called) { X+ runremote = (rmt_syscall != RSYS_nosys X+ && u.u_procp->p_flag & SREMOTE); X+ if (runremote) X+ rmt_called = remote_startup(rmt_cnt, X+ rmt_syscall); X+ if (! rmt_called) { X+ (*callp->sy_call)(); X+ if (u.u_error != EISREMOTE) X+ rmt_called = TRUE; X+ else X+ rmt_cnt++; X+ } X+ } X+ #else REMOTEFS X+ u.u_eosys = NORMALRETURN; X #ifdef SYSCALLTRACE X if (syscalltrace) { X register int i; X*************** X*** 244,249 X } X #endif X (*(callp->sy_call))(); X } X if (u.u_eosys == NORMALRETURN) { X if (u.u_error) { X X--- 280,286 ----- X } X #endif X (*(callp->sy_call))(); X+ #endif REMOTEFS X } X if (u.u_eosys == NORMALRETURN) { X if (u.u_error) { SHAREOF chmod 664 remote/usr.sys.VAX4.3/machine/trap.c.diff # # remote/usr.sys.VAX4.3/sys/init_sysent.c.diff # if [ -f remote/usr.sys.VAX4.3/sys/init_sysent.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.3/sys/init_sysent.c.diff or ^C to quit' read ans rm -f remote/usr.sys.VAX4.3/sys/init_sysent.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.3/sys/init_sysent.c.diff XThese two changes add in the new RFS systems calls, remoteon(), remoteoff() Xand remotename(). If the second hunk fails, then you have some system Xcall numbers that are not in standard 4.2BSD. X*************** X*** 95,100 X #define compat(n, name) 0, nosys X #endif X X /* BEGIN JUNK */ X #ifdef vax X int resuba(); X X--- 95,108 ----- X #define compat(n, name) 0, nosys X #endif X X+ #ifdef REMOTEFS X+ /* X+ * remote file sys stuff (toddb@du) X+ */ X+ int remoteon(), /* remote file sys stuff */ X+ remoteoff(), X+ remotename(); X+ #endif REMOTEFS X /* BEGIN JUNK */ X #ifdef vax X int resuba(); X*************** X*** 269,274 X 2, setquota, /* 148 = quota */ X 4, qquota, /* 149 = qquota */ X 3, getsockname, /* 150 = getsockname */ X 0, nosys, /* 151 = nosys */ X 0, nosys, /* 152 = nosys */ X 0, nosys, /* 153 = nosys */ X X--- 277,287 ----- X 2, setquota, /* 148 = quota */ X 4, qquota, /* 149 = qquota */ X 3, getsockname, /* 150 = getsockname */ X+ #ifdef REMOTEFS X+ 4, remoteon, /* 151 = remoteon */ X+ 1, remoteoff, /* 152 = remoteoff */ X+ 4, remotename, /* 153 = remotename */ X+ #else REMOTEFS X 0, nosys, /* 151 = nosys */ X 0, nosys, /* 152 = nosys */ X 0, nosys, /* 153 = nosys */ X*************** X*** 272,277 X 0, nosys, /* 151 = nosys */ X 0, nosys, /* 152 = nosys */ X 0, nosys, /* 153 = nosys */ X 0, nosys, /* 154 = nosys */ X }; X int nsysent = sizeof (sysent) / sizeof (sysent[0]); X X--- 285,291 ----- X 0, nosys, /* 151 = nosys */ X 0, nosys, /* 152 = nosys */ X 0, nosys, /* 153 = nosys */ X+ #endif REMOTEFS X 0, nosys, /* 154 = nosys */ X }; X int nsysent = sizeof (sysent) / sizeof (sysent[0]); SHAREOF chmod 664 remote/usr.sys.VAX4.3/sys/init_sysent.c.diff
sources-request@panda.UUCP (01/09/86)
Mod.sources: Volume 3, Issue 82 Submitted by: tektronix!tekcrl!toddb #!/bin/sh # # RFS, a kernel-resident remote file system. Shar 6 of 7 # # # This is a shell archive, meaning: # 1. Remove everything above the #!/bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # remote/usr.sys.VAX4.3/sys/kern_exec.c.diff # remote/usr.sys.VAX4.3/sys/kern_exit.c.diff # remote/usr.sys.VAX4.3/sys/ufs_namei.c.diff # remote/usr.sys.VAX4.3/sys/ufs_syscalls.c.diff # remote/usr.sys.remote # remote/usr.sys.remote/remote_mkdata # remote/usr.sys.remote/remotefs.h # remote/usr.sys.remote/rmt_data_template # remote/usr.sys.remote/rmt_exec.c # remote/usr.sys.remote/rmt_final.c # remote/usr.sys.remote/rmt_syscall3.c # # remote/usr.sys.VAX4.3/sys/kern_exec.c.diff # if [ -f remote/usr.sys.VAX4.3/sys/kern_exec.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.3/sys/kern_exec.c.diff or ^C to quit' read ans rm -f remote/usr.sys.VAX4.3/sys/kern_exec.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.3/sys/kern_exec.c.diff XThe following changes implement local execution of an object file that Xlives on another host. X*************** X*** 27,32 X #include "acct.h" X #include "exec.h" X X #ifdef vax X #include "../vax/mtpr.h" X #endif X X--- 27,36 ----- X #include "acct.h" X #include "exec.h" X X+ #ifdef REMOTEFS X+ #include "../h/errno.h" X+ #endif REMOTEFS X+ X #ifdef vax X #include "../vax/mtpr.h" X #endif X*************** X*** 55,61 X int na, ne, ucp, ap, len, cc; X int indir, uid, gid; X char *sharg; X! struct inode *ip; X swblk_t bno; X char cfname[MAXCOMLEN + 1]; X #define SHSIZE 32 X X--- 59,70 ----- X int na, ne, ucp, ap, len, cc; X int indir, uid, gid; X char *sharg; X! #ifdef REMOTEFS X! struct inode *ip; /* have to take address */ X! int remote = -1; X! #else REMOTEFS X! register struct inode *ip; X! #endif REMOTEFS X swblk_t bno; X char cfname[MAXCOMLEN + 1]; X #define SHSIZE 32 X*************** X*** 71,76 X ndp->ni_segflg = UIO_USERSPACE; X ndp->ni_dirp = ((struct execa *)u.u_ap)->fname; X if ((ip = namei(ndp)) == NULL) X return; X bno = 0; X bp = 0; X X--- 80,91 ----- X ndp->ni_segflg = UIO_USERSPACE; X ndp->ni_dirp = ((struct execa *)u.u_ap)->fname; X if ((ip = namei(ndp)) == NULL) X+ #ifdef REMOTEFS X+ if (u.u_error == EISREMOTE) X+ remote = remote_execinfo(&ip, &uid, &gid, X+ &exdata, ((struct execa *)u.u_ap)->fname); X+ if (u.u_error) X+ #endif REMOTEFS X return; X bno = 0; X bp = 0; X*************** X*** 75,80 X bno = 0; X bp = 0; X indir = 0; X uid = u.u_uid; X gid = u.u_gid; X if (ip->i_mode & ISUID) X X--- 90,99 ----- X bno = 0; X bp = 0; X indir = 0; X+ X+ #ifdef REMOTEFS X+ if (remote < 0) { X+ #endif REMOTEFS X uid = u.u_uid; X gid = u.u_gid; X if (ip->i_mode & ISUID) X*************** X*** 112,117 X 0, 1, &resid); X if (u.u_error) X goto bad; X #ifndef lint X if (resid > sizeof(exdata) - sizeof(exdata.ex_exec) && X exdata.ex_shell[0] != '#') { X X--- 131,143 ----- X 0, 1, &resid); X if (u.u_error) X goto bad; X+ #ifdef REMOTEFS X+ } X+ X+ remote_again: X+ X+ #endif REMOTEFS X+ X #ifndef lint X if (resid > sizeof(exdata) - sizeof(exdata.ex_exec) && X exdata.ex_shell[0] != '#') { X*************** X*** 170,176 X bcopy((caddr_t)cp, (caddr_t)cfarg, SHSIZE); X } X indir = 1; X! iput(ip); X ndp->ni_nameiop = LOOKUP | FOLLOW; X ndp->ni_segflg = UIO_SYSSPACE; X ip = namei(ndp); X X--- 196,205 ----- X bcopy((caddr_t)cp, (caddr_t)cfarg, SHSIZE); X } X indir = 1; X! #ifdef REMOTEFS X! if (remote < 0) X! #endif REMOTEFS X! iput(ip); X ndp->ni_nameiop = LOOKUP | FOLLOW; X ndp->ni_segflg = UIO_SYSSPACE; X ip = namei(ndp); X*************** X*** 174,179 X ndp->ni_nameiop = LOOKUP | FOLLOW; X ndp->ni_segflg = UIO_SYSSPACE; X ip = namei(ndp); X if (ip == NULL) X return; X bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)cfname, X X--- 203,220 ----- X ndp->ni_nameiop = LOOKUP | FOLLOW; X ndp->ni_segflg = UIO_SYSSPACE; X ip = namei(ndp); X+ #ifdef REMOTEFS X+ if (ip == NULL) { X+ if (u.u_error == EISREMOTE) X+ remote = remote_execinfo(&ip, 0, 0, 0); X+ if (u.u_error) X+ return; X+ if (ip == NULL) X+ goto remote_again; X+ } X+ else X+ remote = -1; X+ #else REMOTEFS X if (ip == NULL) X return; X #endif REMOTEFS X*************** X*** 176,181 X ip = namei(ndp); X if (ip == NULL) X return; X bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)cfname, X MAXCOMLEN); X cfname[MAXCOMLEN] = '\0'; X X--- 217,223 ----- X #else REMOTEFS X if (ip == NULL) X return; X+ #endif REMOTEFS X bcopy((caddr_t)ndp->ni_dent.d_name, (caddr_t)cfname, X MAXCOMLEN); X cfname[MAXCOMLEN] = '\0'; X*************** X*** 268,274 X bdwrite(bp); X bp = 0; X nc = (nc + NBPW-1) & ~(NBPW-1); X! getxfile(ip, &exdata.ex_exec, nc + (na+4)*NBPW, uid, gid); X if (u.u_error) { X badarg: X for (cc = 0; cc < nc; cc += CLSIZE*NBPG) { X X--- 310,322 ----- X bdwrite(bp); X bp = 0; X nc = (nc + NBPW-1) & ~(NBPW-1); X! X! #ifdef REMOTEFS X! getxfile(ip, &exdata.ex_exec, nc + (na+4)*NBPW, uid, gid, remote); X! #else REMOTEFS X! getxfile(ip, &exdata.ex_exec, nc + (na+4)*NBPW, uid, gid); X! #endif REMOTEFS X! X if (u.u_error) { X badarg: X for (cc = 0; cc < nc; cc += CLSIZE*NBPG) { X*************** X*** 376,381 X /* X * Read in and set up memory for executed file. X */ X getxfile(ip, ep, nargc, uid, gid) X register struct inode *ip; X register struct exec *ep; X X--- 424,432 ----- X /* X * Read in and set up memory for executed file. X */ X+ #ifdef REMOTEFS X+ getxfile(ip, ep, nargc, uid, gid, remote) X+ #else REMOTEFS X getxfile(ip, ep, nargc, uid, gid) X #endif REMOTEFS X register struct inode *ip; X*************** X*** 377,382 X * Read in and set up memory for executed file. X */ X getxfile(ip, ep, nargc, uid, gid) X register struct inode *ip; X register struct exec *ep; X int nargc, uid, gid; X X--- 428,434 ----- X getxfile(ip, ep, nargc, uid, gid, remote) X #else REMOTEFS X getxfile(ip, ep, nargc, uid, gid) X+ #endif REMOTEFS X register struct inode *ip; X register struct exec *ep; X int nargc, uid, gid; X*************** X*** 383,388 X { X size_t ts, ds, ids, uds, ss; X int pagi; X X if (ep->a_magic == 0413) X pagi = SPAGI; X X--- 435,443 ----- X { X size_t ts, ds, ids, uds, ss; X int pagi; X+ #ifdef REMOTEFS X+ int oldtextsize; X+ #endif REMOTEFS X X if (ep->a_magic == 0413) X pagi = SPAGI; X*************** X*** 388,393 X pagi = SPAGI; X else X pagi = 0; X if (ip->i_flag & IXMOD) { /* XXX */ X u.u_error = ETXTBSY; X goto bad; X X--- 443,459 ----- X pagi = SPAGI; X else X pagi = 0; X+ #ifdef REMOTEFS X+ if (remote >= 0) { X+ /* X+ * Prevent xalloc() from making a shared or paged text. X+ */ X+ pagi = 0; X+ oldtextsize = ep->a_text; X+ ep->a_data += ep->a_text; X+ ep->a_text = 0; X+ } X+ #endif REMOTEFS X if (ip->i_flag & IXMOD) { /* XXX */ X u.u_error = ETXTBSY; X goto bad; X*************** X*** 452,457 X u.u_smap = u.u_csmap; X vgetvm(ts, ds, ss); X X if (pagi == 0) X u.u_error = X rdwri(UIO_READ, ip, X X--- 518,528 ----- X u.u_smap = u.u_csmap; X vgetvm(ts, ds, ss); X X+ #ifdef REMOTEFS X+ if (remote >= 0) X+ u.u_error = remote_execread(remote, oldtextsize, ep); X+ else X+ #endif REMOTEFS X if (pagi == 0) X u.u_error = X rdwri(UIO_READ, ip, SHAREOF chmod 664 remote/usr.sys.VAX4.3/sys/kern_exec.c.diff # # remote/usr.sys.VAX4.3/sys/kern_exit.c.diff # if [ -f remote/usr.sys.VAX4.3/sys/kern_exit.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.3/sys/kern_exit.c.diff or ^C to quit' read ans rm -f remote/usr.sys.VAX4.3/sys/kern_exit.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.3/sys/kern_exit.c.diff XThe following changes ensure that upon exit, a process notifies any remote Xservers that may know about him, that he is indeed dead. X*************** X*** 23,28 X #include "mbuf.h" X #include "inode.h" X #include "syslog.h" X X /* X * Exit system call: pass back caller's arg X X--- 23,31 ----- X #include "mbuf.h" X #include "inode.h" X #include "syslog.h" X+ #ifdef REMOTEFS X+ #include "../remote/remotefs.h" X+ #endif REMOTEFS X X /* X * Exit system call: pass back caller's arg X*************** X*** 56,61 X vmsizmon(); X #endif X p = u.u_procp; X p->p_flag &= ~(STRC|SULOCK); X p->p_flag |= SWEXIT; X p->p_sigignore = ~0; X X--- 59,71 ----- X vmsizmon(); X #endif X p = u.u_procp; X+ #ifdef REMOTEFS X+ /* X+ * First, release our server. X+ */ X+ if (p->p_flag & SREMOTE) X+ remote_exit(); X+ #endif REMOTEFS X p->p_flag &= ~(STRC|SULOCK); X p->p_flag |= SWEXIT; X p->p_sigignore = ~0; SHAREOF chmod 664 remote/usr.sys.VAX4.3/sys/kern_exit.c.diff # # remote/usr.sys.VAX4.3/sys/ufs_namei.c.diff # if [ -f remote/usr.sys.VAX4.3/sys/ufs_namei.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.3/sys/ufs_namei.c.diff or ^C to quit' read ans rm -f remote/usr.sys.VAX4.3/sys/ufs_namei.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.3/sys/ufs_namei.c.diff XThese changes are the primary hook into the operating system for detecting Xa "remote" file. X*************** X*** 149,154 X int isdotdot; /* != 0 if current name is ".." */ X int flag; /* op ie, LOOKUP, CREATE, or DELETE */ X off_t enduseful; /* pointer past last used dir slot */ X X lockparent = ndp->ni_nameiop & LOCKPARENT; X docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE; X X--- 149,157 ----- X int isdotdot; /* != 0 if current name is ".." */ X int flag; /* op ie, LOOKUP, CREATE, or DELETE */ X off_t enduseful; /* pointer past last used dir slot */ X+ #ifdef REMOTEFS X+ int remote; X+ #endif X X lockparent = ndp->ni_nameiop & LOCKPARENT; X docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE; X*************** X*** 202,207 X * Check accessiblity of directory. X */ X if ((dp->i_mode&IFMT) != IFDIR) { X u.u_error = ENOTDIR; X goto bad; X } X X--- 205,226 ----- X * Check accessiblity of directory. X */ X if ((dp->i_mode&IFMT) != IFDIR) { X+ #ifdef REMOTEFS X+ remote = isremote(dp, cp, nbp->b_un.b_addr); X+ /* X+ * If it is really local, then start again at the root. X+ */ X+ if (remote < 0) { X+ iput(dp); X+ dp = rootdir; X+ ILOCK(dp); X+ dp->i_count++; X+ fs = dp->i_fs; X+ cp = nbp->b_un.b_addr; X+ goto dirloop2; X+ } X+ else if (! remote) X+ #endif REMOTEFS X u.u_error = ENOTDIR; X goto bad; X } X*************** X*** 642,647 X u.u_error = EPERM; X goto bad; X } X } X } X nbp->av_forw = freenamebuf; X X--- 661,677 ----- X u.u_error = EPERM; X goto bad; X } X+ #ifdef REMOTEFS X+ /* X+ * don't allow anyone to remove a remote mount X+ * point. X+ */ X+ if (rmt_host(dp, &i)) { X+ iput(ndp->ni_pdir); X+ u.u_error = EBUSY; X+ goto bad; X+ } X+ #endif REMOTEFS X } X } X nbp->av_forw = freenamebuf; SHAREOF chmod 664 remote/usr.sys.VAX4.3/sys/ufs_namei.c.diff # # remote/usr.sys.VAX4.3/sys/ufs_syscalls.c.diff # if [ -f remote/usr.sys.VAX4.3/sys/ufs_syscalls.c.diff ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.VAX4.3/sys/ufs_syscalls.c.diff or ^C to quit' read ans rm -f remote/usr.sys.VAX4.3/sys/ufs_syscalls.c.diff fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.VAX4.3/sys/ufs_syscalls.c.diff XThese changes modify chdirec(), which is called by chroot() and chdir(), Xso that you can be allowed to do a chdir() to a remote mount point. XIn addition, the changes ensure that we adjust internal pointers when doing Xa chdir() OUT of a remote mount point. X X*************** X*** 51,56 X chdirec(ipp) X register struct inode **ipp; X { X register struct inode *ip; X struct a { X char *fname; X X--- 51,59 ----- X chdirec(ipp) X register struct inode **ipp; X { X+ #ifdef REMOTEFS X+ int i; X+ #endif REMOTEFS X register struct inode *ip; X struct a { X char *fname; X*************** X*** 64,69 X if (ip == NULL) X return; X if ((ip->i_mode&IFMT) != IFDIR) { X u.u_error = ENOTDIR; X goto bad; X } X X--- 67,77 ----- X if (ip == NULL) X return; X if ((ip->i_mode&IFMT) != IFDIR) { X+ #ifdef REMOTEFS X+ if (rmt_hostdir(ip, &i) != NULL) X+ u.u_error = remotechdir(i); X+ else X+ #endif REMOTEFS X u.u_error = ENOTDIR; X goto bad; X } X*************** X*** 69,74 X } X if (access(ip, IEXEC)) X goto bad; X IUNLOCK(ip); X if (*ipp) X irele(*ipp); X X--- 77,85 ----- X } X if (access(ip, IEXEC)) X goto bad; X+ #ifdef REMOTEFS X+ remotechdir(-1); X+ #endif REMOTEFS X IUNLOCK(ip); X if (*ipp) X irele(*ipp); SHAREOF chmod 664 remote/usr.sys.VAX4.3/sys/ufs_syscalls.c.diff # # remote/usr.sys.remote # mkdir remote/usr.sys.remote chmod 775 remote/usr.sys.remote # # remote/usr.sys.remote/remote_mkdata # if [ -f remote/usr.sys.remote/remote_mkdata ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.remote/remote_mkdata or ^C to quit' read ans rm -f remote/usr.sys.remote/remote_mkdata fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.remote/remote_mkdata X#!/bin/sh X# X# Copyright 1985, Todd Brunhoff. X# X# This software was written at Tektronix Computer Research Laboratories X# as partial fulfillment of a Master's degree at the University of Denver. X# This software is not Tektronix proprietary software and should not be X# confused with any software product sold by Tektronix. No warranty is X# expressed or implied on the reliability of this software; the author, X# the University of Denver, and Tektronix, inc. accept no liability for X# any damage done directly or indirectly by this software. This software X# may be copied, modified or used in any way, without fee, provided this X# comment remains an unaltered part of the software. X# X Xif [ ! -f "$1" ] Xthen X echo "Usage:" X echo " /lib/cpp -DKERNEL ... ..../init_sysent.c | $0 ..../remotefs.h" X exit 1 Xfi X XREMOTE=$1 X X# X# First, get the complete list of remote system calls and put them X# into memory for awk. X# XMEM=`sed -e '/^#define[ ]*RSYS_/!d' \ X -e 's/.*RSYS_\([^ ]*\) \([0-9]*\)$/mem[\2]="\1";last=\2;/' \ X < $REMOTE` X# X# Then, compile a list of all system calls from a cpp expanded listing X# of sys/init_sysent.c which should be on standard input. X# The only kludge here is that we must change internal names for system X# calls: X# internal changed X# name to X# ---------- ---------- X# rexit exit X# saccess access X# Xsed -e '1,/^struct[ ]*sysent[ ]*sysent[ ]*\[\]/d' \ X -e '/^};/,$d' \ X -e '/^#/d' \ X -e 's/ *[0-9], *//' \ X -e 's/,.*//' \ X -e 's/^rexit$/exit/' \ X -e 's/^saccess$/access/' \ X -e '/^[ ]*$/d' \ X| tail +2 \ X| cat -n \ X| awk ' XBEGIN { X '"$MEM"' X syscall = 0; X column = 0; X printf "u_char\tremote_sysmap[] = {\n" X} X{ X while (syscall < $1) { X if (column % 2 == 0) X printf "\t" X printf "%-31s", "RSYS_nosys," X if (column % 2 == 1) X printf "\n" X syscall++ X column++ X } X X if (column % 2 == 0) X printf "\t" X len = length($2); X found = 0; X for (i=0; i <= last; i++) { X if (mem[ i ] == $2) { X found = 1; X break; X } X } X if (found) { X printf "RSYS_%s,", $2 X len = 25-len; X } X else { X printf "RSYS_nosys, /* %s */", $2 X len = 12 - len; X } X if (column % 2 == 1) X printf "\n" X else X while (len-- > 0) X printf " " X column++; X syscall++ X} END { X if (column % 2 == 0) X printf "\n" X printf "};\n" X}' SHAREOF chmod 664 remote/usr.sys.remote/remote_mkdata # # remote/usr.sys.remote/remotefs.h # if [ -f remote/usr.sys.remote/remotefs.h ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.remote/remotefs.h or ^C to quit' read ans rm -f remote/usr.sys.remote/remotefs.h fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.remote/remotefs.h X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Header: remotefs.h,v 2.1 86/01/05 18:17:01 toddb Exp $ X * X * $Log: remotefs.h,v $ X * Revision 2.1 86/01/05 18:17:01 toddb X * Added ifdef'ed constants for pyramids: FREMOTE, SREMOTE and SNOREMOTE. X * X * Revision 2.0 85/12/07 18:17:35 toddb X * First public release. X * X */ X#ifndef RFSDEBUG X#define debug0() X#define debug1() X#define debug2() X#define debug3() X#define debug4() X#define debug5() X#define debug6() X#define debug7() X#define debug8() X#define debug9() X#define debug10() X#define debug11() X#define debug12() X#define debug13() X#define debug14() X#define rmt_showmsg() X#else RFSDEBUG X/* X * Each of the debugging macros are defined here. With this scheme we X * are able to turn on any portion of the debugging with very little overhead X * This appears to be better than similar schemes that test if X * remote_debug <= some-level, because they force the software into having X * more and more debug software run as the number gets higher. X */ Xextern long remote_debug; X X#define debug0 (!(remote_debug&0x00001)) ? 0:rmt_debug /* exec info */ X#define debug1 (!(remote_debug&0x00002)) ? 0:rmt_debug /* startup activity */ X#define debug2 (!(remote_debug&0x00004)) ? 0:rmt_debug /* rmt_copypath() */ X#define debug3 (!(remote_debug&0x00008)) ? 0:rmt_debug /* unused */ X#define debug4 (!(remote_debug&0x00010)) ? 0:rmt_debug /* remote_fork */ X#define debug5 (!(remote_debug&0x00020)) ? 0:rmt_debug /* remote[on|off] */ X#define debug6 (!(remote_debug&0x00040)) ? 0:rmt_debug /* file descriptors */ X#define debug7 (!(remote_debug&0x00080)) ? 0:rmt_debug /* isremote() */ X#define debug8 (!(remote_debug&0x00100)) ? 0:rmt_debug /* file remoteness */ X#define debug9 (!(remote_debug&0x00200)) ? 0:rmt_debug /* connection startup */ X#define debug10 (!(remote_debug&0x00400)) ? 0:rmt_debug /* msg setup */ X#define debug11 (!(remote_debug&0x00800)) ? 0:rmt_debug /* msg exceptions */ X#define debug12 (!(remote_debug&0x01000)) ? 0:rmt_debug /* shutdowns */ X#define debug13 (!(remote_debug&0x02000)) ? 0:rmt_debug /* path translation */ X#define debug14 (!(remote_debug&0x04000)) ? 0:rmt_debug /* chdir() activity */ X#define debug15 (!(remote_debug&0x08000)) ? 0:rmt_debug /* msg content */ X#define debug16 (!(remote_debug&0x10000)) ? 0:rmt_debug /* msg data content */ X#define debug17 (!(remote_debug&0x20000)) ? 0:rmt_debug /* unused */ X#define debug18 (!(remote_debug&0x40000)) ? 0:rmt_debug /* unused */ X#define debug19 (!(remote_debug&0x80000)) ? 0:rmt_debug /* unused */ X X#endif RFSDEBUG X X/* X * Flags for file structures and proc structures. These should really be X * in file.h and proc.h, but are here for now. Note that you must have X * the fix in ino_close() if DTYPE_REMOTE is defined as 3. X */ X#define DTYPE_REMOTE 3 /* file.h: remote file descriptor */ X#ifdef pyr X#define SREMOTE 0x00080000 /* proc.h: activity has occured */ X#define SNOREMOTE 0x80000000 /* proc.h: disallow remote access */ X#define FREMOTE 04000 /* file.h: this is a remote file */ X#endif pyr X#if vax || magnolia || P4400 X#define SREMOTE 0x08000000 /* proc.h: activity has occured */ X#define SNOREMOTE 0x10000000 /* proc.h: disallow remote access */ X#define FREMOTE 08000 /* file.h: this is a remote file */ X#endif vax || magnolia || P4400 X X/* X * Defines for the name server. X */ X#define server_alive(p) \ X ((p) \ X && (p)->p_stat != NULL \ X && remote_ns.rn_pid == (p)->p_pid) X X#define NM_SERVER 0 /* register as name server */ X#define NM_WHATNAME 1 /* what name does the kernel need? */ X#define NM_NAMEIS 2 /* the name is... */ X#define NM_DEBUG 3 /* turn on debugging */ X X/* X * Some manifest constants. X */ X#define TRUE 1 X#define FALSE 0 X#define REMOTE_FS_SERVER "remotefs" X#define R_MAXSYS NREMOTE /* defined in param.h */ X#define R_MNTPATHLEN 30 X#define R_MAXMSG ((MAXPATHLEN * 2) + MLEN) X#define R_RETRY (60*5) /* retry time for connections */ X X/* X * State of the data being sent. X */ X#define R_NOTHINGSENT 1 X#define R_DATANOTSENT 2 X#define R_MSGNOTRED 3 X#define R_DATANOTRED 4 X X/* X * internal flags passed to rmt_msgfin() and rmt_datafin(). X */ X#define RFLG_DATAV 0x1 /* data to remotemsg() is a vector */ X#define RFLG_RD 0x2 /* data to remotemsg() to be read */ X#define RFLG_WR 0x4 /* data to remotemsg() to be written */ X#define RFLG_INFO 0x8 /* send message only (don't receive */ X X/* X * known indices of data in the message. X */ X#define R_PATHOFF 3 /* to server (Offset to 2nd path) */ X#define R_PATHSTART 4 /* to server start of actual path */ X#define R_DATA 2 /* to server */ X#define R_RETVAL 0 /* from server */ X#define R_EXECUID 1 /* from server (exec setuid) */ X#define R_EXECGID 2 /* from server (exec setgid) */ X#define R_EXECREADONLY 3 /* from server (exec text read-only) */ X#define R_EXECDATA 4 /* from server (start of exec info) */ X X/* X * Maximum size for the message arg data in long words. NOT LONGWORDS!! This X * should be the largest of the following three sizes among all machines X * that will use the remote file system: X * X * sizeof(struct exec) * sizeof(long) + R_EXECDATA * sizeof(long) X * (# of stat struct members + 1) * sizeof(long) X */ X#define R_MAXARGS 18 X X/* X * Maximum and minimum message length in bytes that we will ever need on a X * receive (big enough for a stat(), lstat() or fstat(), and small enough for X * a return with no other values. X */ X#define R_MINRMSG (sizeof(struct message)-R_MAXARGS*sizeof(long)) X#define R_MAXRMSG (sizeof(struct message)) X X/* X * The maximum number of mbufs that we need to send a message with X * two paths, each 1024 characters long. This is used only in the user X * level implementation. X */ X#define R_MAXMBUFS (R_MINRMSG+(MAXPATHLEN*2))/MLEN X X/* X * Here, we describe incomming and outgoing messages. Note that the number X * of cells in m_args is only for incomming messages. An outgoing message X * may consume much more. X */ Xstruct message { X long m_totlen; /* length of total message (including data) */ X short m_uid; /* uid of client */ X short m_pid; /* pid of client */ X short m_hdlen; /* length of header (excluding data) */ X short m_syscall; /* syscall number */ X#define m_errno m_syscall /* errno (for server) */ X long m_args[R_MAXARGS];/* remaining arguments or return values */ X}; X X/* X * This structure describes the kernel information kept for each X * connection to a remote server. X */ Xstruct remoteinfo { X char r_mntpath[ R_MNTPATHLEN ]; /* path of mount point */ X u_char r_close:1; /* True if connection to be closed */ X u_char r_received:1; /* True if an incomming msg in r_msg */ X u_char r_failed:1; /* connection failed */ X u_char r_opening:1; /* connection in process of opening */ X u_char r_refcnt; /* a reference count of active use */ X short r_sender; /* owner of outgoing data */ X short r_recver; /* owner of incomming data */ X u_short r_users; /* count of users using this */ X u_short r_nfile; /* count of open files */ X u_short r_nchdir; /* count of chdir() to this host */ X struct mbuf *r_name; /* socket address of remote host */ X struct inode *r_mntpt; /* inode of mount point */ X /* if null, then global */ X struct socket *r_sock; /* socket with active connection */ X#define r_age r_msg.m_totlen /* used for cacheing name lookups */ X#define r_openerr r_msg.m_errno /* used to relay connection errors */ X struct message r_msg; /* incomming message */ X}; X Xtypedef int (*func)(); X X/* X * This describes all info associated with each syscall. Note that while X * the flag information is available, most syscalls don't reference it X * because they have the flag hard coded in-line. It exists for the X * sake of routines like read and write which cannot hard code the flags X * very easily. The follow flag is useful only for system calls that involve X * pathnames. The before entry is to tell syscall whether to try to X * call the remote syscall routine before calling the real system call. X * The size here make each table entry a X * power of 2 in size (16 bytes) which the compiler can make faster code for. X */ Xstruct syscalls { X func sys_gen; X func sys_spec; X long sys_flag; X short sys_follow; X short sys_before; X}; Xtypedef struct syscalls syscalls; X X/* X * This structure simply describes the process willing to act as a X * name server for the remote file system, and the information passing X * to and from it. X */ Xstruct nameserver { X struct proc *rn_proc; /* process registered as nameserver */ X struct mbuf *rn_name; /* input from name server */ X char *rn_path; /* path to translate */ X short rn_pathlen; /* length of path to translate */ X short rn_pid; /* pid of process (for uniqueness) */ X}; X X/* X * System calls X * Note that these have nothing to do with either the vax or magnolia idea X * of the system calls. They are simply an index into the systems calls X * that we are concerned with. X */ X#define RSYS_fork 0 X#define RSYS_read 1 X#define RSYS_write 2 X#define RSYS_open 3 X#define RSYS_close 4 X#define RSYS_creat 5 X#define RSYS_link 6 X#define RSYS_unlink 7 X#define RSYS_chdir 8 X#define RSYS_mknod 9 X#define RSYS_chmod 10 X#define RSYS_chown 11 X#define RSYS_stat 12 X#define RSYS_lseek 13 X#define RSYS_access 14 X#define RSYS_lstat 15 X#define RSYS_dup 16 X#define RSYS_ioctl 17 X#define RSYS_symlink 18 X#define RSYS_readlink 19 X#define RSYS_fstat 20 X#define RSYS_dup2 21 X#define RSYS_fcntl 22 X#define RSYS_fsync 23 X#define RSYS_readv 24 X#define RSYS_writev 25 X#define RSYS_fchown 26 X#define RSYS_fchmod 27 X#define RSYS_rename 28 X#define RSYS_truncate 29 X#define RSYS_ftruncate 30 X#define RSYS_flock 31 X#define RSYS_mkdir 32 X#define RSYS_rmdir 33 X#define RSYS_utimes 34 X#define RSYS_exit 35 X#define RSYS_vfork 36 X#define RSYS_execinfo 37 X#define RSYS_execread 38 X#define RSYS_execve 39 X#define RSYS_nosys 40 X#define RSYS_qlseek 41 X X/* X * This macro fills in some of the information needed on every transfer X * and returns the byte (not longword) offset of the next free byte. X */ X#define introduce(buf, sysnum) \ X ((buf)->m_pid = htons(u.u_procp->p_pid),\ X (buf)->m_uid = htons(u.u_uid), \ X (buf)->m_syscall = htons(sysnum), \ X (R_MINRMSG)) X#define introduce_1extra(buf, sysnum, x1) \ X ((buf)->m_pid = htons(u.u_procp->p_pid),\ X (buf)->m_uid = htons(u.u_uid), \ X (buf)->m_syscall = htons(sysnum), \ X (buf)->m_args[0] = htonl(x1), \ X (R_MINRMSG + sizeof(long))) X#define introduce_2extra(buf, sysnum, x1, x2) \ X ((buf)->m_pid = htons(u.u_procp->p_pid),\ X (buf)->m_uid = htons(u.u_uid), \ X (buf)->m_syscall = htons(sysnum), \ X (buf)->m_args[0] = htonl(x1), \ X (buf)->m_args[1] = htonl(x2), \ X (R_MINRMSG + 2*sizeof(long))) X/* X * This macro defines whether a host is being used or not. X * The rmtclearhosts() and rmtcopyhosts() are for expansion if someone X * wants to use more than 32 hosts. X */ X#define rmthostused(rsys) (u.u_rmtsys & (1<<rsys)) X#define rmtusehost(rsys) (u.u_rmtsys |= (1<<rsys)) X#define rmtunusehost(rsys) (u.u_rmtsys &= ~(1<<rsys)) X#define rmtclearhosts() (u.u_rmtsys = 0) X#define rmtcopyhosts(dest,hosts) (dest = hosts) X X#ifdef pyr X/* X * Pyramid changed the name on ctob and btoc X **/ X#define ctob(x) ptob(x) X#define btoc(x) btop(x) X#endif SHAREOF chmod 444 remote/usr.sys.remote/remotefs.h # # remote/usr.sys.remote/rmt_data_template # if [ -f remote/usr.sys.remote/rmt_data_template ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.remote/rmt_data_template or ^C to quit' read ans rm -f remote/usr.sys.remote/rmt_data_template fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.remote/rmt_data_template X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Header: rmt_data_template,v 2.0 85/12/07 18:19:42 toddb Rel $ X * X * $Log: rmt_data_template,v $ X * Revision 2.0 85/12/07 18:19:42 toddb X * First public release. X * X */ X#include "../h/errno.h" X#include "../h/param.h" X#include "../h/mbuf.h" X#include "../h/socket.h" X#include "../remote/remotefs.h" X X Xextern int X rmt_access(), X rmt_chdir(), X rmt_chmod(), X rmt_chown(), X rmt_dup(), X rmt_dup2(), X rmt_error(), X remote_exit(), X rmt_fcntl(), X rmt_flock(), X remote_fork(), X rmt_fsync(), X rmt_ioctl(), X rmt_lseek(), X rmt_mknod(), X rmt_noop(), X rmt_onearg(), X rmt_open(), X rmt_readlink(), X rmt_stat(), X rmt_truncate(), X rmt_utimes(), X rmt_execinfo(), X rmt_execread(), X rmt_execve(), X remote_fd(), X remote_path1(), X remote_path2(), X rmt_datafin(); X X/* X * This table depends on the order of system calls as defined in X * sys/sys/init_sysent.c, and our local map in remote_sysmap, which X * is generated (and appended to this file) by the program mkdata. X * The latter is a table of indices into remote_syscall[]. X * Remote_syscall[] is a table containing general and specific actions X * for each system call, whether to follow symbolic links in namei and X * flags that are passed to rmt_msgfin() and rmt_datafin(). X */ X Xsyscalls remote_syscall[] = { X/* X * general specific flags to follow call before X * rmt_fin() symlinks real syscall X */ X{ remote_fork, rmt_noop, RFLG_INFO, FALSE, TRUE }, /* RSYS_fork */ X{ remote_fd, rmt_datafin, RFLG_RD, FALSE, TRUE }, /* RSYS_read */ X{ remote_fd, rmt_datafin, RFLG_WR, FALSE, TRUE }, /* RSYS_write */ X{ remote_path1, rmt_open, 0, TRUE, FALSE }, /* RSYS_open */ X{ remote_fd, rmt_onearg, RFLG_INFO, FALSE, TRUE }, /* RSYS_close */ X{ remote_path1, rmt_open, 0, TRUE, FALSE }, /* RSYS_creat */ X{ remote_path2, rmt_noop, 0, FALSE, FALSE }, /* RSYS_link */ X{ remote_path1, rmt_onearg, 0, FALSE, FALSE }, /* RSYS_unlink */ X{ remote_path1, rmt_chdir, 0, TRUE, FALSE }, /* RSYS_chdir */ X{ remote_path1, rmt_mknod, 0, FALSE, FALSE }, /* RSYS_mknod */ X{ remote_path1, rmt_chmod, 0, TRUE, FALSE }, /* RSYS_chmod */ X{ remote_path1, rmt_chown, 0, FALSE, FALSE }, /* RSYS_chown */ X{ remote_path1, rmt_stat, 0, TRUE, FALSE }, /* RSYS_stat */ X{ remote_fd, rmt_lseek, 0, FALSE, TRUE }, /* RSYS_lseek */ X{ remote_path1, rmt_access, 0, FALSE, FALSE }, /* RSYS_lstat */ X{ remote_path1, rmt_stat, 0, TRUE, FALSE }, /* RSYS_access */ X{ remote_fd, rmt_dup, 0, FALSE, TRUE }, /* RSYS_dup */ X{ remote_fd, rmt_ioctl, 0, FALSE, TRUE }, /* RSYS_ioctl */ X{ remote_path2, rmt_noop, 0, TRUE, FALSE }, /* RSYS_symlink */ X{ remote_path1, rmt_readlink, RFLG_RD, FALSE, FALSE }, /* RSYS_readlink */ X{ remote_fd, rmt_stat, 0, FALSE, TRUE }, /* RSYS_fstat */ X{ remote_fd, rmt_dup2, 0, FALSE, TRUE }, /* RSYS_dup2 */ X{ remote_fd, rmt_fcntl, 0, FALSE, TRUE }, /* RSYS_fcntl */ X{ remote_fd, rmt_onearg, RFLG_INFO, FALSE, TRUE }, /* RSYS_fsync */ X{ remote_fd, rmt_datafin, RFLG_RD|RFLG_DATAV, X FALSE, TRUE },/* RSYS_readv */ X{ remote_fd, rmt_datafin, RFLG_WR|RFLG_DATAV, X FALSE, TRUE },/* RSYS_writev */ X{ remote_fd, rmt_chown, 0, FALSE, TRUE }, /* RSYS_fchown */ X{ remote_fd, rmt_chmod, 0, FALSE, TRUE }, /* RSYS_fchmod */ X{ remote_path2, rmt_noop, 0, TRUE, FALSE }, /* RSYS_rename */ X{ remote_path1, rmt_truncate, 0, TRUE, FALSE }, /* RSYS_truncate */ X{ remote_fd, rmt_truncate, 0, FALSE, TRUE }, /* RSYS_ftruncate */ X{ remote_fd, rmt_flock, 0, FALSE, TRUE }, /* RSYS_flock */ X{ remote_path1, rmt_mknod, 0, FALSE, FALSE }, /* RSYS_mkdir */ X{ remote_path1, rmt_onearg, 0, FALSE, FALSE }, /* RSYS_rmdir */ X{ remote_path1, rmt_noop, 0, TRUE, FALSE }, /* RSYS_utimes */ X{ remote_exit, rmt_noop, RFLG_INFO,FALSE, TRUE }, /* RSYS_exit */ X{ remote_fork, rmt_noop, RFLG_INFO, FALSE, TRUE }, /* RSYS_vfork */ X{ remote_path1, rmt_execinfo, 0, TRUE, FALSE }, /* RSYS_execinfo */ X{ rmt_error, rmt_noop, 0, FALSE, FALSE }, /* RSYS_execread */ X{ remote_path1, rmt_error, 0, TRUE, FALSE }, /* RSYS_execve */ X{ rmt_error, rmt_noop, 0, FALSE, FALSE }, /* RSYS_nosys */ X{ rmt_error, rmt_noop, 0, FALSE, FALSE }, /* RSYS_qlseek */ X}; X Xstruct remoteinfo remote_info[ R_MAXSYS ]; Xstruct remoteinfo *remote_generic; Xlong remote_debug; Xlong remote_sysindex; Xlong remote_maxchunk = (1024*10); Xstruct mbuf *remote_path; Xstruct nameserver remote_ns; X X/* X * The following list maps all of the actual system call numbers into our X * idea of the system call numbers. THIS IS GENERATED AUTOMATICALLY... X * DO NOT MODIFY! X */ SHAREOF chmod 444 remote/usr.sys.remote/rmt_data_template # # remote/usr.sys.remote/rmt_exec.c # if [ -f remote/usr.sys.remote/rmt_exec.c ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.remote/rmt_exec.c or ^C to quit' read ans rm -f remote/usr.sys.remote/rmt_exec.c fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.remote/rmt_exec.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Header: rmt_exec.c,v 2.1 85/12/30 16:45:30 toddb Exp $ X * X * $Log: rmt_exec.c,v $ X * Revision 2.1 85/12/30 16:45:30 toddb X * fixed syntax error for 4.3. X * X * Revision 2.0 85/12/07 18:17:54 toddb X * First public release. X * X */ X#ifndef pyr /* Pyramid */ X#include "../machine/reg.h" X#include "../machine/pte.h" X#include "../machine/psl.h" X#endif X X#include "../h/param.h" X#include "../h/systm.h" X#include "../h/map.h" X#include "../h/dir.h" X#include "../h/user.h" X#include "../h/kernel.h" X#include "../h/proc.h" X#include "../h/file.h" X#include "../h/uio.h" X#include "../remote/remotefs.h" X#include "../h/mbuf.h" X#include "../netinet/in.h" X#include "../h/vm.h" X#include "../h/errno.h" X#ifdef BSD4_3 X#include "../h/namei.h" X#include "../h/exec.h" X#else BSD4_3 X#include "../h/nami.h" X#endif BSD4_3 X X#ifdef vax X#include "../vax/mtpr.h" X#endif X Xextern struct remoteinfo remote_info[]; Xextern long remote_sysindex; Xextern long remote_maxchunk; X X#ifdef magnolia X#define DEMAND_PAGED 0513 X#define SHARED_TEXT 0510 X#else magnolia X#define DEMAND_PAGED 0413 X#define SHARED_TEXT 0410 X#endif magnolia X X/* X * Get execution info for a file that is on a remote system. At this point X * we know that the file is remote. We must send one request to get the X * header and then if all is ok, we will be asked for the file to be sent over X * en-masse. X */ X#ifdef BSD4_3 Xremote_execinfo(ip, auid, agid, pexdata, fname) X struct exec *pexdata; X#else BSD4_3 Xremote_execinfo(ip, auid, agid, fname) X#endif BSD4_3 X register struct inode **ip; X long *auid, *agid; X register char *fname; X{ X long error, X sysindex = remote_sysindex, X uid, gid, X hdrsize, X execsize; X struct inode *namei(); X struct remoteinfo *rp = remote_info + remote_sysindex; X struct message *msg; X X u.u_error = 0; X error = remote_path1(RSYS_execinfo); X if (error) { X /* X * Try again if its a local file. X */ X if (error < 0 && fname) { X#ifdef BSD4_3 X struct nameidata *ndp = &u.u_nd; X X ndp->ni_dirp = (caddr_t) fname; X if ((*ip = namei(ndp)) == NULL) X#else BSD4_3 X u.u_dirp = (caddr_t) fname; X if ((*ip = namei(uchar, LOOKUP, 1)) == NULL) X#endif BSD4_3 X if (u.u_error == 0 || u.u_error == EISREMOTE) X u.u_error = ELOOP; X return(remote_sysindex); X } X else if (error < 0) X error = ENOENT; X u.u_error = error; X return(-1); X } X /* X * The R_RETVAL cell contains the total size of the file. So that X * had better be >= the size of the header + size of text + size X * of data. X */ X msg = &rp->r_msg; X#ifdef BSD4_3 X bcopy(msg->m_args+R_EXECDATA, X (caddr_t)pexdata, sizeof(struct exec)); X if (pexdata->a_magic == DEMAND_PAGED) X hdrsize = CLBYTES; X else X hdrsize = sizeof(sizeof(struct exec)); X#else BSD4_3 X bcopy(msg->m_args+R_EXECDATA, X (caddr_t)&u.u_exdata, sizeof (u.u_exdata)); X if (u.u_exdata.ux_mag == DEMAND_PAGED) X hdrsize = CLBYTES; X else X hdrsize = sizeof(u.u_exdata.Ux_A); X#endif BSD4_3 X X execsize = ntohl(msg->m_args[ R_RETVAL ]); X debug0("obj=%d,hrd=%d,error=%d,tx=%d,dat=%d\n", X execsize, hdrsize, u.u_error, X#ifdef BSD4_3 X pexdata->a_text, pexdata->a_text X#else BSD4_3 X u.u_exdata.ux_tsize, u.u_exdata.ux_dsize X#endif BSD4_3 X ); X X#ifdef BSD4_3 X if (pexdata->a_text + pexdata->a_data + hdrsize > execsize X && *((char *)pexdata) != '#') { X error = ENOEXEC; X goto bad; X } X#else BSD4_3 X if (u.u_exdata.ux_tsize + u.u_exdata.ux_dsize + hdrsize > execsize X && u.u_exdata.ux_shell[0] != '#') { X error = ENOEXEC; X goto bad; X } X#endif BSD4_3 X X if ((u.u_procp->p_flag&STRC) && msg->m_args[ R_EXECREADONLY ]) { X error = EACCES; X goto bad; X } X if (auid) { /* first time thru for this exec... set uid/gid stuff */ X uid = ntohl(msg->m_args[ R_EXECUID ]); X if (uid < 0) X uid = u.u_uid; X gid = ntohl(msg->m_args[ R_EXECGID ]); X if (gid < 0) X gid = u.u_gid; X *auid = uid; X *agid = gid; X } X return(sysindex); X Xbad: X u.u_error = error; X return(-1); X} X X/* X * This is the simple routine that is called by remote_path1 as the X * specific routine for handling RSYS_execinfo. remote_execinfo() is X * called from exec, and remote_execinfo() calls remote_path1() who in X * turn calls rmt_execinfo(). X */ Xrmt_execinfo(sysindex, m) X long sysindex; X struct mbuf *m; X{ X struct message *msg = mtod(m, struct message *); X#ifdef BSD4_3 X msg->m_args[0] = htonl(sizeof (struct exec)); X#else BSD4_3 X msg->m_args[0] = htonl(sizeof (u.u_exdata)); X#endif BSD4_3 X return (rmt_msgfin(sysindex, m, 0)); X} X X/* X * Read into memory an executable file from a remote system. X */ X#ifdef BSD4_3 Xremote_execread(sysindex, oldtextsize, ep) X register struct exec *ep; X register int sysindex, oldtextsize; X#else BSD4_3 Xremote_execread(sysindex, oldtextsize) X register int sysindex, oldtextsize; X#endif BSD4_3 X{ X struct remoteinfo *rp = remote_info + sysindex; X struct uio auio; X struct iovec aiov[2]; X struct mbuf *m; X struct message *msg; X register long hdrsize, datasize, textsize, error, len, magic; X register struct proc *p = u.u_procp; X long iovlen; X X#ifdef BSD4_3 X datasize = (int)ep->a_data; X magic = ep->a_magic; X#define HEADERSIZE sizeof(struct exec); X#else BSD4_3 X datasize = (int)u.u_exdata.ux_dsize; X magic = u.u_exdata.ux_mag; X#define HEADERSIZE sizeof(u.u_exdata.Ux_A); X#endif BSD4_3 X if (datasize <= 0) { X u.u_error = ENOEXEC; X return(-1); X } X X /* X * We are guarenteed that at this point the text size is zero. X * But we know what the old text size was passed along for the sake of X * shared-text programs: the binaries for these do not X * necessarily have the data page-aligned in the file (as we X * assume that demand-paged programs do), but instead, X * it is aligned when it is read in. We must do the same here. X */ X if (oldtextsize && magic == SHARED_TEXT) { X aiov[0].iov_len = oldtextsize; X aiov[1].iov_len = datasize - oldtextsize; X iovlen = 2; X aiov[0].iov_base = (char *)ctob(tptov(p, 0)); X aiov[1].iov_base = (char *)ctob(btoc(oldtextsize)); X debug0("execrd: %d @ %x, %d @ %x ", X aiov[0].iov_len, aiov[0].iov_base, X aiov[1].iov_len, aiov[1].iov_base); X } X else { X iovlen = 1; X aiov[0].iov_base = (char *)ctob(dptov(p, 0)), X aiov[0].iov_len = datasize; X debug0("execrd: %d @ %x ", aiov[0].iov_len, aiov[0].iov_base); X } X auio.uio_offset = 0; X auio.uio_segflg = 0; X if (magic == DEMAND_PAGED) X hdrsize = CLBYTES; X else X hdrsize = HEADERSIZE; X X /* X * Now ask for it in remote_maxchunk size chunks. X */ X debug0("hdsz=%d, datasz=%d, rd ", hdrsize, datasize); X error = 0; X while (datasize >= 0) { X auio.uio_resid = MIN(datasize, remote_maxchunk); X if (auio.uio_resid == 0) X datasize = -1; X else { X if (aiov[0].iov_len <= 0 && iovlen == 2) { X aiov[0] = aiov[1]; X iovlen = 1; X } X auio.uio_iov = aiov; X auio.uio_iovcnt = iovlen; X datasize -= auio.uio_resid; X } X MGET(m, M_WAIT, MT_DATA); X if (m == NULL) X return(ENOBUFS); X msg = mtod(m, struct message *); X len = introduce_2extra(msg, RSYS_execread, hdrsize, X auio.uio_resid); X m->m_len = len; X msg->m_hdlen = htons(len); X msg->m_totlen = htonl(len); X#ifdef RFSDEBUG X if (auio.uio_resid) { X debug0("\n %d: %d@%d", auio.uio_resid, X aiov[0].iov_len, aiov[0].iov_base); X if (iovlen == 2) X debug0(",%d@%d.", X aiov[1].iov_len, aiov[1].iov_base); X } X rmt_showmsg(msg, FALSE); X#endif RFSDEBUG X if (datasize >= 0) X error = remoteio(sysindex, &m, &auio, RFLG_RD); X else X remoteio(sysindex, &m, 0, RFLG_INFO); X#ifdef RFSDEBUG X msg = &rp->r_msg; X rmt_showmsg(msg, TRUE); X#endif RFSDEBUG X /* X * If there are any errors, simply send the last X * message: we're all done. X */ X if (error && datasize >= 0) X datasize = 0; X else if (error) X return(error); X } X X debug0("\n"); X return ( error ); X} SHAREOF chmod 444 remote/usr.sys.remote/rmt_exec.c # # remote/usr.sys.remote/rmt_final.c # if [ -f remote/usr.sys.remote/rmt_final.c ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.remote/rmt_final.c or ^C to quit' read ans rm -f remote/usr.sys.remote/rmt_final.c fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.remote/rmt_final.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Header: rmt_final.c,v 2.1 85/12/30 16:51:01 toddb Exp $ X * X * $Log: rmt_final.c,v $ X * Revision 2.1 85/12/30 16:51:01 toddb X * Made rmt_copypath() compatible between 4.2 and 4.3 by adding a c-version X * of copystr() and copyinstr() for 4.2 versions (copystr() and copyinstr() X * are assembler routines in 4.3). X * X * Revision 2.0 85/12/07 18:20:12 toddb X * First public release. X * X */ X#include "../h/param.h" X#ifndef pyr /* Pyramid */ X#include "../machine/pte.h" X#endif X#include "../h/systm.h" X#include "../h/map.h" X#include "../h/dir.h" X#include "../h/user.h" X#include "../h/kernel.h" X#include "../h/proc.h" X#include "../h/mbuf.h" X#include "../h/socket.h" X#include "../h/file.h" X#include "../remote/remotefs.h" X#include "../h/errno.h" X#include "../netinet/in.h" X#include "../h/uio.h" X Xextern struct remoteinfo remote_info[]; X X/* X * rmt_msgfin() finalizes the message by adding in the header and total X * lengths and sending the message. It returns the return value found in the X * reply. X */ Xrmt_msgfin(sysindex, m, flags) X long sysindex, flags; X struct mbuf *m; X{ X long error, len; X struct message *msg = mtod(m, struct message *); X struct remoteinfo *rp = remote_info + sysindex; X X /* X * If the length has been set (by remote_path[12]), then don't X * meddle, otherwise assign it. X */ X if (msg->m_hdlen == 0) X len = m->m_len; X else X len = msg->m_hdlen; X msg->m_hdlen = htons(len); X msg->m_totlen = htonl(len); X X rmt_showmsg(msg, FALSE); X error = remoteio(sysindex, &m, 0, flags); X X if (! error) { X if ((flags & RFLG_INFO) == 0) { X msg = &rp->r_msg; X rmt_showmsg(msg, TRUE); X if ((error = msg->m_errno) == 0) X u.u_r.r_val1 = msg->m_args[R_RETVAL]; X } X else X u.u_r.r_val1 = 0; X } X return ( error ); X} X X/* X * rmt_datafin() finalizes a message and fixes up the header and total X * lengths (like rmt_msgfin()) and sends a message plus data. It returns X * the return value found in the reply. X */ Xrmt_datafin(sysindex, m, flags) X long sysindex, flags; X struct mbuf *m; X{ X register long i, error, len; X struct message *msg = mtod(m, struct message *); X short syscall = ntohs(msg->m_syscall); X struct remoteinfo *rp = remote_info + sysindex; X struct uio auio, *uio; X struct iovec aiov[16], *iov = aiov; X struct a { X long fd; X char *databuf; X long datalen; X } *uap = (struct a *)u.u_ap; X X /* X * Package up the data. X * If the length has been set (by remote_path1 for readlink), X * then don't meddle, otherwise assign it the length of the first X * (and only) mbuf. X */ X if (msg->m_hdlen == 0) X msg->m_hdlen = htons(len = m->m_len); X else X msg->m_hdlen = htons(len = msg->m_hdlen); X if (flags & (RFLG_RD | RFLG_WR)) { X uio = &auio; X uio->uio_iov = iov; X uio->uio_segflg = 0; X uio->uio_offset = 0; X if (flags & RFLG_DATAV) { X uio->uio_iovcnt = uap->datalen; X error = copyin((caddr_t)uap->databuf, (caddr_t)iov, X (unsigned)(uap->datalen * sizeof (struct iovec))); X if (error) X goto done; X uio->uio_resid = 0; X for (i = 0; i < uio->uio_iovcnt; i++) { X if (iov->iov_len < 0) { X error = EINVAL; X goto done; X } X uio->uio_resid += iov->iov_len; X iov++; X } X } X else { X iov->iov_base = uap->databuf; X iov->iov_len = uio->uio_resid = uap->datalen; X uio->uio_iovcnt = 1; X } X if (uio->uio_resid < 0) { X error = EINVAL; X goto done; X } X if (flags & RFLG_WR) X msg->m_totlen = htonl(len + uio->uio_resid); X else X msg->m_totlen = htonl(len); X } X else { X uio = NULL; X msg->m_totlen = htonl(len); X } X rmt_showmsg(msg, FALSE); X error = remoteio(sysindex, &m, uio, flags); X m = NULL; X if (error) X goto done; X X msg = &rp->r_msg; X rmt_showmsg(msg, TRUE); X if ((error = msg->m_errno) == 0) X u.u_r.r_val1 = msg->m_args[R_RETVAL]; Xdone: X if (m) X m_free(m); X return ( error ); X} X X/* X * Copy a path into a string of mbufs. The source pointer may be in user X * space, in which case we must use uchar() to copy. Note that this routine X * expects 'm' to point to the first mbuf in the current chain: it will X * append to the end of the chain, and update the length of the message X * in msg->m_hdlen. X */ Xrmt_copypath(psrc, m, copy_from_user) X register char *psrc; X register struct mbuf *m; X{ X register char *pdest; X register int error, X totlen, X room; X register struct mbuf *m2; X struct message *msg = mtod(m, struct message *); X int copystr(), X copyinstr(), X got; X func copier = copy_from_user ? copyinstr : copystr; X X /* X * find the end of the mbuf chain. X */ X while (m->m_next) X m = m->m_next; X m2 = m; X pdest = mtod(m, char *) + m->m_len; X totlen = msg->m_hdlen; X X debug2("copy %s path @%x-->%x, len=%d\n", X copy_from_user ? "user" : "kernel", psrc, pdest, totlen); X X room = MLEN - m->m_len; X for(;;) { X got = 0; /* copy*str adds copied bytes to 'got' */ X error = (*copier)(psrc, pdest, room, (u_int *)&got); X if (error && error != ENOENT) X return(error); X m2->m_len += got; X totlen += got; X if (got < room) X break; X MGET(m, M_WAIT, MT_DATA); X if (m == NULL) X return(ENOBUFS); X m2 = m2->m_next = m; X m2->m_len = 0; X room = MLEN; X pdest = mtod(m2, char *); X psrc += got; X } X msg->m_hdlen = totlen; X debug2("len now=%d\n", totlen); X X return(0); X} X X#ifdef BSD4_3 X#else BSD4_3 X/* X * C version of copyinstr() from 4.3. X */ Xcopyinstr(src, dest, maxlength, lencopied) X register char *src, *dest; X register int maxlength; X register int *lencopied; X{ X register int c; X int dummy; X X if (!maxlength) X return(EFAULT); X if (lencopied == NULL) X lencopied = &dummy; X for(;;) { X c = *dest++ = fubyte(src++); X if (c == -1) { X *(dest-1) = 0; X return(EFAULT); X } X if (--maxlength < 0) X return(ENOENT); X (*lencopied)++; X if (c == 0) X return(0); X } X} X X/* X * C version of copystr() from 4.3. X */ Xcopystr(src, dest, maxlength, lencopied) X register char *src, *dest; X register int maxlength; X register int *lencopied; X{ X int dummy; X X if (!maxlength) X return(EFAULT); X if (lencopied == NULL) X lencopied = &dummy; X for(;;) { X if (--maxlength < 0) X return(ENOENT); X (*lencopied)++; X if ((*dest++ = *src++) == 0) X return(0); X } X} X#endif BSD4_3 X X#ifdef RFSDEBUG X Xrmt_debug(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9) X{ X printf(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9); X} X Xrmt_showmsg(msg, fromserver) X struct message *msg; X int fromserver; X{ X long end, len, pid, uid, totlen; X X if ((remote_debug & 0x18000) == 0) X return; X if (fromserver) X len = msg->m_hdlen, X totlen = msg->m_totlen, X pid = msg->m_pid, X uid = msg->m_uid; X else X len = ntohs(msg->m_hdlen), X totlen = ntohl(msg->m_totlen), X pid = ntohs(msg->m_pid), X uid = ntohs(msg->m_uid); X debug15("%s srvr: len=%d,tot=%d,pid=%d,uid=%d", X fromserver ? "from" : "to", len, totlen, pid, uid); X X /* round up into long words */ X len = (len - R_MINRMSG + 3) >> 2; X if (fromserver) X { X debug15(",err=%d,ret=%d", X msg->m_errno, X msg->m_args[ R_RETVAL ]); X end = R_RETVAL+1; X } X else X { X debug15(",syscall=%d", htons(msg->m_syscall)); X end = 0; X } X for (; end<len; end++) X debug16(",0x%x", ntohl(msg->m_args[ end ])); X rmt_debug("\n"); X} X#endif RFSDEBUG SHAREOF chmod 444 remote/usr.sys.remote/rmt_final.c # # remote/usr.sys.remote/rmt_syscall3.c # if [ -f remote/usr.sys.remote/rmt_syscall3.c ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.remote/rmt_syscall3.c or ^C to quit' read ans rm -f remote/usr.sys.remote/rmt_syscall3.c fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.remote/rmt_syscall3.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Header: rmt_syscall3.c,v 2.0 85/12/07 18:19:35 toddb Rel $ X * X * $Log: rmt_syscall3.c,v $ X * Revision 2.0 85/12/07 18:19:35 toddb X * First public release. X * X */ X#include "../h/param.h" X#ifndef pyr /* Pyramid */ X#include "../machine/pte.h" X#endif X#include "../h/systm.h" X#include "../h/map.h" X#include "../h/dir.h" X#include "../h/user.h" X#include "../h/kernel.h" X#include "../h/proc.h" X#include "../h/inode.h" X#include "../h/mbuf.h" X#include "../h/socket.h" X#include "../remote/remotefs.h" X#include "../h/file.h" X#include "../h/stat.h" X#include "../h/errno.h" X#include "../netinet/in.h" X Xextern long rmtrw(), rmtioctl(), rmtselect(), rmtclose(); Xstruct fileops remoteops = X { rmtrw, rmtioctl, rmtselect, rmtclose }; Xrmtrw() { return(0); } Xrmtioctl() { return(0); } Xrmtselect() { return(0); } Xrmtclose() { return(0); } X Xextern struct remoteinfo remote_info[]; Xextern struct remoteinfo *remote_generic; X X/* X * Remote open() X */ Xrmt_open (sysindex, m) X long sysindex; X struct mbuf *m; X{ X register long fd, error; X register struct message *msg = mtod(m, struct message *); X register struct file *fp; X struct file *falloc(); X register struct a { X char *path; X long flags, X mode; X } *uap = (struct a *)u.u_ap; X X /* X * Initialize the file structure. X */ X if ((fp = falloc()) == NULL) X return(-1); X fp->f_type = DTYPE_REMOTE; X fp->f_ops = &remoteops; X fd = u.u_r.r_val1; X fp->f_data = (caddr_t)sysindex; X fp->f_flag = (uap->mode&FMASK) | FREMOTE; X remote_info[ sysindex ].r_nfile++; X X if (ntohs(msg->m_syscall) == RSYS_creat) { X uap->mode = uap->flags; X uap->flags = FWRITE|FCREAT|FTRUNC; X msg->m_syscall = htons(RSYS_open); X } X msg->m_args[ 0 ] = htonl(uap->flags); X msg->m_args[ 1 ] = htonl(uap->mode); X msg->m_args[ 2 ] = htonl(fd); X msg->m_args[ 3 ] = htonl(u.u_cmask); X X /* X * Now send it. X */ X error = rmt_msgfin(sysindex, m, 0); X if (error) X rmt_deallocfd(fd); X else { X msg = &remote_info[ sysindex ].r_msg; X fp->f_offset = msg->m_args[1]; X } X return(error); X} X X/* X * Remote readlink() X */ Xrmt_readlink (sysindex, m) X long sysindex; X struct mbuf *m; X{ X struct message *msg = mtod(m, struct message *); X struct a { X char *path; X char *buf; X long len; X } *uap = (struct a *)u.u_ap; X X X msg->m_args[ 0 ] = htonl(uap->len); X /* X * Now send it. X */ X return( rmt_datafin(sysindex, m, RFLG_RD) ); X} X X/* X * Remote stat() and lstat() and fstat() X */ Xrmt_stat (sysindex, m) X long sysindex; X struct mbuf *m; X{ X long error, i; X struct message *msg = mtod(m, struct message *); X struct remoteinfo *rp = remote_info + sysindex; X struct a { X long fd_or_path; X struct stat *statp; X } *uap = (struct a *)u.u_ap; X struct stat st; X X if (ntohl(msg->m_syscall) == RSYS_fstat) X m->m_len = R_MINRMSG + sizeof(long); X if (error = rmt_msgfin(sysindex, m, 0)) X return( error ); X msg = &rp->r_msg; X i = R_RETVAL + 1; X st.st_dev = ntohl(msg->m_args[ i++ ]); X st.st_ino = ntohl(msg->m_args[ i++ ]); X st.st_mode = ntohl(msg->m_args[ i++ ]); X st.st_nlink = ntohl(msg->m_args[ i++ ]); X st.st_uid = ntohl(msg->m_args[ i++ ]); X st.st_gid = ntohl(msg->m_args[ i++ ]); X st.st_rdev = ntohl(msg->m_args[ i++ ]); X st.st_size = ntohl(msg->m_args[ i++ ]); X st.st_atime = ntohl(msg->m_args[ i++ ]); X st.st_mtime = ntohl(msg->m_args[ i++ ]); X st.st_ctime = ntohl(msg->m_args[ i++ ]); X st.st_blksize = ntohl(msg->m_args[ i++ ]); X st.st_blocks = ntohl(msg->m_args[ i++ ]); X st.st_spare1 = sysindex+1; X st.st_spare2 = 0; X st.st_spare3 = 0; X st.st_spare4[0] = st.st_spare4[1] = 0; X if (msg->m_args[ i ]) { /* this is the remote root */ X if (rp->r_mntpt == NULL) X rp = remote_generic; X if (rp && rp->r_mntpt != NULL) { X st.st_dev = rp->r_mntpt->i_dev; X st.st_ino = rp->r_mntpt->i_number; X } X } X (void)copyout((caddr_t)&st, (caddr_t)uap->statp, sizeof(struct stat)); X return(0); X} X X/* X * Remote truncate() and ftrucate() X */ Xrmt_truncate (sysindex, m) X long sysindex; X struct mbuf *m; X{ X long i = 0; X struct message *msg = mtod(m, struct message *); X struct a { X long fd_or_path; X long len; X } *uap = (struct a *)u.u_ap; X X if (htons(msg->m_syscall) == RSYS_ftruncate) X i++; X msg->m_args[ i ] = htonl(uap->len); X /* X * Now send it. X */ X return( rmt_msgfin(sysindex, m, 0) ); X} X X/* X * Remote utimes() X */ Xrmt_utimes (sysindex, m) X long sysindex; X struct mbuf *m; X{ X struct message *msg = mtod(m, struct message *); X struct a { X char *path; X struct timeval *timevalp; X } *uap = (struct a *)u.u_ap; X struct timeval *tv = uap->timevalp; X X msg->m_args[ 0 ] = htonl(tv[0].tv_sec); X msg->m_args[ 1 ] = htonl(tv[0].tv_usec); X msg->m_args[ 2 ] = htonl(tv[1].tv_sec); X msg->m_args[ 3 ] = htonl(tv[1].tv_usec); X X /* X * Now send it. X */ X return( rmt_msgfin(sysindex, m, 0) ); X} SHAREOF chmod 444 remote/usr.sys.remote/rmt_syscall3.c
sources-request@panda.UUCP (01/09/86)
Mod.sources: Volume 3, Issue 83 Submitted by: tektronix!tekcrl!toddb #!/bin/sh # # RFS, a kernel-resident remote file system. Shar 7 of 7 # # # This is a shell archive, meaning: # 1. Remove everything above the #!/bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # remote/usr.sys.remote/rmt_general.c # remote/usr.sys.remote/rmt_generic.c # remote/usr.sys.remote/rmt_io.c # remote/usr.sys.remote/rmt_subr.c # remote/usr.sys.remote/rmt_syscall1.c # remote/usr.sys.remote/rmt_syscall2.c # # remote/usr.sys.remote/rmt_general.c # if [ -f remote/usr.sys.remote/rmt_general.c ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.remote/rmt_general.c or ^C to quit' read ans rm -f remote/usr.sys.remote/rmt_general.c fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.remote/rmt_general.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Header: rmt_general.c,v 2.0 85/12/07 18:18:06 toddb Rel $ X * X * $Log: rmt_general.c,v $ X * Revision 2.0 85/12/07 18:18:06 toddb X * First public release. X * X */ X#include "../h/param.h" X#ifndef pyr /* Pyramid */ X#include "../machine/pte.h" X#endif X#include "../h/systm.h" X#include "../h/map.h" X#include "../h/dir.h" X#include "../h/user.h" X#include "../h/kernel.h" X#include "../h/proc.h" X#ifdef BSD4_3 X#include "../h/namei.h" X#else BSD4_3 X#include "../h/nami.h" X#endif BSD4_3 X#include "../h/inode.h" X#include "../h/mbuf.h" X#include "../h/socket.h" X#include "../remote/remotefs.h" X#include "../h/errno.h" X#include "../netinet/in.h" X#include "../h/file.h" X Xextern long remote_sysindex; Xextern struct mbuf *remote_path; Xextern u_char remote_sysmap[]; Xextern syscalls remote_syscall[]; Xextern struct remoteinfo remote_info[]; X X/* X * This routine is the main gateway into the remote software. It should X * be called from syscall(). Note that sysnum is already mapped to our X * idea of the system call number. X */ X#ifdef pyr /* Pyramid */ Xremote_startup(pass, sysnum, arg1, arg2, arg3, arg4, arg5, arg6) X#else pyr Xremote_startup(pass, sysnum) X#endif X long sysnum, pass; X{ X struct a { X long arg1, X arg2; X } *uap = (struct a *)u.u_ap; X long error, sysindex; X extern long remote_fd(); X register syscalls *sp = remote_syscall + sysnum; X register struct file *fp; X register struct proc *p; X register func general = sp->sys_gen; X register unsigned fd1, X fd2; X#ifdef pyr /* Pyramid */ X long args[ 6 ]; X X args[0] = arg1; X args[1] = arg2; X args[2] = arg3; X args[3] = arg4; X args[4] = arg5; X args[5] = arg6; X u.u_ap = args; X uap = (struct a *) args; X#endif pyr X X debug1("%d strt:#%d,pass%d,%s\n", X u.u_procp->p_pid, sysnum, pass, X pass == 0 ? (!sp->sys_before ? "too soon" : "before") : X (pass == 1 ? "do it" : "too late")); X X /* X * For the greatest of speed we check here for invalid or non- X * remote file descriptors. Make sure that we let a dup2() go X * through, even if the first fd is non-remote. X */ X if (general == remote_fd) { X /* X * Gross kludge from v7 for the bourne shell. X */ X fd1 = uap->arg1; X if (sysnum == RSYS_dup && (fd1 &~ 077)) { X fd1 &= 077; X sysnum = RSYS_dup2; X } X error = 2; X if (fd1 >= NOFILE X || (fp = u.u_ofile[fd1]) == NULL X || (fp->f_flag & FREMOTE) == 0) X error--; X if (sysnum != RSYS_dup2) X error--; X else { X fd2 = uap->arg2; X if (fd2 >= NOFILE X || (fp = u.u_ofile[fd2]) == NULL X || (fp->f_flag & FREMOTE) == 0) X error--; X } X if (! error) X return(FALSE); X uap->arg1 = fd1; X } X /* X * Check to see if this is being done too soon. Note that this is X * on the else side of the check for remote_fd. i.e., this code X * assumes that remote_fd() routines should always be done before X * the real routines. X */ X else if (pass == 0) { X u.u_rmtoffset[0] = -1; X u.u_rmtoffset[1] = -1; X if (! sp->sys_before) X return(FALSE); X } X else if (pass > 1) { X u.u_error = EISREMOTE; X return(TRUE); X } X X /* X * finally, if the user has turned off remote access for himself, X * then just return. X */ X p = u.u_procp; X if (p->p_flag & SNOREMOTE) X return(FALSE); X u.u_error = 0; X X /* X * do the remote syscall. X */ X error = (*general)(sysnum); X debug1("%d startup done: ret1=%d, ret2=%d, err=%d\n", X u.u_procp->p_pid, u.u_r.r_val1, u.u_r.r_val2, error); X if (error < 0) /* call the real system call */ X return(FALSE); X u.u_error = error; X return(TRUE); X} X X/* X * This routine handles most system calls that have no special requirements X * and have a single path in their first argument. X */ Xremote_path1(sysnum) X int sysnum; X{ X struct a { X char *path; X } *uap = (struct a *)u.u_ap; X long sysindex, len; X struct message *msg; X struct mbuf *m; X register syscalls *sp = remote_syscall + sysnum; X register long error; X X /* X * Get the path mbuf chain and its length. Also the remote sys #. X */ X if ((m = remote_path) == NULL) X return(ENOBUFS); X for (len=0; m; m = m->m_next) X len += m->m_len; X m = remote_path; X remote_path = NULL; X sysindex = remote_sysindex; X X /* X * Initialize the message and call the specific syscall handler. X */ X msg = mtod(m, struct message *); X introduce(msg, sysnum); X msg->m_hdlen = len; X error = (*sp->sys_spec)(sysindex, m, sysnum); X X if (error < 0) { X msg = &remote_info[ sysindex ].r_msg; X#ifdef BSD4_3 X#else BSD4_3 X u.u_dirp = (caddr_t) u.u_arg[0]; X#endif BSD4_3 X u.u_rmtoffset[0] = msg->m_args[0]; X return ( -1 ); X } X return ( error ); X} X/* X * This routine handles all two-path system calls. X * X * RSYS_link: the placement of path2 determines where X * we run the syscall because path2 is the file X * that is created. Isremote() must also resolve the X * path1 so that the remote link will know what file to X * link it to. Both path1 and path2 must be on the same X * system. Unfortunately, in kernel mode, we don't know X * which path was found to be remote: we must check both again. X * RSYS_rename: Same as RSYS_link. X * RSYS_symlink: path2 is the only possible remote file and X * path1 does not need to be resolved because symlink() X * blindly creats a symbolic link to it. X */ Xremote_path2(sysnum) X int sysnum; X{ X struct a { X char *path1; X char *path2; X } *uap = (struct a *)u.u_ap; X long sysindex, X len, X error; X struct message *msg; X struct mbuf *m; X X if ((m = remote_path) == NULL) X return(ENOBUFS); X /* X * If this is rename or link, then throw away what is in remote_path X * because we don't know which path it refers to . X */ X remote_path = NULL; X if (sysnum != RSYS_symlink) { X m_freem(m); X m = NULL; X sysindex = rmt_checkpath(uap->path2, &m, sysnum); X if (sysindex < 0) X return(-1); X } X else X sysindex = remote_sysindex; X /* X * Ok, path2 is now safely in our mbuf. Set the PATHOFF field for X * the beginning of where path1 will be. X */ X msg = mtod(m, struct message *); X introduce_1extra(msg, sysnum, u.u_cmask); X msg->m_args[ R_PATHOFF ] = htonl(msg->m_hdlen); X X /* X * If its a symbolic link, we can just copy the path onto the X * end of our mbuf chain. X */ X if (sysnum == RSYS_symlink) { X error = rmt_copypath(uap->path1, m, TRUE); X if (error) { X m_freem(m); X return(error); X } X } X /* X * Link and rename have to have path1 on the same system as path2. X */ X else if (rmt_checkpath(uap->path1, &m, sysnum) != sysindex) { X m_freem(m); X return(-1); X } X X error = rmt_msgfin(sysindex, m, 0); X X if(error < 0) X if (sysnum != RSYS_rename && sysnum != RSYS_link) { X msg = &remote_info[ sysindex ].r_msg; X#ifdef BSD4_3 X#else BSD4_3 X u.u_dirp = (caddr_t) u.u_arg[0]; X#endif BSD4_3 X u.u_rmtoffset[0] = msg->m_args[0]; X u.u_rmtoffset[1] = ntohl(msg->m_args[1]); X return ( -1 ); X } X else X error = EISREMOTE; X return( error ); X} X X/* X * Check a remote file for its "remoteness". After namei() is called (in X * the kernel) and isremote() is called as a result, we can get the result X * from remote_path and put it on the end of 'mhead'. X */ Xrmt_checkpath(path, mhead, sysnum) X char *path; X struct mbuf **mhead; X long sysnum; X{ X char *psrc, *pdest; X struct mbuf *m; X struct message *msg; X long len; X struct inode *ip; X X#ifdef BSD4_3 X register struct nameidata *ndp = &u.u_nd; X long follow = remote_syscall[ sysnum ].sys_follow ? FOLLOW : 0; X X ndp->ni_nameiop = LOOKUP | follow; X ndp->ni_segflg = UIO_USERSPACE; X ndp->ni_dirp = (caddr_t)path; X ip = namei(ndp); X#else BSD4_3 X u.u_dirp = path; X ip = namei(uchar, LOOKUP, remote_syscall[ sysnum ].sys_follow); X#endif BSD4_3 X if (ip != NULL || u.u_error != EISREMOTE) { X if (ip) X iput(ip); X return(-1); X } X u.u_error = 0; X X if (remote_path == NULL) X return(-1); X if (*mhead == NULL) X *mhead = remote_path; X else { X /* X * If we were handed an mbuf, then we tack the new string X * of mbufs on the end. Note that we bump the offset so that X * the mtod(m, char *) points to the beginning of the path. X */ X for (m = *mhead; m->m_next; ) X m = m->m_next; X m->m_next = remote_path; X msg = mtod(remote_path, struct message *); X len = msg->m_hdlen - (R_MINRMSG + R_PATHSTART*sizeof(long)); X remote_path->m_off += R_MINRMSG + R_PATHSTART*sizeof(long); X remote_path->m_len -= R_MINRMSG + R_PATHSTART*sizeof(long); X msg = mtod(*mhead, struct message *); X msg->m_hdlen += len; X } X remote_path = NULL; X return(remote_sysindex); X} X X/* X * Remote exit() X */ Xremote_exit() X{ X struct remoteinfo *rp, *rmt_hostdir(); X struct file *fp; X long i; X struct mbuf *m; X struct message *msg; X X /* X * Throw away remote file descriptors. X */ X for (i=0; i<NOFILE; i++) X if ((fp = u.u_ofile[ i ]) && (fp->f_flag & FREMOTE)) X rmt_deallocfd(i); X u.u_procp->p_flag &= ~SREMOTE; X if (rp = rmt_hostdir(u.u_cdir, &i)) X rp->r_nchdir--; X /* X * Send the exit message to every remote system to which we X * have a connection. X */ X for (rp = remote_info, i=0; i<R_MAXSYS; i++, rp++) X if (rmthostused(i) && rp->r_sock) { X /* X * If ours is the last usage of this connection, then X * shut it down. X */ X debug4("%d off #%d, now %d usrs\n", u.u_procp->p_pid, X i, rp->r_users-1); X if (--rp->r_users <= 0 && rp->r_sock) { X if (rp->r_close) X rmt_shutdown(i); X else X rmt_closehost(rp); X continue; X } X MGET(m, M_WAIT, MT_DATA); X if (m == NULL) X break; X msg = mtod(m, struct message *); X msg->m_hdlen = m->m_len = introduce(msg, RSYS_exit); X rmt_msgfin(i, m, RFLG_INFO); X } X X return( -1 ); /* do the real syscall, too */ X} X X/* X * Remote fork() X */ Xremote_fork(sysnum) X long sysnum; X{ X register long i, child, pid, ppid, val1; X long rmtdir = u.u_rmtcdir, X sysindex; X struct message *msg; X register struct remoteinfo *rp; X struct remoteinfo *rmt_hostdir(); X struct mbuf *m; X register struct file *fp; X long rmtsys; X X /* X * We may not need to even notify anyone, if this process is not X * doing anything interesting. If there are no open files or X * a remote current working directory, then do no more. X */ X rmtcopyhosts(rmtsys, u.u_rmtsys); X rmtclearhosts(); X for (i=0; i<NOFILE; i++) { X if ((fp = u.u_ofile[ i ]) && (fp->f_flag & FREMOTE)) { X remote_info[ (int)fp->f_data ].r_nfile++; X rmtusehost((int)fp->f_data); X } X } X if (rp = rmt_hostdir(u.u_cdir, &sysindex)) { X rmtusehost(sysindex); X rp->r_nchdir++; X } X X /* X * Do the fork. X */ X if (sysnum == RSYS_vfork) X vfork(); X else X fork(); X val1 = u.u_r.r_val1; X child = u.u_r.r_val2; X if (u.u_error) X child = FALSE; X if (u.u_error || u.u_rmtsys == 0) X goto done; X X if (child) { X ppid = u.u_procp->p_ppid; X pid = u.u_procp->p_pid; X u.u_procp->p_flag |= SREMOTE; /* set remote flag in child */ X u.u_rmtcdir = rmtdir; X } X else { /* parent */ X /* "if I am the parent && this is a vfork" */ X if (sysnum == RSYS_vfork) X goto done; X ppid = u.u_procp->p_pid; X pid = u.u_r.r_val1; X } X /* X * Parent (fork() only) and child tell all remote hosts. X * Also, bump the count of users using all connections. X */ X for (rp=remote_info, i=0; i<R_MAXSYS; i++, rp++) X if (rmthostused(i) && rp->r_sock) { X if(child) X rp->r_users++; X debug4("fork: %s %d notify %s(%d), users=%d\n", X child ? "chld" : "prnt", u.u_procp->p_pid, X rp->r_mntpath, i, rp->r_users); X MGET(m, M_WAIT, MT_DATA); X if (m == NULL) X continue; X msg = mtod(m, struct message *); X msg->m_hdlen = m->m_len = X introduce_2extra(msg, sysnum, pid, ppid); X rmt_msgfin(i, m, RFLG_INFO); X } X /* X * In the kernel, the r_val[12] elements get tromped on by the X * io to the server hosts, so restore them here. X * The 'u.u_error = 0;' is so that we don't run the real syscall X * (already run) and so that any io errors while notifying servers X * don't returned to the user... otherwise he might think the fork X * or vfork failed. X */ X u.u_r.r_val1 = val1; X u.u_r.r_val2 = child; X u.u_error = 0; Xdone: X if (! child) X rmtcopyhosts(u.u_rmtsys, rmtsys); X return(u.u_error); X} X X/* X * This routine handles most system calls having a file descriptor as X * its first argument. We are guarenteed at this point that uap->fd is X * a valid remote file descriptor. We optimize for reads and writes. X */ Xremote_fd(sysnum) X register long sysnum; X{ X struct a { X long fd; X char *buf; X long len; X } *uap = (struct a *)u.u_ap; X register long sysindex, error; X register struct message *msg; X register struct mbuf *m; X register syscalls *sp = remote_syscall + sysnum; X register struct file *fp = u.u_ofile[ uap->fd ]; X X MGET(m, M_WAIT, MT_DATA); X if (m == NULL) X return(ENOBUFS); X msg = mtod(m, struct message *); X msg->m_hdlen = 0; /* rmt_datafin() or rmt_msgfin() will assign this */ X m->m_len = introduce_2extra(msg, sysnum, uap->fd, uap->len); X X sysindex = (long)fp->f_data; X error = (*sp->sys_spec)(sysindex, m, sp->sys_flag); X if (! error) X switch (sysnum) { X case RSYS_read: X case RSYS_write: X case RSYS_readv: X case RSYS_writev: X fp->f_offset += u.u_r.r_val1; X break; X } X return(error); X} X X/* X * Deallocate a file descriptor. X */ Xrmt_deallocfd(fd) X int fd; X{ X register struct file *fp; X register struct remoteinfo *rp; X register unsigned system; X X fp = u.u_ofile[fd]; X u.u_ofile[fd] = NULL; X if (fp == NULL X || ((system = (unsigned)fp->f_data) >= R_MAXSYS)) { X debug6("dealloc: fp=%x,fd=%d,sys=%d,pid=%d\n", X fp, fd, system, u.u_procp->p_pid); X return; X } X X remote_info[ (int)fp->f_data ].r_nfile--; X closef(fp); X} SHAREOF chmod 444 remote/usr.sys.remote/rmt_general.c # # remote/usr.sys.remote/rmt_generic.c # if [ -f remote/usr.sys.remote/rmt_generic.c ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.remote/rmt_generic.c or ^C to quit' read ans rm -f remote/usr.sys.remote/rmt_generic.c fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.remote/rmt_generic.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Header: rmt_generic.c,v 2.2 86/01/02 13:52:32 toddb Exp $ X * X * $Log: rmt_generic.c,v $ X * Revision 2.2 86/01/02 13:52:32 toddb X * Ifdef'ed calls to sockargs() for the differences in 4.2 vs. 4.3. X * X * Revision 2.1 85/12/30 16:58:59 toddb X * Isremote() was not freeing it's chain of mbufs if rmt_copypath() failed. X * Now it does. X * X * Revision 2.0 85/12/07 18:18:27 toddb X * First public release. X * X */ X#include "../h/param.h" X#include "../h/systm.h" X#include "../h/inode.h" X#include "../h/dir.h" X#ifdef BSD4_3 X#include "../h/namei.h" X#else BSD4_3 X#include "../h/nami.h" X#endif BSD4_3 X#ifndef pyr /* Pyramid */ X#include "../machine/pte.h" X#endif X#include "../h/user.h" X#include "../h/proc.h" X#include "../h/buf.h" X#include "../h/file.h" X#include "../h/uio.h" X#include "../h/mbuf.h" X#include "../h/socket.h" X#include "../h/socketvar.h" X#include "../h/errno.h" X#include "../remote/remotefs.h" X Xextern long remote_sysindex; Xextern struct mbuf *remote_path; Xextern struct remoteinfo remote_info[]; Xextern struct remoteinfo *remote_generic; Xextern struct nameserver remote_ns; X X/* X * Remote "mount point" definition. X */ X#ifdef pyr /* Pyramid */ Xremoteon(arg1, arg2, arg3, arg4) X{ X#ifdef BSD4_3 X register struct nameidata *ndp = &u.u_nd; X#else BSD4_3 X#endif BSD4_3 X struct a { X char *path; X unsigned pathlen; X caddr_t name; X unsigned namelen; X } ua; X register struct a *uap = &ua; X register struct inode *ip; X register struct remoteinfo *rp; X struct remoteinfo *rmt_findslot(), X *rmt_host(); X register int error = 0; X long sysnum; X struct mbuf *m = NULL; X X uap->path = (char *)arg1; X uap->pathlen = (unsigned)arg2; X uap->name = (caddr_t)arg3; X uap->namelen = (unsigned)arg4; X#else pyr Xremoteon() X{ X#ifdef BSD4_3 X register struct nameidata *ndp = &u.u_nd; X#else BSD4_3 X#endif BSD4_3 X register struct a { X char *path; X unsigned pathlen; X caddr_t name; X unsigned namelen; X } *uap = (struct a *)u.u_ap; X register struct inode *ip; X register struct remoteinfo *rp; X struct remoteinfo *rmt_findslot(), X *rmt_host(); X register int error = 0; X long sysnum; X struct mbuf *m = NULL; X#endif X X if (uap->path == NULL) { X u.u_procp->p_flag &= ~SNOREMOTE; X return; X } X if (!suser()) X return; X#ifdef BSD4_3 X ndp->ni_nameiop = LOOKUP; X ndp->ni_segflg = UIO_USERSPACE; X ndp->ni_dirp = (caddr_t)uap->path; X ip = namei(ndp); X#else BSD4_3 X ip = namei(uchar, LOOKUP, 0); X#endif BSD4_3 X debug5("remote on ip=%x,path=%x,pthlen=%d,name=%x,nmlen=%d\n", X ip, uap->path, uap->pathlen, uap->name, uap->namelen); X if (ip == NULL) X return; X if (uap->pathlen >= R_MNTPATHLEN) X uap->pathlen = R_MNTPATHLEN - 1; X X /* X * Check for all kinds of errors. X */ X if (rmt_host(ip, &sysnum) || (uap->name == NULL && remote_generic)) X error = EBUSY; X else if ((ip->i_mode&IFMT) == IFDIR) X error = EISDIR; X else if (uap->name) X#ifdef BSD4_3 X error = sockargs(&m, uap->name, uap->namelen, MT_SONAME); X#else BSD4_3 X error = sockargs(&m, uap->name, uap->namelen); X#endif BSD4_3 X if (error) X goto out; X X /* X * Everything is ok... so put it in our list. X */ X rp = rmt_findslot(&sysnum); X if (rp == NULL) X error = ETOOMANYREMOTE; X else { X debug5("rp=%x, m=%x ip=%x sys=%d\n", rp, m, ip, sysnum); X rp->r_mntpt = ip; X if ((rp->r_name = m) == NULL) X remote_generic = rp; X (void)copyin((caddr_t)uap->path, (caddr_t)rp->r_mntpath, X MIN(uap->pathlen, R_MNTPATHLEN)); X u.u_r.r_val1 = sysnum; X iunlock(ip); X return; X } X Xout: X u.u_error = error; X iput(ip); X} X X/* X * Turn off the remote file system. If the path to unmount is NULL, then X * turn off all remote access for this process. X */ X#ifdef pyr /* Pyramid */ Xremoteoff(arg1) X{ X#ifdef BSD4_3 X register struct nameidata *ndp = &u.u_nd; X#else BSD4_3 X#endif BSD4_3 X struct a { X char *path; X } ua; X register struct a *uap = &ua; X register struct inode *ip; X register struct remoteinfo *rp; X struct remoteinfo *rmt_host(); X long sysnum; X X uap->path = (char *)arg1; X#else pyr Xremoteoff() X{ X#ifdef BSD4_3 X register struct nameidata *ndp = &u.u_nd; X#else BSD4_3 X#endif BSD4_3 X register struct a { X char *path; X } *uap = (struct a *)u.u_ap; X register struct inode *ip; X register struct remoteinfo *rp; X struct remoteinfo *rmt_host(); X long sysnum; X#endif pyr X X if (uap->path == NULL) { X u.u_procp->p_flag |= SNOREMOTE; X return; X } X if (!suser()) X return; X#ifdef BSD4_3 X ndp->ni_nameiop = LOOKUP; X ndp->ni_segflg = UIO_USERSPACE; X ndp->ni_dirp = (caddr_t)uap->path; X ip = namei(ndp); X#else BSD4_3 X ip = namei(uchar, LOOKUP, 0); X#endif BSD4_3 X if (ip == NULL || (rp = rmt_host(ip, &sysnum)) == NULL) { X if (ip) X iput(ip); X debug5("remoteoff: nope! ip=%x error=%d\n", X ip, u.u_error); X u.u_error = EINVAL; X return; X } X X debug5("remote off ip=%x\n", ip); X iput(ip); X X /* X * Now try to shut it down. X */ X rp->r_close = TRUE; X if (u.u_error = rmt_shutdown(sysnum)) X return; X u.u_r.r_val1 = remote_sysindex; X /* X * reinitialize the structure for the next time, X * freeing the mbuf and closing the socket. X */ X rp->r_refcnt = 0; X rp->r_nchdir = 0; X rp->r_nfile = 0; X if (rp->r_mntpt) X irele(rp->r_mntpt); X rp->r_mntpt = 0; X if (rp->r_name) X (void)m_free(rp->r_name); X else X remote_generic = NULL; X rp->r_name = 0; X return; X} X X/* X * This provides the nameserver function allowing X * name information to pass to and from a server and the kernel. X */ X#ifdef pyr /* Pyramid */ Xremotename(arg1, arg2, arg3, arg4) X{ X struct a { X long action; X caddr_t name; X long namelen; X char *path; X } ap; X register struct a *uap = ≈ X register long error = 0; X struct mbuf *m; X register struct proc *p = u.u_procp; X X uap->action = (long)arg1; X uap->name = (caddr_t)arg2; X uap->namelen = (long)arg3; X uap->path = (char *)arg4; X#else pyr Xremotename() X{ X register struct a { X long action; X caddr_t name; X long namelen; X char *path; X } *uap = (struct a *)u.u_ap; X register long error = 0; X struct mbuf *m; X register struct proc *p = u.u_procp; X#endif pyr X X if ((uap->action == NM_WHATNAME || uap->action == NM_NAMEIS) X && ! server_alive(p)) X error = EPERM; X else switch (uap->action) { X case NM_SERVER: /* register as name server */ X { X struct proc *p2; X short pid; X X if (!suser()) X return; X p2 = remote_ns.rn_proc; X pid = remote_ns.rn_pid; X if (server_alive(p2)) X error = EBUSY; X else { X remote_ns.rn_proc = p; X remote_ns.rn_pid = p->p_pid; X } X break; X } X case NM_WHATNAME: X if (remote_ns.rn_path) X error = copyout((caddr_t)remote_ns.rn_path, X (caddr_t)uap->path, X MIN(uap->namelen, remote_ns.rn_pathlen)); X else X error = ENOREMOTEFS; X break; X case NM_NAMEIS: X { X register char *cp; X X m = remote_ns.rn_name; X if (m) { X debug13("free old mbuf@%x\n", m); X m_free(m); /* free extra mbuf */ X m = remote_ns.rn_name = NULL; X } X#ifdef BSD4_3 X error = sockargs(&m, uap->name, uap->namelen, MT_SONAME); X#else BSD4_3 X error = sockargs(&m, uap->name, uap->namelen); X#endif BSD4_3 X if (error == 0) { X cp = mtod(m, char *) + m->m_len; X if (error = copyin((caddr_t)uap->path, (caddr_t)cp, X MIN(R_MNTPATHLEN, MLEN - m->m_len))) { X m_free(m); X m = NULL; X } X debug13("nmsrv: %s@%x\n", cp, m); X } X remote_ns.rn_name = m; X wakeup(&remote_ns.rn_name); X break; X } X#ifdef RFSDEBUG X case NM_DEBUG: X remote_debug = (long)uap->name; X printf("dbg=%d\n", remote_debug); X break; X#endif RFSDEBUG X default: X error = EINVAL; X break; X } X if (error) X u.u_error = error; X} X X/* X * This is the routine called by namei() when it encounters what it thinks X * might be a remote mount point. X */ Xisremote(ip, path, base) X register struct inode *ip; X char *path, *base; X{ X struct remoteinfo *rmt_host(), *rmt_findhost(); X register short offset; X register struct remoteinfo *rp; X register struct mbuf *m; X register struct message *msg; X register int error; X long sysnum; X X rp = rmt_host(ip, &sysnum); X if (rp == NULL) { X debug7("%s, ip=\"%x\" is not remote\n", path, ip); X return(FALSE); X } X if (remote_path) X m_freem(remote_path); X remote_path = NULL; X X /* X * Adjust the path so that if there is a leading '/', the path X * will start there. X */ X if (path != base && *path != '/' && *(path-1) == '/') X path--; X X /* X * Although we know the file is remote, it may have a loop back X * to this side; a simple case being if the path is '..' while X * in the root directory of the remote system. If this is the case X * then the server will reply with errno == -1, remote_path[12]() X * will assign u.u_rmtoffset[0,1] and the real system call will be X * run again, bringing us back to here. We know that that has X * happened if either of u.u_rmtoffset[0,1] is >= 0. We then X * just adjust the path handed to us by namei() and return X * -1 which signals namei() to begin again with the new X * path with directory set to root (/). X */ X if ((u.u_procp->p_flag & SREMOTE) == 0) { X u.u_rmtcdir = -1; X offset = -1; X } X else if ((offset = u.u_rmtoffset[0]) >= 0) X u.u_rmtoffset[0] = -1; X else if ((offset = u.u_rmtoffset[1]) >= 0) X u.u_rmtoffset[1] = -1; X if (offset >= 0) { X register char *pstart = path + offset; X register char *p = path; X X debug8("restart path %s locally, offset=%d\n", path, offset); X if (offset) /* validate offset value */ X while (p <= pstart) X if (*p++ == '\0') { X u.u_error = EINVAL; X return(FALSE); X } X if (base != pstart) { X path = base; X do { X *path++ = *pstart; X } while (*pstart++); X } X return(-1); X } X X /* X * We have a remote mount point. However, it may be in the midst of X * shutting down from some error. This mount point may also be X * a "generic" mount point, in which case, we must figure out X * the host. X */ X if (rp->r_name == NULL) { X rp = rmt_findhost(&path, &sysnum); X if (rp == NULL) { X debug8("isremote: can't map path %s\n", path); X return(TRUE); X } X } X if (rp->r_close) { X debug8("isremote: host %s is closing\n", rp->r_mntpath); X u.u_error = ENOREMOTEFS; X return(TRUE); X } X u.u_error = EISREMOTE; X remote_sysindex = sysnum; X /* X * Set the remote flag for this user and bump the X * user count. X */ X u.u_procp->p_flag |= SREMOTE; X if (! rmthostused(sysnum)) { X rp->r_users++; X rmtusehost(sysnum); X debug4("%d uses rmt %d\n", u.u_procp->p_pid, sysnum); X } X rmtusehost(sysnum); X debug7("%s, ip=%x is remote, idx=%d\n", path, ip, remote_sysindex); X MGET(m, M_WAIT, MT_DATA); X if (m != NULL) { X msg = mtod(m, struct message *); X msg->m_hdlen = R_MINRMSG + R_PATHSTART*sizeof(long); X m->m_len = R_MINRMSG + R_PATHSTART*sizeof(long); X if (error = rmt_copypath(path, m, FALSE)) { X m_freem(m); X u.u_error = error; X return(TRUE); X } X remote_path = m; X } X else X u.u_error = ENOBUFS; X return(TRUE); X} SHAREOF chmod 444 remote/usr.sys.remote/rmt_generic.c # # remote/usr.sys.remote/rmt_io.c # if [ -f remote/usr.sys.remote/rmt_io.c ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.remote/rmt_io.c or ^C to quit' read ans rm -f remote/usr.sys.remote/rmt_io.c fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.remote/rmt_io.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Header: rmt_io.c,v 2.1 85/12/30 16:53:01 toddb Exp $ X * X * $Log: rmt_io.c,v $ X * Revision 2.1 85/12/30 16:53:01 toddb X * Changed shutdown messages for the remotefs from debug messages to X * printf messages. Also fixed a bug where the return value field in X * rp->r_msg.m_args[ R_RETVAL ] was getting cleared for process `x' X * by process `y' when process `y' was executing an INFO_ONLY type X * of remote system call (like close or fork). This bug was causing X * random system calls (like read or write) to return 0 when it should X * have returned something non-zero. X * X * Revision 2.0 85/12/07 18:18:51 toddb X * First public release. X * X */ X#include "../h/param.h" X#include "../h/dir.h" X#ifndef pyr /* Pyramid */ X#include "../machine/pte.h" X#endif X#include "../h/user.h" X#include "../h/proc.h" X#include "../h/buf.h" X#include "../h/uio.h" X#include "../h/mbuf.h" X#include "../h/socket.h" X#include "../h/socketvar.h" X#include "../h/protosw.h" X#include "../h/errno.h" X#include "../remote/remotefs.h" X#include "../h/inode.h" X#include "../h/kernel.h" X#include "../netinet/in.h" X Xextern struct remoteinfo remote_info[]; Xextern struct remoteinfo *remote_generic; X X/* X * Obtain a connection to 'system'. X */ Xremote_getconnection(system) X register int system; X{ X register struct remoteinfo *rp = remote_info + system; X register err, s, opening = FALSE; X short uid; X struct socket *so = NULL; X X if (! rp->r_name) { X rmt_unuse(rp, system); X return(ENOREMOTEFS); /* no address to call. */ X } X X /* X * Lock out other processes from doing an open at the same time. X */ X if (rp->r_opening) { X if (setjmp(&u.u_qsave)) { X rmt_unuse(rp, system); X return(EINTR); X } X while (rp->r_opening) X sleep((caddr_t)&rp->r_sock); X if (rp->r_sock) X return(0); X rmt_unuse(rp, system); X return(rp->r_openerr); X } X /* X * We may already have a connection X */ X else if (rp->r_sock) X return(0); X /* X * If we have failed previously, it may be time to try again. X */ X else if (rp->r_failed) { X if (rp->r_age > time.tv_sec) X return(rp->r_openerr); X rp->r_failed = FALSE; X } X rp->r_opening = TRUE; X X /* X * pseudo loop to avoid labels... X */ X do { X /* X * Fortunately, there is security with ports. Unfortunately, X * you must be root to do it. So we change our uid for a X * brief moment. X */ X uid = u.u_uid; X if (setjmp(&u.u_qsave)) { X u.u_uid = uid; X if (u.u_error == 0) X err = EINTR; X break; X } X X /* X * first, make a socket for the connection; then connect. (the X * connection code is basically connect(2)). X */ X if (err = socreate(AF_INET, &rp->r_sock, SOCK_STREAM, 0)) X break; X X so = rp->r_sock; X debug9("connect..."); X err = soconnect(so, rp->r_name); X u.u_uid = uid; X if (err) X break; X X s = splnet(); X if ((so->so_state & SS_NBIO) && X (so->so_state & SS_ISCONNECTING)) { X err = EINPROGRESS; X splx(s); X break; X } X while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { X debug9("."); X sleep((caddr_t)&so->so_timeo, PZERO+1); X } X err = so->so_error; X so->so_error = 0; X rp->r_sock = so; X rp->r_sender = rp->r_recver = -1; X sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, NULL); X splx(s); X } while (FALSE); X X if (err) { X rp->r_sock = 0; X rp->r_openerr = err; X rp->r_failed = TRUE; X rp->r_age = time.tv_sec + R_RETRY; X debug9("err=%d\n", err); X rmt_unuse(rp, system); X if (so) X soclose(so); X } X else X debug9(" done.\n"); X rp->r_opening = FALSE; X wakeup((caddr_t)&rp->r_sock); X return(err); X} X X/* X * Back out of references to a remote host. X */ Xrmt_unuse(rp, system) X register struct remoteinfo *rp; X register long system; X{ X rp->r_users--; X rmtunusehost(system); X if (u.u_rmtsys == 0) X u.u_procp->p_flag &= ~SREMOTE; X} X X/* X * Send out the message. X */ Xremoteio(system, m, uio, flags) X register int system; X register struct mbuf **m; X register struct uio *uio; X int flags; X{ X register int error, signaled = 0, position; X register struct remoteinfo *rp = remote_info + system; X register struct socket *so; X register struct iovec *iov; X register struct proc *p; X long soreceive(), sosend(); X long oldmask; X X X /* X * get a connection. X */ X if ((so = rp->r_sock) == NULL) X if (error = remote_getconnection(system)) { X (void) m_freem(*m); X return(error); X } X else X so = rp->r_sock; X X /* X * "Hold" SIGTSTP and SIGSTOP signals until we are done. X */ X p = u.u_procp; X oldmask = (1 << (SIGTSTP-1)) X | (1 << (SIGSTOP-1)); X oldmask = (p->p_sigmask & oldmask); X p->p_sigmask |= (1 << (SIGTSTP-1)) X | (1 << (SIGSTOP-1)); X X /* X * Note that we re-do the setjmp each time we change state. X * Two reasons: 1) we are effectively ignoring interrupts until X * either the message has been completely sent or has been X * completely recieved. 2) setjmp() restores register variables to X * their state at the time of the call and since we modify them X * all the time, we need to re-save the state. X */ X position = R_NOTHINGSENT; X rp->r_refcnt++; /* we are actively using conection */ X X while(position != 0) { X if (setjmp(&u.u_qsave)) { X error = EINTR; X debug10("signal to %d\n", u.u_procp->p_pid); X if (rp->r_close) X goto remoteio_done; X signaled++; X continue; X } X X switch (position) { X case R_NOTHINGSENT: X /* X * make sure that this is not someone elses data. X */ X if (signaled) X goto remoteio_done; X while (!rp->r_close && rp->r_sender >= 0) { X debug10("I am %d, not %d. Goodnight.\n", X u.u_procp->p_pid, rp->r_sender); X sleep((caddr_t)&rp->r_sender, PZERO+1); X } X if (rp->r_close) X goto remoteio_done; X X /* X * We update position BEFORE we call tcp_usrreq() X * because we are guarenteed that the data will be X * sent just by making the call. i.e. we will never X * come back to this point once we've been here. X */ X if (uio && (flags & RFLG_WR)) X position = R_DATANOTSENT; X else X position = R_MSGNOTRED; X rp->r_sender = u.u_procp->p_pid; X debug10("%d sending... ", rp->r_sender); X error = (*so->so_proto->pr_usrreq)(so, X PRU_SEND, *m, 0, 0); X if (error) { X printf("error=%d on sending msg\n", error); X rp->r_close = TRUE; X goto remoteio_done; X } X *m = 0; X break; X X case R_DATANOTSENT: X debug10("%d data\n", u.u_procp->p_pid); X if (error = rmt_uio(rp, uio, sosend)) X flushmsg(rp, uio->uio_resid, FALSE); X position = R_MSGNOTRED; X break; X X case R_MSGNOTRED: X /* X * Finally, read from the socket. Also, if X * we have been interrupted, now is the time to X * notify the other side. X */ X rp->r_sender = -1; X wakeup(&rp->r_sender); X if (flags & RFLG_INFO) { X position = 0; X break; X } X debug10("%d recving\n", u.u_procp->p_pid); X if (signaled) X sendrsig(system); X error = rmt_getmsg(system); X rp->r_received = FALSE; X if (error || rp->r_close) X goto remoteio_done; X if (uio && (flags & RFLG_RD)) X position = R_DATANOTRED; X else { X rp->r_recver = -1; X position = 0; X wakeup(&rp->r_recver); X } X break; X case R_DATANOTRED: X debug10("%d recving data\n", u.u_procp->p_pid); X if (rp->r_msg.m_args[ R_RETVAL ] > uio->uio_resid) { X printf("usr needs %d, srvr says %d\n", X uio->uio_resid, X rp->r_msg.m_args[ R_RETVAL ]); X rp->r_close = TRUE; X goto remoteio_done; X } X X uio->uio_resid = rp->r_msg.m_args[ R_RETVAL ]; X if (error = rmt_uio(rp, uio, soreceive)) { X flushmsg(rp, uio->uio_resid, TRUE); X break; X } X rp->r_recver = -1; X wakeup(&rp->r_recver); X position = 0; X break; X } X } Xremoteio_done: X /* X * Restore mask by first taking out SIGTSTP and SIGSTOP, whatever X * their values. And then or'ing in the original value. X */ X p = u.u_procp; X p->p_sigmask &= ~((1 << (SIGTSTP-1)) X | (1 << (SIGSTOP-1))); X p->p_sigmask |= oldmask; X X rp->r_refcnt--; /* we are done with this transaction */ X if (rp->r_close) X error = ECONNABORTED; X if (error) { X debug11("remoteio: err=%d, close=%s\n", X error, rp->r_close ? "true" : "false"); X rmt_shutdown(system); X } X return(error); X} X X/* X * Force io to happen and consume all of uio->uio_resid. X */ Xrmt_uio(rp, uio, sockfunc) X register struct remoteinfo *rp; X register struct uio *uio; X register func sockfunc; X{ X register struct socket *so = rp->r_sock; X label_t qsave; X register long error = 0, X flag = (sockfunc == soreceive) X ? SS_CANTRCVMORE : SS_CANTSENDMORE; X X bcopy(&u.u_qsave, &qsave, sizeof(label_t)); X if (setjmp(&u.u_qsave)) { X debug11("rmt_uio: sig %d\n", u.u_procp->p_pid); X if (rp->r_close) X error = ECONNABORTED; X } X while(uio->uio_resid > 0 && ! error && (so->so_state & flag) == 0) X error = (*sockfunc)(so, 0, uio, 0, 0); X bcopy(&qsave, &u.u_qsave, sizeof(label_t)); X if (so->so_state & flag) { X rp->r_close = TRUE; X error = ECONNABORTED; X } X return(error); X} X X/* X * Obtain the next message from the server. We don't return from this X * routine until our personal message has been received or an error X * has occured. X */ Xrmt_getmsg(system) X register int system; X{ X struct proc *p = NULL; X struct remoteinfo *rp = remote_info + system; X struct socket *so = rp->r_sock; X struct uio auio; X struct iovec iov; X register long msglen, len, error = 0; X long soreceive(); X X for(;;) { X iov.iov_len = auio.uio_resid = R_MINRMSG+sizeof(long); X auio.uio_segflg = 1; /* kernel bcopy */ X auio.uio_iov = &iov; X auio.uio_iovcnt = 1; X auio.uio_offset = 0; X iov.iov_base = (caddr_t)&rp->r_msg; X X /* X * Since we may have been usurped by this time, or a different X * syscall may have been repsponded to, we must make sure X * that we are the recipient of this message. In fact, X * the message may have already arrived. X */ X while (rp->r_recver != u.u_procp->p_pid && rp->r_recver != -1) X sleep((caddr_t)&rp->r_recver, PZERO+1); X if (rp->r_recver == u.u_procp->p_pid && rp->r_received) { X auio.uio_resid = 0; X break; X } X rp->r_recver = u.u_procp->p_pid; X X /* X * get the message. X */ X if (error = rmt_uio(rp, &auio, soreceive)) { X debug11("1st: err=%d\n", error); X break; X } X#ifndef magnolia X rp->r_msg.m_totlen = ntohl(rp->r_msg.m_totlen); X rp->r_msg.m_hdlen = ntohs(rp->r_msg.m_hdlen); X rp->r_msg.m_pid = ntohs(rp->r_msg.m_pid); X rp->r_msg.m_uid = ntohs(rp->r_msg.m_uid); X rp->r_msg.m_errno = ntohs(rp->r_msg.m_errno); X rp->r_msg.m_args[ R_RETVAL ] X = ntohl(rp->r_msg.m_args[ R_RETVAL ]); X#endif X msglen = rp->r_msg.m_hdlen; X if (msglen > R_MAXRMSG X || msglen < R_MINRMSG+sizeof(long) X || auio.uio_offset < R_MINRMSG+sizeof(long)) { X debug11("msg len=%d, off=%d!\n", X msglen, auio.uio_offset); X error = ECONNABORTED; X break; X } X X /* X * We may need a few more bytes. X */ X if (msglen > R_MINRMSG + sizeof(long)) { X iov.iov_len = auio.uio_resid = X msglen - auio.uio_offset; X auio.uio_iov = &iov; X auio.uio_iovcnt = 1; X debug10("getmsg2: resid=%d... cc=%d\n", X auio.uio_resid, so->so_rcv.sb_cc); X if (error = rmt_uio(rp, &auio, soreceive)) { X debug11("2nd: err=%d, resid=%d, msglen=%d\n", X error, auio.uio_resid, msglen); X break; X } X } X X /* X * Now find the right recipient. X */ X rp->r_received = TRUE; X rp->r_recver = rp->r_msg.m_pid; X if (rp->r_recver == u.u_procp->p_pid) X break; X if (rp->r_recver >= 0 && (p = pfind(rp->r_recver))) { X debug11("%d: msg for %d@%x\n", X u.u_procp->p_pid, rp->r_recver, p->p_wchan); X if (p->p_wchan == (caddr_t)&rp->r_recver) X setrun(p); X continue; X } X else X debug11("proc %d?\n", rp->r_recver); X flushmsg(rp, rp->r_msg.m_totlen - rp->r_msg.m_hdlen, TRUE); X } X X /* X * Wrap up and decide if everything is still kosher... X */ X if (rp->r_close || error || auio.uio_resid) { X debug11("%d: getmsg: close=%s,err=%d,resid=%d\n", X u.u_procp->p_pid, rp->r_close ? "true" : "false", X error, auio.uio_resid); X rp->r_close = TRUE; X rmt_shutdown(system); X error = ECONNABORTED; X } X return(error); X} X Xflushmsg(rp, len, input) X register struct remoteinfo *rp; X register long len, input; X{ X register struct socket *so = rp->r_sock; X register long error = 0, need; X struct uio auio; X struct iovec iov; X char buf[ MLEN ]; X extern long sosend(), soreceive(); X func ioroutine = (input ? soreceive : sosend); X X debug11("flush %d %s bytes\n", len, input ? "input" : "output"); X auio.uio_segflg = 1; /* kernel bcopy */ X while (len > 0 && ! error) { X need = iov.iov_len = auio.uio_resid = MIN(len, MLEN); X auio.uio_iov = &iov; X auio.uio_iovcnt = 1; X iov.iov_base = (caddr_t)buf; X debug11("flush: resid=%d... cc=%d\n", X auio.uio_resid, so->so_rcv.sb_cc); X error = rmt_uio(rp, &auio, ioroutine); X len -= need - auio.uio_resid; X } X if (error) X rp->r_close = TRUE; X if (input) { X rp->r_recver = -1; X rp->r_received = FALSE; X wakeup((caddr_t)&rp->r_recver); X } X else { X rp->r_sender = -1; X ioroutine = sosend; X wakeup((caddr_t)&rp->r_sender); X } X debug11("flush: error=%d\n", error); X} X Xrmt_shutdown(system) X register int system; X{ X register struct remoteinfo *rp = remote_info + system; X register struct proc *p; X X wakeup((caddr_t)&rp->r_sender); X wakeup((caddr_t)&rp->r_recver); X if (rp->r_recver >= 0 && (p = pfind(rp->r_recver)) && p->p_wchan) { X debug12("wake rder %d\n", p->p_pid); X wakeup((caddr_t)p->p_wchan); X } X if (rp->r_sender >= 0 && (p = pfind(rp->r_sender)) && p->p_wchan) { X debug12("wake wrter %d\n", p->p_pid); X wakeup((caddr_t)p->p_wchan); X } X debug12("shtdwn: ref=%d, reason=", rp->r_refcnt); X if (rp->r_close || (rp->r_sock->so_state & SS_CANTRCVMORE)) X debug12("%s\n", X (rp->r_sock->so_state & SS_CANTRCVMORE) X ? "no more" : "closed"); X else { X debug12("?, not done\n"); X return(EBUSY); X } X rp->r_close = TRUE; X if (rp->r_refcnt || rp->r_users) X return(EBUSY); X rmt_closehost(rp); X return(0); X} X X/* X * Close a host connection. X */ Xrmt_closehost(rp) X register struct remoteinfo *rp; X{ X struct socket *so; X X so = rp->r_sock; X rp->r_recver = rp->r_sender = -1; X rp->r_sock = NULL; X rp->r_age = time.tv_sec; X rp->r_close = 0; X if (so) X soclose(so); X else X debug12("rmt_closehost: so == 0, rp=%x\n", rp); X} X Xsendrsig(system) X register int system; X{ X debug11("would have sent sig to system %d\n", system); X} SHAREOF chmod 444 remote/usr.sys.remote/rmt_io.c # # remote/usr.sys.remote/rmt_subr.c # if [ -f remote/usr.sys.remote/rmt_subr.c ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.remote/rmt_subr.c or ^C to quit' read ans rm -f remote/usr.sys.remote/rmt_subr.c fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.remote/rmt_subr.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Header: rmt_subr.c,v 2.0 85/12/07 18:19:10 toddb Rel $ X * X * $Log: rmt_subr.c,v $ X * Revision 2.0 85/12/07 18:19:10 toddb X * First public release. X * X */ X#include "../h/param.h" X#ifndef pyr /* Pyramid */ X#include "../machine/pte.h" X#endif X#include "../h/systm.h" X#include "../h/map.h" X#include "../h/dir.h" X#include "../h/user.h" X#include "../h/proc.h" X#ifdef BSD4_3 X#include "../h/namei.h" X#else BSD4_3 X#include "../h/nami.h" X#endif BSD4_3 X#include "../h/inode.h" X#include "../h/mbuf.h" X#include "../h/socket.h" X#include "../remote/remotefs.h" X#include "../h/errno.h" X#include "../netinet/in.h" X#include "../h/file.h" X Xextern struct remoteinfo remote_info[]; Xextern struct remoteinfo *remote_generic; Xextern struct nameserver remote_ns; X X/* X * A fast routine for determining whether an inode is in the list of X * remote hosts, and returning a pointer into that list. X * Failure returns NULL. X */ Xstruct remoteinfo *rmt_host(ip, asysnum) X register struct inode *ip; X register long *asysnum; X{ X register struct remoteinfo *rp = remote_info; X register long i; X X if (ip == NULL) X printf("rmt_host: ip=0\n"); X else for(i=0; i < R_MAXSYS; i++, rp++) X if (rp->r_mntpt == ip) { X *asysnum = i; X return(rp); X } X return(NULL); X} X X/* X * This is an extension to rmt_host() in that if rmt_host() returns a X * pointer to a generic mount point, we return the pointer to the entry X * that describes where we have our current working directory. X */ Xstruct remoteinfo *rmt_hostdir(ip, asysnum) X register struct inode *ip; X register long *asysnum; X{ X register struct remoteinfo *rp; X X rp = rmt_host(ip, asysnum); X if (rp == NULL) X return(NULL); X if (rp->r_name == NULL) X if (u.u_rmtcdir < 0) X return(rp); X else X return(remote_info + (*asysnum = u.u_rmtcdir)); X return(rp); X} X X/* X * called by isremote() to figure out if there is a host implied by X * 'path'. Note that a user process must have ``registered'' with X * the kernel as being willing to provide name service. X */ Xstruct remoteinfo *rmt_findhost(apath, asysnum) X char **apath; X register long *asysnum; X{ X label_t qsave; X register struct remoteinfo *rp; X char savec; X struct remoteinfo *rmt_findaddr(), X *rmt_findslot(); X register struct proc *p; X register char *path = *apath, *cp; X register struct mbuf *m = NULL; X register long error = 0, X i; X X /* X * If the path is relative, then it must be because we have done X * a remote chdir()... take the directory from there. X */ X if (*path != '/' && u.u_rmtcdir >= 0) { X debug13("path %s==>cwd=#%d\n", path, u.u_rmtcdir); X *asysnum = u.u_rmtcdir; X return (remote_info + u.u_rmtcdir); X } X X /* X * First try to satisfy the name from the existing table... there X * may have been a mount done explicitly that has the form X * "/hostname", or there may have been an implicit mount. Check X * for both. X */ X rp = remote_info; X for(i=0; i < R_MAXSYS; i++, rp++) X if (rp->r_name && rmt_pathimplies(rp, apath)) { X debug13("%s==>mntpt=%s(#%d)\n", X *apath, rp->r_mntpath, i); X *asysnum = i; X return(rp); X } X X /* X * If that fails, then give the name server a crack at it. Note that X * we don't check to see if we found an open slot, because the address X * that we get back may match an existing address. X * If the nameserver is around, send him a signal. Then wait X * patiently for the response. X */ X while (remote_ns.rn_path) /* Lock out all other nameserver action */ X sleep((caddr_t)&remote_ns.rn_path, PZERO+1); X X bcopy(&u.u_qsave, &qsave, sizeof(label_t)); X if (setjmp(&u.u_qsave)) { X error = EINTR; X goto out; X } X X /* X * The nameserver only needs the first component. X */ X cp = path; X while (*cp == '/') X cp++; X while (*cp && *cp != '/') X cp++; X savec = *cp; X *cp = '\0'; X remote_ns.rn_pathlen = cp - path + 1; X remote_ns.rn_path = path; X p = remote_ns.rn_proc; X if (server_alive(p)) { X psignal(p, SIGURG); X sleep((caddr_t)&remote_ns.rn_name, PZERO+1); X } X *cp = savec; X X /* X * Ok, now see what the server had to say... X */ X m = remote_ns.rn_name; X remote_ns.rn_name = NULL; X if (m == NULL) X error = EADDRNOTAVAIL; X else { X rp = rmt_findaddr(m, asysnum); X *apath = cp; X } X if (rp || m == NULL) X goto out; X X if ((rp = rmt_findslot(asysnum)) == NULL) X error = ETOOMANYREMOTE; X else { X if (rp->r_name) { X debug13("findhost: reusing %d, %s\n", X asysnum, rp->r_mntpath); X (void) m_free(rp->r_name); X } X rp->r_name = m; X bcopy (mtod(m, caddr_t) + m->m_len, rp->r_mntpath, X MIN(R_MNTPATHLEN, MLEN - m->m_len)); X m = NULL; X } X Xout: X if (remote_ns.rn_name) X (void) m_free(remote_ns.rn_name); X else if (m) X (void) m_free(m); X remote_ns.rn_name = NULL; X remote_ns.rn_path = NULL; X wakeup((caddr_t)&remote_ns.rn_path); X if (error) { X rp = NULL; X u.u_error = error; X } X X /* X * Since we are returning and may sleep again, we must restore the X * setjmp info so that we don't kill ourselves. X */ X bcopy(&qsave, &u.u_qsave, sizeof(label_t)); X return (rp); X} X X/* X * if (index >= 0) i.e. valid remote host X * Set the working directory to the mount point for system 'index'. X * This, along with what the server does, will effect a chdir("remotedir"); X * if (index < 0) X * then simply decrement the number of chdir's on the current remote X * host, if any. X */ Xremotechdir(index) X long index; X{ X register struct inode *ip = NULL, *oip; X register struct remoteinfo *rp; X register long error = 0; X long i; X struct remoteinfo *rmt_host(); X X debug14("cd #%d\n", index); X if (index >= R_MAXSYS) X return(ENOENT); X /* X * If we are currently cd'ed to another remote host, decrement its' X * reference count. X */ X oip = u.u_cdir; X if (rp = rmt_hostdir(oip, &i)) { X debug14("uncd #%d, ip=%x\n", i, oip); X rp->r_nchdir--; X } X rp = remote_info + index; X if (index >= 0) { X /* X * If this is an implied mount point, find the inode for the X * generic mount pt. X */ X if (rp->r_mntpt == NULL) { X if (remote_generic) X ip = remote_generic->r_mntpt; X debug14("cd is generic, ip=%x\n", ip); X if (ip == NULL) X return(ENOENT); X } X else X ip = rp->r_mntpt; X rp->r_nchdir++; /* bump the reference count */ X u.u_rmtcdir = index; X irele(oip); X ip->i_count++; X u.u_cdir = ip; X } X X return(error); X} X X/* X * See if a host is implied in a remote_info entry from the path name 'path'. X */ Xrmt_pathimplies(rp, path) X register struct remoteinfo *rp; X register char **path; X{ X register char *p1, *p2, *pend; X X p1 = rp->r_mntpath; X while(*p1 == '/') X p1++; X p2 = *path; X while(*p2 == '/') X p2++; X X /* X * Compare against the mount point. X */ X pend = rp->r_mntpath + R_MNTPATHLEN; X while (*p1 == *p2 && *p1 && p1 < pend) X p1++, p2++; X if (*p1 == *p2 || (*p1 == '\0' && *p2 == '/')) { X *path = p2; X return(TRUE); X } X X return (FALSE); X} X X/* X * See if any remote entry already had address 'addr'. X */ Xstruct remoteinfo *rmt_findaddr(m, asysnum) X register struct mbuf *m; X register long *asysnum; X{ X register struct remoteinfo *rp; X register caddr_t addr; X register int i, len; X X addr = mtod(m, caddr_t); X len = m->m_len; X for (i=0, rp = remote_info; i < R_MAXSYS; i++, rp++) X if (rp->r_name X && len == rp->r_name->m_len X && bcmp(rp->r_name, addr, len) == 0) { X *asysnum = i; X debug13("%s: same as mnt %d\n", addr+len, i); X return(rp); X } X return(NULL); X} X X/* X * Find an open slot in the remote info. X */ Xstruct remoteinfo *rmt_findslot(asysnum) X register long *asysnum; X{ X register struct remoteinfo *rp, X *frp = NULL; X register int i, fi; X X for (i=0, rp = remote_info; i < R_MAXSYS; i++, rp++) { X if (rp->r_mntpt || rp ->r_sock) /* active connections */ X continue; X if (rp->r_name == NULL) { X frp = rp; X fi = i; X break; X } X if (frp == NULL || rp->r_age < frp->r_age) { X frp = rp; X fi = i; X } X } X if (frp) { X debug13("slt: %d\n", fi); X *asysnum = fi; X return(frp); X } X X /* X * No slot... do garbage collection. X */ X for (i=0, rp = remote_info; i < R_MAXSYS; i++, rp++) X if (rp->r_mntpt == NULL X && rp->r_nchdir == 0 && rp->r_nfile == 0) { X debug13("fndslt: usurp %d=%s\n", X rp - remote_info, rp->r_mntpath); X *asysnum = i; X rmt_closehost(rp); X (void) m_free(rp->r_name); X rp->r_name = NULL; X return(rp); X } X X return(NULL); X} SHAREOF chmod 444 remote/usr.sys.remote/rmt_subr.c # # remote/usr.sys.remote/rmt_syscall1.c # if [ -f remote/usr.sys.remote/rmt_syscall1.c ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.remote/rmt_syscall1.c or ^C to quit' read ans rm -f remote/usr.sys.remote/rmt_syscall1.c fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.remote/rmt_syscall1.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Header: rmt_syscall1.c,v 2.0 85/12/07 18:19:21 toddb Rel $ X * X * $Log: rmt_syscall1.c,v $ X * Revision 2.0 85/12/07 18:19:21 toddb X * First public release. X * X */ X#include "../h/param.h" X#ifndef pyr /* Pyramid */ X#include "../machine/pte.h" X#endif X#include "../h/systm.h" X#include "../h/map.h" X#include "../h/dir.h" X#include "../h/user.h" X#include "../h/kernel.h" X#include "../h/proc.h" X#include "../h/mbuf.h" X#include "../h/socket.h" X#include "../h/file.h" X#include "../remote/remotefs.h" X#include "../h/stat.h" X#include "../h/errno.h" X#include "../netinet/in.h" X Xextern struct remoteinfo remote_info[]; X X/* X * Remote access() X */ Xrmt_access (sysindex, m) X int sysindex; X struct mbuf *m; X{ X struct message *msg = mtod(m, struct message *); X struct a { X char *path; X long mode; X } *uap = (struct a *)u.u_ap; X X msg->m_args[ 0 ] = htonl(uap->mode); X X /* X * Now send it. X */ X return( rmt_msgfin(sysindex, m, 0) ); X} X X/* X * Remote chdir() X */ Xrmt_chdir (sysindex, m) X int sysindex; X struct mbuf *m; X{ X int error; X X /* X * Now send it. X */ X if ((error = rmt_msgfin(sysindex, m, 0)) == 0) X error = remotechdir(sysindex); X X return( error ); X} X X/* X * Remote chmod() and fchmod() X */ Xrmt_chmod (sysindex, m) X int sysindex; X struct mbuf *m; X{ X int i = 0; X struct message *msg = mtod(m, struct message *); X struct a { X long path_or_fd; X long mode; X } *uap = (struct a *)u.u_ap; X X if (htons(msg->m_syscall) == RSYS_fchmod) X i++; X msg->m_args[ i ] = htonl(uap->mode); X /* X * Now send it. X */ X return( rmt_msgfin(sysindex, m, 0) ); X} X X/* X * Remote chown() and fchown() X */ Xrmt_chown (sysindex, m) X int sysindex; X struct mbuf *m; X{ X int i = 0; X struct message *msg = mtod(m, struct message *); X struct a { X long path_or_fd; X long owner, group; X } *uap = (struct a *)u.u_ap; X X if (htons(msg->m_syscall) == RSYS_fchown) X i++, m->m_len = R_MINRMSG + 3*sizeof(long); X msg->m_args[ i++ ] = htonl(uap->owner); X msg->m_args[ i ] = htonl(uap->group); X /* X * Now send it. X */ X return( rmt_msgfin(sysindex, m, 0) ); X} X X/* X * Remote dup() X */ Xrmt_dup (sysindex, m) X long sysindex; X struct mbuf *m; X{ X int fd, error; X struct message *msg = mtod(m, struct message *); X struct file *fp; X struct a { X long fd; X } *uap = (struct a *)u.u_ap; X X fp = u.u_ofile[ uap->fd ]; X fd = ufalloc(0); X if (fd < 0) X return(-1); X remote_info[ (int)fp->f_data ].r_nfile++; X dupit(fd, fp, u.u_pofile[uap->fd]); X msg->m_args[ 1 ] = htonl(fd); X X /* X * Now send it. X */ X error = rmt_msgfin(sysindex, m, 0); X if (error) X rmt_deallocfd(fd); X return(error); X} X X/* X * Remote dup2() X */ Xrmt_dup2 (sysindex, m) X long sysindex; X struct mbuf *m; X{ X struct message *msg = mtod(m, struct message *); X struct file *oldfp, *newfp; X struct a { X long oldfd, X newfd; X } *uap = (struct a *)u.u_ap; X long oldfd = uap->oldfd, X newfd = uap->newfd, X error; X X oldfp = u.u_ofile[ oldfd ]; X if (newfd >= NOFILE) X return(EBADF); X if (oldfd == newfd) X return(newfd); X if (newfp = u.u_ofile[ newfd ]) { X /* X * If the new file descriptor (which must be closed) is X * remote on system 'n', then we may have to send a close X * message to system 'n', but only if X * 1. the file descriptor being duped is non-remote X * or X * 2. the file descriptor being duped is on a different X * remote system. X * Note that case number 1 implies that there is no more X * remote work to be done. X */ X if (newfp->f_flag & FREMOTE) { X if ((oldfp->f_flag & FREMOTE) == 0 X || newfp->f_data != oldfp->f_data) { X if ((oldfp->f_flag & FREMOTE) == 0) X sysindex = -1; X uap->oldfd = uap->newfd; X remote_fd(RSYS_close); X } X else X closef(newfp); X } X else X closef(newfp); X } X dupit(newfd, oldfp, u.u_pofile[ oldfd ]); X X /* X * We may already be done. X */ X if (sysindex < 0) X return(0); X X /* X * Now send it. X */ X remote_info[ sysindex ].r_nfile++; X msg->m_args[ 1 ] = htonl(newfd); X error = rmt_msgfin(sysindex, m, 0); X if (error) X rmt_deallocfd(newfd); X X return(error); X} X X/* X * routine for handling an error. We should never get here... but if we X * do..... X */ Xrmt_error(sysnum) X int sysnum; X{ X debug1("error reached\n"); X return(EINVAL); X} SHAREOF chmod 444 remote/usr.sys.remote/rmt_syscall1.c # # remote/usr.sys.remote/rmt_syscall2.c # if [ -f remote/usr.sys.remote/rmt_syscall2.c ]; then echo -n 'Hit <return> to overwrite remote/usr.sys.remote/rmt_syscall2.c or ^C to quit' read ans rm -f remote/usr.sys.remote/rmt_syscall2.c fi sed -e 's/^.//' << \SHAREOF > remote/usr.sys.remote/rmt_syscall2.c X/* X * Copyright 1985, Todd Brunhoff. X * X * This software was written at Tektronix Computer Research Laboratories X * as partial fulfillment of a Master's degree at the University of Denver. X * This is not Tektronix proprietary software and should not be X * confused with any software product sold by Tektronix. No warranty is X * expressed or implied on the reliability of this software; the author, X * the University of Denver, and Tektronix, inc. accept no liability for X * any damage done directly or indirectly by this software. This software X * may be copied, modified or used in any way, without fee, provided this X * notice remains an unaltered part of the software. X * X * $Header: rmt_syscall2.c,v 2.0 85/12/07 18:19:28 toddb Rel $ X * X * $Log: rmt_syscall2.c,v $ X * Revision 2.0 85/12/07 18:19:28 toddb X * First public release. X * X */ X#include "../h/param.h" X#ifndef pyr /* Pyramid */ X#include "../machine/pte.h" X#endif X#include "../h/systm.h" X#include "../h/map.h" X#include "../h/dir.h" X#include "../h/user.h" X#include "../h/kernel.h" X#include "../h/proc.h" X#include "../h/mbuf.h" X#include "../h/socket.h" X#include "../remote/remotefs.h" X#include "../h/file.h" X#include "../h/stat.h" X#include "../h/errno.h" X#include "../netinet/in.h" X#include "../h/uio.h" X Xextern struct remoteinfo remote_info[]; Xextern syscalls remote_syscall[]; X X/* X * Remote fcntl() X */ X Xrmt_fcntl (sysindex, m) X int sysindex; X struct mbuf *m; X{ X register long fd, X error; X register struct message *msg = mtod(m, struct message *); X register struct a { X long fd, X command, X arg; X } *uap = (struct a *)u.u_ap; X register struct file *fp; X X if (uap->command == F_DUPFD) { X fp = u.u_ofile[ uap->fd ]; X fd = ufalloc(uap->arg); X if (fd < 0) X return(-1); X remote_info[ (int)fp->f_data ].r_nfile++; X dupit(fd, fp, u.u_pofile[uap->fd]); X msg->m_args[ 1 ] = htonl(fd); X msg->m_syscall = htons(RSYS_dup); X } X else { X msg->m_args[ 1 ] = htonl(uap->command); X msg->m_args[ 2 ] = htonl(uap->arg); X m->m_len += sizeof(long); X } X X /* X * Now send it X */ X error = rmt_msgfin(sysindex, m, 0); X if (error && uap->command == F_DUPFD) X rmt_deallocfd(fd); X X return(error); X} X X/* X * Remote flock() X */ Xrmt_flock (sysindex, m) X int sysindex; X struct mbuf *m; X{ X struct message *msg = mtod(m, struct message *); X struct a { X long fd; X long operation; X } *uap = (struct a *)u.u_ap; X X msg->m_args[ 1 ] = htonl(uap->operation); X /* X * Now send it. X */ X return( rmt_msgfin(sysindex, m, 0) ); X} X X/* X * Remote ioctl() X */ X Xrmt_ioctl (sysindex, m, request, argp) X int sysindex, X request; X struct mbuf *m; X char *argp; X{ X X /* X * for now always fail. X */ X return(EINVAL); X} X X/* X * Remote lseek() X */ Xrmt_lseek (sysindex, m) X long sysindex; X struct mbuf *m; X{ X struct message *msg = mtod(m, struct message *); X struct a { X long fd, X offset, X whence; X } *uap = (struct a *)u.u_ap; X register long flags = RFLG_INFO; X register long twhence = uap->whence; X register long error; X register struct file *fp = u.u_ofile[ uap->fd ]; X X /* X * As a special case for the sake of speed, L_INCR and L_SET can be X * done locally and then the message can be sent as X * info only (no reply). X */ X switch (twhence) { X case L_INCR: X /* X * Very special case: lseek(fd, 0, L_INCR) is a noop. X */ X if (uap->offset == 0) { X m_free(m); X u.u_r.r_off = fp->f_offset; X return(0); X } X fp->f_offset += uap->offset; X break; X case L_XTND: X flags = 0; X break; X case L_SET: X fp->f_offset = uap->offset; X break; X default: X m_free(m); X u.u_error = EINVAL; X return(0); X } X msg->m_args[ 1 ] = htonl(uap->offset); X msg->m_args[ 2 ] = htonl(twhence); X m->m_len += sizeof(long); X if (flags == RFLG_INFO) X msg->m_syscall = htons(RSYS_qlseek); X X /* X * Now send it. X */ X error = rmt_msgfin(sysindex, m, flags); X if (flags != RFLG_INFO) X fp->f_offset = u.u_r.r_val1; X else X u.u_r.r_off = fp->f_offset; X return( error ); X} X X/* X * Remote mknod() X */ Xrmt_mknod (sysindex, m, mode, dev) X long sysindex, X mode, dev; X struct mbuf *m; X{ X struct message *msg = mtod(m, struct message *); X struct a { X char *path; X long mode, X dev; X } *uap = (struct a *)u.u_ap; X X msg->m_args[ 0 ] = htonl(uap->mode); X msg->m_args[ 1 ] = htonl(uap->dev); X msg->m_args[ 2 ] = htonl(u.u_cmask); X X /* X * Now send it. X */ X return( rmt_msgfin(sysindex, m, 0) ); X} X Xrmt_noop() { return; } X X/* X * Remote mkdir() and rmdir() and unlink() and fsync() and close() X */ Xrmt_onearg (sysindex, m) X int sysindex; X struct mbuf *m; X{ X struct message *msg = mtod(m, struct message *); X short syscall = ntohs(msg->m_syscall); X long error; X X if (syscall == RSYS_close) { X struct a { X long fd; X } *uap = (struct a *)u.u_ap; X rmt_deallocfd(uap->fd); X m->m_len = R_MINRMSG + sizeof(long); X } X else if (syscall == RSYS_fsync) X m->m_len = R_MINRMSG + sizeof(long); X else X msg->m_args[ 0 ] = htonl(u.u_cmask); X X error = rmt_msgfin(sysindex, m, remote_syscall[ syscall ].sys_flag); X return(error); X} SHAREOF chmod 444 remote/usr.sys.remote/rmt_syscall2.c