home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume10 / dev.fd / dev_fd.c next >
Encoding:
C/C++ Source or Header  |  1987-08-06  |  8.8 KB  |  341 lines

  1. #ifndef lint
  2. static char rcsid[] = "@(#)$Header: dev_fd.c,v 1.6 87/07/10 10:24:13 root Locked $";
  3. #endif lint
  4.  
  5. /*
  6.  * fd.c        Fred Blonder - U of Maryland    11-Sep-1984
  7.  *
  8.  * ``File Descriptor'' pseudo-device driver, rewritten for Berkeley 4.2.
  9.  *
  10.  * Opening minor device N opens the file (if any) connected to file-descriptor
  11.  * N belonging to the calling process. Note that this driver consists of only
  12.  * the ``open()'' routine, because all subsequent references to this file will
  13.  * be direct to the other driver.
  14.  *
  15.  * NFS version by
  16.  * Arnold Robbins -- Emory University Computing Center -- Summer 87
  17.  */
  18.  
  19. /*
  20.  * $Log:    dev_fd.c,v $
  21.  * Revision 1.6  87/07/10  10:24:13  root
  22.  * Removed debugging printfs. ADR.
  23.  * 
  24.  * Revision 1.5  87/07/10  10:20:12  root
  25.  * Added ENXIO check to inode version. ADR.
  26.  * 
  27.  * Revision 1.4  87/07/05  14:19:41  root
  28.  * Added NOFILE/ENXIO check, some minor cleanup. ADR.
  29.  * 
  30.  * Revision 1.3  87/07/05  10:46:48  root
  31.  * Brought the comments into sync with reality. Bug fix to inode version. ADR.
  32.  * 
  33.  * Revision 1.2  87/07/03  16:53:46  root
  34.  * NFS version of the driver. Works just fine on a sun. ADR.
  35.  * 
  36.  * Revision 1.1  84/12/01  21:38:17  chris
  37.  * Initial revision
  38.  * 
  39.  */
  40.  
  41. #include "fd.h"
  42. #if NFD > 0
  43.  
  44. #include "../h/param.h"
  45. #ifdef NFS
  46. #include "../h/time.h"
  47. #include "../h/vnode.h"
  48. #else
  49. #include "../h/inode.h"
  50. #endif
  51. #include "../h/file.h"
  52. #include "../h/dir.h"
  53. #include "../h/user.h"
  54. #include "../h/errno.h"
  55.  
  56. /*
  57.  * THIS CODE NEEDS CLEANING AS SOON AS ASSIGNMENTS TO u.u_* GO AWAY
  58.  */
  59.  
  60. /*
  61.  * The NFS mods are so extensive that I have decided to provide two whole
  62.  * copies of the routine, one for NFS and one for regular BSD, instead
  63.  * of mixing them up with ifdefs. The non-NFS code is the original
  64.  * version from UMD.  A.D.R.
  65.  */
  66.  
  67. #ifdef NFS
  68. /*
  69.  * XXX
  70.  *
  71.  * WARNING!!!!! This piece of code requires that a patch be made
  72.  * to the stock NFS 3.2 code in specfs/spec_vnodeops.c$spec_open().
  73.  * The modification is to pass a pointer to the vnode for this file
  74.  * into this routine in the call to (*cdewsw[major(dev)])(), as a fourth
  75.  * argument.
  76.  *
  77.  * Why? you ask. When this device is opened, open() calls copen() which calls
  78.  * vn_open(). Now, the whole idea behind this "device" is to substitute an
  79.  * already open file for this one. The way to do this is to hand back up a vnode
  80.  * for said open file. The regular inode version of this code has it easy.
  81.  * The file structure for this device points at the device's inode. Chuck
  82.  * that inode and substitute the inode of the already open file. It is not
  83.  * so easy in the NFS case, because *the file structure does not yet
  84.  * point at a vnode*. That is only done in copen() after the vn_open()
  85.  * completes. Right now, we're still in the middle of the open. So we have
  86.  * no way of getting at the original vnode unless it is passed in to us.
  87.  * So that is why spec_open() has to pass a pointer to the vnode (pointer)
  88.  * to us, so we can switch it around.
  89.  */
  90.  
  91. fdopen (dev, mode, newdev, vpp)
  92. dev_t dev;
  93. int mode;
  94. dev_t *newdev;
  95. struct vnode **vpp;    /* vnode for this device */
  96. {
  97.     struct file *fp, *wfp;
  98.     struct vnode *vp, *wvp;
  99.     int vmode = 0;
  100.     int rwmode, error;
  101.  
  102.     if (minor(dev) >= NOFILE)    /* sanity check */
  103.         return (ENXIO);
  104.  
  105.     *newdev = dev;    /* XXX - force loop termination in spec_open() */
  106.  
  107.     /*
  108.      * Note the horrid kludge here: u.u_r.r_val1 contains the value
  109.      * of the new file descriptor, which has not been disturbed since
  110.      * it was allocated.
  111.      */
  112.  
  113.     if ((fp = getf(u.u_r.r_val1)) == NULL)
  114.         return (u.u_error);
  115.  
  116.     if ((wfp = getf(minor(dev))) == NULL)
  117.         return (u.u_error);
  118.  
  119.     /*
  120.      * We must explicitly test for this case because ufalloc() may
  121.      * have allocated us the same file desriptor we are referring
  122.      * to, if the proccess referred to an invalid (closed) descriptor.
  123.      * Ordinarily this would be caught by getf(), but by the time we
  124.      * reach this routine u_pofile[minor(dev)] could already be set
  125.      * to point to our file struct.
  126.      */
  127.     if (fp == wfp)
  128.         return (EBADF);
  129.  
  130.     vp = *vpp;
  131.  
  132.     /*
  133.      * Fake a ``dup()'' sys call if it isn't a vnode.
  134.      */
  135.     if (wfp->f_type != DTYPE_VNODE) {
  136.         /*
  137.          * Check that the mode the file is being opened
  138.          * for is consistent with the mode of the existing
  139.          * descriptor. This isn't as clean as it should be,
  140.          * but this entire driver is a real kludge anyway.
  141.          */
  142.         rwmode = mode & (FREAD|FWRITE);
  143.         if ((wfp->f_flag & rwmode) != rwmode)
  144.             return (EACCES);
  145.  
  146.         /* Delete references to this pseudo-device. */
  147.         VN_RELE(vp);        /* Chuck the vnode. */
  148.         fp->f_count = 0;    /* Chuck the file structure. */
  149.         crfree(fp->f_cred);
  150.         /* Dup the file descriptor. */
  151.         dupit(u.u_r.r_val1, wfp, u.u_pofile[minor(dev)]);
  152.         *vpp = (struct vnode *)wfp->f_data;    /* needed? */
  153.         return (0);
  154.     }
  155.  
  156.     /*
  157.      * now have a regular vnode.
  158.      */
  159.     error = 0;
  160.     wvp = (struct vnode *)wfp->f_data;
  161.  
  162.     /*
  163.      * Since we're opening a file again, we run through all the
  164.      * permission checks so this can't be used as a loophole to
  165.      * get access to a file we shouldn't have.  (GROT)
  166.      */
  167.     if (mode & FREAD && (error = VOP_ACCESS(wvp, VREAD, u.u_cred)))
  168.         goto bad;
  169.     if (mode & (FWRITE|FTRUNC)) {
  170.         if (vp->v_type == VDIR) {
  171.             error = EISDIR;
  172.             goto bad;
  173.         }
  174.         if ((error = VOP_ACCESS(wvp, VWRITE, u.u_cred)))
  175.             goto bad;
  176.     }
  177.  
  178.     /*
  179.      * The file must always exist, so we don't even bother testing
  180.      * for its presence.
  181.      */
  182.     if ((mode & (FCREAT|FEXCL)) == (FCREAT|FEXCL)) {
  183.         error = EEXIST;
  184.         goto bad;
  185.     }
  186.  
  187.     /*
  188.      * This may not make any sense, but I'm paranoid and figure that
  189.      * it's probably an error.
  190.      */
  191.     if (mode & FTRUNC) {
  192.         error = EBUSY;
  193.         goto bad;
  194.     }
  195.  
  196.     /* Call the device-specific open routine, if any. */
  197.     vmode = mode & ~(FCREAT | FEXCL);
  198.     if (wvp->v_type != VREG &&
  199.             (error = VOP_OPEN(&wvp, vmode, u.u_cred)) != 0)
  200.         goto bad;
  201.  
  202.     /*
  203.      * Made it this far, now return the other vnode back up the
  204.      * call chain for insertion into the file table entry.
  205.      */
  206.     VN_RELE(vp);        /* We don't need this anymore. */
  207.     wvp->v_count++;
  208.     *vpp = wvp;
  209.     return (0);
  210.  
  211. bad:
  212.     return (error);
  213. }
  214.  
  215. #else    /* ! NFS */
  216.  
  217. fdopen(dev, mode)
  218. dev_t dev;
  219. int mode;
  220. {
  221.     struct file *fp, *wfp;
  222.     struct inode *ip, *wip;
  223.     int rwmode, error;
  224.  
  225.     /* this check added by ADR */
  226.     if (minor(dev) >= NOFILE)    /* sanity check */
  227.         return (ENXIO);
  228.  
  229.     /*
  230.      * Note the horrid kludge here: u.u_r.r_val1 contains the value
  231.      * of the new file descriptor, which has not been disturbed since
  232.      * it was allocated.
  233.      */
  234.     if ((fp = getf(u.u_r.r_val1)) == NULL)
  235.         return (u.u_error);
  236.  
  237.     if ((wfp = getf(minor(dev))) == NULL)
  238.         return (u.u_error);
  239.  
  240.     /*
  241.      * We must explicitly test for this case because ufalloc() may
  242.      * have allocated us the same file desriptor we are referring
  243.      * to, if the proccess referred to an invalid (closed) descriptor.
  244.      * Ordinarily this would be caught by getf(), but by the time we
  245.      * reach this routine u_pofile[minor(dev)] could already be set
  246.      * to point to our file struct.
  247.      */
  248.     if (fp == wfp)
  249.         return (EBADF);
  250.  
  251.     ip = (struct inode *)fp->f_data;
  252.  
  253.     /*
  254.      * Fake a ``dup()'' sys call if it isn't an inode.
  255.      */
  256.     if (wfp->f_type != DTYPE_INODE) {
  257.         /*
  258.          * Check that the mode the file is being opened
  259.          * for is consistent with the mode of the existing
  260.          * descriptor. This isn't as clean as it should be,
  261.          * but this entire driver is a real kludge anyway.
  262.          */
  263.         rwmode = mode & (FREAD|FWRITE);
  264.         /* ADR: Bug fix: wfp below was originally fp */
  265.         if ((wfp->f_flag & rwmode) != rwmode)
  266.             return (EACCES);
  267.  
  268.         /* Delete references to this pseudo-device. */
  269.         irele(ip);        /* Chuck the inode. */
  270.         fp->f_count = 0;    /* Chuck the file structure. */
  271.         /* Dup the file descriptor. */
  272.         dupit(u.u_r.r_val1, wfp, u.u_pofile[minor(dev)]);
  273.         return (0);
  274.     }
  275.  
  276.     error = 0;
  277.     wip = (struct inode *)wfp->f_data;
  278.  
  279.     /*
  280.      * I'm not sure that we really need to lock the inode here,
  281.      * but why not be paranoid?
  282.      */
  283.     ilock(wip);
  284.  
  285.     /*
  286.      * Since we're opening a file again, we run through all the
  287.      * permission checks so this can't be used as a loophole to
  288.      * get access to a file we shouldn't have.  (GROT)
  289.      */
  290.     if (mode & FREAD && access(wip, IREAD))
  291.         goto bad;
  292.     if (mode & (FWRITE|FTRUNC)) {
  293.         if ((ip->i_mode&IFMT) == IFDIR) {
  294.             error = EISDIR;
  295.             goto bad;
  296.         }
  297.         if (access(wip, IWRITE))
  298.             goto bad;
  299.     }
  300.  
  301.     /*
  302.      * The file must always exist, so we don't even bother testing
  303.      * for its presence.
  304.      */
  305.     if ((mode & (FCREAT|FEXCL)) == (FCREAT|FEXCL)) {
  306.         error = EEXIST;
  307.         goto bad;
  308.     }
  309.  
  310.     /*
  311.      * This may not make any sense, but I'm paranoid and figure that
  312.      * it's probably an error.
  313.      */
  314.     if (mode & FTRUNC) {
  315.         error = EBUSY;
  316.         goto bad;
  317.     }
  318.  
  319.     /* Call the device-specific open routine, if any. */
  320.     if ((error = openi(wip, mode)) != 0)
  321.         goto bad;
  322.  
  323.     /*
  324.      * Made it this far, now switch the inode pointers in the
  325.      * file descriptors around, to make this file open refer
  326.      * to the other file.
  327.      */
  328.     irele(ip);        /* We don't need this anymore. */
  329.     fp->f_data = (caddr_t)wip;
  330.     wip->i_count++;
  331.     iunlock(wip);
  332.     return (0);
  333.  
  334. bad:
  335.     iunlock(wip);
  336.     return (error);
  337. }
  338.  
  339. #endif /* NFS */
  340. #endif /* NFD > 0 */
  341.