BSD 4_4_Lite1 release
[unix-history] / usr / src / sys / miscfs / specfs / spec_vnops.c
index c0a24dc..111c517 100644 (file)
@@ -1,10 +1,36 @@
 /*
 /*
- * Copyright (c) 1989 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  *
- * %sccs.include.redist.c%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
  *
  *
- *     @(#)spec_vnops.c        7.52 (Berkeley) %G%
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)spec_vnops.c        8.6 (Berkeley) 4/9/94
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -38,20 +64,20 @@ struct vnodeopv_entry_desc spec_vnodeop_entries[] = {
        { &vop_lookup_desc, spec_lookup },              /* lookup */
        { &vop_create_desc, spec_create },              /* create */
        { &vop_mknod_desc, spec_mknod },                /* mknod */
        { &vop_lookup_desc, spec_lookup },              /* lookup */
        { &vop_create_desc, spec_create },              /* create */
        { &vop_mknod_desc, spec_mknod },                /* mknod */
-       { &vop_open_desc, spec_open },          /* open */
+       { &vop_open_desc, spec_open },                  /* open */
        { &vop_close_desc, spec_close },                /* close */
        { &vop_access_desc, spec_access },              /* access */
        { &vop_getattr_desc, spec_getattr },            /* getattr */
        { &vop_setattr_desc, spec_setattr },            /* setattr */
        { &vop_close_desc, spec_close },                /* close */
        { &vop_access_desc, spec_access },              /* access */
        { &vop_getattr_desc, spec_getattr },            /* getattr */
        { &vop_setattr_desc, spec_setattr },            /* setattr */
-       { &vop_read_desc, spec_read },          /* read */
+       { &vop_read_desc, spec_read },                  /* read */
        { &vop_write_desc, spec_write },                /* write */
        { &vop_ioctl_desc, spec_ioctl },                /* ioctl */
        { &vop_select_desc, spec_select },              /* select */
        { &vop_write_desc, spec_write },                /* write */
        { &vop_ioctl_desc, spec_ioctl },                /* ioctl */
        { &vop_select_desc, spec_select },              /* select */
-       { &vop_mmap_desc, spec_mmap },          /* mmap */
+       { &vop_mmap_desc, spec_mmap },                  /* mmap */
        { &vop_fsync_desc, spec_fsync },                /* fsync */
        { &vop_fsync_desc, spec_fsync },                /* fsync */
-       { &vop_seek_desc, spec_seek },          /* seek */
+       { &vop_seek_desc, spec_seek },                  /* seek */
        { &vop_remove_desc, spec_remove },              /* remove */
        { &vop_remove_desc, spec_remove },              /* remove */
-       { &vop_link_desc, spec_link },          /* link */
+       { &vop_link_desc, spec_link },                  /* link */
        { &vop_rename_desc, spec_rename },              /* rename */
        { &vop_mkdir_desc, spec_mkdir },                /* mkdir */
        { &vop_rmdir_desc, spec_rmdir },                /* rmdir */
        { &vop_rename_desc, spec_rename },              /* rename */
        { &vop_mkdir_desc, spec_mkdir },                /* mkdir */
        { &vop_rmdir_desc, spec_rmdir },                /* rmdir */
