Relay-Version: version B 2.10.3 beta 11/15/85; site seismo.CSS.GOV Posting-Version: version B 2.10.2 9/3/84; site panda.UUCP Path: seismo!harvard!talcott!panda!sources-request From: sources-request@panda.UUCP Newsgroups: mod.sources Subject: RFS: remote file system (part 7 of 7) Message-ID: <1282@panda.UUCP> Date: 9 Jan 86 14:11:59 GMT Sender: jpn@panda.UUCP Lines: 2572 Approved: jpn@panda.UUCP 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 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; if_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; ir_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; if_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; ir_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 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 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 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 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 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