home *** CD-ROM | disk | FTP | other *** search
- #ifndef lint
- static char rcsid[] = "@(#)$Header: dev_fd.c,v 1.6 87/07/10 10:24:13 root Locked $";
- #endif lint
-
- /*
- * fd.c Fred Blonder - U of Maryland 11-Sep-1984
- *
- * ``File Descriptor'' pseudo-device driver, rewritten for Berkeley 4.2.
- *
- * Opening minor device N opens the file (if any) connected to file-descriptor
- * N belonging to the calling process. Note that this driver consists of only
- * the ``open()'' routine, because all subsequent references to this file will
- * be direct to the other driver.
- *
- * NFS version by
- * Arnold Robbins -- Emory University Computing Center -- Summer 87
- */
-
- /*
- * $Log: dev_fd.c,v $
- * Revision 1.6 87/07/10 10:24:13 root
- * Removed debugging printfs. ADR.
- *
- * Revision 1.5 87/07/10 10:20:12 root
- * Added ENXIO check to inode version. ADR.
- *
- * Revision 1.4 87/07/05 14:19:41 root
- * Added NOFILE/ENXIO check, some minor cleanup. ADR.
- *
- * Revision 1.3 87/07/05 10:46:48 root
- * Brought the comments into sync with reality. Bug fix to inode version. ADR.
- *
- * Revision 1.2 87/07/03 16:53:46 root
- * NFS version of the driver. Works just fine on a sun. ADR.
- *
- * Revision 1.1 84/12/01 21:38:17 chris
- * Initial revision
- *
- */
-
- #include "fd.h"
- #if NFD > 0
-
- #include "../h/param.h"
- #ifdef NFS
- #include "../h/time.h"
- #include "../h/vnode.h"
- #else
- #include "../h/inode.h"
- #endif
- #include "../h/file.h"
- #include "../h/dir.h"
- #include "../h/user.h"
- #include "../h/errno.h"
-
- /*
- * THIS CODE NEEDS CLEANING AS SOON AS ASSIGNMENTS TO u.u_* GO AWAY
- */
-
- /*
- * The NFS mods are so extensive that I have decided to provide two whole
- * copies of the routine, one for NFS and one for regular BSD, instead
- * of mixing them up with ifdefs. The non-NFS code is the original
- * version from UMD. A.D.R.
- */
-
- #ifdef NFS
- /*
- * XXX
- *
- * WARNING!!!!! This piece of code requires that a patch be made
- * to the stock NFS 3.2 code in specfs/spec_vnodeops.c$spec_open().
- * The modification is to pass a pointer to the vnode for this file
- * into this routine in the call to (*cdewsw[major(dev)])(), as a fourth
- * argument.
- *
- * Why? you ask. When this device is opened, open() calls copen() which calls
- * vn_open(). Now, the whole idea behind this "device" is to substitute an
- * already open file for this one. The way to do this is to hand back up a vnode
- * for said open file. The regular inode version of this code has it easy.
- * The file structure for this device points at the device's inode. Chuck
- * that inode and substitute the inode of the already open file. It is not
- * so easy in the NFS case, because *the file structure does not yet
- * point at a vnode*. That is only done in copen() after the vn_open()
- * completes. Right now, we're still in the middle of the open. So we have
- * no way of getting at the original vnode unless it is passed in to us.
- * So that is why spec_open() has to pass a pointer to the vnode (pointer)
- * to us, so we can switch it around.
- */
-
- fdopen (dev, mode, newdev, vpp)
- dev_t dev;
- int mode;
- dev_t *newdev;
- struct vnode **vpp; /* vnode for this device */
- {
- struct file *fp, *wfp;
- struct vnode *vp, *wvp;
- int vmode = 0;
- int rwmode, error;
-
- if (minor(dev) >= NOFILE) /* sanity check */
- return (ENXIO);
-
- *newdev = dev; /* XXX - force loop termination in spec_open() */
-
- /*
- * Note the horrid kludge here: u.u_r.r_val1 contains the value
- * of the new file descriptor, which has not been disturbed since
- * it was allocated.
- */
-
- if ((fp = getf(u.u_r.r_val1)) == NULL)
- return (u.u_error);
-
- if ((wfp = getf(minor(dev))) == NULL)
- return (u.u_error);
-
- /*
- * We must explicitly test for this case because ufalloc() may
- * have allocated us the same file desriptor we are referring
- * to, if the proccess referred to an invalid (closed) descriptor.
- * Ordinarily this would be caught by getf(), but by the time we
- * reach this routine u_pofile[minor(dev)] could already be set
- * to point to our file struct.
- */
- if (fp == wfp)
- return (EBADF);
-
- vp = *vpp;
-
- /*
- * Fake a ``dup()'' sys call if it isn't a vnode.
- */
- if (wfp->f_type != DTYPE_VNODE) {
- /*
- * Check that the mode the file is being opened
- * for is consistent with the mode of the existing
- * descriptor. This isn't as clean as it should be,
- * but this entire driver is a real kludge anyway.
- */
- rwmode = mode & (FREAD|FWRITE);
- if ((wfp->f_flag & rwmode) != rwmode)
- return (EACCES);
-
- /* Delete references to this pseudo-device. */
- VN_RELE(vp); /* Chuck the vnode. */
- fp->f_count = 0; /* Chuck the file structure. */
- crfree(fp->f_cred);
- /* Dup the file descriptor. */
- dupit(u.u_r.r_val1, wfp, u.u_pofile[minor(dev)]);
- *vpp = (struct vnode *)wfp->f_data; /* needed? */
- return (0);
- }
-
- /*
- * now have a regular vnode.
- */
- error = 0;
- wvp = (struct vnode *)wfp->f_data;
-
- /*
- * Since we're opening a file again, we run through all the
- * permission checks so this can't be used as a loophole to
- * get access to a file we shouldn't have. (GROT)
- */
- if (mode & FREAD && (error = VOP_ACCESS(wvp, VREAD, u.u_cred)))
- goto bad;
- if (mode & (FWRITE|FTRUNC)) {
- if (vp->v_type == VDIR) {
- error = EISDIR;
- goto bad;
- }
- if ((error = VOP_ACCESS(wvp, VWRITE, u.u_cred)))
- goto bad;
- }
-
- /*
- * The file must always exist, so we don't even bother testing
- * for its presence.
- */
- if ((mode & (FCREAT|FEXCL)) == (FCREAT|FEXCL)) {
- error = EEXIST;
- goto bad;
- }
-
- /*
- * This may not make any sense, but I'm paranoid and figure that
- * it's probably an error.
- */
- if (mode & FTRUNC) {
- error = EBUSY;
- goto bad;
- }
-
- /* Call the device-specific open routine, if any. */
- vmode = mode & ~(FCREAT | FEXCL);
- if (wvp->v_type != VREG &&
- (error = VOP_OPEN(&wvp, vmode, u.u_cred)) != 0)
- goto bad;
-
- /*
- * Made it this far, now return the other vnode back up the
- * call chain for insertion into the file table entry.
- */
- VN_RELE(vp); /* We don't need this anymore. */
- wvp->v_count++;
- *vpp = wvp;
- return (0);
-
- bad:
- return (error);
- }
-
- #else /* ! NFS */
-
- fdopen(dev, mode)
- dev_t dev;
- int mode;
- {
- struct file *fp, *wfp;
- struct inode *ip, *wip;
- int rwmode, error;
-
- /* this check added by ADR */
- if (minor(dev) >= NOFILE) /* sanity check */
- return (ENXIO);
-
- /*
- * Note the horrid kludge here: u.u_r.r_val1 contains the value
- * of the new file descriptor, which has not been disturbed since
- * it was allocated.
- */
- if ((fp = getf(u.u_r.r_val1)) == NULL)
- return (u.u_error);
-
- if ((wfp = getf(minor(dev))) == NULL)
- return (u.u_error);
-
- /*
- * We must explicitly test for this case because ufalloc() may
- * have allocated us the same file desriptor we are referring
- * to, if the proccess referred to an invalid (closed) descriptor.
- * Ordinarily this would be caught by getf(), but by the time we
- * reach this routine u_pofile[minor(dev)] could already be set
- * to point to our file struct.
- */
- if (fp == wfp)
- return (EBADF);
-
- ip = (struct inode *)fp->f_data;
-
- /*
- * Fake a ``dup()'' sys call if it isn't an inode.
- */
- if (wfp->f_type != DTYPE_INODE) {
- /*
- * Check that the mode the file is being opened
- * for is consistent with the mode of the existing
- * descriptor. This isn't as clean as it should be,
- * but this entire driver is a real kludge anyway.
- */
- rwmode = mode & (FREAD|FWRITE);
- /* ADR: Bug fix: wfp below was originally fp */
- if ((wfp->f_flag & rwmode) != rwmode)
- return (EACCES);
-
- /* Delete references to this pseudo-device. */
- irele(ip); /* Chuck the inode. */
- fp->f_count = 0; /* Chuck the file structure. */
- /* Dup the file descriptor. */
- dupit(u.u_r.r_val1, wfp, u.u_pofile[minor(dev)]);
- return (0);
- }
-
- error = 0;
- wip = (struct inode *)wfp->f_data;
-
- /*
- * I'm not sure that we really need to lock the inode here,
- * but why not be paranoid?
- */
- ilock(wip);
-
- /*
- * Since we're opening a file again, we run through all the
- * permission checks so this can't be used as a loophole to
- * get access to a file we shouldn't have. (GROT)
- */
- if (mode & FREAD && access(wip, IREAD))
- goto bad;
- if (mode & (FWRITE|FTRUNC)) {
- if ((ip->i_mode&IFMT) == IFDIR) {
- error = EISDIR;
- goto bad;
- }
- if (access(wip, IWRITE))
- goto bad;
- }
-
- /*
- * The file must always exist, so we don't even bother testing
- * for its presence.
- */
- if ((mode & (FCREAT|FEXCL)) == (FCREAT|FEXCL)) {
- error = EEXIST;
- goto bad;
- }
-
- /*
- * This may not make any sense, but I'm paranoid and figure that
- * it's probably an error.
- */
- if (mode & FTRUNC) {
- error = EBUSY;
- goto bad;
- }
-
- /* Call the device-specific open routine, if any. */
- if ((error = openi(wip, mode)) != 0)
- goto bad;
-
- /*
- * Made it this far, now switch the inode pointers in the
- * file descriptors around, to make this file open refer
- * to the other file.
- */
- irele(ip); /* We don't need this anymore. */
- fp->f_data = (caddr_t)wip;
- wip->i_count++;
- iunlock(wip);
- return (0);
-
- bad:
- iunlock(wip);
- return (error);
- }
-
- #endif /* NFS */
- #endif /* NFD > 0 */
-