@@ -61,12 +87,13 @@ struct vnodeopv_entry_desc spec_vnodeop_entries[] = {
        { &vop_abortop_desc, spec_abortop },            /* abortop */
        { &vop_inactive_desc, spec_inactive },          /* inactive */
        { &vop_reclaim_desc, spec_reclaim },            /* reclaim */
        { &vop_abortop_desc, spec_abortop },            /* abortop */
        { &vop_inactive_desc, spec_inactive },          /* inactive */
        { &vop_reclaim_desc, spec_reclaim },            /* reclaim */
-       { &vop_lock_desc, spec_lock },          /* lock */
+       { &vop_lock_desc, spec_lock },                  /* lock */
        { &vop_unlock_desc, spec_unlock },              /* unlock */
        { &vop_unlock_desc, spec_unlock },              /* unlock */
-       { &vop_bmap_desc, spec_bmap },          /* bmap */
+       { &vop_bmap_desc, spec_bmap },                  /* bmap */
        { &vop_strategy_desc, spec_strategy },          /* strategy */
        { &vop_print_desc, spec_print },                /* print */
        { &vop_islocked_desc, spec_islocked },          /* islocked */
        { &vop_strategy_desc, spec_strategy },          /* strategy */
        { &vop_print_desc, spec_print },                /* print */
        { &vop_islocked_desc, spec_islocked },          /* islocked */
+       { &vop_pathconf_desc, spec_pathconf },          /* pathconf */
        { &vop_advlock_desc, spec_advlock },            /* advlock */
        { &vop_blkatoff_desc, spec_blkatoff },          /* blkatoff */
        { &vop_valloc_desc, spec_valloc },              /* valloc */
        { &vop_advlock_desc, spec_advlock },            /* advlock */
        { &vop_blkatoff_desc, spec_blkatoff },          /* blkatoff */
        { &vop_valloc_desc, spec_valloc },              /* valloc */
@@ -96,9 +123,7 @@ spec_lookup(ap)
 }
 
 /*
 }
 
 /*
- * Open a special file: Don't allow open if fs is mounted -nodev,
- * and don't allow opens of block devices that are currently mounted.
- * Otherwise, call device driver open function.
+ * Open a special file.
  */
 /* ARGSUSED */
 spec_open(ap)
  */
 /* ARGSUSED */
 spec_open(ap)
@@ -109,11 +134,14 @@ spec_open(ap)
                struct proc *a_p;
        } */ *ap;
 {
                struct proc *a_p;
        } */ *ap;
 {
-       register struct vnode *vp = ap->a_vp;
-       dev_t dev = (dev_t)vp->v_rdev;
+       struct vnode *bvp, *vp = ap->a_vp;
+       dev_t bdev, dev = (dev_t)vp->v_rdev;
        register int maj = major(dev);
        int error;
 
        register int maj = major(dev);
        int error;
 
+       /*
+        * Don't allow open if fs is mounted -nodev.
+        */
        if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV))
                return (ENXIO);
 
        if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV))
                return (ENXIO);
 
@@ -122,6 +150,29 @@ spec_open(ap)
        case VCHR:
                if ((u_int)maj >= nchrdev)
                        return (ENXIO);
        case VCHR:
                if ((u_int)maj >= nchrdev)
                        return (ENXIO);
+               if (ap->a_cred != FSCRED && (ap->a_mode & FWRITE)) {
+                       /*
+                        * When running in very secure mode, do not allow
+                        * opens for writing of any disk character devices.
+                        */
+                       if (securelevel >= 2 && isdisk(dev, VCHR))
+                               return (EPERM);
+                       /*
+                        * When running in secure mode, do not allow opens
+                        * for writing of /dev/mem, /dev/kmem, or character
+                        * devices whose corresponding block devices are
+                        * currently mounted.
+                        */
+                       if (securelevel >= 1) {
+                               if ((bdev = chrtoblk(dev)) != NODEV &&
+                                   vfinddev(bdev, VBLK, &bvp) &&
+                                   bvp->v_usecount > 0 &&
+                                   (error = vfs_mountedon(bvp)))
+                                       return (error);
+                               if (iskmemdev(dev))
+                                       return (EPERM);
+                       }
+               }
                VOP_UNLOCK(vp);
                error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, ap->a_p);
                VOP_LOCK(vp);
                VOP_UNLOCK(vp);
                error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, ap->a_p);
                VOP_LOCK(vp);
@@ -130,7 +181,18 @@ spec_open(ap)
        case VBLK:
                if ((u_int)maj >= nblkdev)
                        return (ENXIO);
        case VBLK:
                if ((u_int)maj >= nblkdev)
                        return (ENXIO);
