RFS: remote file system (part 7 of 7)
sources-request at panda.UUCP
sources-request at panda.UUCP
Fri Jan 10 00:11:59 AEST 1986
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
More information about the Mod.sources
mailing list