-               if (error = ufs_mountedon(vp))
+               /*
+                * When running in very secure mode, do not allow
+                * opens for writing of any disk block devices.
+                */
+               if (securelevel >= 2 && ap->a_cred != FSCRED &&
+                   (ap->a_mode & FWRITE) && isdisk(dev, VBLK))
+                       return (EPERM);
+               /*
+                * Do not allow opens of block devices that are
+                * currently mounted.
+                */
+               if (error = vfs_mountedon(vp))
                        return (error);
                return ((*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, ap->a_p));
        }
                        return (error);
                return ((*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, ap->a_p));
        }
@@ -156,8 +218,9 @@ spec_read(ap)
        daddr_t bn, nextbn;
        long bsize, bscale;
        struct partinfo dpart;
        daddr_t bn, nextbn;
        long bsize, bscale;
        struct partinfo dpart;
-       register int n, on;
+       int n, on, majordev, (*ioctl)();
        int error = 0;
        int error = 0;
+       dev_t dev;
 
 #ifdef DIAGNOSTIC
        if (uio->uio_rw != UIO_READ)
 
 #ifdef DIAGNOSTIC
        if (uio->uio_rw != UIO_READ)
@@ -181,13 +244,13 @@ spec_read(ap)
                if (uio->uio_offset < 0)
                        return (EINVAL);
                bsize = BLKDEV_IOSIZE;
                if (uio->uio_offset < 0)
                        return (EINVAL);
                bsize = BLKDEV_IOSIZE;
-               if ((*bdevsw[major(vp->v_rdev)].d_ioctl)(vp->v_rdev, DIOCGPART,
-                   (caddr_t)&dpart, FREAD, p) == 0) {
-                       if (dpart.part->p_fstype == FS_BSDFFS &&
-                           dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
-                               bsize = dpart.part->p_frag *
-                                   dpart.part->p_fsize;
-               }
+               dev = vp->v_rdev;
+               if ((majordev = major(dev)) < nblkdev &&
+                   (ioctl = bdevsw[majordev].d_ioctl) != NULL &&
+                   (*ioctl)(dev, DIOCGPART, (caddr_t)&dpart, FREAD, p) == 0 &&
+                   dpart.part->p_fstype == FS_BSDFFS &&
+                   dpart.part->p_frag != 0 && dpart.part->p_fsize != 0)
+                       bsize = dpart.part->p_frag * dpart.part->p_fsize;
                bscale = bsize / DEV_BSIZE;
                do {
                        bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1);
                bscale = bsize / DEV_BSIZE;
                do {
                        bn = (uio->uio_offset / DEV_BSIZE) &~ (bscale - 1);
@@ -205,7 +268,7 @@ spec_read(ap)
                                brelse(bp);
                                return (error);
                        }
                                brelse(bp);
                                return (error);
                        }
-                       error = uiomove(bp->b_un.b_addr + on, n, uio);
+                       error = uiomove((char *)bp->b_data + on, n, uio);
                        if (n + on == bsize)
                                bp->b_flags |= B_AGE;
                        brelse(bp);
                        if (n + on == bsize)
                                bp->b_flags |= B_AGE;
                        brelse(bp);
@@ -283,7 +346,7 @@ spec_write(ap)
                                brelse(bp);
                                return (error);
                        }
                                brelse(bp);
                                return (error);
                        }
-                       error = uiomove(bp->b_un.b_addr + on, n, uio);
+                       error = uiomove((char *)bp->b_data + on, n, uio);
                        if (n + on == bsize) {
                                bp->b_flags |= B_AGE;
                                bawrite(bp);
                        if (n + on == bsize) {
                                bp->b_flags |= B_AGE;
                                bawrite(bp);
@@ -382,8 +445,8 @@ spec_fsync(ap)
         */
 loop:
        s = splbio();
         */
 loop:
        s = splbio();
-       for (bp = vp->v_dirtyblkhd.le_next; bp; bp = nbp) {
-               nbp = bp->b_vnbufs.qe_next;
+       for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
+               nbp = bp->b_vnbufs.le_next;
                if ((bp->b_flags & B_BUSY))
                        continue;
                if ((bp->b_flags & B_DELWRI) == 0)
                if ((bp->b_flags & B_BUSY))
                        continue;
                if ((bp->b_flags & B_DELWRI) == 0)
@@ -400,7 +463,7 @@ loop:
                        sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1);
                }
 #ifdef DIAGNOSTIC
                        sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1);
                }
 #ifdef DIAGNOSTIC
-               if (vp->v_dirtyblkhd.le_next) {
+               if (vp->v_dirtyblkhd.lh_first) {
                        vprint("spec_fsync: dirty", vp);
                        goto loop;
                }
                        vprint("spec_fsync: dirty", vp);
                        goto loop;
                }
@@ -485,6 +548,20 @@ spec_close(ap)
        switch (vp->v_type) {
 
        case VCHR:
        switch (vp->v_type) {
 
        case VCHR:
+               /*
+                * Hack: a tty device that is a controlling terminal
+                * has a reference from the session structure.
+                * We cannot easily tell that a character device is
+                * a controlling terminal, unless it is the closing
+                * process' controlling terminal.  In that case,
+                * if the reference count is 2 (this last descriptor
+                * plus the session), release the reference from the session.
+                */
+               if (vcount(vp) == 2 && ap->a_p &&
+                   vp == ap->a_p->p_session->s_ttyvp) {
+                       vrele(vp);
+                       ap->a_p->p_session->s_ttyvp = NULL;
+               }
                /*
                 * If the vnode is locked, then we are in the midst
                 * of forcably closing the device, otherwise we only
                /*
                 * If the vnode is locked, then we are in the midst
                 * of forcably closing the device, otherwise we only
@@ -502,7 +579,7 @@ spec_close(ap)
                 * we must invalidate any in core blocks, so that
                 * we can, for instance, change floppy disks.
                 */
                 * we must invalidate any in core blocks, so that
                 * we can, for instance, change floppy disks.
                 */
-               if (error = vinvalbuf(vp, 1, ap->a_cred, ap->a_p, 0, 0))
+               if (error = vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 0, 0))
                        return (error);
                /*
                 * We do not want to really close the device if it
                        return (error);
                /*
                 * We do not want to really close the device if it
@@ -539,6 +616,42 @@ spec_print(ap)
                minor(ap->a_vp->v_rdev));
 }
 
                minor(ap->a_vp->v_rdev));
 }
 
+/*
+ * Return POSIX pathconf information applicable to special devices.
+ */
+spec_pathconf(ap)
+       struct vop_pathconf_args /* {
+               struct vnode *a_vp;
+               int a_name;
+               int *a_retval;
+       } */ *ap;
+{
+
+       switch (ap->a_name) {
+       case _PC_LINK_MAX:
+               *ap->a_retval = LINK_MAX;
+               return (0);
+       case _PC_MAX_CANON:
+               *ap->a_retval = MAX_CANON;
+               return (0);
+       case _PC_MAX_INPUT:
+               *ap->a_retval = MAX_INPUT;
+               return (0);
+       case _PC_PIPE_BUF:
+               *ap->a_retval = PIPE_BUF;
+               return (0);
+       case _PC_CHOWN_RESTRICTED:
+               *ap->a_retval = 1;
+               return (0);
+       case _PC_VDISABLE:
+               *ap->a_retval = _POSIX_VDISABLE;
+               return (0);
+       default:
+               return (EINVAL);
+       }
+       /* NOTREACHED */
+}
+
 /*
  * Special device advisory byte-level locks.
  */
 /*
  * Special device advisory byte-level locks.
  */