mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
Import 4.4BSD-Lite2 onto the vendor branch, note that in the kernel, all
files are off the vendor branch, so this should not change anything. A "U" marker generally means that the file was not changed in between the 4.4Lite and Lite-2 releases, and does not need a merge. "C" generally means that there was a change. [two new auxillary files in miscfs/union]
This commit is contained in:
parent
91b6e176b3
commit
5e5861b9c6
38 changed files with 15178 additions and 0 deletions
356
sys/miscfs/deadfs/dead_vnops.c
Normal file
356
sys/miscfs/deadfs/dead_vnops.c
Normal file
|
|
@ -0,0 +1,356 @@
|
|||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)dead_vnops.c 8.3 (Berkeley) 5/14/95
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/buf.h>
|
||||
|
||||
/*
|
||||
* Prototypes for dead operations on vnodes.
|
||||
*/
|
||||
int dead_badop(),
|
||||
dead_ebadf();
|
||||
int dead_lookup __P((struct vop_lookup_args *));
|
||||
#define dead_create ((int (*) __P((struct vop_create_args *)))dead_badop)
|
||||
#define dead_mknod ((int (*) __P((struct vop_mknod_args *)))dead_badop)
|
||||
int dead_open __P((struct vop_open_args *));
|
||||
#define dead_close ((int (*) __P((struct vop_close_args *)))nullop)
|
||||
#define dead_access ((int (*) __P((struct vop_access_args *)))dead_ebadf)
|
||||
#define dead_getattr ((int (*) __P((struct vop_getattr_args *)))dead_ebadf)
|
||||
#define dead_setattr ((int (*) __P((struct vop_setattr_args *)))dead_ebadf)
|
||||
int dead_read __P((struct vop_read_args *));
|
||||
int dead_write __P((struct vop_write_args *));
|
||||
int dead_ioctl __P((struct vop_ioctl_args *));
|
||||
int dead_select __P((struct vop_select_args *));
|
||||
#define dead_mmap ((int (*) __P((struct vop_mmap_args *)))dead_badop)
|
||||
#define dead_fsync ((int (*) __P((struct vop_fsync_args *)))nullop)
|
||||
#define dead_seek ((int (*) __P((struct vop_seek_args *)))nullop)
|
||||
#define dead_remove ((int (*) __P((struct vop_remove_args *)))dead_badop)
|
||||
#define dead_link ((int (*) __P((struct vop_link_args *)))dead_badop)
|
||||
#define dead_rename ((int (*) __P((struct vop_rename_args *)))dead_badop)
|
||||
#define dead_mkdir ((int (*) __P((struct vop_mkdir_args *)))dead_badop)
|
||||
#define dead_rmdir ((int (*) __P((struct vop_rmdir_args *)))dead_badop)
|
||||
#define dead_symlink ((int (*) __P((struct vop_symlink_args *)))dead_badop)
|
||||
#define dead_readdir ((int (*) __P((struct vop_readdir_args *)))dead_ebadf)
|
||||
#define dead_readlink ((int (*) __P((struct vop_readlink_args *)))dead_ebadf)
|
||||
#define dead_abortop ((int (*) __P((struct vop_abortop_args *)))dead_badop)
|
||||
#define dead_inactive ((int (*) __P((struct vop_inactive_args *)))nullop)
|
||||
#define dead_reclaim ((int (*) __P((struct vop_reclaim_args *)))nullop)
|
||||
int dead_lock __P((struct vop_lock_args *));
|
||||
#define dead_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock)
|
||||
int dead_bmap __P((struct vop_bmap_args *));
|
||||
int dead_strategy __P((struct vop_strategy_args *));
|
||||
int dead_print __P((struct vop_print_args *));
|
||||
#define dead_islocked ((int(*) __P((struct vop_islocked_args *)))vop_noislocked)
|
||||
#define dead_pathconf ((int (*) __P((struct vop_pathconf_args *)))dead_ebadf)
|
||||
#define dead_advlock ((int (*) __P((struct vop_advlock_args *)))dead_ebadf)
|
||||
#define dead_blkatoff ((int (*) __P((struct vop_blkatoff_args *)))dead_badop)
|
||||
#define dead_valloc ((int (*) __P((struct vop_valloc_args *)))dead_badop)
|
||||
#define dead_vfree ((int (*) __P((struct vop_vfree_args *)))dead_badop)
|
||||
#define dead_truncate ((int (*) __P((struct vop_truncate_args *)))nullop)
|
||||
#define dead_update ((int (*) __P((struct vop_update_args *)))nullop)
|
||||
#define dead_bwrite ((int (*) __P((struct vop_bwrite_args *)))nullop)
|
||||
|
||||
int (**dead_vnodeop_p)();
|
||||
struct vnodeopv_entry_desc dead_vnodeop_entries[] = {
|
||||
{ &vop_default_desc, vn_default_error },
|
||||
{ &vop_lookup_desc, dead_lookup }, /* lookup */
|
||||
{ &vop_create_desc, dead_create }, /* create */
|
||||
{ &vop_mknod_desc, dead_mknod }, /* mknod */
|
||||
{ &vop_open_desc, dead_open }, /* open */
|
||||
{ &vop_close_desc, dead_close }, /* close */
|
||||
{ &vop_access_desc, dead_access }, /* access */
|
||||
{ &vop_getattr_desc, dead_getattr }, /* getattr */
|
||||
{ &vop_setattr_desc, dead_setattr }, /* setattr */
|
||||
{ &vop_read_desc, dead_read }, /* read */
|
||||
{ &vop_write_desc, dead_write }, /* write */
|
||||
{ &vop_ioctl_desc, dead_ioctl }, /* ioctl */
|
||||
{ &vop_select_desc, dead_select }, /* select */
|
||||
{ &vop_mmap_desc, dead_mmap }, /* mmap */
|
||||
{ &vop_fsync_desc, dead_fsync }, /* fsync */
|
||||
{ &vop_seek_desc, dead_seek }, /* seek */
|
||||
{ &vop_remove_desc, dead_remove }, /* remove */
|
||||
{ &vop_link_desc, dead_link }, /* link */
|
||||
{ &vop_rename_desc, dead_rename }, /* rename */
|
||||
{ &vop_mkdir_desc, dead_mkdir }, /* mkdir */
|
||||
{ &vop_rmdir_desc, dead_rmdir }, /* rmdir */
|
||||
{ &vop_symlink_desc, dead_symlink }, /* symlink */
|
||||
{ &vop_readdir_desc, dead_readdir }, /* readdir */
|
||||
{ &vop_readlink_desc, dead_readlink }, /* readlink */
|
||||
{ &vop_abortop_desc, dead_abortop }, /* abortop */
|
||||
{ &vop_inactive_desc, dead_inactive }, /* inactive */
|
||||
{ &vop_reclaim_desc, dead_reclaim }, /* reclaim */
|
||||
{ &vop_lock_desc, dead_lock }, /* lock */
|
||||
{ &vop_unlock_desc, dead_unlock }, /* unlock */
|
||||
{ &vop_bmap_desc, dead_bmap }, /* bmap */
|
||||
{ &vop_strategy_desc, dead_strategy }, /* strategy */
|
||||
{ &vop_print_desc, dead_print }, /* print */
|
||||
{ &vop_islocked_desc, dead_islocked }, /* islocked */
|
||||
{ &vop_pathconf_desc, dead_pathconf }, /* pathconf */
|
||||
{ &vop_advlock_desc, dead_advlock }, /* advlock */
|
||||
{ &vop_blkatoff_desc, dead_blkatoff }, /* blkatoff */
|
||||
{ &vop_valloc_desc, dead_valloc }, /* valloc */
|
||||
{ &vop_vfree_desc, dead_vfree }, /* vfree */
|
||||
{ &vop_truncate_desc, dead_truncate }, /* truncate */
|
||||
{ &vop_update_desc, dead_update }, /* update */
|
||||
{ &vop_bwrite_desc, dead_bwrite }, /* bwrite */
|
||||
{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
|
||||
};
|
||||
struct vnodeopv_desc dead_vnodeop_opv_desc =
|
||||
{ &dead_vnodeop_p, dead_vnodeop_entries };
|
||||
|
||||
/*
|
||||
* Trivial lookup routine that always fails.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
int
|
||||
dead_lookup(ap)
|
||||
struct vop_lookup_args /* {
|
||||
struct vnode * a_dvp;
|
||||
struct vnode ** a_vpp;
|
||||
struct componentname * a_cnp;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
*ap->a_vpp = NULL;
|
||||
return (ENOTDIR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open always fails as if device did not exist.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
dead_open(ap)
|
||||
struct vop_open_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_mode;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/*
|
||||
* Vnode op for read
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
dead_read(ap)
|
||||
struct vop_read_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
int a_ioflag;
|
||||
struct ucred *a_cred;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
if (chkvnlock(ap->a_vp))
|
||||
panic("dead_read: lock");
|
||||
/*
|
||||
* Return EOF for tty devices, EIO for others
|
||||
*/
|
||||
if ((ap->a_vp->v_flag & VISTTY) == 0)
|
||||
return (EIO);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Vnode op for write
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
dead_write(ap)
|
||||
struct vop_write_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
int a_ioflag;
|
||||
struct ucred *a_cred;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
if (chkvnlock(ap->a_vp))
|
||||
panic("dead_write: lock");
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
/*
|
||||
* Device ioctl operation.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
dead_ioctl(ap)
|
||||
struct vop_ioctl_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_command;
|
||||
caddr_t a_data;
|
||||
int a_fflag;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
if (!chkvnlock(ap->a_vp))
|
||||
return (EBADF);
|
||||
return (VCALL(ap->a_vp, VOFFSET(vop_ioctl), ap));
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
dead_select(ap)
|
||||
struct vop_select_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_which;
|
||||
int a_fflags;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
/*
|
||||
* Let the user find out that the descriptor is gone.
|
||||
*/
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Just call the device strategy routine
|
||||
*/
|
||||
dead_strategy(ap)
|
||||
struct vop_strategy_args /* {
|
||||
struct buf *a_bp;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
if (ap->a_bp->b_vp == NULL || !chkvnlock(ap->a_bp->b_vp)) {
|
||||
ap->a_bp->b_flags |= B_ERROR;
|
||||
biodone(ap->a_bp);
|
||||
return (EIO);
|
||||
}
|
||||
return (VOP_STRATEGY(ap->a_bp));
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait until the vnode has finished changing state.
|
||||
*/
|
||||
dead_lock(ap)
|
||||
struct vop_lock_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_flags;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
|
||||
/*
|
||||
* Since we are not using the lock manager, we must clear
|
||||
* the interlock here.
|
||||
*/
|
||||
if (ap->a_flags & LK_INTERLOCK) {
|
||||
simple_unlock(&vp->v_interlock);
|
||||
ap->a_flags &= ~LK_INTERLOCK;
|
||||
}
|
||||
if (!chkvnlock(vp))
|
||||
return (0);
|
||||
return (VCALL(vp, VOFFSET(vop_lock), ap));
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait until the vnode has finished changing state.
|
||||
*/
|
||||
dead_bmap(ap)
|
||||
struct vop_bmap_args /* {
|
||||
struct vnode *a_vp;
|
||||
daddr_t a_bn;
|
||||
struct vnode **a_vpp;
|
||||
daddr_t *a_bnp;
|
||||
int *a_runp;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
if (!chkvnlock(ap->a_vp))
|
||||
return (EIO);
|
||||
return (VOP_BMAP(ap->a_vp, ap->a_bn, ap->a_vpp, ap->a_bnp, ap->a_runp));
|
||||
}
|
||||
|
||||
/*
|
||||
* Print out the contents of a dead vnode.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
dead_print(ap)
|
||||
struct vop_print_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
printf("tag VT_NON, dead vnode\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Empty vnode failed operation
|
||||
*/
|
||||
dead_ebadf()
|
||||
{
|
||||
|
||||
return (EBADF);
|
||||
}
|
||||
|
||||
/*
|
||||
* Empty vnode bad operation
|
||||
*/
|
||||
dead_badop()
|
||||
{
|
||||
|
||||
panic("dead_badop called");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to wait during times when the vnode is
|
||||
* in a state of change.
|
||||
*/
|
||||
chkvnlock(vp)
|
||||
register struct vnode *vp;
|
||||
{
|
||||
int locked = 0;
|
||||
|
||||
while (vp->v_flag & VXLOCK) {
|
||||
vp->v_flag |= VXWANT;
|
||||
sleep((caddr_t)vp, PINOD);
|
||||
locked = 1;
|
||||
}
|
||||
return (locked);
|
||||
}
|
||||
81
sys/miscfs/fdesc/fdesc.h
Normal file
81
sys/miscfs/fdesc/fdesc.h
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)fdesc.h 8.8 (Berkeley) 4/3/95
|
||||
*
|
||||
* $Id: fdesc.h,v 1.8 1993/04/06 15:28:33 jsp Exp $
|
||||
*/
|
||||
|
||||
#ifdef KERNEL
|
||||
struct fdescmount {
|
||||
struct vnode *f_root; /* Root node */
|
||||
};
|
||||
|
||||
#define FD_ROOT 2
|
||||
#define FD_DEVFD 3
|
||||
#define FD_STDIN 4
|
||||
#define FD_STDOUT 5
|
||||
#define FD_STDERR 6
|
||||
#define FD_CTTY 7
|
||||
#define FD_DESC 8
|
||||
#define FD_MAX 12
|
||||
|
||||
typedef enum {
|
||||
Froot,
|
||||
Fdevfd,
|
||||
Fdesc,
|
||||
Flink,
|
||||
Fctty
|
||||
} fdntype;
|
||||
|
||||
struct fdescnode {
|
||||
LIST_ENTRY(fdescnode) fd_hash; /* Hash list */
|
||||
struct vnode *fd_vnode; /* Back ptr to vnode */
|
||||
fdntype fd_type; /* Type of this node */
|
||||
unsigned fd_fd; /* Fd to be dup'ed */
|
||||
char *fd_link; /* Link to fd/n */
|
||||
int fd_ix; /* filesystem index */
|
||||
};
|
||||
|
||||
#define VFSTOFDESC(mp) ((struct fdescmount *)((mp)->mnt_data))
|
||||
#define VTOFDESC(vp) ((struct fdescnode *)(vp)->v_data)
|
||||
|
||||
extern dev_t devctty;
|
||||
extern int fdesc_init __P((struct vfsconf *));
|
||||
extern int fdesc_root __P((struct mount *, struct vnode **));
|
||||
extern int fdesc_allocvp __P((fdntype, int, struct mount *, struct vnode **));
|
||||
extern int (**fdesc_vnodeop_p)();
|
||||
extern struct vfsops fdesc_vfsops;
|
||||
#endif /* KERNEL */
|
||||
250
sys/miscfs/fdesc/fdesc_vfsops.c
Normal file
250
sys/miscfs/fdesc/fdesc_vfsops.c
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* Copyright (c) 1992, 1993, 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)fdesc_vfsops.c 8.10 (Berkeley) 5/14/95
|
||||
*
|
||||
* $Id: fdesc_vfsops.c,v 1.9 1993/04/06 15:28:33 jsp Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* /dev/fd Filesystem
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/resourcevar.h>
|
||||
#include <sys/filedesc.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <miscfs/fdesc/fdesc.h>
|
||||
|
||||
/*
|
||||
* Mount the per-process file descriptors (/dev/fd)
|
||||
*/
|
||||
int
|
||||
fdesc_mount(mp, path, data, ndp, p)
|
||||
struct mount *mp;
|
||||
char *path;
|
||||
caddr_t data;
|
||||
struct nameidata *ndp;
|
||||
struct proc *p;
|
||||
{
|
||||
int error = 0;
|
||||
u_int size;
|
||||
struct fdescmount *fmp;
|
||||
struct vnode *rvp;
|
||||
|
||||
/*
|
||||
* Update is a no-op
|
||||
*/
|
||||
if (mp->mnt_flag & MNT_UPDATE)
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
error = fdesc_allocvp(Froot, FD_ROOT, mp, &rvp);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
MALLOC(fmp, struct fdescmount *, sizeof(struct fdescmount),
|
||||
M_UFSMNT, M_WAITOK); /* XXX */
|
||||
rvp->v_type = VDIR;
|
||||
rvp->v_flag |= VROOT;
|
||||
fmp->f_root = rvp;
|
||||
/* XXX -- don't mark as local to work around fts() problems */
|
||||
/*mp->mnt_flag |= MNT_LOCAL;*/
|
||||
mp->mnt_data = (qaddr_t) fmp;
|
||||
vfs_getnewfsid(mp);
|
||||
|
||||
(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
|
||||
bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
|
||||
bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
|
||||
bcopy("fdesc", mp->mnt_stat.f_mntfromname, sizeof("fdesc"));
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
fdesc_start(mp, flags, p)
|
||||
struct mount *mp;
|
||||
int flags;
|
||||
struct proc *p;
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
fdesc_unmount(mp, mntflags, p)
|
||||
struct mount *mp;
|
||||
int mntflags;
|
||||
struct proc *p;
|
||||
{
|
||||
int error;
|
||||
int flags = 0;
|
||||
struct vnode *rootvp = VFSTOFDESC(mp)->f_root;
|
||||
|
||||
if (mntflags & MNT_FORCE)
|
||||
flags |= FORCECLOSE;
|
||||
|
||||
/*
|
||||
* Clear out buffer cache. I don't think we
|
||||
* ever get anything cached at this level at the
|
||||
* moment, but who knows...
|
||||
*/
|
||||
if (rootvp->v_usecount > 1)
|
||||
return (EBUSY);
|
||||
if (error = vflush(mp, rootvp, flags))
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Release reference on underlying root vnode
|
||||
*/
|
||||
vrele(rootvp);
|
||||
/*
|
||||
* And blow it away for future re-use
|
||||
*/
|
||||
vgone(rootvp);
|
||||
/*
|
||||
* Finally, throw away the fdescmount structure
|
||||
*/
|
||||
free(mp->mnt_data, M_UFSMNT); /* XXX */
|
||||
mp->mnt_data = 0;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
fdesc_root(mp, vpp)
|
||||
struct mount *mp;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
struct proc *p = curproc; /* XXX */
|
||||
struct vnode *vp;
|
||||
|
||||
/*
|
||||
* Return locked reference to root.
|
||||
*/
|
||||
vp = VFSTOFDESC(mp)->f_root;
|
||||
VREF(vp);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
*vpp = vp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
fdesc_statfs(mp, sbp, p)
|
||||
struct mount *mp;
|
||||
struct statfs *sbp;
|
||||
struct proc *p;
|
||||
{
|
||||
struct filedesc *fdp;
|
||||
int lim;
|
||||
int i;
|
||||
int last;
|
||||
int freefd;
|
||||
|
||||
/*
|
||||
* Compute number of free file descriptors.
|
||||
* [ Strange results will ensue if the open file
|
||||
* limit is ever reduced below the current number
|
||||
* of open files... ]
|
||||
*/
|
||||
lim = p->p_rlimit[RLIMIT_NOFILE].rlim_cur;
|
||||
fdp = p->p_fd;
|
||||
last = min(fdp->fd_nfiles, lim);
|
||||
freefd = 0;
|
||||
for (i = fdp->fd_freefile; i < last; i++)
|
||||
if (fdp->fd_ofiles[i] == NULL)
|
||||
freefd++;
|
||||
|
||||
/*
|
||||
* Adjust for the fact that the fdesc array may not
|
||||
* have been fully allocated yet.
|
||||
*/
|
||||
if (fdp->fd_nfiles < lim)
|
||||
freefd += (lim - fdp->fd_nfiles);
|
||||
|
||||
sbp->f_flags = 0;
|
||||
sbp->f_bsize = DEV_BSIZE;
|
||||
sbp->f_iosize = DEV_BSIZE;
|
||||
sbp->f_blocks = 2; /* 1K to keep df happy */
|
||||
sbp->f_bfree = 0;
|
||||
sbp->f_bavail = 0;
|
||||
sbp->f_files = lim + 1; /* Allow for "." */
|
||||
sbp->f_ffree = freefd; /* See comments above */
|
||||
if (sbp != &mp->mnt_stat) {
|
||||
sbp->f_type = mp->mnt_vfc->vfc_typenum;
|
||||
bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
|
||||
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
|
||||
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
fdesc_sync(mp, waitfor)
|
||||
struct mount *mp;
|
||||
int waitfor;
|
||||
{
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#define fdesc_fhtovp ((int (*) __P((struct mount *, struct fid *, \
|
||||
struct mbuf *, struct vnode **, int *, struct ucred **)))eopnotsupp)
|
||||
#define fdesc_quotactl ((int (*) __P((struct mount *, int, uid_t, caddr_t, \
|
||||
struct proc *)))eopnotsupp)
|
||||
#define fdesc_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \
|
||||
size_t, struct proc *)))eopnotsupp)
|
||||
#define fdesc_vget ((int (*) __P((struct mount *, ino_t, struct vnode **))) \
|
||||
eopnotsupp)
|
||||
#define fdesc_vptofh ((int (*) __P((struct vnode *, struct fid *)))eopnotsupp)
|
||||
|
||||
struct vfsops fdesc_vfsops = {
|
||||
fdesc_mount,
|
||||
fdesc_start,
|
||||
fdesc_unmount,
|
||||
fdesc_root,
|
||||
fdesc_quotactl,
|
||||
fdesc_statfs,
|
||||
fdesc_sync,
|
||||
fdesc_vget,
|
||||
fdesc_fhtovp,
|
||||
fdesc_vptofh,
|
||||
fdesc_init,
|
||||
fdesc_sysctl,
|
||||
};
|
||||
951
sys/miscfs/fdesc/fdesc_vnops.c
Normal file
951
sys/miscfs/fdesc/fdesc_vnops.c
Normal file
|
|
@ -0,0 +1,951 @@
|
|||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)fdesc_vnops.c 8.17 (Berkeley) 5/22/95
|
||||
*
|
||||
* $Id: fdesc_vnops.c,v 1.12 1993/04/06 16:17:17 jsp Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* /dev/fd Filesystem
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/kernel.h> /* boottime */
|
||||
#include <sys/resourcevar.h>
|
||||
#include <sys/filedesc.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/dirent.h>
|
||||
#include <miscfs/fdesc/fdesc.h>
|
||||
|
||||
#define cttyvp(p) ((p)->p_flag & P_CONTROLT ? (p)->p_session->s_ttyvp : NULL)
|
||||
|
||||
#define FDL_WANT 0x01
|
||||
#define FDL_LOCKED 0x02
|
||||
static int fdcache_lock;
|
||||
|
||||
dev_t devctty;
|
||||
|
||||
#if (FD_STDIN != FD_STDOUT-1) || (FD_STDOUT != FD_STDERR-1)
|
||||
FD_STDIN, FD_STDOUT, FD_STDERR must be a sequence n, n+1, n+2
|
||||
#endif
|
||||
|
||||
#define NFDCACHE 4
|
||||
|
||||
#define FD_NHASH(ix) \
|
||||
(&fdhashtbl[(ix) & fdhash])
|
||||
LIST_HEAD(fdhashhead, fdescnode) *fdhashtbl;
|
||||
u_long fdhash;
|
||||
|
||||
/*
|
||||
* Initialise cache headers
|
||||
*/
|
||||
fdesc_init(vfsp)
|
||||
struct vfsconf *vfsp;
|
||||
{
|
||||
|
||||
devctty = makedev(nchrdev, 0);
|
||||
fdhashtbl = hashinit(NFDCACHE, M_CACHE, &fdhash);
|
||||
}
|
||||
|
||||
int
|
||||
fdesc_allocvp(ftype, ix, mp, vpp)
|
||||
fdntype ftype;
|
||||
int ix;
|
||||
struct mount *mp;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
struct proc *p = curproc; /* XXX */
|
||||
struct fdhashhead *fc;
|
||||
struct fdescnode *fd;
|
||||
int error = 0;
|
||||
|
||||
fc = FD_NHASH(ix);
|
||||
loop:
|
||||
for (fd = fc->lh_first; fd != 0; fd = fd->fd_hash.le_next) {
|
||||
if (fd->fd_ix == ix && fd->fd_vnode->v_mount == mp) {
|
||||
if (vget(fd->fd_vnode, 0, p))
|
||||
goto loop;
|
||||
*vpp = fd->fd_vnode;
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* otherwise lock the array while we call getnewvnode
|
||||
* since that can block.
|
||||
*/
|
||||
if (fdcache_lock & FDL_LOCKED) {
|
||||
fdcache_lock |= FDL_WANT;
|
||||
sleep((caddr_t) &fdcache_lock, PINOD);
|
||||
goto loop;
|
||||
}
|
||||
fdcache_lock |= FDL_LOCKED;
|
||||
|
||||
error = getnewvnode(VT_FDESC, mp, fdesc_vnodeop_p, vpp);
|
||||
if (error)
|
||||
goto out;
|
||||
MALLOC(fd, void *, sizeof(struct fdescnode), M_TEMP, M_WAITOK);
|
||||
(*vpp)->v_data = fd;
|
||||
fd->fd_vnode = *vpp;
|
||||
fd->fd_type = ftype;
|
||||
fd->fd_fd = -1;
|
||||
fd->fd_link = 0;
|
||||
fd->fd_ix = ix;
|
||||
LIST_INSERT_HEAD(fc, fd, fd_hash);
|
||||
|
||||
out:;
|
||||
fdcache_lock &= ~FDL_LOCKED;
|
||||
|
||||
if (fdcache_lock & FDL_WANT) {
|
||||
fdcache_lock &= ~FDL_WANT;
|
||||
wakeup((caddr_t) &fdcache_lock);
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* vp is the current namei directory
|
||||
* ndp is the name to locate in that directory...
|
||||
*/
|
||||
int
|
||||
fdesc_lookup(ap)
|
||||
struct vop_lookup_args /* {
|
||||
struct vnode * a_dvp;
|
||||
struct vnode ** a_vpp;
|
||||
struct componentname * a_cnp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode **vpp = ap->a_vpp;
|
||||
struct vnode *dvp = ap->a_dvp;
|
||||
struct componentname *cnp = ap->a_cnp;
|
||||
char *pname = cnp->cn_nameptr;
|
||||
struct proc *p = cnp->cn_proc;
|
||||
int nfiles = p->p_fd->fd_nfiles;
|
||||
unsigned fd;
|
||||
int error;
|
||||
struct vnode *fvp;
|
||||
char *ln;
|
||||
|
||||
VOP_UNLOCK(dvp, 0, p);
|
||||
if (cnp->cn_namelen == 1 && *pname == '.') {
|
||||
*vpp = dvp;
|
||||
VREF(dvp);
|
||||
vn_lock(dvp, LK_SHARED | LK_RETRY, p);
|
||||
return (0);
|
||||
}
|
||||
|
||||
switch (VTOFDESC(dvp)->fd_type) {
|
||||
default:
|
||||
case Flink:
|
||||
case Fdesc:
|
||||
case Fctty:
|
||||
error = ENOTDIR;
|
||||
goto bad;
|
||||
|
||||
case Froot:
|
||||
if (cnp->cn_namelen == 2 && bcmp(pname, "fd", 2) == 0) {
|
||||
error = fdesc_allocvp(Fdevfd, FD_DEVFD, dvp->v_mount, &fvp);
|
||||
if (error)
|
||||
goto bad;
|
||||
*vpp = fvp;
|
||||
fvp->v_type = VDIR;
|
||||
vn_lock(fvp, LK_SHARED | LK_RETRY, p);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (cnp->cn_namelen == 3 && bcmp(pname, "tty", 3) == 0) {
|
||||
struct vnode *ttyvp = cttyvp(p);
|
||||
if (ttyvp == NULL) {
|
||||
error = ENXIO;
|
||||
goto bad;
|
||||
}
|
||||
error = fdesc_allocvp(Fctty, FD_CTTY, dvp->v_mount, &fvp);
|
||||
if (error)
|
||||
goto bad;
|
||||
*vpp = fvp;
|
||||
fvp->v_type = VFIFO;
|
||||
vn_lock(fvp, LK_SHARED | LK_RETRY, p);
|
||||
return (0);
|
||||
}
|
||||
|
||||
ln = 0;
|
||||
switch (cnp->cn_namelen) {
|
||||
case 5:
|
||||
if (bcmp(pname, "stdin", 5) == 0) {
|
||||
ln = "fd/0";
|
||||
fd = FD_STDIN;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
if (bcmp(pname, "stdout", 6) == 0) {
|
||||
ln = "fd/1";
|
||||
fd = FD_STDOUT;
|
||||
} else
|
||||
if (bcmp(pname, "stderr", 6) == 0) {
|
||||
ln = "fd/2";
|
||||
fd = FD_STDERR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (ln) {
|
||||
error = fdesc_allocvp(Flink, fd, dvp->v_mount, &fvp);
|
||||
if (error)
|
||||
goto bad;
|
||||
VTOFDESC(fvp)->fd_link = ln;
|
||||
*vpp = fvp;
|
||||
fvp->v_type = VLNK;
|
||||
vn_lock(fvp, LK_SHARED | LK_RETRY, p);
|
||||
return (0);
|
||||
} else {
|
||||
error = ENOENT;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* FALL THROUGH */
|
||||
|
||||
case Fdevfd:
|
||||
if (cnp->cn_namelen == 2 && bcmp(pname, "..", 2) == 0) {
|
||||
if (error = fdesc_root(dvp->v_mount, vpp))
|
||||
goto bad;
|
||||
return (0);
|
||||
}
|
||||
|
||||
fd = 0;
|
||||
while (*pname >= '0' && *pname <= '9') {
|
||||
fd = 10 * fd + *pname++ - '0';
|
||||
if (fd >= nfiles)
|
||||
break;
|
||||
}
|
||||
|
||||
if (*pname != '\0') {
|
||||
error = ENOENT;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (fd >= nfiles || p->p_fd->fd_ofiles[fd] == NULL) {
|
||||
error = EBADF;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
error = fdesc_allocvp(Fdesc, FD_DESC+fd, dvp->v_mount, &fvp);
|
||||
if (error)
|
||||
goto bad;
|
||||
VTOFDESC(fvp)->fd_fd = fd;
|
||||
vn_lock(fvp, LK_SHARED | LK_RETRY, p);
|
||||
*vpp = fvp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
bad:;
|
||||
vn_lock(dvp, LK_SHARED | LK_RETRY, p);
|
||||
*vpp = NULL;
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
fdesc_open(ap)
|
||||
struct vop_open_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_mode;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
int error = 0;
|
||||
|
||||
switch (VTOFDESC(vp)->fd_type) {
|
||||
case Fdesc:
|
||||
/*
|
||||
* XXX Kludge: set p->p_dupfd to contain the value of the
|
||||
* the file descriptor being sought for duplication. The error
|
||||
* return ensures that the vnode for this device will be
|
||||
* released by vn_open. Open will detect this special error and
|
||||
* take the actions in dupfdopen. Other callers of vn_open or
|
||||
* VOP_OPEN will simply report the error.
|
||||
*/
|
||||
ap->a_p->p_dupfd = VTOFDESC(vp)->fd_fd; /* XXX */
|
||||
error = ENODEV;
|
||||
break;
|
||||
|
||||
case Fctty:
|
||||
error = cttyopen(devctty, ap->a_mode, 0, ap->a_p);
|
||||
break;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
fdesc_attr(fd, vap, cred, p)
|
||||
int fd;
|
||||
struct vattr *vap;
|
||||
struct ucred *cred;
|
||||
struct proc *p;
|
||||
{
|
||||
struct filedesc *fdp = p->p_fd;
|
||||
struct file *fp;
|
||||
struct stat stb;
|
||||
int error;
|
||||
|
||||
if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL)
|
||||
return (EBADF);
|
||||
|
||||
switch (fp->f_type) {
|
||||
case DTYPE_VNODE:
|
||||
error = VOP_GETATTR((struct vnode *) fp->f_data, vap, cred, p);
|
||||
if (error == 0 && vap->va_type == VDIR) {
|
||||
/*
|
||||
* directories can cause loops in the namespace,
|
||||
* so turn off the 'x' bits to avoid trouble.
|
||||
*/
|
||||
vap->va_mode &= ~((VEXEC)|(VEXEC>>3)|(VEXEC>>6));
|
||||
}
|
||||
break;
|
||||
|
||||
case DTYPE_SOCKET:
|
||||
error = soo_stat((struct socket *)fp->f_data, &stb);
|
||||
if (error == 0) {
|
||||
vattr_null(vap);
|
||||
vap->va_type = VSOCK;
|
||||
vap->va_mode = stb.st_mode;
|
||||
vap->va_nlink = stb.st_nlink;
|
||||
vap->va_uid = stb.st_uid;
|
||||
vap->va_gid = stb.st_gid;
|
||||
vap->va_fsid = stb.st_dev;
|
||||
vap->va_fileid = stb.st_ino;
|
||||
vap->va_size = stb.st_size;
|
||||
vap->va_blocksize = stb.st_blksize;
|
||||
vap->va_atime = stb.st_atimespec;
|
||||
vap->va_mtime = stb.st_mtimespec;
|
||||
vap->va_ctime = stb.st_ctimespec;
|
||||
vap->va_gen = stb.st_gen;
|
||||
vap->va_flags = stb.st_flags;
|
||||
vap->va_rdev = stb.st_rdev;
|
||||
vap->va_bytes = stb.st_blocks * stb.st_blksize;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("fdesc attr");
|
||||
break;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
fdesc_getattr(ap)
|
||||
struct vop_getattr_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct vattr *a_vap;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct vattr *vap = ap->a_vap;
|
||||
unsigned fd;
|
||||
int error = 0;
|
||||
|
||||
switch (VTOFDESC(vp)->fd_type) {
|
||||
case Froot:
|
||||
case Fdevfd:
|
||||
case Flink:
|
||||
case Fctty:
|
||||
bzero((caddr_t) vap, sizeof(*vap));
|
||||
vattr_null(vap);
|
||||
vap->va_fileid = VTOFDESC(vp)->fd_ix;
|
||||
|
||||
switch (VTOFDESC(vp)->fd_type) {
|
||||
case Flink:
|
||||
vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
|
||||
vap->va_type = VLNK;
|
||||
vap->va_nlink = 1;
|
||||
vap->va_size = strlen(VTOFDESC(vp)->fd_link);
|
||||
break;
|
||||
|
||||
case Fctty:
|
||||
vap->va_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
|
||||
vap->va_type = VFIFO;
|
||||
vap->va_nlink = 1;
|
||||
vap->va_size = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
|
||||
vap->va_type = VDIR;
|
||||
vap->va_nlink = 2;
|
||||
vap->va_size = DEV_BSIZE;
|
||||
break;
|
||||
}
|
||||
vap->va_uid = 0;
|
||||
vap->va_gid = 0;
|
||||
vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
|
||||
vap->va_blocksize = DEV_BSIZE;
|
||||
vap->va_atime.ts_sec = boottime.tv_sec;
|
||||
vap->va_atime.ts_nsec = 0;
|
||||
vap->va_mtime = vap->va_atime;
|
||||
vap->va_ctime = vap->va_mtime;
|
||||
vap->va_gen = 0;
|
||||
vap->va_flags = 0;
|
||||
vap->va_rdev = 0;
|
||||
vap->va_bytes = 0;
|
||||
break;
|
||||
|
||||
case Fdesc:
|
||||
fd = VTOFDESC(vp)->fd_fd;
|
||||
error = fdesc_attr(fd, vap, ap->a_cred, ap->a_p);
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("fdesc_getattr");
|
||||
break;
|
||||
}
|
||||
|
||||
if (error == 0)
|
||||
vp->v_type = vap->va_type;
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
fdesc_setattr(ap)
|
||||
struct vop_setattr_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct vattr *a_vap;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct filedesc *fdp = ap->a_p->p_fd;
|
||||
struct file *fp;
|
||||
unsigned fd;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Can't mess with the root vnode
|
||||
*/
|
||||
switch (VTOFDESC(ap->a_vp)->fd_type) {
|
||||
case Fdesc:
|
||||
break;
|
||||
|
||||
case Fctty:
|
||||
return (0);
|
||||
|
||||
default:
|
||||
return (EACCES);
|
||||
}
|
||||
|
||||
fd = VTOFDESC(ap->a_vp)->fd_fd;
|
||||
if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) {
|
||||
return (EBADF);
|
||||
}
|
||||
|
||||
/*
|
||||
* Can setattr the underlying vnode, but not sockets!
|
||||
*/
|
||||
switch (fp->f_type) {
|
||||
case DTYPE_VNODE:
|
||||
error = VOP_SETATTR((struct vnode *) fp->f_data, ap->a_vap, ap->a_cred, ap->a_p);
|
||||
break;
|
||||
|
||||
case DTYPE_SOCKET:
|
||||
error = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("fdesc setattr");
|
||||
break;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
#define UIO_MX 16
|
||||
|
||||
static struct dirtmp {
|
||||
u_long d_fileno;
|
||||
u_short d_reclen;
|
||||
u_short d_namlen;
|
||||
char d_name[8];
|
||||
} rootent[] = {
|
||||
{ FD_DEVFD, UIO_MX, 2, "fd" },
|
||||
{ FD_STDIN, UIO_MX, 5, "stdin" },
|
||||
{ FD_STDOUT, UIO_MX, 6, "stdout" },
|
||||
{ FD_STDERR, UIO_MX, 6, "stderr" },
|
||||
{ FD_CTTY, UIO_MX, 3, "tty" },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
int
|
||||
fdesc_readdir(ap)
|
||||
struct vop_readdir_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
struct ucred *a_cred;
|
||||
int *a_eofflag;
|
||||
u_long *a_cookies;
|
||||
int a_ncookies;
|
||||
} */ *ap;
|
||||
{
|
||||
struct uio *uio = ap->a_uio;
|
||||
struct filedesc *fdp;
|
||||
int i;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* We don't allow exporting fdesc mounts, and currently local
|
||||
* requests do not need cookies.
|
||||
*/
|
||||
if (ap->a_ncookies)
|
||||
panic("fdesc_readdir: not hungry");
|
||||
|
||||
switch (VTOFDESC(ap->a_vp)->fd_type) {
|
||||
case Fctty:
|
||||
return (0);
|
||||
|
||||
case Fdesc:
|
||||
return (ENOTDIR);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
fdp = uio->uio_procp->p_fd;
|
||||
|
||||
if (VTOFDESC(ap->a_vp)->fd_type == Froot) {
|
||||
struct dirent d;
|
||||
struct dirent *dp = &d;
|
||||
struct dirtmp *dt;
|
||||
|
||||
i = uio->uio_offset / UIO_MX;
|
||||
error = 0;
|
||||
|
||||
while (uio->uio_resid > 0) {
|
||||
dt = &rootent[i];
|
||||
if (dt->d_fileno == 0) {
|
||||
/**eofflagp = 1;*/
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
|
||||
switch (dt->d_fileno) {
|
||||
case FD_CTTY:
|
||||
if (cttyvp(uio->uio_procp) == NULL)
|
||||
continue;
|
||||
break;
|
||||
|
||||
case FD_STDIN:
|
||||
case FD_STDOUT:
|
||||
case FD_STDERR:
|
||||
if ((dt->d_fileno-FD_STDIN) >= fdp->fd_nfiles)
|
||||
continue;
|
||||
if (fdp->fd_ofiles[dt->d_fileno-FD_STDIN] == NULL)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
bzero((caddr_t) dp, UIO_MX);
|
||||
dp->d_fileno = dt->d_fileno;
|
||||
dp->d_namlen = dt->d_namlen;
|
||||
dp->d_type = DT_UNKNOWN;
|
||||
dp->d_reclen = dt->d_reclen;
|
||||
bcopy(dt->d_name, dp->d_name, dp->d_namlen+1);
|
||||
error = uiomove((caddr_t) dp, UIO_MX, uio);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
uio->uio_offset = i * UIO_MX;
|
||||
return (error);
|
||||
}
|
||||
|
||||
i = uio->uio_offset / UIO_MX;
|
||||
error = 0;
|
||||
while (uio->uio_resid > 0) {
|
||||
if (i >= fdp->fd_nfiles)
|
||||
break;
|
||||
|
||||
if (fdp->fd_ofiles[i] != NULL) {
|
||||
struct dirent d;
|
||||
struct dirent *dp = &d;
|
||||
|
||||
bzero((caddr_t) dp, UIO_MX);
|
||||
|
||||
dp->d_namlen = sprintf(dp->d_name, "%d", i);
|
||||
dp->d_reclen = UIO_MX;
|
||||
dp->d_type = DT_UNKNOWN;
|
||||
dp->d_fileno = i + FD_STDIN;
|
||||
/*
|
||||
* And ship to userland
|
||||
*/
|
||||
error = uiomove((caddr_t) dp, UIO_MX, uio);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
uio->uio_offset = i * UIO_MX;
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
fdesc_readlink(ap)
|
||||
struct vop_readlink_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
struct ucred *a_cred;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
int error;
|
||||
|
||||
if (vp->v_type != VLNK)
|
||||
return (EPERM);
|
||||
|
||||
if (VTOFDESC(vp)->fd_type == Flink) {
|
||||
char *ln = VTOFDESC(vp)->fd_link;
|
||||
error = uiomove(ln, strlen(ln), ap->a_uio);
|
||||
} else {
|
||||
error = EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
fdesc_read(ap)
|
||||
struct vop_read_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
int a_ioflag;
|
||||
struct ucred *a_cred;
|
||||
} */ *ap;
|
||||
{
|
||||
int error = EOPNOTSUPP;
|
||||
|
||||
switch (VTOFDESC(ap->a_vp)->fd_type) {
|
||||
case Fctty:
|
||||
error = cttyread(devctty, ap->a_uio, ap->a_ioflag);
|
||||
break;
|
||||
|
||||
default:
|
||||
error = EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
fdesc_write(ap)
|
||||
struct vop_write_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
int a_ioflag;
|
||||
struct ucred *a_cred;
|
||||
} */ *ap;
|
||||
{
|
||||
int error = EOPNOTSUPP;
|
||||
|
||||
switch (VTOFDESC(ap->a_vp)->fd_type) {
|
||||
case Fctty:
|
||||
error = cttywrite(devctty, ap->a_uio, ap->a_ioflag);
|
||||
break;
|
||||
|
||||
default:
|
||||
error = EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
fdesc_ioctl(ap)
|
||||
struct vop_ioctl_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_command;
|
||||
caddr_t a_data;
|
||||
int a_fflag;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
int error = EOPNOTSUPP;
|
||||
|
||||
switch (VTOFDESC(ap->a_vp)->fd_type) {
|
||||
case Fctty:
|
||||
error = cttyioctl(devctty, ap->a_command, ap->a_data,
|
||||
ap->a_fflag, ap->a_p);
|
||||
break;
|
||||
|
||||
default:
|
||||
error = EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
fdesc_select(ap)
|
||||
struct vop_select_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_which;
|
||||
int a_fflags;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
int error = EOPNOTSUPP;
|
||||
|
||||
switch (VTOFDESC(ap->a_vp)->fd_type) {
|
||||
case Fctty:
|
||||
error = cttyselect(devctty, ap->a_fflags, ap->a_p);
|
||||
break;
|
||||
|
||||
default:
|
||||
error = EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
fdesc_inactive(ap)
|
||||
struct vop_inactive_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
|
||||
/*
|
||||
* Clear out the v_type field to avoid
|
||||
* nasty things happening in vgone().
|
||||
*/
|
||||
VOP_UNLOCK(vp, 0, ap->a_p);
|
||||
vp->v_type = VNON;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
fdesc_reclaim(ap)
|
||||
struct vop_reclaim_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct fdescnode *fd = VTOFDESC(vp);
|
||||
|
||||
LIST_REMOVE(fd, fd_hash);
|
||||
FREE(vp->v_data, M_TEMP);
|
||||
vp->v_data = 0;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return POSIX pathconf information applicable to special devices.
|
||||
*/
|
||||
fdesc_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 */
|
||||
}
|
||||
|
||||
/*
|
||||
* Print out the contents of a /dev/fd vnode.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
int
|
||||
fdesc_print(ap)
|
||||
struct vop_print_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
printf("tag VT_NON, fdesc vnode\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*void*/
|
||||
int
|
||||
fdesc_vfree(ap)
|
||||
struct vop_vfree_args /* {
|
||||
struct vnode *a_pvp;
|
||||
ino_t a_ino;
|
||||
int a_mode;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* /dev/fd "should never get here" operation
|
||||
*/
|
||||
int
|
||||
fdesc_badop()
|
||||
{
|
||||
|
||||
panic("fdesc: bad op");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
#define fdesc_create ((int (*) __P((struct vop_create_args *)))eopnotsupp)
|
||||
#define fdesc_mknod ((int (*) __P((struct vop_mknod_args *)))eopnotsupp)
|
||||
#define fdesc_close ((int (*) __P((struct vop_close_args *)))nullop)
|
||||
#define fdesc_access ((int (*) __P((struct vop_access_args *)))nullop)
|
||||
#define fdesc_mmap ((int (*) __P((struct vop_mmap_args *)))eopnotsupp)
|
||||
#define fdesc_revoke vop_revoke
|
||||
#define fdesc_fsync ((int (*) __P((struct vop_fsync_args *)))nullop)
|
||||
#define fdesc_seek ((int (*) __P((struct vop_seek_args *)))nullop)
|
||||
#define fdesc_remove ((int (*) __P((struct vop_remove_args *)))eopnotsupp)
|
||||
#define fdesc_link ((int (*) __P((struct vop_link_args *)))eopnotsupp)
|
||||
#define fdesc_rename ((int (*) __P((struct vop_rename_args *)))eopnotsupp)
|
||||
#define fdesc_mkdir ((int (*) __P((struct vop_mkdir_args *)))eopnotsupp)
|
||||
#define fdesc_rmdir ((int (*) __P((struct vop_rmdir_args *)))eopnotsupp)
|
||||
#define fdesc_symlink ((int (*) __P((struct vop_symlink_args *)))eopnotsupp)
|
||||
#define fdesc_abortop ((int (*) __P((struct vop_abortop_args *)))nullop)
|
||||
#define fdesc_lock ((int (*) __P((struct vop_lock_args *)))vop_nolock)
|
||||
#define fdesc_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock)
|
||||
#define fdesc_bmap ((int (*) __P((struct vop_bmap_args *)))fdesc_badop)
|
||||
#define fdesc_strategy ((int (*) __P((struct vop_strategy_args *)))fdesc_badop)
|
||||
#define fdesc_islocked \
|
||||
((int (*) __P((struct vop_islocked_args *)))vop_noislocked)
|
||||
#define fdesc_advlock ((int (*) __P((struct vop_advlock_args *)))eopnotsupp)
|
||||
#define fdesc_blkatoff \
|
||||
((int (*) __P((struct vop_blkatoff_args *)))eopnotsupp)
|
||||
#define fdesc_valloc ((int(*) __P(( \
|
||||
struct vnode *pvp, \
|
||||
int mode, \
|
||||
struct ucred *cred, \
|
||||
struct vnode **vpp))) eopnotsupp)
|
||||
#define fdesc_truncate \
|
||||
((int (*) __P((struct vop_truncate_args *)))eopnotsupp)
|
||||
#define fdesc_update ((int (*) __P((struct vop_update_args *)))eopnotsupp)
|
||||
#define fdesc_bwrite ((int (*) __P((struct vop_bwrite_args *)))eopnotsupp)
|
||||
|
||||
int (**fdesc_vnodeop_p)();
|
||||
struct vnodeopv_entry_desc fdesc_vnodeop_entries[] = {
|
||||
{ &vop_default_desc, vn_default_error },
|
||||
{ &vop_lookup_desc, fdesc_lookup }, /* lookup */
|
||||
{ &vop_create_desc, fdesc_create }, /* create */
|
||||
{ &vop_mknod_desc, fdesc_mknod }, /* mknod */
|
||||
{ &vop_open_desc, fdesc_open }, /* open */
|
||||
{ &vop_close_desc, fdesc_close }, /* close */
|
||||
{ &vop_access_desc, fdesc_access }, /* access */
|
||||
{ &vop_getattr_desc, fdesc_getattr }, /* getattr */
|
||||
{ &vop_setattr_desc, fdesc_setattr }, /* setattr */
|
||||
{ &vop_read_desc, fdesc_read }, /* read */
|
||||
{ &vop_write_desc, fdesc_write }, /* write */
|
||||
{ &vop_ioctl_desc, fdesc_ioctl }, /* ioctl */
|
||||
{ &vop_select_desc, fdesc_select }, /* select */
|
||||
{ &vop_revoke_desc, fdesc_revoke }, /* revoke */
|
||||
{ &vop_mmap_desc, fdesc_mmap }, /* mmap */
|
||||
{ &vop_fsync_desc, fdesc_fsync }, /* fsync */
|
||||
{ &vop_seek_desc, fdesc_seek }, /* seek */
|
||||
{ &vop_remove_desc, fdesc_remove }, /* remove */
|
||||
{ &vop_link_desc, fdesc_link }, /* link */
|
||||
{ &vop_rename_desc, fdesc_rename }, /* rename */
|
||||
{ &vop_mkdir_desc, fdesc_mkdir }, /* mkdir */
|
||||
{ &vop_rmdir_desc, fdesc_rmdir }, /* rmdir */
|
||||
{ &vop_symlink_desc, fdesc_symlink }, /* symlink */
|
||||
{ &vop_readdir_desc, fdesc_readdir }, /* readdir */
|
||||
{ &vop_readlink_desc, fdesc_readlink }, /* readlink */
|
||||
{ &vop_abortop_desc, fdesc_abortop }, /* abortop */
|
||||
{ &vop_inactive_desc, fdesc_inactive }, /* inactive */
|
||||
{ &vop_reclaim_desc, fdesc_reclaim }, /* reclaim */
|
||||
{ &vop_lock_desc, fdesc_lock }, /* lock */
|
||||
{ &vop_unlock_desc, fdesc_unlock }, /* unlock */
|
||||
{ &vop_bmap_desc, fdesc_bmap }, /* bmap */
|
||||
{ &vop_strategy_desc, fdesc_strategy }, /* strategy */
|
||||
{ &vop_print_desc, fdesc_print }, /* print */
|
||||
{ &vop_islocked_desc, fdesc_islocked }, /* islocked */
|
||||
{ &vop_pathconf_desc, fdesc_pathconf }, /* pathconf */
|
||||
{ &vop_advlock_desc, fdesc_advlock }, /* advlock */
|
||||
{ &vop_blkatoff_desc, fdesc_blkatoff }, /* blkatoff */
|
||||
{ &vop_valloc_desc, fdesc_valloc }, /* valloc */
|
||||
{ &vop_vfree_desc, fdesc_vfree }, /* vfree */
|
||||
{ &vop_truncate_desc, fdesc_truncate }, /* truncate */
|
||||
{ &vop_update_desc, fdesc_update }, /* update */
|
||||
{ &vop_bwrite_desc, fdesc_bwrite }, /* bwrite */
|
||||
{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
|
||||
};
|
||||
struct vnodeopv_desc fdesc_vnodeop_opv_desc =
|
||||
{ &fdesc_vnodeop_p, fdesc_vnodeop_entries };
|
||||
87
sys/miscfs/fifofs/fifo.h
Normal file
87
sys/miscfs/fifofs/fifo.h
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)fifo.h 8.6 (Berkeley) 5/21/95
|
||||
*/
|
||||
|
||||
#ifdef FIFO
|
||||
/*
|
||||
* Prototypes for fifo operations on vnodes.
|
||||
*/
|
||||
int fifo_badop(),
|
||||
fifo_ebadf();
|
||||
|
||||
int fifo_lookup __P((struct vop_lookup_args *));
|
||||
#define fifo_create ((int (*) __P((struct vop_create_args *)))fifo_badop)
|
||||
#define fifo_mknod ((int (*) __P((struct vop_mknod_args *)))fifo_badop)
|
||||
int fifo_open __P((struct vop_open_args *));
|
||||
int fifo_close __P((struct vop_close_args *));
|
||||
#define fifo_access ((int (*) __P((struct vop_access_args *)))fifo_ebadf)
|
||||
#define fifo_getattr ((int (*) __P((struct vop_getattr_args *)))fifo_ebadf)
|
||||
#define fifo_setattr ((int (*) __P((struct vop_setattr_args *)))fifo_ebadf)
|
||||
int fifo_read __P((struct vop_read_args *));
|
||||
int fifo_write __P((struct vop_write_args *));
|
||||
#define fifo_lease_check ((int (*) __P((struct vop_lease_args *)))nullop)
|
||||
int fifo_ioctl __P((struct vop_ioctl_args *));
|
||||
int fifo_select __P((struct vop_select_args *));
|
||||
#define fifo_revoke vop_revoke
|
||||
#define fifo_mmap ((int (*) __P((struct vop_mmap_args *)))fifo_badop)
|
||||
#define fifo_fsync ((int (*) __P((struct vop_fsync_args *)))nullop)
|
||||
#define fifo_seek ((int (*) __P((struct vop_seek_args *)))fifo_badop)
|
||||
#define fifo_remove ((int (*) __P((struct vop_remove_args *)))fifo_badop)
|
||||
#define fifo_link ((int (*) __P((struct vop_link_args *)))fifo_badop)
|
||||
#define fifo_rename ((int (*) __P((struct vop_rename_args *)))fifo_badop)
|
||||
#define fifo_mkdir ((int (*) __P((struct vop_mkdir_args *)))fifo_badop)
|
||||
#define fifo_rmdir ((int (*) __P((struct vop_rmdir_args *)))fifo_badop)
|
||||
#define fifo_symlink ((int (*) __P((struct vop_symlink_args *)))fifo_badop)
|
||||
#define fifo_readdir ((int (*) __P((struct vop_readdir_args *)))fifo_badop)
|
||||
#define fifo_readlink ((int (*) __P((struct vop_readlink_args *)))fifo_badop)
|
||||
#define fifo_abortop ((int (*) __P((struct vop_abortop_args *)))fifo_badop)
|
||||
int fifo_inactive __P((struct vop_inactive_args *));
|
||||
#define fifo_reclaim ((int (*) __P((struct vop_reclaim_args *)))nullop)
|
||||
#define fifo_lock ((int (*) __P((struct vop_lock_args *)))vop_nolock)
|
||||
#define fifo_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock)
|
||||
int fifo_bmap __P((struct vop_bmap_args *));
|
||||
#define fifo_strategy ((int (*) __P((struct vop_strategy_args *)))fifo_badop)
|
||||
int fifo_print __P((struct vop_print_args *));
|
||||
#define fifo_islocked ((int(*) __P((struct vop_islocked_args *)))vop_noislocked)
|
||||
int fifo_pathconf __P((struct vop_pathconf_args *));
|
||||
int fifo_advlock __P((struct vop_advlock_args *));
|
||||
#define fifo_blkatoff ((int (*) __P((struct vop_blkatoff_args *)))fifo_badop)
|
||||
#define fifo_valloc ((int (*) __P((struct vop_valloc_args *)))fifo_badop)
|
||||
#define fifo_reallocblks \
|
||||
((int (*) __P((struct vop_reallocblks_args *)))fifo_badop)
|
||||
#define fifo_vfree ((int (*) __P((struct vop_vfree_args *)))fifo_badop)
|
||||
#define fifo_truncate ((int (*) __P((struct vop_truncate_args *)))nullop)
|
||||
#define fifo_update ((int (*) __P((struct vop_update_args *)))nullop)
|
||||
#define fifo_bwrite ((int (*) __P((struct vop_bwrite_args *)))nullop)
|
||||
#endif /* FIFO */
|
||||
515
sys/miscfs/fifofs/fifo_vnops.c
Normal file
515
sys/miscfs/fifofs/fifo_vnops.c
Normal file
|
|
@ -0,0 +1,515 @@
|
|||
/*
|
||||
* Copyright (c) 1990, 1993, 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)fifo_vnops.c 8.10 (Berkeley) 5/27/95
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <miscfs/fifofs/fifo.h>
|
||||
|
||||
/*
|
||||
* This structure is associated with the FIFO vnode and stores
|
||||
* the state associated with the FIFO.
|
||||
*/
|
||||
struct fifoinfo {
|
||||
struct socket *fi_readsock;
|
||||
struct socket *fi_writesock;
|
||||
long fi_readers;
|
||||
long fi_writers;
|
||||
};
|
||||
|
||||
int (**fifo_vnodeop_p)();
|
||||
struct vnodeopv_entry_desc fifo_vnodeop_entries[] = {
|
||||
{ &vop_default_desc, vn_default_error },
|
||||
{ &vop_lookup_desc, fifo_lookup }, /* lookup */
|
||||
{ &vop_create_desc, fifo_create }, /* create */
|
||||
{ &vop_mknod_desc, fifo_mknod }, /* mknod */
|
||||
{ &vop_open_desc, fifo_open }, /* open */
|
||||
{ &vop_close_desc, fifo_close }, /* close */
|
||||
{ &vop_access_desc, fifo_access }, /* access */
|
||||
{ &vop_getattr_desc, fifo_getattr }, /* getattr */
|
||||
{ &vop_setattr_desc, fifo_setattr }, /* setattr */
|
||||
{ &vop_read_desc, fifo_read }, /* read */
|
||||
{ &vop_write_desc, fifo_write }, /* write */
|
||||
{ &vop_lease_desc, fifo_lease_check }, /* lease */
|
||||
{ &vop_ioctl_desc, fifo_ioctl }, /* ioctl */
|
||||
{ &vop_select_desc, fifo_select }, /* select */
|
||||
{ &vop_revoke_desc, fifo_revoke }, /* revoke */
|
||||
{ &vop_mmap_desc, fifo_mmap }, /* mmap */
|
||||
{ &vop_fsync_desc, fifo_fsync }, /* fsync */
|
||||
{ &vop_seek_desc, fifo_seek }, /* seek */
|
||||
{ &vop_remove_desc, fifo_remove }, /* remove */
|
||||
{ &vop_link_desc, fifo_link }, /* link */
|
||||
{ &vop_rename_desc, fifo_rename }, /* rename */
|
||||
{ &vop_mkdir_desc, fifo_mkdir }, /* mkdir */
|
||||
{ &vop_rmdir_desc, fifo_rmdir }, /* rmdir */
|
||||
{ &vop_symlink_desc, fifo_symlink }, /* symlink */
|
||||
{ &vop_readdir_desc, fifo_readdir }, /* readdir */
|
||||
{ &vop_readlink_desc, fifo_readlink }, /* readlink */
|
||||
{ &vop_abortop_desc, fifo_abortop }, /* abortop */
|
||||
{ &vop_inactive_desc, fifo_inactive }, /* inactive */
|
||||
{ &vop_reclaim_desc, fifo_reclaim }, /* reclaim */
|
||||
{ &vop_lock_desc, fifo_lock }, /* lock */
|
||||
{ &vop_unlock_desc, fifo_unlock }, /* unlock */
|
||||
{ &vop_bmap_desc, fifo_bmap }, /* bmap */
|
||||
{ &vop_strategy_desc, fifo_strategy }, /* strategy */
|
||||
{ &vop_print_desc, fifo_print }, /* print */
|
||||
{ &vop_islocked_desc, fifo_islocked }, /* islocked */
|
||||
{ &vop_pathconf_desc, fifo_pathconf }, /* pathconf */
|
||||
{ &vop_advlock_desc, fifo_advlock }, /* advlock */
|
||||
{ &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */
|
||||
{ &vop_valloc_desc, fifo_valloc }, /* valloc */
|
||||
{ &vop_vfree_desc, fifo_vfree }, /* vfree */
|
||||
{ &vop_truncate_desc, fifo_truncate }, /* truncate */
|
||||
{ &vop_update_desc, fifo_update }, /* update */
|
||||
{ &vop_bwrite_desc, fifo_bwrite }, /* bwrite */
|
||||
{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
|
||||
};
|
||||
struct vnodeopv_desc fifo_vnodeop_opv_desc =
|
||||
{ &fifo_vnodeop_p, fifo_vnodeop_entries };
|
||||
|
||||
/*
|
||||
* Trivial lookup routine that always fails.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
fifo_lookup(ap)
|
||||
struct vop_lookup_args /* {
|
||||
struct vnode * a_dvp;
|
||||
struct vnode ** a_vpp;
|
||||
struct componentname * a_cnp;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
*ap->a_vpp = NULL;
|
||||
return (ENOTDIR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open called to set up a new instance of a fifo or
|
||||
* to find an active instance of a fifo.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
fifo_open(ap)
|
||||
struct vop_open_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_mode;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct fifoinfo *fip;
|
||||
struct proc *p = ap->a_p;
|
||||
struct socket *rso, *wso;
|
||||
int error;
|
||||
static char openstr[] = "fifo";
|
||||
|
||||
if ((fip = vp->v_fifoinfo) == NULL) {
|
||||
MALLOC(fip, struct fifoinfo *, sizeof(*fip), M_VNODE, M_WAITOK);
|
||||
vp->v_fifoinfo = fip;
|
||||
if (error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0)) {
|
||||
free(fip, M_VNODE);
|
||||
vp->v_fifoinfo = NULL;
|
||||
return (error);
|
||||
}
|
||||
fip->fi_readsock = rso;
|
||||
if (error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0)) {
|
||||
(void)soclose(rso);
|
||||
free(fip, M_VNODE);
|
||||
vp->v_fifoinfo = NULL;
|
||||
return (error);
|
||||
}
|
||||
fip->fi_writesock = wso;
|
||||
if (error = unp_connect2(wso, rso)) {
|
||||
(void)soclose(wso);
|
||||
(void)soclose(rso);
|
||||
free(fip, M_VNODE);
|
||||
vp->v_fifoinfo = NULL;
|
||||
return (error);
|
||||
}
|
||||
fip->fi_readers = fip->fi_writers = 0;
|
||||
wso->so_state |= SS_CANTRCVMORE;
|
||||
rso->so_state |= SS_CANTSENDMORE;
|
||||
}
|
||||
if (ap->a_mode & FREAD) {
|
||||
fip->fi_readers++;
|
||||
if (fip->fi_readers == 1) {
|
||||
fip->fi_writesock->so_state &= ~SS_CANTSENDMORE;
|
||||
if (fip->fi_writers > 0)
|
||||
wakeup((caddr_t)&fip->fi_writers);
|
||||
}
|
||||
}
|
||||
if (ap->a_mode & FWRITE) {
|
||||
fip->fi_writers++;
|
||||
if (fip->fi_writers == 1) {
|
||||
fip->fi_readsock->so_state &= ~SS_CANTRCVMORE;
|
||||
if (fip->fi_readers > 0)
|
||||
wakeup((caddr_t)&fip->fi_readers);
|
||||
}
|
||||
}
|
||||
if ((ap->a_mode & FREAD) && (ap->a_mode & O_NONBLOCK) == 0) {
|
||||
while (fip->fi_writers == 0) {
|
||||
VOP_UNLOCK(vp, 0, p);
|
||||
error = tsleep((caddr_t)&fip->fi_readers,
|
||||
PCATCH | PSOCK, openstr, 0);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
if (error)
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
if (ap->a_mode & FWRITE) {
|
||||
if (ap->a_mode & O_NONBLOCK) {
|
||||
if (fip->fi_readers == 0) {
|
||||
error = ENXIO;
|
||||
goto bad;
|
||||
}
|
||||
} else {
|
||||
while (fip->fi_readers == 0) {
|
||||
VOP_UNLOCK(vp, 0, p);
|
||||
error = tsleep((caddr_t)&fip->fi_writers,
|
||||
PCATCH | PSOCK, openstr, 0);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
if (error)
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
bad:
|
||||
if (error)
|
||||
VOP_CLOSE(vp, ap->a_mode, ap->a_cred, p);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Vnode op for read
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
fifo_read(ap)
|
||||
struct vop_read_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
int a_ioflag;
|
||||
struct ucred *a_cred;
|
||||
} */ *ap;
|
||||
{
|
||||
struct uio *uio = ap->a_uio;
|
||||
struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock;
|
||||
struct proc *p = uio->uio_procp;
|
||||
int error, startresid;
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
if (uio->uio_rw != UIO_READ)
|
||||
panic("fifo_read mode");
|
||||
#endif
|
||||
if (uio->uio_resid == 0)
|
||||
return (0);
|
||||
if (ap->a_ioflag & IO_NDELAY)
|
||||
rso->so_state |= SS_NBIO;
|
||||
startresid = uio->uio_resid;
|
||||
VOP_UNLOCK(ap->a_vp, 0, p);
|
||||
error = soreceive(rso, (struct mbuf **)0, uio, (struct mbuf **)0,
|
||||
(struct mbuf **)0, (int *)0);
|
||||
vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
/*
|
||||
* Clear EOF indication after first such return.
|
||||
*/
|
||||
if (uio->uio_resid == startresid)
|
||||
rso->so_state &= ~SS_CANTRCVMORE;
|
||||
if (ap->a_ioflag & IO_NDELAY)
|
||||
rso->so_state &= ~SS_NBIO;
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Vnode op for write
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
fifo_write(ap)
|
||||
struct vop_write_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
int a_ioflag;
|
||||
struct ucred *a_cred;
|
||||
} */ *ap;
|
||||
{
|
||||
struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock;
|
||||
struct proc *p = ap->a_uio->uio_procp;
|
||||
int error;
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
if (ap->a_uio->uio_rw != UIO_WRITE)
|
||||
panic("fifo_write mode");
|
||||
#endif
|
||||
if (ap->a_ioflag & IO_NDELAY)
|
||||
wso->so_state |= SS_NBIO;
|
||||
VOP_UNLOCK(ap->a_vp, 0, p);
|
||||
error = sosend(wso, (struct mbuf *)0, ap->a_uio, 0, (struct mbuf *)0, 0);
|
||||
vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
if (ap->a_ioflag & IO_NDELAY)
|
||||
wso->so_state &= ~SS_NBIO;
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Device ioctl operation.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
fifo_ioctl(ap)
|
||||
struct vop_ioctl_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_command;
|
||||
caddr_t a_data;
|
||||
int a_fflag;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct file filetmp;
|
||||
int error;
|
||||
|
||||
if (ap->a_command == FIONBIO)
|
||||
return (0);
|
||||
if (ap->a_fflag & FREAD) {
|
||||
filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock;
|
||||
error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
if (ap->a_fflag & FWRITE) {
|
||||
filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock;
|
||||
error = soo_ioctl(&filetmp, ap->a_command, ap->a_data, ap->a_p);
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
fifo_select(ap)
|
||||
struct vop_select_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_which;
|
||||
int a_fflags;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct file filetmp;
|
||||
int ready;
|
||||
|
||||
if (ap->a_fflags & FREAD) {
|
||||
filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock;
|
||||
ready = soo_select(&filetmp, ap->a_which, ap->a_p);
|
||||
if (ready)
|
||||
return (ready);
|
||||
}
|
||||
if (ap->a_fflags & FWRITE) {
|
||||
filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock;
|
||||
ready = soo_select(&filetmp, ap->a_which, ap->a_p);
|
||||
if (ready)
|
||||
return (ready);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
fifo_inactive(ap)
|
||||
struct vop_inactive_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a noop, simply returning what one has been given.
|
||||
*/
|
||||
fifo_bmap(ap)
|
||||
struct vop_bmap_args /* {
|
||||
struct vnode *a_vp;
|
||||
daddr_t a_bn;
|
||||
struct vnode **a_vpp;
|
||||
daddr_t *a_bnp;
|
||||
int *a_runp;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
if (ap->a_vpp != NULL)
|
||||
*ap->a_vpp = ap->a_vp;
|
||||
if (ap->a_bnp != NULL)
|
||||
*ap->a_bnp = ap->a_bn;
|
||||
if (ap->a_runp != NULL)
|
||||
*ap->a_runp = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Device close routine
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
fifo_close(ap)
|
||||
struct vop_close_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_fflag;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
register struct vnode *vp = ap->a_vp;
|
||||
register struct fifoinfo *fip = vp->v_fifoinfo;
|
||||
int error1, error2;
|
||||
|
||||
if (ap->a_fflag & FREAD) {
|
||||
fip->fi_readers--;
|
||||
if (fip->fi_readers == 0)
|
||||
socantsendmore(fip->fi_writesock);
|
||||
}
|
||||
if (ap->a_fflag & FWRITE) {
|
||||
fip->fi_writers--;
|
||||
if (fip->fi_writers == 0)
|
||||
socantrcvmore(fip->fi_readsock);
|
||||
}
|
||||
if (vp->v_usecount > 1)
|
||||
return (0);
|
||||
error1 = soclose(fip->fi_readsock);
|
||||
error2 = soclose(fip->fi_writesock);
|
||||
FREE(fip, M_VNODE);
|
||||
vp->v_fifoinfo = NULL;
|
||||
if (error1)
|
||||
return (error1);
|
||||
return (error2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print out the contents of a fifo vnode.
|
||||
*/
|
||||
fifo_print(ap)
|
||||
struct vop_print_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
printf("tag VT_NON");
|
||||
fifo_printinfo(ap->a_vp);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Print out internal contents of a fifo vnode.
|
||||
*/
|
||||
fifo_printinfo(vp)
|
||||
struct vnode *vp;
|
||||
{
|
||||
register struct fifoinfo *fip = vp->v_fifoinfo;
|
||||
|
||||
printf(", fifo with %d readers and %d writers",
|
||||
fip->fi_readers, fip->fi_writers);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return POSIX pathconf information applicable to fifo's.
|
||||
*/
|
||||
fifo_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_PIPE_BUF:
|
||||
*ap->a_retval = PIPE_BUF;
|
||||
return (0);
|
||||
case _PC_CHOWN_RESTRICTED:
|
||||
*ap->a_retval = 1;
|
||||
return (0);
|
||||
default:
|
||||
return (EINVAL);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
* Fifo failed operation
|
||||
*/
|
||||
fifo_ebadf()
|
||||
{
|
||||
|
||||
return (EBADF);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fifo advisory byte-level locks.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
fifo_advlock(ap)
|
||||
struct vop_advlock_args /* {
|
||||
struct vnode *a_vp;
|
||||
caddr_t a_id;
|
||||
int a_op;
|
||||
struct flock *a_fl;
|
||||
int a_flags;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
return (EOPNOTSUPP);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fifo bad operation
|
||||
*/
|
||||
fifo_badop()
|
||||
{
|
||||
|
||||
panic("fifo_badop called");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
67
sys/miscfs/kernfs/kernfs.h
Normal file
67
sys/miscfs/kernfs/kernfs.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)kernfs.h 8.6 (Berkeley) 3/29/95
|
||||
*/
|
||||
|
||||
#define _PATH_KERNFS "/kern" /* Default mountpoint */
|
||||
|
||||
#ifdef KERNEL
|
||||
struct kernfs_mount {
|
||||
struct vnode *kf_root; /* Root node */
|
||||
};
|
||||
|
||||
struct kernfs_node {
|
||||
struct kern_target *kf_kt;
|
||||
};
|
||||
|
||||
#define VFSTOKERNFS(mp) ((struct kernfs_mount *)((mp)->mnt_data))
|
||||
#define VTOKERN(vp) ((struct kernfs_node *)(vp)->v_data)
|
||||
|
||||
#define kernfs_fhtovp ((int (*) __P((struct mount *, struct fid *, \
|
||||
struct mbuf *, struct vnode **, int *, struct ucred **)))eopnotsupp)
|
||||
#define kernfs_quotactl ((int (*) __P((struct mount *, int, uid_t, caddr_t, \
|
||||
struct proc *)))eopnotsupp)
|
||||
#define kernfs_sync ((int (*) __P((struct mount *, int, struct ucred *, \
|
||||
struct proc *)))nullop)
|
||||
#define kernfs_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \
|
||||
size_t, struct proc *)))eopnotsupp)
|
||||
#define kernfs_vget ((int (*) __P((struct mount *, ino_t, struct vnode **))) \
|
||||
eopnotsupp)
|
||||
#define kernfs_vptofh ((int (*) __P((struct vnode *, struct fid *)))eopnotsupp)
|
||||
extern int (**kernfs_vnodeop_p)();
|
||||
extern struct vfsops kernfs_vfsops;
|
||||
extern dev_t rrootdev;
|
||||
#endif /* KERNEL */
|
||||
257
sys/miscfs/kernfs/kernfs_vfsops.c
Normal file
257
sys/miscfs/kernfs/kernfs_vfsops.c
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
* Copyright (c) 1992, 1993, 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)kernfs_vfsops.c 8.10 (Berkeley) 5/14/95
|
||||
*/
|
||||
|
||||
/*
|
||||
* Kernel params Filesystem
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <miscfs/specfs/specdev.h>
|
||||
#include <miscfs/kernfs/kernfs.h>
|
||||
|
||||
dev_t rrootdev = NODEV;
|
||||
|
||||
kernfs_init(vfsp)
|
||||
struct vfsconf *vfsp;
|
||||
{
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
kernfs_get_rrootdev()
|
||||
{
|
||||
static int tried = 0;
|
||||
int cmaj;
|
||||
|
||||
if (tried) {
|
||||
/* Already did it once. */
|
||||
return;
|
||||
}
|
||||
tried = 1;
|
||||
|
||||
if (rootdev == NODEV)
|
||||
return;
|
||||
for (cmaj = 0; cmaj < nchrdev; cmaj++) {
|
||||
rrootdev = makedev(cmaj, minor(rootdev));
|
||||
if (chrtoblk(rrootdev) == rootdev)
|
||||
return;
|
||||
}
|
||||
rrootdev = NODEV;
|
||||
printf("kernfs_get_rrootdev: no raw root device\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Mount the Kernel params filesystem
|
||||
*/
|
||||
kernfs_mount(mp, path, data, ndp, p)
|
||||
struct mount *mp;
|
||||
char *path;
|
||||
caddr_t data;
|
||||
struct nameidata *ndp;
|
||||
struct proc *p;
|
||||
{
|
||||
int error = 0;
|
||||
u_int size;
|
||||
struct kernfs_mount *fmp;
|
||||
struct vnode *rvp;
|
||||
|
||||
#ifdef KERNFS_DIAGNOSTIC
|
||||
printf("kernfs_mount(mp = %x)\n", mp);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Update is a no-op
|
||||
*/
|
||||
if (mp->mnt_flag & MNT_UPDATE)
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
error = getnewvnode(VT_KERNFS, mp, kernfs_vnodeop_p, &rvp); /* XXX */
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
MALLOC(fmp, struct kernfs_mount *, sizeof(struct kernfs_mount),
|
||||
M_UFSMNT, M_WAITOK); /* XXX */
|
||||
rvp->v_type = VDIR;
|
||||
rvp->v_flag |= VROOT;
|
||||
#ifdef KERNFS_DIAGNOSTIC
|
||||
printf("kernfs_mount: root vp = %x\n", rvp);
|
||||
#endif
|
||||
fmp->kf_root = rvp;
|
||||
mp->mnt_flag |= MNT_LOCAL;
|
||||
mp->mnt_data = (qaddr_t) fmp;
|
||||
vfs_getnewfsid(mp);
|
||||
|
||||
(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
|
||||
bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
|
||||
bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
|
||||
bcopy("kernfs", mp->mnt_stat.f_mntfromname, sizeof("kernfs"));
|
||||
#ifdef KERNFS_DIAGNOSTIC
|
||||
printf("kernfs_mount: at %s\n", mp->mnt_stat.f_mntonname);
|
||||
#endif
|
||||
|
||||
kernfs_get_rrootdev();
|
||||
return (0);
|
||||
}
|
||||
|
||||
kernfs_start(mp, flags, p)
|
||||
struct mount *mp;
|
||||
int flags;
|
||||
struct proc *p;
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
kernfs_unmount(mp, mntflags, p)
|
||||
struct mount *mp;
|
||||
int mntflags;
|
||||
struct proc *p;
|
||||
{
|
||||
int error;
|
||||
int flags = 0;
|
||||
struct vnode *rootvp = VFSTOKERNFS(mp)->kf_root;
|
||||
|
||||
#ifdef KERNFS_DIAGNOSTIC
|
||||
printf("kernfs_unmount(mp = %x)\n", mp);
|
||||
#endif
|
||||
|
||||
if (mntflags & MNT_FORCE)
|
||||
flags |= FORCECLOSE;
|
||||
|
||||
/*
|
||||
* Clear out buffer cache. I don't think we
|
||||
* ever get anything cached at this level at the
|
||||
* moment, but who knows...
|
||||
*/
|
||||
if (rootvp->v_usecount > 1)
|
||||
return (EBUSY);
|
||||
#ifdef KERNFS_DIAGNOSTIC
|
||||
printf("kernfs_unmount: calling vflush\n");
|
||||
#endif
|
||||
if (error = vflush(mp, rootvp, flags))
|
||||
return (error);
|
||||
|
||||
#ifdef KERNFS_DIAGNOSTIC
|
||||
vprint("kernfs root", rootvp);
|
||||
#endif
|
||||
/*
|
||||
* Release reference on underlying root vnode
|
||||
*/
|
||||
vrele(rootvp);
|
||||
/*
|
||||
* And blow it away for future re-use
|
||||
*/
|
||||
vgone(rootvp);
|
||||
/*
|
||||
* Finally, throw away the kernfs_mount structure
|
||||
*/
|
||||
free(mp->mnt_data, M_UFSMNT); /* XXX */
|
||||
mp->mnt_data = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
kernfs_root(mp, vpp)
|
||||
struct mount *mp;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
struct proc *p = curproc; /* XXX */
|
||||
struct vnode *vp;
|
||||
|
||||
#ifdef KERNFS_DIAGNOSTIC
|
||||
printf("kernfs_root(mp = %x)\n", mp);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Return locked reference to root.
|
||||
*/
|
||||
vp = VFSTOKERNFS(mp)->kf_root;
|
||||
VREF(vp);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
*vpp = vp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
kernfs_statfs(mp, sbp, p)
|
||||
struct mount *mp;
|
||||
struct statfs *sbp;
|
||||
struct proc *p;
|
||||
{
|
||||
#ifdef KERNFS_DIAGNOSTIC
|
||||
printf("kernfs_statfs(mp = %x)\n", mp);
|
||||
#endif
|
||||
|
||||
sbp->f_flags = 0;
|
||||
sbp->f_bsize = DEV_BSIZE;
|
||||
sbp->f_iosize = DEV_BSIZE;
|
||||
sbp->f_blocks = 2; /* 1K to keep df happy */
|
||||
sbp->f_bfree = 0;
|
||||
sbp->f_bavail = 0;
|
||||
sbp->f_files = 0;
|
||||
sbp->f_ffree = 0;
|
||||
if (sbp != &mp->mnt_stat) {
|
||||
sbp->f_type = mp->mnt_vfc->vfc_typenum;
|
||||
bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
|
||||
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
|
||||
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
struct vfsops kernfs_vfsops = {
|
||||
kernfs_mount,
|
||||
kernfs_start,
|
||||
kernfs_unmount,
|
||||
kernfs_root,
|
||||
kernfs_quotactl,
|
||||
kernfs_statfs,
|
||||
kernfs_sync,
|
||||
kernfs_vget,
|
||||
kernfs_fhtovp,
|
||||
kernfs_vptofh,
|
||||
kernfs_init,
|
||||
kernfs_sysctl,
|
||||
};
|
||||
760
sys/miscfs/kernfs/kernfs_vnops.c
Normal file
760
sys/miscfs/kernfs/kernfs_vnops.c
Normal file
|
|
@ -0,0 +1,760 @@
|
|||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)kernfs_vnops.c 8.15 (Berkeley) 5/21/95
|
||||
*/
|
||||
|
||||
/*
|
||||
* Kernel parameter filesystem (/kern)
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/vmmeter.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/dirent.h>
|
||||
#include <miscfs/kernfs/kernfs.h>
|
||||
|
||||
#define KSTRING 256 /* Largest I/O available via this filesystem */
|
||||
#define UIO_MX 32
|
||||
|
||||
#define READ_MODE (S_IRUSR|S_IRGRP|S_IROTH)
|
||||
#define WRITE_MODE (S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)
|
||||
#define DIR_MODE (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
|
||||
|
||||
struct kern_target {
|
||||
u_char kt_type;
|
||||
u_char kt_namlen;
|
||||
char *kt_name;
|
||||
void *kt_data;
|
||||
#define KTT_NULL 1
|
||||
#define KTT_TIME 5
|
||||
#define KTT_INT 17
|
||||
#define KTT_STRING 31
|
||||
#define KTT_HOSTNAME 47
|
||||
#define KTT_AVENRUN 53
|
||||
#define KTT_DEVICE 71
|
||||
u_char kt_tag;
|
||||
u_char kt_vtype;
|
||||
mode_t kt_mode;
|
||||
} kern_targets[] = {
|
||||
/* NOTE: The name must be less than UIO_MX-16 chars in length */
|
||||
#define N(s) sizeof(s)-1, s
|
||||
/* name data tag type ro/rw */
|
||||
{ DT_DIR, N("."), 0, KTT_NULL, VDIR, DIR_MODE },
|
||||
{ DT_DIR, N(".."), 0, KTT_NULL, VDIR, DIR_MODE },
|
||||
{ DT_REG, N("boottime"), &boottime.tv_sec, KTT_INT, VREG, READ_MODE },
|
||||
{ DT_REG, N("copyright"), copyright, KTT_STRING, VREG, READ_MODE },
|
||||
{ DT_REG, N("hostname"), 0, KTT_HOSTNAME, VREG, WRITE_MODE },
|
||||
{ DT_REG, N("hz"), &hz, KTT_INT, VREG, READ_MODE },
|
||||
{ DT_REG, N("loadavg"), 0, KTT_AVENRUN, VREG, READ_MODE },
|
||||
{ DT_REG, N("pagesize"), &cnt.v_page_size, KTT_INT, VREG, READ_MODE },
|
||||
{ DT_REG, N("physmem"), &physmem, KTT_INT, VREG, READ_MODE },
|
||||
#if 0
|
||||
{ DT_DIR, N("root"), 0, KTT_NULL, VDIR, DIR_MODE },
|
||||
#endif
|
||||
{ DT_BLK, N("rootdev"), &rootdev, KTT_DEVICE, VBLK, READ_MODE },
|
||||
{ DT_CHR, N("rrootdev"), &rrootdev, KTT_DEVICE, VCHR, READ_MODE },
|
||||
{ DT_REG, N("time"), 0, KTT_TIME, VREG, READ_MODE },
|
||||
{ DT_REG, N("version"), version, KTT_STRING, VREG, READ_MODE },
|
||||
#undef N
|
||||
};
|
||||
static int nkern_targets = sizeof(kern_targets) / sizeof(kern_targets[0]);
|
||||
|
||||
static int
|
||||
kernfs_xread(kt, buf, len, lenp)
|
||||
struct kern_target *kt;
|
||||
char *buf;
|
||||
int len;
|
||||
int *lenp;
|
||||
{
|
||||
|
||||
switch (kt->kt_tag) {
|
||||
case KTT_TIME: {
|
||||
struct timeval tv;
|
||||
microtime(&tv);
|
||||
sprintf(buf, "%d %d\n", tv.tv_sec, tv.tv_usec);
|
||||
break;
|
||||
}
|
||||
|
||||
case KTT_INT: {
|
||||
int *ip = kt->kt_data;
|
||||
sprintf(buf, "%d\n", *ip);
|
||||
break;
|
||||
}
|
||||
|
||||
case KTT_STRING: {
|
||||
char *cp = kt->kt_data;
|
||||
int xlen = strlen(cp) + 1;
|
||||
|
||||
if (xlen >= len)
|
||||
return (EINVAL);
|
||||
|
||||
bcopy(cp, buf, xlen);
|
||||
break;
|
||||
}
|
||||
|
||||
case KTT_HOSTNAME: {
|
||||
char *cp = hostname;
|
||||
int xlen = hostnamelen;
|
||||
|
||||
if (xlen >= (len-2))
|
||||
return (EINVAL);
|
||||
|
||||
bcopy(cp, buf, xlen);
|
||||
buf[xlen] = '\n';
|
||||
buf[xlen+1] = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
case KTT_AVENRUN:
|
||||
sprintf(buf, "%ld %ld %ld %ld\n",
|
||||
averunnable.ldavg[0], averunnable.ldavg[1],
|
||||
averunnable.ldavg[2], averunnable.fscale);
|
||||
break;
|
||||
|
||||
default:
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
*lenp = strlen(buf);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
kernfs_xwrite(kt, buf, len)
|
||||
struct kern_target *kt;
|
||||
char *buf;
|
||||
int len;
|
||||
{
|
||||
|
||||
switch (kt->kt_tag) {
|
||||
case KTT_HOSTNAME:
|
||||
if (buf[len-1] == '\n')
|
||||
--len;
|
||||
bcopy(buf, hostname, len);
|
||||
hostname[len] = '\0';
|
||||
hostnamelen = len;
|
||||
return (0);
|
||||
|
||||
default:
|
||||
return (EIO);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* vp is the current namei directory
|
||||
* ndp is the name to locate in that directory...
|
||||
*/
|
||||
kernfs_lookup(ap)
|
||||
struct vop_lookup_args /* {
|
||||
struct vnode * a_dvp;
|
||||
struct vnode ** a_vpp;
|
||||
struct componentname * a_cnp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct componentname *cnp = ap->a_cnp;
|
||||
struct vnode **vpp = ap->a_vpp;
|
||||
struct vnode *dvp = ap->a_dvp;
|
||||
char *pname = cnp->cn_nameptr;
|
||||
struct proc *p = cnp->cn_proc;
|
||||
struct kern_target *kt;
|
||||
struct vnode *fvp;
|
||||
int error, i;
|
||||
|
||||
#ifdef KERNFS_DIAGNOSTIC
|
||||
printf("kernfs_lookup(%x)\n", ap);
|
||||
printf("kernfs_lookup(dp = %x, vpp = %x, cnp = %x)\n", dvp, vpp, ap->a_cnp);
|
||||
printf("kernfs_lookup(%s)\n", pname);
|
||||
#endif
|
||||
|
||||
*vpp = NULLVP;
|
||||
|
||||
if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
|
||||
return (EROFS);
|
||||
|
||||
VOP_UNLOCK(dvp, 0, p);
|
||||
if (cnp->cn_namelen == 1 && *pname == '.') {
|
||||
*vpp = dvp;
|
||||
VREF(dvp);
|
||||
vn_lock(dvp, LK_SHARED | LK_RETRY, p);
|
||||
return (0);
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (cnp->cn_namelen == 4 && bcmp(pname, "root", 4) == 0) {
|
||||
*vpp = rootdir;
|
||||
VREF(rootdir);
|
||||
vn_lock(rootdir, LK_SHARED | LK_RETRY, p)
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (kt = kern_targets, i = 0; i < nkern_targets; kt++, i++) {
|
||||
if (cnp->cn_namelen == kt->kt_namlen &&
|
||||
bcmp(kt->kt_name, pname, cnp->cn_namelen) == 0)
|
||||
goto found;
|
||||
}
|
||||
|
||||
#ifdef KERNFS_DIAGNOSTIC
|
||||
printf("kernfs_lookup: i = %d, failed", i);
|
||||
#endif
|
||||
|
||||
vn_lock(dvp, LK_SHARED | LK_RETRY, p);
|
||||
return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS);
|
||||
|
||||
found:
|
||||
if (kt->kt_tag == KTT_DEVICE) {
|
||||
dev_t *dp = kt->kt_data;
|
||||
loop:
|
||||
if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp)) {
|
||||
vn_lock(dvp, LK_SHARED | LK_RETRY, p);
|
||||
return (ENOENT);
|
||||
}
|
||||
*vpp = fvp;
|
||||
if (vget(fvp, LK_EXCLUSIVE, p))
|
||||
goto loop;
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef KERNFS_DIAGNOSTIC
|
||||
printf("kernfs_lookup: allocate new vnode\n");
|
||||
#endif
|
||||
if (error = getnewvnode(VT_KERNFS, dvp->v_mount, kernfs_vnodeop_p,
|
||||
&fvp)) {
|
||||
vn_lock(dvp, LK_SHARED | LK_RETRY, p);
|
||||
return (error);
|
||||
}
|
||||
|
||||
MALLOC(fvp->v_data, void *, sizeof(struct kernfs_node), M_TEMP,
|
||||
M_WAITOK);
|
||||
VTOKERN(fvp)->kf_kt = kt;
|
||||
fvp->v_type = kt->kt_vtype;
|
||||
vn_lock(fvp, LK_SHARED | LK_RETRY, p);
|
||||
*vpp = fvp;
|
||||
|
||||
#ifdef KERNFS_DIAGNOSTIC
|
||||
printf("kernfs_lookup: newvp = %x\n", fvp);
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
kernfs_open(ap)
|
||||
struct vop_open_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_mode;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
/* Only need to check access permissions. */
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
kernfs_access(ap)
|
||||
struct vop_access_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_mode;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
register struct vnode *vp = ap->a_vp;
|
||||
register struct ucred *cred = ap->a_cred;
|
||||
mode_t amode = ap->a_mode;
|
||||
mode_t fmode =
|
||||
(vp->v_flag & VROOT) ? DIR_MODE : VTOKERN(vp)->kf_kt->kt_mode;
|
||||
mode_t mask = 0;
|
||||
register gid_t *gp;
|
||||
int i;
|
||||
|
||||
/* Some files are simply not modifiable. */
|
||||
if ((amode & VWRITE) && (fmode & (S_IWUSR|S_IWGRP|S_IWOTH)) == 0)
|
||||
return (EPERM);
|
||||
|
||||
/* Root can do anything else. */
|
||||
if (cred->cr_uid == 0)
|
||||
return (0);
|
||||
|
||||
/* Check for group 0 (wheel) permissions. */
|
||||
for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
|
||||
if (*gp == 0) {
|
||||
if (amode & VEXEC)
|
||||
mask |= S_IXGRP;
|
||||
if (amode & VREAD)
|
||||
mask |= S_IRGRP;
|
||||
if (amode & VWRITE)
|
||||
mask |= S_IWGRP;
|
||||
return ((fmode & mask) == mask ? 0 : EACCES);
|
||||
}
|
||||
|
||||
/* Otherwise, check everyone else. */
|
||||
if (amode & VEXEC)
|
||||
mask |= S_IXOTH;
|
||||
if (amode & VREAD)
|
||||
mask |= S_IROTH;
|
||||
if (amode & VWRITE)
|
||||
mask |= S_IWOTH;
|
||||
return ((fmode & mask) == mask ? 0 : EACCES);
|
||||
}
|
||||
|
||||
kernfs_getattr(ap)
|
||||
struct vop_getattr_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct vattr *a_vap;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct vattr *vap = ap->a_vap;
|
||||
struct timeval tv;
|
||||
int error = 0;
|
||||
char strbuf[KSTRING];
|
||||
|
||||
bzero((caddr_t) vap, sizeof(*vap));
|
||||
vattr_null(vap);
|
||||
vap->va_uid = 0;
|
||||
vap->va_gid = 0;
|
||||
vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
|
||||
vap->va_size = 0;
|
||||
vap->va_blocksize = DEV_BSIZE;
|
||||
microtime(&tv);
|
||||
TIMEVAL_TO_TIMESPEC(&tv, &vap->va_atime);
|
||||
vap->va_mtime = vap->va_atime;
|
||||
vap->va_ctime = vap->va_ctime;
|
||||
vap->va_gen = 0;
|
||||
vap->va_flags = 0;
|
||||
vap->va_rdev = 0;
|
||||
vap->va_bytes = 0;
|
||||
|
||||
if (vp->v_flag & VROOT) {
|
||||
#ifdef KERNFS_DIAGNOSTIC
|
||||
printf("kernfs_getattr: stat rootdir\n");
|
||||
#endif
|
||||
vap->va_type = VDIR;
|
||||
vap->va_mode = DIR_MODE;
|
||||
vap->va_nlink = 2;
|
||||
vap->va_fileid = 2;
|
||||
vap->va_size = DEV_BSIZE;
|
||||
} else {
|
||||
struct kern_target *kt = VTOKERN(vp)->kf_kt;
|
||||
int nbytes;
|
||||
#ifdef KERNFS_DIAGNOSTIC
|
||||
printf("kernfs_getattr: stat target %s\n", kt->kt_name);
|
||||
#endif
|
||||
vap->va_type = kt->kt_vtype;
|
||||
vap->va_mode = kt->kt_mode;
|
||||
vap->va_nlink = 1;
|
||||
vap->va_fileid = 1 + (kt - kern_targets) / sizeof(*kt);
|
||||
error = kernfs_xread(kt, strbuf, sizeof(strbuf), &nbytes);
|
||||
vap->va_size = nbytes;
|
||||
}
|
||||
|
||||
#ifdef KERNFS_DIAGNOSTIC
|
||||
printf("kernfs_getattr: return error %d\n", error);
|
||||
#endif
|
||||
return (error);
|
||||
}
|
||||
|
||||
kernfs_setattr(ap)
|
||||
struct vop_setattr_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct vattr *a_vap;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
/*
|
||||
* Silently ignore attribute changes.
|
||||
* This allows for open with truncate to have no
|
||||
* effect until some data is written. I want to
|
||||
* do it this way because all writes are atomic.
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
kernfs_read(ap)
|
||||
struct vop_read_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
int a_ioflag;
|
||||
struct ucred *a_cred;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct uio *uio = ap->a_uio;
|
||||
struct kern_target *kt;
|
||||
char strbuf[KSTRING];
|
||||
int off = uio->uio_offset;
|
||||
int error, len;
|
||||
char *cp;
|
||||
|
||||
if (vp->v_type == VDIR)
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
kt = VTOKERN(vp)->kf_kt;
|
||||
|
||||
#ifdef KERNFS_DIAGNOSTIC
|
||||
printf("kern_read %s\n", kt->kt_name);
|
||||
#endif
|
||||
|
||||
len = 0;
|
||||
if (error = kernfs_xread(kt, strbuf, sizeof(strbuf), &len))
|
||||
return (error);
|
||||
if (len <= off)
|
||||
return (0);
|
||||
return (uiomove(&strbuf[off], len - off, uio));
|
||||
}
|
||||
|
||||
static int
|
||||
kernfs_write(ap)
|
||||
struct vop_write_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
int a_ioflag;
|
||||
struct ucred *a_cred;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct uio *uio = ap->a_uio;
|
||||
struct kern_target *kt;
|
||||
int error, xlen;
|
||||
char strbuf[KSTRING];
|
||||
|
||||
if (vp->v_type == VDIR)
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
kt = VTOKERN(vp)->kf_kt;
|
||||
|
||||
if (uio->uio_offset != 0)
|
||||
return (EINVAL);
|
||||
|
||||
xlen = min(uio->uio_resid, KSTRING-1);
|
||||
if (error = uiomove(strbuf, xlen, uio))
|
||||
return (error);
|
||||
|
||||
if (uio->uio_resid != 0)
|
||||
return (EIO);
|
||||
|
||||
strbuf[xlen] = '\0';
|
||||
xlen = strlen(strbuf);
|
||||
return (kernfs_xwrite(kt, strbuf, xlen));
|
||||
}
|
||||
|
||||
kernfs_readdir(ap)
|
||||
struct vop_readdir_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
struct ucred *a_cred;
|
||||
int *a_eofflag;
|
||||
u_long *a_cookies;
|
||||
int a_ncookies;
|
||||
} */ *ap;
|
||||
{
|
||||
int error, i;
|
||||
struct uio *uio = ap->a_uio;
|
||||
struct kern_target *kt;
|
||||
struct dirent d;
|
||||
|
||||
if (ap->a_vp->v_type != VDIR)
|
||||
return (ENOTDIR);
|
||||
|
||||
/*
|
||||
* We don't allow exporting kernfs mounts, and currently local
|
||||
* requests do not need cookies.
|
||||
*/
|
||||
if (ap->a_ncookies != NULL)
|
||||
panic("kernfs_readdir: not hungry");
|
||||
|
||||
i = uio->uio_offset / UIO_MX;
|
||||
error = 0;
|
||||
for (kt = &kern_targets[i];
|
||||
uio->uio_resid >= UIO_MX && i < nkern_targets; kt++, i++) {
|
||||
struct dirent *dp = &d;
|
||||
#ifdef KERNFS_DIAGNOSTIC
|
||||
printf("kernfs_readdir: i = %d\n", i);
|
||||
#endif
|
||||
|
||||
if (kt->kt_tag == KTT_DEVICE) {
|
||||
dev_t *dp = kt->kt_data;
|
||||
struct vnode *fvp;
|
||||
|
||||
if (*dp == NODEV || !vfinddev(*dp, kt->kt_vtype, &fvp))
|
||||
continue;
|
||||
}
|
||||
|
||||
bzero((caddr_t)dp, UIO_MX);
|
||||
dp->d_namlen = kt->kt_namlen;
|
||||
bcopy(kt->kt_name, dp->d_name, kt->kt_namlen+1);
|
||||
|
||||
#ifdef KERNFS_DIAGNOSTIC
|
||||
printf("kernfs_readdir: name = %s, len = %d\n",
|
||||
dp->d_name, dp->d_namlen);
|
||||
#endif
|
||||
/*
|
||||
* Fill in the remaining fields
|
||||
*/
|
||||
dp->d_reclen = UIO_MX;
|
||||
dp->d_fileno = i + 3;
|
||||
dp->d_type = kt->kt_type;
|
||||
/*
|
||||
* And ship to userland
|
||||
*/
|
||||
if (error = uiomove((caddr_t)dp, UIO_MX, uio))
|
||||
break;
|
||||
}
|
||||
|
||||
uio->uio_offset = i * UIO_MX;
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
kernfs_inactive(ap)
|
||||
struct vop_inactive_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
|
||||
#ifdef KERNFS_DIAGNOSTIC
|
||||
printf("kernfs_inactive(%x)\n", vp);
|
||||
#endif
|
||||
/*
|
||||
* Clear out the v_type field to avoid
|
||||
* nasty things happening in vgone().
|
||||
*/
|
||||
VOP_UNLOCK(vp, 0, ap->a_p);
|
||||
vp->v_type = VNON;
|
||||
return (0);
|
||||
}
|
||||
|
||||
kernfs_reclaim(ap)
|
||||
struct vop_reclaim_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
|
||||
#ifdef KERNFS_DIAGNOSTIC
|
||||
printf("kernfs_reclaim(%x)\n", vp);
|
||||
#endif
|
||||
if (vp->v_data) {
|
||||
FREE(vp->v_data, M_TEMP);
|
||||
vp->v_data = 0;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return POSIX pathconf information applicable to special devices.
|
||||
*/
|
||||
kernfs_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 */
|
||||
}
|
||||
|
||||
/*
|
||||
* Print out the contents of a /dev/fd vnode.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
kernfs_print(ap)
|
||||
struct vop_print_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
printf("tag VT_KERNFS, kernfs vnode\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*void*/
|
||||
kernfs_vfree(ap)
|
||||
struct vop_vfree_args /* {
|
||||
struct vnode *a_pvp;
|
||||
ino_t a_ino;
|
||||
int a_mode;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* /dev/fd "should never get here" operation
|
||||
*/
|
||||
kernfs_badop()
|
||||
{
|
||||
|
||||
panic("kernfs: bad op");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
* kernfs vnode null operation
|
||||
*/
|
||||
kernfs_nullop()
|
||||
{
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#define kernfs_create ((int (*) __P((struct vop_create_args *)))eopnotsupp)
|
||||
#define kernfs_mknod ((int (*) __P((struct vop_mknod_args *)))eopnotsupp)
|
||||
#define kernfs_close ((int (*) __P((struct vop_close_args *)))nullop)
|
||||
#define kernfs_ioctl ((int (*) __P((struct vop_ioctl_args *)))eopnotsupp)
|
||||
#define kernfs_select ((int (*) __P((struct vop_select_args *)))eopnotsupp)
|
||||
#define kernfs_revoke vop_revoke
|
||||
#define kernfs_mmap ((int (*) __P((struct vop_mmap_args *)))eopnotsupp)
|
||||
#define kernfs_fsync ((int (*) __P((struct vop_fsync_args *)))nullop)
|
||||
#define kernfs_seek ((int (*) __P((struct vop_seek_args *)))nullop)
|
||||
#define kernfs_remove ((int (*) __P((struct vop_remove_args *)))eopnotsupp)
|
||||
#define kernfs_link ((int (*) __P((struct vop_link_args *)))eopnotsupp)
|
||||
#define kernfs_rename ((int (*) __P((struct vop_rename_args *)))eopnotsupp)
|
||||
#define kernfs_mkdir ((int (*) __P((struct vop_mkdir_args *)))eopnotsupp)
|
||||
#define kernfs_rmdir ((int (*) __P((struct vop_rmdir_args *)))eopnotsupp)
|
||||
#define kernfs_symlink ((int (*) __P((struct vop_symlink_args *)))eopnotsupp)
|
||||
#define kernfs_readlink ((int (*) __P((struct vop_readlink_args *)))eopnotsupp)
|
||||
#define kernfs_abortop ((int (*) __P((struct vop_abortop_args *)))nullop)
|
||||
#define kernfs_lock ((int (*) __P((struct vop_lock_args *)))vop_nolock)
|
||||
#define kernfs_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock)
|
||||
#define kernfs_bmap ((int (*) __P((struct vop_bmap_args *)))kernfs_badop)
|
||||
#define kernfs_strategy \
|
||||
((int (*) __P((struct vop_strategy_args *)))kernfs_badop)
|
||||
#define kernfs_islocked \
|
||||
((int (*) __P((struct vop_islocked_args *)))vop_noislocked)
|
||||
#define kernfs_advlock ((int (*) __P((struct vop_advlock_args *)))eopnotsupp)
|
||||
#define kernfs_blkatoff ((int (*) __P((struct vop_blkatoff_args *)))eopnotsupp)
|
||||
#define kernfs_valloc ((int(*) __P(( \
|
||||
struct vnode *pvp, \
|
||||
int mode, \
|
||||
struct ucred *cred, \
|
||||
struct vnode **vpp))) eopnotsupp)
|
||||
#define kernfs_truncate ((int (*) __P((struct vop_truncate_args *)))eopnotsupp)
|
||||
#define kernfs_update ((int (*) __P((struct vop_update_args *)))eopnotsupp)
|
||||
#define kernfs_bwrite ((int (*) __P((struct vop_bwrite_args *)))eopnotsupp)
|
||||
|
||||
int (**kernfs_vnodeop_p)();
|
||||
struct vnodeopv_entry_desc kernfs_vnodeop_entries[] = {
|
||||
{ &vop_default_desc, vn_default_error },
|
||||
{ &vop_lookup_desc, kernfs_lookup }, /* lookup */
|
||||
{ &vop_create_desc, kernfs_create }, /* create */
|
||||
{ &vop_mknod_desc, kernfs_mknod }, /* mknod */
|
||||
{ &vop_open_desc, kernfs_open }, /* open */
|
||||
{ &vop_close_desc, kernfs_close }, /* close */
|
||||
{ &vop_access_desc, kernfs_access }, /* access */
|
||||
{ &vop_getattr_desc, kernfs_getattr }, /* getattr */
|
||||
{ &vop_setattr_desc, kernfs_setattr }, /* setattr */
|
||||
{ &vop_read_desc, kernfs_read }, /* read */
|
||||
{ &vop_write_desc, kernfs_write }, /* write */
|
||||
{ &vop_ioctl_desc, kernfs_ioctl }, /* ioctl */
|
||||
{ &vop_select_desc, kernfs_select }, /* select */
|
||||
{ &vop_revoke_desc, kernfs_revoke }, /* revoke */
|
||||
{ &vop_mmap_desc, kernfs_mmap }, /* mmap */
|
||||
{ &vop_fsync_desc, kernfs_fsync }, /* fsync */
|
||||
{ &vop_seek_desc, kernfs_seek }, /* seek */
|
||||
{ &vop_remove_desc, kernfs_remove }, /* remove */
|
||||
{ &vop_link_desc, kernfs_link }, /* link */
|
||||
{ &vop_rename_desc, kernfs_rename }, /* rename */
|
||||
{ &vop_mkdir_desc, kernfs_mkdir }, /* mkdir */
|
||||
{ &vop_rmdir_desc, kernfs_rmdir }, /* rmdir */
|
||||
{ &vop_symlink_desc, kernfs_symlink }, /* symlink */
|
||||
{ &vop_readdir_desc, kernfs_readdir }, /* readdir */
|
||||
{ &vop_readlink_desc, kernfs_readlink },/* readlink */
|
||||
{ &vop_abortop_desc, kernfs_abortop }, /* abortop */
|
||||
{ &vop_inactive_desc, kernfs_inactive },/* inactive */
|
||||
{ &vop_reclaim_desc, kernfs_reclaim }, /* reclaim */
|
||||
{ &vop_lock_desc, kernfs_lock }, /* lock */
|
||||
{ &vop_unlock_desc, kernfs_unlock }, /* unlock */
|
||||
{ &vop_bmap_desc, kernfs_bmap }, /* bmap */
|
||||
{ &vop_strategy_desc, kernfs_strategy },/* strategy */
|
||||
{ &vop_print_desc, kernfs_print }, /* print */
|
||||
{ &vop_islocked_desc, kernfs_islocked },/* islocked */
|
||||
{ &vop_pathconf_desc, kernfs_pathconf },/* pathconf */
|
||||
{ &vop_advlock_desc, kernfs_advlock }, /* advlock */
|
||||
{ &vop_blkatoff_desc, kernfs_blkatoff },/* blkatoff */
|
||||
{ &vop_valloc_desc, kernfs_valloc }, /* valloc */
|
||||
{ &vop_vfree_desc, kernfs_vfree }, /* vfree */
|
||||
{ &vop_truncate_desc, kernfs_truncate },/* truncate */
|
||||
{ &vop_update_desc, kernfs_update }, /* update */
|
||||
{ &vop_bwrite_desc, kernfs_bwrite }, /* bwrite */
|
||||
{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
|
||||
};
|
||||
struct vnodeopv_desc kernfs_vnodeop_opv_desc =
|
||||
{ &kernfs_vnodeop_p, kernfs_vnodeop_entries };
|
||||
74
sys/miscfs/nullfs/null.h
Normal file
74
sys/miscfs/nullfs/null.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)null.h 8.3 (Berkeley) 8/20/94
|
||||
*
|
||||
* $Id: lofs.h,v 1.8 1992/05/30 10:05:43 jsp Exp jsp $
|
||||
*/
|
||||
|
||||
struct null_args {
|
||||
char *target; /* Target of loopback */
|
||||
};
|
||||
|
||||
struct null_mount {
|
||||
struct mount *nullm_vfs;
|
||||
struct vnode *nullm_rootvp; /* Reference to root null_node */
|
||||
};
|
||||
|
||||
#ifdef KERNEL
|
||||
/*
|
||||
* A cache of vnode references
|
||||
*/
|
||||
struct null_node {
|
||||
LIST_ENTRY(null_node) null_hash; /* Hash list */
|
||||
struct vnode *null_lowervp; /* VREFed once */
|
||||
struct vnode *null_vnode; /* Back pointer */
|
||||
};
|
||||
|
||||
extern int null_node_create __P((struct mount *mp, struct vnode *target, struct vnode **vpp));
|
||||
|
||||
#define MOUNTTONULLMOUNT(mp) ((struct null_mount *)((mp)->mnt_data))
|
||||
#define VTONULL(vp) ((struct null_node *)(vp)->v_data)
|
||||
#define NULLTOV(xp) ((xp)->null_vnode)
|
||||
#ifdef NULLFS_DIAGNOSTIC
|
||||
extern struct vnode *null_checkvp __P((struct vnode *vp, char *fil, int lno));
|
||||
#define NULLVPTOLOWERVP(vp) null_checkvp((vp), __FILE__, __LINE__)
|
||||
#else
|
||||
#define NULLVPTOLOWERVP(vp) (VTONULL(vp)->null_lowervp)
|
||||
#endif
|
||||
|
||||
extern int (**null_vnodeop_p)();
|
||||
extern struct vfsops null_vfsops;
|
||||
#endif /* KERNEL */
|
||||
275
sys/miscfs/nullfs/null_subr.c
Normal file
275
sys/miscfs/nullfs/null_subr.c
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)null_subr.c 8.7 (Berkeley) 5/14/95
|
||||
*
|
||||
* $Id: lofs_subr.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <miscfs/nullfs/null.h>
|
||||
|
||||
#define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */
|
||||
#define NNULLNODECACHE 16
|
||||
|
||||
/*
|
||||
* Null layer cache:
|
||||
* Each cache entry holds a reference to the lower vnode
|
||||
* along with a pointer to the alias vnode. When an
|
||||
* entry is added the lower vnode is VREF'd. When the
|
||||
* alias is removed the lower vnode is vrele'd.
|
||||
*/
|
||||
|
||||
#define NULL_NHASH(vp) \
|
||||
(&null_node_hashtbl[(((u_long)vp)>>LOG2_SIZEVNODE) & null_node_hash])
|
||||
LIST_HEAD(null_node_hashhead, null_node) *null_node_hashtbl;
|
||||
u_long null_node_hash;
|
||||
|
||||
/*
|
||||
* Initialise cache headers
|
||||
*/
|
||||
nullfs_init()
|
||||
{
|
||||
|
||||
#ifdef NULLFS_DIAGNOSTIC
|
||||
printf("nullfs_init\n"); /* printed during system boot */
|
||||
#endif
|
||||
null_node_hashtbl = hashinit(NNULLNODECACHE, M_CACHE, &null_node_hash);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a VREF'ed alias for lower vnode if already exists, else 0.
|
||||
*/
|
||||
static struct vnode *
|
||||
null_node_find(mp, lowervp)
|
||||
struct mount *mp;
|
||||
struct vnode *lowervp;
|
||||
{
|
||||
struct proc *p = curproc; /* XXX */
|
||||
struct null_node_hashhead *hd;
|
||||
struct null_node *a;
|
||||
struct vnode *vp;
|
||||
|
||||
/*
|
||||
* Find hash base, and then search the (two-way) linked
|
||||
* list looking for a null_node structure which is referencing
|
||||
* the lower vnode. If found, the increment the null_node
|
||||
* reference count (but NOT the lower vnode's VREF counter).
|
||||
*/
|
||||
hd = NULL_NHASH(lowervp);
|
||||
loop:
|
||||
for (a = hd->lh_first; a != 0; a = a->null_hash.le_next) {
|
||||
if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) {
|
||||
vp = NULLTOV(a);
|
||||
/*
|
||||
* We need vget for the VXLOCK
|
||||
* stuff, but we don't want to lock
|
||||
* the lower node.
|
||||
*/
|
||||
if (vget(vp, 0, p)) {
|
||||
printf ("null_node_find: vget failed.\n");
|
||||
goto loop;
|
||||
};
|
||||
return (vp);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Make a new null_node node.
|
||||
* Vp is the alias vnode, lofsvp is the lower vnode.
|
||||
* Maintain a reference to (lowervp).
|
||||
*/
|
||||
static int
|
||||
null_node_alloc(mp, lowervp, vpp)
|
||||
struct mount *mp;
|
||||
struct vnode *lowervp;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
struct null_node_hashhead *hd;
|
||||
struct null_node *xp;
|
||||
struct vnode *othervp, *vp;
|
||||
int error;
|
||||
|
||||
if (error = getnewvnode(VT_NULL, mp, null_vnodeop_p, vpp))
|
||||
return (error);
|
||||
vp = *vpp;
|
||||
|
||||
MALLOC(xp, struct null_node *, sizeof(struct null_node), M_TEMP, M_WAITOK);
|
||||
vp->v_type = lowervp->v_type;
|
||||
xp->null_vnode = vp;
|
||||
vp->v_data = xp;
|
||||
xp->null_lowervp = lowervp;
|
||||
/*
|
||||
* Before we insert our new node onto the hash chains,
|
||||
* check to see if someone else has beaten us to it.
|
||||
* (We could have slept in MALLOC.)
|
||||
*/
|
||||
if (othervp = null_node_find(lowervp)) {
|
||||
FREE(xp, M_TEMP);
|
||||
vp->v_type = VBAD; /* node is discarded */
|
||||
vp->v_usecount = 0; /* XXX */
|
||||
*vpp = othervp;
|
||||
return 0;
|
||||
};
|
||||
VREF(lowervp); /* Extra VREF will be vrele'd in null_node_create */
|
||||
hd = NULL_NHASH(lowervp);
|
||||
LIST_INSERT_HEAD(hd, xp, null_hash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Try to find an existing null_node vnode refering
|
||||
* to it, otherwise make a new null_node vnode which
|
||||
* contains a reference to the lower vnode.
|
||||
*/
|
||||
int
|
||||
null_node_create(mp, lowervp, newvpp)
|
||||
struct mount *mp;
|
||||
struct vnode *lowervp;
|
||||
struct vnode **newvpp;
|
||||
{
|
||||
struct vnode *aliasvp;
|
||||
|
||||
if (aliasvp = null_node_find(mp, lowervp)) {
|
||||
/*
|
||||
* null_node_find has taken another reference
|
||||
* to the alias vnode.
|
||||
*/
|
||||
#ifdef NULLFS_DIAGNOSTIC
|
||||
vprint("null_node_create: exists", NULLTOV(ap));
|
||||
#endif
|
||||
/* VREF(aliasvp); --- done in null_node_find */
|
||||
} else {
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Get new vnode.
|
||||
*/
|
||||
#ifdef NULLFS_DIAGNOSTIC
|
||||
printf("null_node_create: create new alias vnode\n");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Make new vnode reference the null_node.
|
||||
*/
|
||||
if (error = null_node_alloc(mp, lowervp, &aliasvp))
|
||||
return error;
|
||||
|
||||
/*
|
||||
* aliasvp is already VREF'd by getnewvnode()
|
||||
*/
|
||||
}
|
||||
|
||||
vrele(lowervp);
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
if (lowervp->v_usecount < 1) {
|
||||
/* Should never happen... */
|
||||
vprint ("null_node_create: alias ", aliasvp);
|
||||
vprint ("null_node_create: lower ", lowervp);
|
||||
panic ("null_node_create: lower has 0 usecount.");
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef NULLFS_DIAGNOSTIC
|
||||
vprint("null_node_create: alias", aliasvp);
|
||||
vprint("null_node_create: lower", lowervp);
|
||||
#endif
|
||||
|
||||
*newvpp = aliasvp;
|
||||
return (0);
|
||||
}
|
||||
#ifdef NULLFS_DIAGNOSTIC
|
||||
struct vnode *
|
||||
null_checkvp(vp, fil, lno)
|
||||
struct vnode *vp;
|
||||
char *fil;
|
||||
int lno;
|
||||
{
|
||||
struct null_node *a = VTONULL(vp);
|
||||
#ifdef notyet
|
||||
/*
|
||||
* Can't do this check because vop_reclaim runs
|
||||
* with a funny vop vector.
|
||||
*/
|
||||
if (vp->v_op != null_vnodeop_p) {
|
||||
printf ("null_checkvp: on non-null-node\n");
|
||||
while (null_checkvp_barrier) /*WAIT*/ ;
|
||||
panic("null_checkvp");
|
||||
};
|
||||
#endif
|
||||
if (a->null_lowervp == NULL) {
|
||||
/* Should never happen */
|
||||
int i; u_long *p;
|
||||
printf("vp = %x, ZERO ptr\n", vp);
|
||||
for (p = (u_long *) a, i = 0; i < 8; i++)
|
||||
printf(" %x", p[i]);
|
||||
printf("\n");
|
||||
/* wait for debugger */
|
||||
while (null_checkvp_barrier) /*WAIT*/ ;
|
||||
panic("null_checkvp");
|
||||
}
|
||||
if (a->null_lowervp->v_usecount < 1) {
|
||||
int i; u_long *p;
|
||||
printf("vp = %x, unref'ed lowervp\n", vp);
|
||||
for (p = (u_long *) a, i = 0; i < 8; i++)
|
||||
printf(" %x", p[i]);
|
||||
printf("\n");
|
||||
/* wait for debugger */
|
||||
while (null_checkvp_barrier) /*WAIT*/ ;
|
||||
panic ("null with unref'ed lowervp");
|
||||
};
|
||||
#ifdef notyet
|
||||
printf("null %x/%d -> %x/%d [%s, %d]\n",
|
||||
NULLTOV(a), NULLTOV(a)->v_usecount,
|
||||
a->null_lowervp, a->null_lowervp->v_usecount,
|
||||
fil, lno);
|
||||
#endif
|
||||
return a->null_lowervp;
|
||||
}
|
||||
#endif
|
||||
367
sys/miscfs/nullfs/null_vfsops.c
Normal file
367
sys/miscfs/nullfs/null_vfsops.c
Normal file
|
|
@ -0,0 +1,367 @@
|
|||
/*
|
||||
* Copyright (c) 1992, 1993, 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)null_vfsops.c 8.7 (Berkeley) 5/14/95
|
||||
*
|
||||
* @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92
|
||||
* $Id: lofs_vfsops.c,v 1.9 1992/05/30 10:26:24 jsp Exp jsp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* Null Layer
|
||||
* (See null_vnops.c for a description of what this does.)
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <miscfs/nullfs/null.h>
|
||||
|
||||
/*
|
||||
* Mount null layer
|
||||
*/
|
||||
int
|
||||
nullfs_mount(mp, path, data, ndp, p)
|
||||
struct mount *mp;
|
||||
char *path;
|
||||
caddr_t data;
|
||||
struct nameidata *ndp;
|
||||
struct proc *p;
|
||||
{
|
||||
int error = 0;
|
||||
struct null_args args;
|
||||
struct vnode *lowerrootvp, *vp;
|
||||
struct vnode *nullm_rootvp;
|
||||
struct null_mount *xmp;
|
||||
u_int size;
|
||||
|
||||
#ifdef NULLFS_DIAGNOSTIC
|
||||
printf("nullfs_mount(mp = %x)\n", mp);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Update is a no-op
|
||||
*/
|
||||
if (mp->mnt_flag & MNT_UPDATE) {
|
||||
return (EOPNOTSUPP);
|
||||
/* return VFS_MOUNT(MOUNTTONULLMOUNT(mp)->nullm_vfs, path, data, ndp, p);*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Get argument
|
||||
*/
|
||||
if (error = copyin(data, (caddr_t)&args, sizeof(struct null_args)))
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Find lower node
|
||||
*/
|
||||
NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF,
|
||||
UIO_USERSPACE, args.target, p);
|
||||
if (error = namei(ndp))
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Sanity check on lower vnode
|
||||
*/
|
||||
lowerrootvp = ndp->ni_vp;
|
||||
|
||||
vrele(ndp->ni_dvp);
|
||||
ndp->ni_dvp = NULL;
|
||||
|
||||
xmp = (struct null_mount *) malloc(sizeof(struct null_mount),
|
||||
M_UFSMNT, M_WAITOK); /* XXX */
|
||||
|
||||
/*
|
||||
* Save reference to underlying FS
|
||||
*/
|
||||
xmp->nullm_vfs = lowerrootvp->v_mount;
|
||||
|
||||
/*
|
||||
* Save reference. Each mount also holds
|
||||
* a reference on the root vnode.
|
||||
*/
|
||||
error = null_node_create(mp, lowerrootvp, &vp);
|
||||
/*
|
||||
* Unlock the node (either the lower or the alias)
|
||||
*/
|
||||
VOP_UNLOCK(vp, 0, p);
|
||||
/*
|
||||
* Make sure the node alias worked
|
||||
*/
|
||||
if (error) {
|
||||
vrele(lowerrootvp);
|
||||
free(xmp, M_UFSMNT); /* XXX */
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Keep a held reference to the root vnode.
|
||||
* It is vrele'd in nullfs_unmount.
|
||||
*/
|
||||
nullm_rootvp = vp;
|
||||
nullm_rootvp->v_flag |= VROOT;
|
||||
xmp->nullm_rootvp = nullm_rootvp;
|
||||
if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL)
|
||||
mp->mnt_flag |= MNT_LOCAL;
|
||||
mp->mnt_data = (qaddr_t) xmp;
|
||||
vfs_getnewfsid(mp);
|
||||
|
||||
(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
|
||||
bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
|
||||
(void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
|
||||
&size);
|
||||
bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
|
||||
#ifdef NULLFS_DIAGNOSTIC
|
||||
printf("nullfs_mount: lower %s, alias at %s\n",
|
||||
mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* VFS start. Nothing needed here - the start routine
|
||||
* on the underlying filesystem will have been called
|
||||
* when that filesystem was mounted.
|
||||
*/
|
||||
int
|
||||
nullfs_start(mp, flags, p)
|
||||
struct mount *mp;
|
||||
int flags;
|
||||
struct proc *p;
|
||||
{
|
||||
return (0);
|
||||
/* return VFS_START(MOUNTTONULLMOUNT(mp)->nullm_vfs, flags, p); */
|
||||
}
|
||||
|
||||
/*
|
||||
* Free reference to null layer
|
||||
*/
|
||||
int
|
||||
nullfs_unmount(mp, mntflags, p)
|
||||
struct mount *mp;
|
||||
int mntflags;
|
||||
struct proc *p;
|
||||
{
|
||||
struct vnode *nullm_rootvp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
|
||||
int error;
|
||||
int flags = 0;
|
||||
|
||||
#ifdef NULLFS_DIAGNOSTIC
|
||||
printf("nullfs_unmount(mp = %x)\n", mp);
|
||||
#endif
|
||||
|
||||
if (mntflags & MNT_FORCE)
|
||||
flags |= FORCECLOSE;
|
||||
|
||||
/*
|
||||
* Clear out buffer cache. I don't think we
|
||||
* ever get anything cached at this level at the
|
||||
* moment, but who knows...
|
||||
*/
|
||||
#if 0
|
||||
mntflushbuf(mp, 0);
|
||||
if (mntinvalbuf(mp, 1))
|
||||
return (EBUSY);
|
||||
#endif
|
||||
if (nullm_rootvp->v_usecount > 1)
|
||||
return (EBUSY);
|
||||
if (error = vflush(mp, nullm_rootvp, flags))
|
||||
return (error);
|
||||
|
||||
#ifdef NULLFS_DIAGNOSTIC
|
||||
vprint("alias root of lower", nullm_rootvp);
|
||||
#endif
|
||||
/*
|
||||
* Release reference on underlying root vnode
|
||||
*/
|
||||
vrele(nullm_rootvp);
|
||||
/*
|
||||
* And blow it away for future re-use
|
||||
*/
|
||||
vgone(nullm_rootvp);
|
||||
/*
|
||||
* Finally, throw away the null_mount structure
|
||||
*/
|
||||
free(mp->mnt_data, M_UFSMNT); /* XXX */
|
||||
mp->mnt_data = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nullfs_root(mp, vpp)
|
||||
struct mount *mp;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
struct proc *p = curproc; /* XXX */
|
||||
struct vnode *vp;
|
||||
|
||||
#ifdef NULLFS_DIAGNOSTIC
|
||||
printf("nullfs_root(mp = %x, vp = %x->%x)\n", mp,
|
||||
MOUNTTONULLMOUNT(mp)->nullm_rootvp,
|
||||
NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)
|
||||
);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Return locked reference to root.
|
||||
*/
|
||||
vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
|
||||
VREF(vp);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
*vpp = vp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nullfs_quotactl(mp, cmd, uid, arg, p)
|
||||
struct mount *mp;
|
||||
int cmd;
|
||||
uid_t uid;
|
||||
caddr_t arg;
|
||||
struct proc *p;
|
||||
{
|
||||
return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, p);
|
||||
}
|
||||
|
||||
int
|
||||
nullfs_statfs(mp, sbp, p)
|
||||
struct mount *mp;
|
||||
struct statfs *sbp;
|
||||
struct proc *p;
|
||||
{
|
||||
int error;
|
||||
struct statfs mstat;
|
||||
|
||||
#ifdef NULLFS_DIAGNOSTIC
|
||||
printf("nullfs_statfs(mp = %x, vp = %x->%x)\n", mp,
|
||||
MOUNTTONULLMOUNT(mp)->nullm_rootvp,
|
||||
NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)
|
||||
);
|
||||
#endif
|
||||
|
||||
bzero(&mstat, sizeof(mstat));
|
||||
|
||||
error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, p);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* now copy across the "interesting" information and fake the rest */
|
||||
sbp->f_type = mstat.f_type;
|
||||
sbp->f_flags = mstat.f_flags;
|
||||
sbp->f_bsize = mstat.f_bsize;
|
||||
sbp->f_iosize = mstat.f_iosize;
|
||||
sbp->f_blocks = mstat.f_blocks;
|
||||
sbp->f_bfree = mstat.f_bfree;
|
||||
sbp->f_bavail = mstat.f_bavail;
|
||||
sbp->f_files = mstat.f_files;
|
||||
sbp->f_ffree = mstat.f_ffree;
|
||||
if (sbp != &mp->mnt_stat) {
|
||||
bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
|
||||
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
|
||||
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
nullfs_sync(mp, waitfor, cred, p)
|
||||
struct mount *mp;
|
||||
int waitfor;
|
||||
struct ucred *cred;
|
||||
struct proc *p;
|
||||
{
|
||||
/*
|
||||
* XXX - Assumes no data cached at null layer.
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
nullfs_vget(mp, ino, vpp)
|
||||
struct mount *mp;
|
||||
ino_t ino;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
|
||||
return VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, vpp);
|
||||
}
|
||||
|
||||
int
|
||||
nullfs_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp)
|
||||
struct mount *mp;
|
||||
struct fid *fidp;
|
||||
struct mbuf *nam;
|
||||
struct vnode **vpp;
|
||||
int *exflagsp;
|
||||
struct ucred**credanonp;
|
||||
{
|
||||
|
||||
return VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, nam, vpp, exflagsp,credanonp);
|
||||
}
|
||||
|
||||
int
|
||||
nullfs_vptofh(vp, fhp)
|
||||
struct vnode *vp;
|
||||
struct fid *fhp;
|
||||
{
|
||||
return VFS_VPTOFH(NULLVPTOLOWERVP(vp), fhp);
|
||||
}
|
||||
|
||||
int nullfs_init __P((struct vfsconf *));
|
||||
|
||||
#define nullfs_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \
|
||||
size_t, struct proc *)))eopnotsupp)
|
||||
|
||||
struct vfsops null_vfsops = {
|
||||
nullfs_mount,
|
||||
nullfs_start,
|
||||
nullfs_unmount,
|
||||
nullfs_root,
|
||||
nullfs_quotactl,
|
||||
nullfs_statfs,
|
||||
nullfs_sync,
|
||||
nullfs_vget,
|
||||
nullfs_fhtovp,
|
||||
nullfs_vptofh,
|
||||
nullfs_init,
|
||||
nullfs_sysctl,
|
||||
};
|
||||
645
sys/miscfs/nullfs/null_vnops.c
Normal file
645
sys/miscfs/nullfs/null_vnops.c
Normal file
|
|
@ -0,0 +1,645 @@
|
|||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* John Heidemann of the UCLA Ficus project.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)null_vnops.c 8.6 (Berkeley) 5/27/95
|
||||
*
|
||||
* Ancestors:
|
||||
* @(#)lofs_vnops.c 1.2 (Berkeley) 6/18/92
|
||||
* $Id: lofs_vnops.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp $
|
||||
* ...and...
|
||||
* @(#)null_vnodeops.c 1.20 92/07/07 UCLA Ficus project
|
||||
*/
|
||||
|
||||
/*
|
||||
* Null Layer
|
||||
*
|
||||
* (See mount_null(8) for more information.)
|
||||
*
|
||||
* The null layer duplicates a portion of the file system
|
||||
* name space under a new name. In this respect, it is
|
||||
* similar to the loopback file system. It differs from
|
||||
* the loopback fs in two respects: it is implemented using
|
||||
* a stackable layers techniques, and it's "null-node"s stack above
|
||||
* all lower-layer vnodes, not just over directory vnodes.
|
||||
*
|
||||
* The null layer has two purposes. First, it serves as a demonstration
|
||||
* of layering by proving a layer which does nothing. (It actually
|
||||
* does everything the loopback file system does, which is slightly
|
||||
* more than nothing.) Second, the null layer can serve as a prototype
|
||||
* layer. Since it provides all necessary layer framework,
|
||||
* new file system layers can be created very easily be starting
|
||||
* with a null layer.
|
||||
*
|
||||
* The remainder of this man page examines the null layer as a basis
|
||||
* for constructing new layers.
|
||||
*
|
||||
*
|
||||
* INSTANTIATING NEW NULL LAYERS
|
||||
*
|
||||
* New null layers are created with mount_null(8).
|
||||
* Mount_null(8) takes two arguments, the pathname
|
||||
* of the lower vfs (target-pn) and the pathname where the null
|
||||
* layer will appear in the namespace (alias-pn). After
|
||||
* the null layer is put into place, the contents
|
||||
* of target-pn subtree will be aliased under alias-pn.
|
||||
*
|
||||
*
|
||||
* OPERATION OF A NULL LAYER
|
||||
*
|
||||
* The null layer is the minimum file system layer,
|
||||
* simply bypassing all possible operations to the lower layer
|
||||
* for processing there. The majority of its activity centers
|
||||
* on the bypass routine, though which nearly all vnode operations
|
||||
* pass.
|
||||
*
|
||||
* The bypass routine accepts arbitrary vnode operations for
|
||||
* handling by the lower layer. It begins by examing vnode
|
||||
* operation arguments and replacing any null-nodes by their
|
||||
* lower-layer equivlants. It then invokes the operation
|
||||
* on the lower layer. Finally, it replaces the null-nodes
|
||||
* in the arguments and, if a vnode is return by the operation,
|
||||
* stacks a null-node on top of the returned vnode.
|
||||
*
|
||||
* Although bypass handles most operations, vop_getattr, vop_lock,
|
||||
* vop_unlock, vop_inactive, vop_reclaim, and vop_print are not
|
||||
* bypassed. Vop_getattr must change the fsid being returned.
|
||||
* Vop_lock and vop_unlock must handle any locking for the
|
||||
* current vnode as well as pass the lock request down.
|
||||
* Vop_inactive and vop_reclaim are not bypassed so that
|
||||
* they can handle freeing null-layer specific data. Vop_print
|
||||
* is not bypassed to avoid excessive debugging information.
|
||||
* Also, certain vnode operations change the locking state within
|
||||
* the operation (create, mknod, remove, link, rename, mkdir, rmdir,
|
||||
* and symlink). Ideally these operations should not change the
|
||||
* lock state, but should be changed to let the caller of the
|
||||
* function unlock them. Otherwise all intermediate vnode layers
|
||||
* (such as union, umapfs, etc) must catch these functions to do
|
||||
* the necessary locking at their layer.
|
||||
*
|
||||
*
|
||||
* INSTANTIATING VNODE STACKS
|
||||
*
|
||||
* Mounting associates the null layer with a lower layer,
|
||||
* effect stacking two VFSes. Vnode stacks are instead
|
||||
* created on demand as files are accessed.
|
||||
*
|
||||
* The initial mount creates a single vnode stack for the
|
||||
* root of the new null layer. All other vnode stacks
|
||||
* are created as a result of vnode operations on
|
||||
* this or other null vnode stacks.
|
||||
*
|
||||
* New vnode stacks come into existance as a result of
|
||||
* an operation which returns a vnode.
|
||||
* The bypass routine stacks a null-node above the new
|
||||
* vnode before returning it to the caller.
|
||||
*
|
||||
* For example, imagine mounting a null layer with
|
||||
* "mount_null /usr/include /dev/layer/null".
|
||||
* Changing directory to /dev/layer/null will assign
|
||||
* the root null-node (which was created when the null layer was mounted).
|
||||
* Now consider opening "sys". A vop_lookup would be
|
||||
* done on the root null-node. This operation would bypass through
|
||||
* to the lower layer which would return a vnode representing
|
||||
* the UFS "sys". Null_bypass then builds a null-node
|
||||
* aliasing the UFS "sys" and returns this to the caller.
|
||||
* Later operations on the null-node "sys" will repeat this
|
||||
* process when constructing other vnode stacks.
|
||||
*
|
||||
*
|
||||
* CREATING OTHER FILE SYSTEM LAYERS
|
||||
*
|
||||
* One of the easiest ways to construct new file system layers is to make
|
||||
* a copy of the null layer, rename all files and variables, and
|
||||
* then begin modifing the copy. Sed can be used to easily rename
|
||||
* all variables.
|
||||
*
|
||||
* The umap layer is an example of a layer descended from the
|
||||
* null layer.
|
||||
*
|
||||
*
|
||||
* INVOKING OPERATIONS ON LOWER LAYERS
|
||||
*
|
||||
* There are two techniques to invoke operations on a lower layer
|
||||
* when the operation cannot be completely bypassed. Each method
|
||||
* is appropriate in different situations. In both cases,
|
||||
* it is the responsibility of the aliasing layer to make
|
||||
* the operation arguments "correct" for the lower layer
|
||||
* by mapping an vnode arguments to the lower layer.
|
||||
*
|
||||
* The first approach is to call the aliasing layer's bypass routine.
|
||||
* This method is most suitable when you wish to invoke the operation
|
||||
* currently being hanldled on the lower layer. It has the advantage
|
||||
* that the bypass routine already must do argument mapping.
|
||||
* An example of this is null_getattrs in the null layer.
|
||||
*
|
||||
* A second approach is to directly invoked vnode operations on
|
||||
* the lower layer with the VOP_OPERATIONNAME interface.
|
||||
* The advantage of this method is that it is easy to invoke
|
||||
* arbitrary operations on the lower layer. The disadvantage
|
||||
* is that vnodes arguments must be manualy mapped.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/buf.h>
|
||||
#include <miscfs/nullfs/null.h>
|
||||
|
||||
|
||||
int null_bug_bypass = 0; /* for debugging: enables bypass printf'ing */
|
||||
|
||||
/*
|
||||
* This is the 10-Apr-92 bypass routine.
|
||||
* This version has been optimized for speed, throwing away some
|
||||
* safety checks. It should still always work, but it's not as
|
||||
* robust to programmer errors.
|
||||
* Define SAFETY to include some error checking code.
|
||||
*
|
||||
* In general, we map all vnodes going down and unmap them on the way back.
|
||||
* As an exception to this, vnodes can be marked "unmapped" by setting
|
||||
* the Nth bit in operation's vdesc_flags.
|
||||
*
|
||||
* Also, some BSD vnode operations have the side effect of vrele'ing
|
||||
* their arguments. With stacking, the reference counts are held
|
||||
* by the upper node, not the lower one, so we must handle these
|
||||
* side-effects here. This is not of concern in Sun-derived systems
|
||||
* since there are no such side-effects.
|
||||
*
|
||||
* This makes the following assumptions:
|
||||
* - only one returned vpp
|
||||
* - no INOUT vpp's (Sun's vop_open has one of these)
|
||||
* - the vnode operation vector of the first vnode should be used
|
||||
* to determine what implementation of the op should be invoked
|
||||
* - all mapped vnodes are of our vnode-type (NEEDSWORK:
|
||||
* problems on rmdir'ing mount points and renaming?)
|
||||
*/
|
||||
int
|
||||
null_bypass(ap)
|
||||
struct vop_generic_args /* {
|
||||
struct vnodeop_desc *a_desc;
|
||||
<other random data follows, presumably>
|
||||
} */ *ap;
|
||||
{
|
||||
extern int (**null_vnodeop_p)(); /* not extern, really "forward" */
|
||||
register struct vnode **this_vp_p;
|
||||
int error;
|
||||
struct vnode *old_vps[VDESC_MAX_VPS];
|
||||
struct vnode **vps_p[VDESC_MAX_VPS];
|
||||
struct vnode ***vppp;
|
||||
struct vnodeop_desc *descp = ap->a_desc;
|
||||
int reles, i;
|
||||
|
||||
if (null_bug_bypass)
|
||||
printf ("null_bypass: %s\n", descp->vdesc_name);
|
||||
|
||||
#ifdef SAFETY
|
||||
/*
|
||||
* We require at least one vp.
|
||||
*/
|
||||
if (descp->vdesc_vp_offsets == NULL ||
|
||||
descp->vdesc_vp_offsets[0] == VDESC_NO_OFFSET)
|
||||
panic ("null_bypass: no vp's in map.\n");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Map the vnodes going in.
|
||||
* Later, we'll invoke the operation based on
|
||||
* the first mapped vnode's operation vector.
|
||||
*/
|
||||
reles = descp->vdesc_flags;
|
||||
for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) {
|
||||
if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET)
|
||||
break; /* bail out at end of list */
|
||||
vps_p[i] = this_vp_p =
|
||||
VOPARG_OFFSETTO(struct vnode**,descp->vdesc_vp_offsets[i],ap);
|
||||
/*
|
||||
* We're not guaranteed that any but the first vnode
|
||||
* are of our type. Check for and don't map any
|
||||
* that aren't. (We must always map first vp or vclean fails.)
|
||||
*/
|
||||
if (i && (*this_vp_p == NULL ||
|
||||
(*this_vp_p)->v_op != null_vnodeop_p)) {
|
||||
old_vps[i] = NULL;
|
||||
} else {
|
||||
old_vps[i] = *this_vp_p;
|
||||
*(vps_p[i]) = NULLVPTOLOWERVP(*this_vp_p);
|
||||
/*
|
||||
* XXX - Several operations have the side effect
|
||||
* of vrele'ing their vp's. We must account for
|
||||
* that. (This should go away in the future.)
|
||||
*/
|
||||
if (reles & 1)
|
||||
VREF(*this_vp_p);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Call the operation on the lower layer
|
||||
* with the modified argument structure.
|
||||
*/
|
||||
error = VCALL(*(vps_p[0]), descp->vdesc_offset, ap);
|
||||
|
||||
/*
|
||||
* Maintain the illusion of call-by-value
|
||||
* by restoring vnodes in the argument structure
|
||||
* to their original value.
|
||||
*/
|
||||
reles = descp->vdesc_flags;
|
||||
for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) {
|
||||
if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET)
|
||||
break; /* bail out at end of list */
|
||||
if (old_vps[i]) {
|
||||
*(vps_p[i]) = old_vps[i];
|
||||
if (reles & 1)
|
||||
vrele(*(vps_p[i]));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Map the possible out-going vpp
|
||||
* (Assumes that the lower layer always returns
|
||||
* a VREF'ed vpp unless it gets an error.)
|
||||
*/
|
||||
if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET &&
|
||||
!(descp->vdesc_flags & VDESC_NOMAP_VPP) &&
|
||||
!error) {
|
||||
/*
|
||||
* XXX - even though some ops have vpp returned vp's,
|
||||
* several ops actually vrele this before returning.
|
||||
* We must avoid these ops.
|
||||
* (This should go away when these ops are regularized.)
|
||||
*/
|
||||
if (descp->vdesc_flags & VDESC_VPP_WILLRELE)
|
||||
goto out;
|
||||
vppp = VOPARG_OFFSETTO(struct vnode***,
|
||||
descp->vdesc_vpp_offset,ap);
|
||||
error = null_node_create(old_vps[0]->v_mount, **vppp, *vppp);
|
||||
}
|
||||
|
||||
out:
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to carry on the locking protocol on the null layer vnodes
|
||||
* as we progress through the tree. We also have to enforce read-only
|
||||
* if this layer is mounted read-only.
|
||||
*/
|
||||
null_lookup(ap)
|
||||
struct vop_lookup_args /* {
|
||||
struct vnode * a_dvp;
|
||||
struct vnode ** a_vpp;
|
||||
struct componentname * a_cnp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct componentname *cnp = ap->a_cnp;
|
||||
struct proc *p = cnp->cn_proc;
|
||||
int flags = cnp->cn_flags;
|
||||
struct vop_lock_args lockargs;
|
||||
struct vop_unlock_args unlockargs;
|
||||
struct vnode *dvp, *vp;
|
||||
int error;
|
||||
|
||||
if ((flags & ISLASTCN) && (ap->a_dvp->v_mount->mnt_flag & MNT_RDONLY) &&
|
||||
(cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
|
||||
return (EROFS);
|
||||
error = null_bypass(ap);
|
||||
if (error == EJUSTRETURN && (flags & ISLASTCN) &&
|
||||
(ap->a_dvp->v_mount->mnt_flag & MNT_RDONLY) &&
|
||||
(cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME))
|
||||
error = EROFS;
|
||||
/*
|
||||
* We must do the same locking and unlocking at this layer as
|
||||
* is done in the layers below us. We could figure this out
|
||||
* based on the error return and the LASTCN, LOCKPARENT, and
|
||||
* LOCKLEAF flags. However, it is more expidient to just find
|
||||
* out the state of the lower level vnodes and set ours to the
|
||||
* same state.
|
||||
*/
|
||||
dvp = ap->a_dvp;
|
||||
vp = *ap->a_vpp;
|
||||
if (dvp == vp)
|
||||
return (error);
|
||||
if (!VOP_ISLOCKED(dvp)) {
|
||||
unlockargs.a_vp = dvp;
|
||||
unlockargs.a_flags = 0;
|
||||
unlockargs.a_p = p;
|
||||
vop_nounlock(&unlockargs);
|
||||
}
|
||||
if (vp != NULL && VOP_ISLOCKED(vp)) {
|
||||
lockargs.a_vp = vp;
|
||||
lockargs.a_flags = LK_SHARED;
|
||||
lockargs.a_p = p;
|
||||
vop_nolock(&lockargs);
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Setattr call. Disallow write attempts if the layer is mounted read-only.
|
||||
*/
|
||||
int
|
||||
null_setattr(ap)
|
||||
struct vop_setattr_args /* {
|
||||
struct vnodeop_desc *a_desc;
|
||||
struct vnode *a_vp;
|
||||
struct vattr *a_vap;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct vattr *vap = ap->a_vap;
|
||||
|
||||
if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
|
||||
vap->va_gid != (gid_t)VNOVAL || vap->va_atime.ts_sec != VNOVAL ||
|
||||
vap->va_mtime.ts_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) &&
|
||||
(vp->v_mount->mnt_flag & MNT_RDONLY))
|
||||
return (EROFS);
|
||||
if (vap->va_size != VNOVAL) {
|
||||
switch (vp->v_type) {
|
||||
case VDIR:
|
||||
return (EISDIR);
|
||||
case VCHR:
|
||||
case VBLK:
|
||||
case VSOCK:
|
||||
case VFIFO:
|
||||
return (0);
|
||||
case VREG:
|
||||
case VLNK:
|
||||
default:
|
||||
/*
|
||||
* Disallow write attempts if the filesystem is
|
||||
* mounted read-only.
|
||||
*/
|
||||
if (vp->v_mount->mnt_flag & MNT_RDONLY)
|
||||
return (EROFS);
|
||||
}
|
||||
}
|
||||
return (null_bypass(ap));
|
||||
}
|
||||
|
||||
/*
|
||||
* We handle getattr only to change the fsid.
|
||||
*/
|
||||
int
|
||||
null_getattr(ap)
|
||||
struct vop_getattr_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct vattr *a_vap;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
int error;
|
||||
|
||||
if (error = null_bypass(ap))
|
||||
return (error);
|
||||
/* Requires that arguments be restored. */
|
||||
ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
null_access(ap)
|
||||
struct vop_access_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_mode;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
mode_t mode = ap->a_mode;
|
||||
|
||||
/*
|
||||
* Disallow write attempts on read-only layers;
|
||||
* unless the file is a socket, fifo, or a block or
|
||||
* character device resident on the file system.
|
||||
*/
|
||||
if (mode & VWRITE) {
|
||||
switch (vp->v_type) {
|
||||
case VDIR:
|
||||
case VLNK:
|
||||
case VREG:
|
||||
if (vp->v_mount->mnt_flag & MNT_RDONLY)
|
||||
return (EROFS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (null_bypass(ap));
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to process our own vnode lock and then clear the
|
||||
* interlock flag as it applies only to our vnode, not the
|
||||
* vnodes below us on the stack.
|
||||
*/
|
||||
int
|
||||
null_lock(ap)
|
||||
struct vop_lock_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_flags;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
vop_nolock(ap);
|
||||
if ((ap->a_flags & LK_TYPE_MASK) == LK_DRAIN)
|
||||
return (0);
|
||||
ap->a_flags &= ~LK_INTERLOCK;
|
||||
return (null_bypass(ap));
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to process our own vnode unlock and then clear the
|
||||
* interlock flag as it applies only to our vnode, not the
|
||||
* vnodes below us on the stack.
|
||||
*/
|
||||
int
|
||||
null_unlock(ap)
|
||||
struct vop_unlock_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_flags;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
|
||||
vop_nounlock(ap);
|
||||
ap->a_flags &= ~LK_INTERLOCK;
|
||||
return (null_bypass(ap));
|
||||
}
|
||||
|
||||
int
|
||||
null_inactive(ap)
|
||||
struct vop_inactive_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
/*
|
||||
* Do nothing (and _don't_ bypass).
|
||||
* Wait to vrele lowervp until reclaim,
|
||||
* so that until then our null_node is in the
|
||||
* cache and reusable.
|
||||
*
|
||||
* NEEDSWORK: Someday, consider inactive'ing
|
||||
* the lowervp and then trying to reactivate it
|
||||
* with capabilities (v_id)
|
||||
* like they do in the name lookup cache code.
|
||||
* That's too much work for now.
|
||||
*/
|
||||
VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
null_reclaim(ap)
|
||||
struct vop_reclaim_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct null_node *xp = VTONULL(vp);
|
||||
struct vnode *lowervp = xp->null_lowervp;
|
||||
|
||||
/*
|
||||
* Note: in vop_reclaim, vp->v_op == dead_vnodeop_p,
|
||||
* so we can't call VOPs on ourself.
|
||||
*/
|
||||
/* After this assignment, this node will not be re-used. */
|
||||
xp->null_lowervp = NULL;
|
||||
LIST_REMOVE(xp, null_hash);
|
||||
FREE(vp->v_data, M_TEMP);
|
||||
vp->v_data = NULL;
|
||||
vrele (lowervp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
null_print(ap)
|
||||
struct vop_print_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
register struct vnode *vp = ap->a_vp;
|
||||
printf ("\ttag VT_NULLFS, vp=%x, lowervp=%x\n", vp, NULLVPTOLOWERVP(vp));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX - vop_strategy must be hand coded because it has no
|
||||
* vnode in its arguments.
|
||||
* This goes away with a merged VM/buffer cache.
|
||||
*/
|
||||
int
|
||||
null_strategy(ap)
|
||||
struct vop_strategy_args /* {
|
||||
struct buf *a_bp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct buf *bp = ap->a_bp;
|
||||
int error;
|
||||
struct vnode *savedvp;
|
||||
|
||||
savedvp = bp->b_vp;
|
||||
bp->b_vp = NULLVPTOLOWERVP(bp->b_vp);
|
||||
|
||||
error = VOP_STRATEGY(bp);
|
||||
|
||||
bp->b_vp = savedvp;
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX - like vop_strategy, vop_bwrite must be hand coded because it has no
|
||||
* vnode in its arguments.
|
||||
* This goes away with a merged VM/buffer cache.
|
||||
*/
|
||||
int
|
||||
null_bwrite(ap)
|
||||
struct vop_bwrite_args /* {
|
||||
struct buf *a_bp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct buf *bp = ap->a_bp;
|
||||
int error;
|
||||
struct vnode *savedvp;
|
||||
|
||||
savedvp = bp->b_vp;
|
||||
bp->b_vp = NULLVPTOLOWERVP(bp->b_vp);
|
||||
|
||||
error = VOP_BWRITE(bp);
|
||||
|
||||
bp->b_vp = savedvp;
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Global vfs data structures
|
||||
*/
|
||||
int (**null_vnodeop_p)();
|
||||
struct vnodeopv_entry_desc null_vnodeop_entries[] = {
|
||||
{ &vop_default_desc, null_bypass },
|
||||
|
||||
{ &vop_lookup_desc, null_lookup },
|
||||
{ &vop_setattr_desc, null_setattr },
|
||||
{ &vop_getattr_desc, null_getattr },
|
||||
{ &vop_access_desc, null_access },
|
||||
{ &vop_lock_desc, null_lock },
|
||||
{ &vop_unlock_desc, null_unlock },
|
||||
{ &vop_inactive_desc, null_inactive },
|
||||
{ &vop_reclaim_desc, null_reclaim },
|
||||
{ &vop_print_desc, null_print },
|
||||
|
||||
{ &vop_strategy_desc, null_strategy },
|
||||
{ &vop_bwrite_desc, null_bwrite },
|
||||
|
||||
{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
|
||||
};
|
||||
struct vnodeopv_desc null_vnodeop_opv_desc =
|
||||
{ &null_vnodeop_p, null_vnodeop_entries };
|
||||
272
sys/miscfs/portal/portal_vfsops.c
Normal file
272
sys/miscfs/portal/portal_vfsops.c
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
/*
|
||||
* Copyright (c) 1992, 1993, 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)portal_vfsops.c 8.11 (Berkeley) 5/14/95
|
||||
*
|
||||
* $Id: portal_vfsops.c,v 1.5 1992/05/30 10:25:27 jsp Exp jsp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portal Filesystem
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/filedesc.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/domain.h>
|
||||
#include <sys/un.h>
|
||||
#include <miscfs/portal/portal.h>
|
||||
|
||||
int
|
||||
portal_init(vfsp)
|
||||
struct vfsconf *vfsp;
|
||||
{
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mount the per-process file descriptors (/dev/fd)
|
||||
*/
|
||||
int
|
||||
portal_mount(mp, path, data, ndp, p)
|
||||
struct mount *mp;
|
||||
char *path;
|
||||
caddr_t data;
|
||||
struct nameidata *ndp;
|
||||
struct proc *p;
|
||||
{
|
||||
struct file *fp;
|
||||
struct portal_args args;
|
||||
struct portalmount *fmp;
|
||||
struct socket *so;
|
||||
struct vnode *rvp;
|
||||
u_int size;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Update is a no-op
|
||||
*/
|
||||
if (mp->mnt_flag & MNT_UPDATE)
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
if (error = copyin(data, (caddr_t) &args, sizeof(struct portal_args)))
|
||||
return (error);
|
||||
|
||||
if (error = getsock(p->p_fd, args.pa_socket, &fp))
|
||||
return (error);
|
||||
so = (struct socket *) fp->f_data;
|
||||
if (so->so_proto->pr_domain->dom_family != AF_UNIX)
|
||||
return (ESOCKTNOSUPPORT);
|
||||
|
||||
error = getnewvnode(VT_PORTAL, mp, portal_vnodeop_p, &rvp); /* XXX */
|
||||
if (error)
|
||||
return (error);
|
||||
MALLOC(rvp->v_data, void *, sizeof(struct portalnode),
|
||||
M_TEMP, M_WAITOK);
|
||||
|
||||
fmp = (struct portalmount *) malloc(sizeof(struct portalmount),
|
||||
M_UFSMNT, M_WAITOK); /* XXX */
|
||||
rvp->v_type = VDIR;
|
||||
rvp->v_flag |= VROOT;
|
||||
VTOPORTAL(rvp)->pt_arg = 0;
|
||||
VTOPORTAL(rvp)->pt_size = 0;
|
||||
VTOPORTAL(rvp)->pt_fileid = PORTAL_ROOTFILEID;
|
||||
fmp->pm_root = rvp;
|
||||
fmp->pm_server = fp; fp->f_count++;
|
||||
|
||||
mp->mnt_flag |= MNT_LOCAL;
|
||||
mp->mnt_data = (qaddr_t) fmp;
|
||||
vfs_getnewfsid(mp);
|
||||
|
||||
(void)copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
|
||||
bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
|
||||
(void)copyinstr(args.pa_config,
|
||||
mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
|
||||
bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
|
||||
|
||||
#ifdef notdef
|
||||
bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
|
||||
bcopy("portal", mp->mnt_stat.f_mntfromname, sizeof("portal"));
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
portal_start(mp, flags, p)
|
||||
struct mount *mp;
|
||||
int flags;
|
||||
struct proc *p;
|
||||
{
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
portal_unmount(mp, mntflags, p)
|
||||
struct mount *mp;
|
||||
int mntflags;
|
||||
struct proc *p;
|
||||
{
|
||||
struct vnode *rootvp = VFSTOPORTAL(mp)->pm_root;
|
||||
int error, flags = 0;
|
||||
|
||||
|
||||
if (mntflags & MNT_FORCE)
|
||||
flags |= FORCECLOSE;
|
||||
|
||||
/*
|
||||
* Clear out buffer cache. I don't think we
|
||||
* ever get anything cached at this level at the
|
||||
* moment, but who knows...
|
||||
*/
|
||||
#ifdef notyet
|
||||
mntflushbuf(mp, 0);
|
||||
if (mntinvalbuf(mp, 1))
|
||||
return (EBUSY);
|
||||
#endif
|
||||
if (rootvp->v_usecount > 1)
|
||||
return (EBUSY);
|
||||
if (error = vflush(mp, rootvp, flags))
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Release reference on underlying root vnode
|
||||
*/
|
||||
vrele(rootvp);
|
||||
/*
|
||||
* And blow it away for future re-use
|
||||
*/
|
||||
vgone(rootvp);
|
||||
/*
|
||||
* Shutdown the socket. This will cause the select in the
|
||||
* daemon to wake up, and then the accept will get ECONNABORTED
|
||||
* which it interprets as a request to go and bury itself.
|
||||
*/
|
||||
soshutdown((struct socket *) VFSTOPORTAL(mp)->pm_server->f_data, 2);
|
||||
/*
|
||||
* Discard reference to underlying file. Must call closef because
|
||||
* this may be the last reference.
|
||||
*/
|
||||
closef(VFSTOPORTAL(mp)->pm_server, (struct proc *) 0);
|
||||
/*
|
||||
* Finally, throw away the portalmount structure
|
||||
*/
|
||||
free(mp->mnt_data, M_UFSMNT); /* XXX */
|
||||
mp->mnt_data = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
portal_root(mp, vpp)
|
||||
struct mount *mp;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
struct proc *p = curproc; /* XXX */
|
||||
struct vnode *vp;
|
||||
|
||||
/*
|
||||
* Return locked reference to root.
|
||||
*/
|
||||
vp = VFSTOPORTAL(mp)->pm_root;
|
||||
VREF(vp);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
*vpp = vp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
portal_statfs(mp, sbp, p)
|
||||
struct mount *mp;
|
||||
struct statfs *sbp;
|
||||
struct proc *p;
|
||||
{
|
||||
|
||||
sbp->f_flags = 0;
|
||||
sbp->f_bsize = DEV_BSIZE;
|
||||
sbp->f_iosize = DEV_BSIZE;
|
||||
sbp->f_blocks = 2; /* 1K to keep df happy */
|
||||
sbp->f_bfree = 0;
|
||||
sbp->f_bavail = 0;
|
||||
sbp->f_files = 1; /* Allow for "." */
|
||||
sbp->f_ffree = 0; /* See comments above */
|
||||
if (sbp != &mp->mnt_stat) {
|
||||
sbp->f_type = mp->mnt_vfc->vfc_typenum;
|
||||
bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
|
||||
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
|
||||
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
#define portal_fhtovp ((int (*) __P((struct mount *, struct fid *, \
|
||||
struct mbuf *, struct vnode **, int *, struct ucred **)))eopnotsupp)
|
||||
#define portal_quotactl ((int (*) __P((struct mount *, int, uid_t, caddr_t, \
|
||||
struct proc *)))eopnotsupp)
|
||||
#define portal_sync ((int (*) __P((struct mount *, int, struct ucred *, \
|
||||
struct proc *)))nullop)
|
||||
#define portal_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \
|
||||
size_t, struct proc *)))eopnotsupp)
|
||||
#define portal_vget ((int (*) __P((struct mount *, ino_t, struct vnode **))) \
|
||||
eopnotsupp)
|
||||
#define portal_vptofh ((int (*) __P((struct vnode *, struct fid *)))eopnotsupp)
|
||||
|
||||
struct vfsops portal_vfsops = {
|
||||
portal_mount,
|
||||
portal_start,
|
||||
portal_unmount,
|
||||
portal_root,
|
||||
portal_quotactl,
|
||||
portal_statfs,
|
||||
portal_sync,
|
||||
portal_vget,
|
||||
portal_fhtovp,
|
||||
portal_vptofh,
|
||||
portal_init,
|
||||
portal_sysctl,
|
||||
};
|
||||
730
sys/miscfs/portal/portal_vnops.c
Normal file
730
sys/miscfs/portal/portal_vnops.c
Normal file
|
|
@ -0,0 +1,730 @@
|
|||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)portal_vnops.c 8.14 (Berkeley) 5/21/95
|
||||
*
|
||||
* $Id: portal_vnops.c,v 1.4 1992/05/30 10:05:24 jsp Exp jsp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portal Filesystem
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/filedesc.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/unpcb.h>
|
||||
#include <miscfs/portal/portal.h>
|
||||
|
||||
static int portal_fileid = PORTAL_ROOTFILEID+1;
|
||||
|
||||
static void
|
||||
portal_closefd(p, fd)
|
||||
struct proc *p;
|
||||
int fd;
|
||||
{
|
||||
int error;
|
||||
struct {
|
||||
int fd;
|
||||
} ua;
|
||||
int rc;
|
||||
|
||||
ua.fd = fd;
|
||||
error = close(p, &ua, &rc);
|
||||
/*
|
||||
* We should never get an error, and there isn't anything
|
||||
* we could do if we got one, so just print a message.
|
||||
*/
|
||||
if (error)
|
||||
printf("portal_closefd: error = %d\n", error);
|
||||
}
|
||||
|
||||
/*
|
||||
* vp is the current namei directory
|
||||
* cnp is the name to locate in that directory...
|
||||
*/
|
||||
int
|
||||
portal_lookup(ap)
|
||||
struct vop_lookup_args /* {
|
||||
struct vnode * a_dvp;
|
||||
struct vnode ** a_vpp;
|
||||
struct componentname * a_cnp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct componentname *cnp = ap->a_cnp;
|
||||
struct vnode **vpp = ap->a_vpp;
|
||||
struct vnode *dvp = ap->a_dvp;
|
||||
char *pname = cnp->cn_nameptr;
|
||||
struct portalnode *pt;
|
||||
int error;
|
||||
struct vnode *fvp = 0;
|
||||
char *path;
|
||||
int size;
|
||||
|
||||
*vpp = NULLVP;
|
||||
|
||||
if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
|
||||
return (EROFS);
|
||||
|
||||
if (cnp->cn_namelen == 1 && *pname == '.') {
|
||||
*vpp = dvp;
|
||||
VREF(dvp);
|
||||
/*VOP_LOCK(dvp);*/
|
||||
return (0);
|
||||
}
|
||||
|
||||
error = getnewvnode(VT_PORTAL, dvp->v_mount, portal_vnodeop_p, &fvp);
|
||||
if (error)
|
||||
goto bad;
|
||||
fvp->v_type = VREG;
|
||||
MALLOC(fvp->v_data, void *, sizeof(struct portalnode), M_TEMP,
|
||||
M_WAITOK);
|
||||
|
||||
pt = VTOPORTAL(fvp);
|
||||
/*
|
||||
* Save all of the remaining pathname and
|
||||
* advance the namei next pointer to the end
|
||||
* of the string.
|
||||
*/
|
||||
for (size = 0, path = pname; *path; path++)
|
||||
size++;
|
||||
cnp->cn_consume = size - cnp->cn_namelen;
|
||||
|
||||
pt->pt_arg = malloc(size+1, M_TEMP, M_WAITOK);
|
||||
pt->pt_size = size+1;
|
||||
bcopy(pname, pt->pt_arg, pt->pt_size);
|
||||
pt->pt_fileid = portal_fileid++;
|
||||
|
||||
*vpp = fvp;
|
||||
/*VOP_LOCK(fvp);*/
|
||||
return (0);
|
||||
|
||||
bad:;
|
||||
if (fvp)
|
||||
vrele(fvp);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
portal_connect(so, so2)
|
||||
struct socket *so;
|
||||
struct socket *so2;
|
||||
{
|
||||
/* from unp_connect, bypassing the namei stuff... */
|
||||
struct socket *so3;
|
||||
struct unpcb *unp2;
|
||||
struct unpcb *unp3;
|
||||
|
||||
if (so2 == 0)
|
||||
return (ECONNREFUSED);
|
||||
|
||||
if (so->so_type != so2->so_type)
|
||||
return (EPROTOTYPE);
|
||||
|
||||
if ((so2->so_options & SO_ACCEPTCONN) == 0)
|
||||
return (ECONNREFUSED);
|
||||
|
||||
if ((so3 = sonewconn(so2, 0)) == 0)
|
||||
return (ECONNREFUSED);
|
||||
|
||||
unp2 = sotounpcb(so2);
|
||||
unp3 = sotounpcb(so3);
|
||||
if (unp2->unp_addr)
|
||||
unp3->unp_addr = m_copy(unp2->unp_addr, 0, (int)M_COPYALL);
|
||||
|
||||
so2 = so3;
|
||||
|
||||
|
||||
return (unp_connect2(so, so2));
|
||||
}
|
||||
|
||||
int
|
||||
portal_open(ap)
|
||||
struct vop_open_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_mode;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct socket *so = 0;
|
||||
struct portalnode *pt;
|
||||
struct proc *p = ap->a_p;
|
||||
struct vnode *vp = ap->a_vp;
|
||||
int s;
|
||||
struct uio auio;
|
||||
struct iovec aiov[2];
|
||||
int res;
|
||||
struct mbuf *cm = 0;
|
||||
struct cmsghdr *cmsg;
|
||||
int newfds;
|
||||
int *ip;
|
||||
int fd;
|
||||
int error;
|
||||
int len;
|
||||
struct portalmount *fmp;
|
||||
struct file *fp;
|
||||
struct portal_cred pcred;
|
||||
|
||||
/*
|
||||
* Nothing to do when opening the root node.
|
||||
*/
|
||||
if (vp->v_flag & VROOT)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Can't be opened unless the caller is set up
|
||||
* to deal with the side effects. Check for this
|
||||
* by testing whether the p_dupfd has been set.
|
||||
*/
|
||||
if (p->p_dupfd >= 0)
|
||||
return (ENODEV);
|
||||
|
||||
pt = VTOPORTAL(vp);
|
||||
fmp = VFSTOPORTAL(vp->v_mount);
|
||||
|
||||
/*
|
||||
* Create a new socket.
|
||||
*/
|
||||
error = socreate(AF_UNIX, &so, SOCK_STREAM, 0);
|
||||
if (error)
|
||||
goto bad;
|
||||
|
||||
/*
|
||||
* Reserve some buffer space
|
||||
*/
|
||||
res = pt->pt_size + sizeof(pcred) + 512; /* XXX */
|
||||
error = soreserve(so, res, res);
|
||||
if (error)
|
||||
goto bad;
|
||||
|
||||
/*
|
||||
* Kick off connection
|
||||
*/
|
||||
error = portal_connect(so, (struct socket *)fmp->pm_server->f_data);
|
||||
if (error)
|
||||
goto bad;
|
||||
|
||||
/*
|
||||
* Wait for connection to complete
|
||||
*/
|
||||
/*
|
||||
* XXX: Since the mount point is holding a reference on the
|
||||
* underlying server socket, it is not easy to find out whether
|
||||
* the server process is still running. To handle this problem
|
||||
* we loop waiting for the new socket to be connected (something
|
||||
* which will only happen if the server is still running) or for
|
||||
* the reference count on the server socket to drop to 1, which
|
||||
* will happen if the server dies. Sleep for 5 second intervals
|
||||
* and keep polling the reference count. XXX.
|
||||
*/
|
||||
s = splnet();
|
||||
while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
|
||||
if (fmp->pm_server->f_count == 1) {
|
||||
error = ECONNREFUSED;
|
||||
splx(s);
|
||||
goto bad;
|
||||
}
|
||||
(void) tsleep((caddr_t) &so->so_timeo, PSOCK, "portalcon", 5 * hz);
|
||||
}
|
||||
splx(s);
|
||||
|
||||
if (so->so_error) {
|
||||
error = so->so_error;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set miscellaneous flags
|
||||
*/
|
||||
so->so_rcv.sb_timeo = 0;
|
||||
so->so_snd.sb_timeo = 0;
|
||||
so->so_rcv.sb_flags |= SB_NOINTR;
|
||||
so->so_snd.sb_flags |= SB_NOINTR;
|
||||
|
||||
|
||||
pcred.pcr_flag = ap->a_mode;
|
||||
pcred.pcr_uid = ap->a_cred->cr_uid;
|
||||
pcred.pcr_ngroups = ap->a_cred->cr_ngroups;
|
||||
bcopy(ap->a_cred->cr_groups, pcred.pcr_groups, NGROUPS * sizeof(gid_t));
|
||||
aiov[0].iov_base = (caddr_t) &pcred;
|
||||
aiov[0].iov_len = sizeof(pcred);
|
||||
aiov[1].iov_base = pt->pt_arg;
|
||||
aiov[1].iov_len = pt->pt_size;
|
||||
auio.uio_iov = aiov;
|
||||
auio.uio_iovcnt = 2;
|
||||
auio.uio_rw = UIO_WRITE;
|
||||
auio.uio_segflg = UIO_SYSSPACE;
|
||||
auio.uio_procp = p;
|
||||
auio.uio_offset = 0;
|
||||
auio.uio_resid = aiov[0].iov_len + aiov[1].iov_len;
|
||||
|
||||
error = sosend(so, (struct mbuf *) 0, &auio,
|
||||
(struct mbuf *) 0, (struct mbuf *) 0, 0);
|
||||
if (error)
|
||||
goto bad;
|
||||
|
||||
len = auio.uio_resid = sizeof(int);
|
||||
do {
|
||||
struct mbuf *m = 0;
|
||||
int flags = MSG_WAITALL;
|
||||
error = soreceive(so, (struct mbuf **) 0, &auio,
|
||||
&m, &cm, &flags);
|
||||
if (error)
|
||||
goto bad;
|
||||
|
||||
/*
|
||||
* Grab an error code from the mbuf.
|
||||
*/
|
||||
if (m) {
|
||||
m = m_pullup(m, sizeof(int)); /* Needed? */
|
||||
if (m) {
|
||||
error = *(mtod(m, int *));
|
||||
m_freem(m);
|
||||
} else {
|
||||
error = EINVAL;
|
||||
}
|
||||
} else {
|
||||
if (cm == 0) {
|
||||
error = ECONNRESET; /* XXX */
|
||||
#ifdef notdef
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} while (cm == 0 && auio.uio_resid == len && !error);
|
||||
|
||||
if (cm == 0)
|
||||
goto bad;
|
||||
|
||||
if (auio.uio_resid) {
|
||||
error = 0;
|
||||
#ifdef notdef
|
||||
error = EMSGSIZE;
|
||||
goto bad;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: Break apart the control message, and retrieve the
|
||||
* received file descriptor. Note that more than one descriptor
|
||||
* may have been received, or that the rights chain may have more
|
||||
* than a single mbuf in it. What to do?
|
||||
*/
|
||||
cmsg = mtod(cm, struct cmsghdr *);
|
||||
newfds = (cmsg->cmsg_len - sizeof(*cmsg)) / sizeof (int);
|
||||
if (newfds == 0) {
|
||||
error = ECONNREFUSED;
|
||||
goto bad;
|
||||
}
|
||||
/*
|
||||
* At this point the rights message consists of a control message
|
||||
* header, followed by a data region containing a vector of
|
||||
* integer file descriptors. The fds were allocated by the action
|
||||
* of receiving the control message.
|
||||
*/
|
||||
ip = (int *) (cmsg + 1);
|
||||
fd = *ip++;
|
||||
if (newfds > 1) {
|
||||
/*
|
||||
* Close extra fds.
|
||||
*/
|
||||
int i;
|
||||
printf("portal_open: %d extra fds\n", newfds - 1);
|
||||
for (i = 1; i < newfds; i++) {
|
||||
portal_closefd(p, *ip);
|
||||
ip++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that the mode the file is being opened for is a subset
|
||||
* of the mode of the existing descriptor.
|
||||
*/
|
||||
fp = p->p_fd->fd_ofiles[fd];
|
||||
if (((ap->a_mode & (FREAD|FWRITE)) | fp->f_flag) != fp->f_flag) {
|
||||
portal_closefd(p, fd);
|
||||
error = EACCES;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the dup fd in the proc structure then return the
|
||||
* special error code (ENXIO) which causes magic things to
|
||||
* happen in vn_open. The whole concept is, well, hmmm.
|
||||
*/
|
||||
p->p_dupfd = fd;
|
||||
error = ENXIO;
|
||||
|
||||
bad:;
|
||||
/*
|
||||
* And discard the control message.
|
||||
*/
|
||||
if (cm) {
|
||||
m_freem(cm);
|
||||
}
|
||||
|
||||
if (so) {
|
||||
soshutdown(so, 2);
|
||||
soclose(so);
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
portal_getattr(ap)
|
||||
struct vop_getattr_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct vattr *a_vap;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct vattr *vap = ap->a_vap;
|
||||
struct timeval tv;
|
||||
|
||||
bzero(vap, sizeof(*vap));
|
||||
vattr_null(vap);
|
||||
vap->va_uid = 0;
|
||||
vap->va_gid = 0;
|
||||
vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
|
||||
vap->va_size = DEV_BSIZE;
|
||||
vap->va_blocksize = DEV_BSIZE;
|
||||
microtime(&tv);
|
||||
TIMEVAL_TO_TIMESPEC(&tv, &vap->va_atime);
|
||||
vap->va_mtime = vap->va_atime;
|
||||
vap->va_ctime = vap->va_ctime;
|
||||
vap->va_gen = 0;
|
||||
vap->va_flags = 0;
|
||||
vap->va_rdev = 0;
|
||||
/* vap->va_qbytes = 0; */
|
||||
vap->va_bytes = 0;
|
||||
/* vap->va_qsize = 0; */
|
||||
if (vp->v_flag & VROOT) {
|
||||
vap->va_type = VDIR;
|
||||
vap->va_mode = S_IRUSR|S_IWUSR|S_IXUSR|
|
||||
S_IRGRP|S_IWGRP|S_IXGRP|
|
||||
S_IROTH|S_IWOTH|S_IXOTH;
|
||||
vap->va_nlink = 2;
|
||||
vap->va_fileid = 2;
|
||||
} else {
|
||||
vap->va_type = VREG;
|
||||
vap->va_mode = S_IRUSR|S_IWUSR|
|
||||
S_IRGRP|S_IWGRP|
|
||||
S_IROTH|S_IWOTH;
|
||||
vap->va_nlink = 1;
|
||||
vap->va_fileid = VTOPORTAL(vp)->pt_fileid;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
portal_setattr(ap)
|
||||
struct vop_setattr_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct vattr *a_vap;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
/*
|
||||
* Can't mess with the root vnode
|
||||
*/
|
||||
if (ap->a_vp->v_flag & VROOT)
|
||||
return (EACCES);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fake readdir, just return empty directory.
|
||||
* It is hard to deal with '.' and '..' so don't bother.
|
||||
*/
|
||||
int
|
||||
portal_readdir(ap)
|
||||
struct vop_readdir_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
struct ucred *a_cred;
|
||||
int *a_eofflag;
|
||||
u_long *a_cookies;
|
||||
int a_ncookies;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
/*
|
||||
* We don't allow exporting portal mounts, and currently local
|
||||
* requests do not need cookies.
|
||||
*/
|
||||
if (ap->a_ncookies)
|
||||
panic("portal_readdir: not hungry");
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
portal_inactive(ap)
|
||||
struct vop_inactive_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
portal_reclaim(ap)
|
||||
struct vop_reclaim_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct portalnode *pt = VTOPORTAL(ap->a_vp);
|
||||
|
||||
if (pt->pt_arg) {
|
||||
free((caddr_t) pt->pt_arg, M_TEMP);
|
||||
pt->pt_arg = 0;
|
||||
}
|
||||
FREE(ap->a_vp->v_data, M_TEMP);
|
||||
ap->a_vp->v_data = 0;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return POSIX pathconf information applicable to special devices.
|
||||
*/
|
||||
portal_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 */
|
||||
}
|
||||
|
||||
/*
|
||||
* Print out the contents of a Portal vnode.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
int
|
||||
portal_print(ap)
|
||||
struct vop_print_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
printf("tag VT_PORTAL, portal vnode\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*void*/
|
||||
int
|
||||
portal_vfree(ap)
|
||||
struct vop_vfree_args /* {
|
||||
struct vnode *a_pvp;
|
||||
ino_t a_ino;
|
||||
int a_mode;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Portal vnode unsupported operation
|
||||
*/
|
||||
int
|
||||
portal_enotsupp()
|
||||
{
|
||||
|
||||
return (EOPNOTSUPP);
|
||||
}
|
||||
|
||||
/*
|
||||
* Portal "should never get here" operation
|
||||
*/
|
||||
int
|
||||
portal_badop()
|
||||
{
|
||||
|
||||
panic("portal: bad op");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
* Portal vnode null operation
|
||||
*/
|
||||
int
|
||||
portal_nullop()
|
||||
{
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#define portal_create ((int (*) __P((struct vop_create_args *)))portal_enotsupp)
|
||||
#define portal_mknod ((int (*) __P((struct vop_mknod_args *)))portal_enotsupp)
|
||||
#define portal_close ((int (*) __P((struct vop_close_args *)))nullop)
|
||||
#define portal_access ((int (*) __P((struct vop_access_args *)))nullop)
|
||||
#define portal_read ((int (*) __P((struct vop_read_args *)))portal_enotsupp)
|
||||
#define portal_write ((int (*) __P((struct vop_write_args *)))portal_enotsupp)
|
||||
#define portal_ioctl ((int (*) __P((struct vop_ioctl_args *)))portal_enotsupp)
|
||||
#define portal_select ((int (*) __P((struct vop_select_args *)))portal_enotsupp)
|
||||
#define portal_mmap ((int (*) __P((struct vop_mmap_args *)))portal_enotsupp)
|
||||
#define portal_revoke vop_revoke
|
||||
#define portal_fsync ((int (*) __P((struct vop_fsync_args *)))nullop)
|
||||
#define portal_seek ((int (*) __P((struct vop_seek_args *)))nullop)
|
||||
#define portal_remove ((int (*) __P((struct vop_remove_args *)))portal_enotsupp)
|
||||
#define portal_link ((int (*) __P((struct vop_link_args *)))portal_enotsupp)
|
||||
#define portal_rename ((int (*) __P((struct vop_rename_args *)))portal_enotsupp)
|
||||
#define portal_mkdir ((int (*) __P((struct vop_mkdir_args *)))portal_enotsupp)
|
||||
#define portal_rmdir ((int (*) __P((struct vop_rmdir_args *)))portal_enotsupp)
|
||||
#define portal_symlink \
|
||||
((int (*) __P((struct vop_symlink_args *)))portal_enotsupp)
|
||||
#define portal_readlink \
|
||||
((int (*) __P((struct vop_readlink_args *)))portal_enotsupp)
|
||||
#define portal_abortop ((int (*) __P((struct vop_abortop_args *)))nullop)
|
||||
#define portal_lock ((int (*) __P((struct vop_lock_args *)))vop_nolock)
|
||||
#define portal_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock)
|
||||
#define portal_bmap ((int (*) __P((struct vop_bmap_args *)))portal_badop)
|
||||
#define portal_strategy \
|
||||
((int (*) __P((struct vop_strategy_args *)))portal_badop)
|
||||
#define portal_islocked \
|
||||
((int (*) __P((struct vop_islocked_args *)))vop_noislocked)
|
||||
#define fifo_islocked ((int(*) __P((struct vop_islocked_args *)))vop_noislocked)
|
||||
#define portal_advlock \
|
||||
((int (*) __P((struct vop_advlock_args *)))portal_enotsupp)
|
||||
#define portal_blkatoff \
|
||||
((int (*) __P((struct vop_blkatoff_args *)))portal_enotsupp)
|
||||
#define portal_valloc ((int(*) __P(( \
|
||||
struct vnode *pvp, \
|
||||
int mode, \
|
||||
struct ucred *cred, \
|
||||
struct vnode **vpp))) portal_enotsupp)
|
||||
#define portal_truncate \
|
||||
((int (*) __P((struct vop_truncate_args *)))portal_enotsupp)
|
||||
#define portal_update ((int (*) __P((struct vop_update_args *)))portal_enotsupp)
|
||||
#define portal_bwrite ((int (*) __P((struct vop_bwrite_args *)))portal_enotsupp)
|
||||
|
||||
int (**portal_vnodeop_p)();
|
||||
struct vnodeopv_entry_desc portal_vnodeop_entries[] = {
|
||||
{ &vop_default_desc, vn_default_error },
|
||||
{ &vop_lookup_desc, portal_lookup }, /* lookup */
|
||||
{ &vop_create_desc, portal_create }, /* create */
|
||||
{ &vop_mknod_desc, portal_mknod }, /* mknod */
|
||||
{ &vop_open_desc, portal_open }, /* open */
|
||||
{ &vop_close_desc, portal_close }, /* close */
|
||||
{ &vop_access_desc, portal_access }, /* access */
|
||||
{ &vop_getattr_desc, portal_getattr }, /* getattr */
|
||||
{ &vop_setattr_desc, portal_setattr }, /* setattr */
|
||||
{ &vop_read_desc, portal_read }, /* read */
|
||||
{ &vop_write_desc, portal_write }, /* write */
|
||||
{ &vop_ioctl_desc, portal_ioctl }, /* ioctl */
|
||||
{ &vop_select_desc, portal_select }, /* select */
|
||||
{ &vop_mmap_desc, portal_mmap }, /* mmap */
|
||||
{ &vop_revoke_desc, portal_revoke }, /* revoke */
|
||||
{ &vop_fsync_desc, portal_fsync }, /* fsync */
|
||||
{ &vop_seek_desc, portal_seek }, /* seek */
|
||||
{ &vop_remove_desc, portal_remove }, /* remove */
|
||||
{ &vop_link_desc, portal_link }, /* link */
|
||||
{ &vop_rename_desc, portal_rename }, /* rename */
|
||||
{ &vop_mkdir_desc, portal_mkdir }, /* mkdir */
|
||||
{ &vop_rmdir_desc, portal_rmdir }, /* rmdir */
|
||||
{ &vop_symlink_desc, portal_symlink }, /* symlink */
|
||||
{ &vop_readdir_desc, portal_readdir }, /* readdir */
|
||||
{ &vop_readlink_desc, portal_readlink }, /* readlink */
|
||||
{ &vop_abortop_desc, portal_abortop }, /* abortop */
|
||||
{ &vop_inactive_desc, portal_inactive }, /* inactive */
|
||||
{ &vop_reclaim_desc, portal_reclaim }, /* reclaim */
|
||||
{ &vop_lock_desc, portal_lock }, /* lock */
|
||||
{ &vop_unlock_desc, portal_unlock }, /* unlock */
|
||||
{ &vop_bmap_desc, portal_bmap }, /* bmap */
|
||||
{ &vop_strategy_desc, portal_strategy }, /* strategy */
|
||||
{ &vop_print_desc, portal_print }, /* print */
|
||||
{ &vop_islocked_desc, portal_islocked }, /* islocked */
|
||||
{ &vop_pathconf_desc, portal_pathconf }, /* pathconf */
|
||||
{ &vop_advlock_desc, portal_advlock }, /* advlock */
|
||||
{ &vop_blkatoff_desc, portal_blkatoff }, /* blkatoff */
|
||||
{ &vop_valloc_desc, portal_valloc }, /* valloc */
|
||||
{ &vop_vfree_desc, portal_vfree }, /* vfree */
|
||||
{ &vop_truncate_desc, portal_truncate }, /* truncate */
|
||||
{ &vop_update_desc, portal_update }, /* update */
|
||||
{ &vop_bwrite_desc, portal_bwrite }, /* bwrite */
|
||||
{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
|
||||
};
|
||||
struct vnodeopv_desc portal_vnodeop_opv_desc =
|
||||
{ &portal_vnodeop_p, portal_vnodeop_entries };
|
||||
194
sys/miscfs/procfs/procfs.h
Normal file
194
sys/miscfs/procfs/procfs.h
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* Copyright (c) 1993 Jan-Simon Pendry
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)procfs.h 8.9 (Berkeley) 5/14/95
|
||||
*
|
||||
* From:
|
||||
* $Id: procfs.h,v 3.2 1993/12/15 09:40:17 jsp Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* The different types of node in a procfs filesystem
|
||||
*/
|
||||
typedef enum {
|
||||
Proot, /* the filesystem root */
|
||||
Pcurproc, /* symbolic link for curproc */
|
||||
Pproc, /* a process-specific sub-directory */
|
||||
Pfile, /* the executable file */
|
||||
Pmem, /* the process's memory image */
|
||||
Pregs, /* the process's register set */
|
||||
Pfpregs, /* the process's FP register set */
|
||||
Pctl, /* process control */
|
||||
Pstatus, /* process status */
|
||||
Pnote, /* process notifier */
|
||||
Pnotepg /* process group notifier */
|
||||
} pfstype;
|
||||
|
||||
/*
|
||||
* control data for the proc file system.
|
||||
*/
|
||||
struct pfsnode {
|
||||
struct pfsnode *pfs_next; /* next on list */
|
||||
struct vnode *pfs_vnode; /* vnode associated with this pfsnode */
|
||||
pfstype pfs_type; /* type of procfs node */
|
||||
pid_t pfs_pid; /* associated process */
|
||||
u_short pfs_mode; /* mode bits for stat() */
|
||||
u_long pfs_flags; /* open flags */
|
||||
u_long pfs_fileno; /* unique file id */
|
||||
};
|
||||
|
||||
#define PROCFS_NOTELEN 64 /* max length of a note (/proc/$pid/note) */
|
||||
#define PROCFS_CTLLEN 8 /* max length of a ctl msg (/proc/$pid/ctl */
|
||||
|
||||
/*
|
||||
* Kernel stuff follows
|
||||
*/
|
||||
#ifdef KERNEL
|
||||
#define CNEQ(cnp, s, len) \
|
||||
((cnp)->cn_namelen == (len) && \
|
||||
(bcmp((s), (cnp)->cn_nameptr, (len)) == 0))
|
||||
|
||||
/*
|
||||
* Format of a directory entry in /proc, ...
|
||||
* This must map onto struct dirent (see <dirent.h>)
|
||||
*/
|
||||
#define PROCFS_NAMELEN 8
|
||||
struct pfsdent {
|
||||
u_long d_fileno;
|
||||
u_short d_reclen;
|
||||
u_char d_type;
|
||||
u_char d_namlen;
|
||||
char d_name[PROCFS_NAMELEN];
|
||||
};
|
||||
#define UIO_MX sizeof(struct pfsdent)
|
||||
#define PROCFS_FILENO(pid, type) \
|
||||
(((type) < Pproc) ? \
|
||||
((type) + 2) : \
|
||||
((((pid)+1) << 4) + ((int) (type))))
|
||||
|
||||
/*
|
||||
* Convert between pfsnode vnode
|
||||
*/
|
||||
#define VTOPFS(vp) ((struct pfsnode *)(vp)->v_data)
|
||||
#define PFSTOV(pfs) ((pfs)->pfs_vnode)
|
||||
|
||||
typedef struct vfs_namemap vfs_namemap_t;
|
||||
struct vfs_namemap {
|
||||
const char *nm_name;
|
||||
int nm_val;
|
||||
};
|
||||
|
||||
int vfs_getuserstr __P((struct uio *, char *, int *));
|
||||
vfs_namemap_t *vfs_findname __P((vfs_namemap_t *, char *, int));
|
||||
|
||||
/* <machine/reg.h> */
|
||||
struct reg;
|
||||
struct fpreg;
|
||||
|
||||
#define PFIND(pid) ((pid) ? pfind(pid) : &proc0)
|
||||
int procfs_freevp __P((struct vnode *));
|
||||
int procfs_allocvp __P((struct mount *, struct vnode **, long, pfstype));
|
||||
struct vnode *procfs_findtextvp __P((struct proc *));
|
||||
int procfs_sstep __P((struct proc *, int));
|
||||
void procfs_fix_sstep __P((struct proc *));
|
||||
int procfs_read_regs __P((struct proc *, struct reg *));
|
||||
int procfs_write_regs __P((struct proc *, struct reg *));
|
||||
int procfs_read_fpregs __P((struct proc *, struct fpreg *));
|
||||
int procfs_write_fpregs __P((struct proc *, struct fpreg *));
|
||||
int procfs_donote __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
|
||||
int procfs_doregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
|
||||
int procfs_dofpregs __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
|
||||
int procfs_domem __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
|
||||
int procfs_doctl __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
|
||||
int procfs_dostatus __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio));
|
||||
|
||||
/* functions to check whether or not files should be displayed */
|
||||
int procfs_validfile __P((struct proc *));
|
||||
int procfs_validfpregs __P((struct proc *));
|
||||
int procfs_validregs __P((struct proc *));
|
||||
|
||||
#define PROCFS_LOCKED 0x01
|
||||
#define PROCFS_WANT 0x02
|
||||
|
||||
extern int (**procfs_vnodeop_p)();
|
||||
extern struct vfsops procfs_vfsops;
|
||||
|
||||
/*
|
||||
* Prototypes for procfs vnode ops
|
||||
*/
|
||||
int procfs_badop(); /* varargs */
|
||||
int procfs_rw __P((struct vop_read_args *));
|
||||
int procfs_lookup __P((struct vop_lookup_args *));
|
||||
#define procfs_create ((int (*) __P((struct vop_create_args *))) procfs_badop)
|
||||
#define procfs_mknod ((int (*) __P((struct vop_mknod_args *))) procfs_badop)
|
||||
int procfs_open __P((struct vop_open_args *));
|
||||
int procfs_close __P((struct vop_close_args *));
|
||||
int procfs_access __P((struct vop_access_args *));
|
||||
int procfs_getattr __P((struct vop_getattr_args *));
|
||||
int procfs_setattr __P((struct vop_setattr_args *));
|
||||
#define procfs_read procfs_rw
|
||||
#define procfs_write procfs_rw
|
||||
int procfs_ioctl __P((struct vop_ioctl_args *));
|
||||
#define procfs_select ((int (*) __P((struct vop_select_args *))) procfs_badop)
|
||||
#define procfs_mmap ((int (*) __P((struct vop_mmap_args *))) procfs_badop)
|
||||
#define procfs_revoke vop_revoke
|
||||
#define procfs_fsync ((int (*) __P((struct vop_fsync_args *))) procfs_badop)
|
||||
#define procfs_seek ((int (*) __P((struct vop_seek_args *))) procfs_badop)
|
||||
#define procfs_remove ((int (*) __P((struct vop_remove_args *))) procfs_badop)
|
||||
#define procfs_link ((int (*) __P((struct vop_link_args *))) procfs_badop)
|
||||
#define procfs_rename ((int (*) __P((struct vop_rename_args *))) procfs_badop)
|
||||
#define procfs_mkdir ((int (*) __P((struct vop_mkdir_args *))) procfs_badop)
|
||||
#define procfs_rmdir ((int (*) __P((struct vop_rmdir_args *))) procfs_badop)
|
||||
#define procfs_symlink ((int (*) __P((struct vop_symlink_args *))) procfs_badop)
|
||||
int procfs_readdir __P((struct vop_readdir_args *));
|
||||
int procfs_readlink __P((struct vop_readlink_args *));
|
||||
int procfs_abortop __P((struct vop_abortop_args *));
|
||||
int procfs_inactive __P((struct vop_inactive_args *));
|
||||
int procfs_reclaim __P((struct vop_reclaim_args *));
|
||||
#define procfs_lock ((int (*) __P((struct vop_lock_args *)))vop_nolock)
|
||||
#define procfs_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock)
|
||||
int procfs_bmap __P((struct vop_bmap_args *));
|
||||
#define procfs_strategy ((int (*) __P((struct vop_strategy_args *))) procfs_badop)
|
||||
int procfs_print __P((struct vop_print_args *));
|
||||
#define procfs_islocked \
|
||||
((int (*) __P((struct vop_islocked_args *)))vop_noislocked)
|
||||
#define procfs_advlock ((int (*) __P((struct vop_advlock_args *))) procfs_badop)
|
||||
#define procfs_blkatoff ((int (*) __P((struct vop_blkatoff_args *))) procfs_badop)
|
||||
#define procfs_valloc ((int (*) __P((struct vop_valloc_args *))) procfs_badop)
|
||||
#define procfs_vfree ((int (*) __P((struct vop_vfree_args *))) nullop)
|
||||
#define procfs_truncate ((int (*) __P((struct vop_truncate_args *))) procfs_badop)
|
||||
#define procfs_update ((int (*) __P((struct vop_update_args *))) nullop)
|
||||
#endif /* KERNEL */
|
||||
300
sys/miscfs/procfs/procfs_ctl.c
Normal file
300
sys/miscfs/procfs/procfs_ctl.c
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
/*
|
||||
* Copyright (c) 1993 Jan-Simon Pendry
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)procfs_ctl.c 8.4 (Berkeley) 6/15/94
|
||||
*
|
||||
* From:
|
||||
* $Id: procfs_ctl.c,v 3.2 1993/12/15 09:40:17 jsp Exp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/tty.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/resourcevar.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
|
||||
#ifndef FIX_SSTEP
|
||||
#define FIX_SSTEP(p)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* True iff process (p) is in trace wait state
|
||||
* relative to process (curp)
|
||||
*/
|
||||
#define TRACE_WAIT_P(curp, p) \
|
||||
((p)->p_stat == SSTOP && \
|
||||
(p)->p_pptr == (curp) && \
|
||||
((p)->p_flag & P_TRACED))
|
||||
|
||||
#define PROCFS_CTL_ATTACH 1
|
||||
#define PROCFS_CTL_DETACH 2
|
||||
#define PROCFS_CTL_STEP 3
|
||||
#define PROCFS_CTL_RUN 4
|
||||
#define PROCFS_CTL_WAIT 5
|
||||
|
||||
static vfs_namemap_t ctlnames[] = {
|
||||
/* special /proc commands */
|
||||
{ "attach", PROCFS_CTL_ATTACH },
|
||||
{ "detach", PROCFS_CTL_DETACH },
|
||||
{ "step", PROCFS_CTL_STEP },
|
||||
{ "run", PROCFS_CTL_RUN },
|
||||
{ "wait", PROCFS_CTL_WAIT },
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
static vfs_namemap_t signames[] = {
|
||||
/* regular signal names */
|
||||
{ "hup", SIGHUP }, { "int", SIGINT },
|
||||
{ "quit", SIGQUIT }, { "ill", SIGILL },
|
||||
{ "trap", SIGTRAP }, { "abrt", SIGABRT },
|
||||
{ "iot", SIGIOT }, { "emt", SIGEMT },
|
||||
{ "fpe", SIGFPE }, { "kill", SIGKILL },
|
||||
{ "bus", SIGBUS }, { "segv", SIGSEGV },
|
||||
{ "sys", SIGSYS }, { "pipe", SIGPIPE },
|
||||
{ "alrm", SIGALRM }, { "term", SIGTERM },
|
||||
{ "urg", SIGURG }, { "stop", SIGSTOP },
|
||||
{ "tstp", SIGTSTP }, { "cont", SIGCONT },
|
||||
{ "chld", SIGCHLD }, { "ttin", SIGTTIN },
|
||||
{ "ttou", SIGTTOU }, { "io", SIGIO },
|
||||
{ "xcpu", SIGXCPU }, { "xfsz", SIGXFSZ },
|
||||
{ "vtalrm", SIGVTALRM }, { "prof", SIGPROF },
|
||||
{ "winch", SIGWINCH }, { "info", SIGINFO },
|
||||
{ "usr1", SIGUSR1 }, { "usr2", SIGUSR2 },
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
static int
|
||||
procfs_control(curp, p, op)
|
||||
struct proc *curp;
|
||||
struct proc *p;
|
||||
int op;
|
||||
{
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Attach - attaches the target process for debugging
|
||||
* by the calling process.
|
||||
*/
|
||||
if (op == PROCFS_CTL_ATTACH) {
|
||||
/* check whether already being traced */
|
||||
if (p->p_flag & P_TRACED)
|
||||
return (EBUSY);
|
||||
|
||||
/* can't trace yourself! */
|
||||
if (p->p_pid == curp->p_pid)
|
||||
return (EINVAL);
|
||||
|
||||
/*
|
||||
* Go ahead and set the trace flag.
|
||||
* Save the old parent (it's reset in
|
||||
* _DETACH, and also in kern_exit.c:wait4()
|
||||
* Reparent the process so that the tracing
|
||||
* proc gets to see all the action.
|
||||
* Stop the target.
|
||||
*/
|
||||
p->p_flag |= P_TRACED;
|
||||
p->p_xstat = 0; /* XXX ? */
|
||||
if (p->p_pptr != curp) {
|
||||
p->p_oppid = p->p_pptr->p_pid;
|
||||
proc_reparent(p, curp);
|
||||
}
|
||||
psignal(p, SIGSTOP);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Target process must be stopped, owned by (curp) and
|
||||
* be set up for tracing (P_TRACED flag set).
|
||||
* Allow DETACH to take place at any time for sanity.
|
||||
* Allow WAIT any time, of course.
|
||||
*/
|
||||
switch (op) {
|
||||
case PROCFS_CTL_DETACH:
|
||||
case PROCFS_CTL_WAIT:
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!TRACE_WAIT_P(curp, p))
|
||||
return (EBUSY);
|
||||
}
|
||||
|
||||
/*
|
||||
* do single-step fixup if needed
|
||||
*/
|
||||
FIX_SSTEP(p);
|
||||
|
||||
/*
|
||||
* Don't deliver any signal by default.
|
||||
* To continue with a signal, just send
|
||||
* the signal name to the ctl file
|
||||
*/
|
||||
p->p_xstat = 0;
|
||||
|
||||
switch (op) {
|
||||
/*
|
||||
* Detach. Cleans up the target process, reparent it if possible
|
||||
* and set it running once more.
|
||||
*/
|
||||
case PROCFS_CTL_DETACH:
|
||||
/* if not being traced, then this is a painless no-op */
|
||||
if ((p->p_flag & P_TRACED) == 0)
|
||||
return (0);
|
||||
|
||||
/* not being traced any more */
|
||||
p->p_flag &= ~P_TRACED;
|
||||
|
||||
/* give process back to original parent */
|
||||
if (p->p_oppid != p->p_pptr->p_pid) {
|
||||
struct proc *pp;
|
||||
|
||||
pp = pfind(p->p_oppid);
|
||||
if (pp)
|
||||
proc_reparent(p, pp);
|
||||
}
|
||||
|
||||
p->p_oppid = 0;
|
||||
p->p_flag &= ~P_WAITED; /* XXX ? */
|
||||
wakeup((caddr_t) curp); /* XXX for CTL_WAIT below ? */
|
||||
|
||||
break;
|
||||
|
||||
/*
|
||||
* Step. Let the target process execute a single instruction.
|
||||
*/
|
||||
case PROCFS_CTL_STEP:
|
||||
if (error = procfs_sstep(p, 1))
|
||||
return (error);
|
||||
break;
|
||||
|
||||
/*
|
||||
* Run. Let the target process continue running until a breakpoint
|
||||
* or some other trap.
|
||||
*/
|
||||
case PROCFS_CTL_RUN:
|
||||
break;
|
||||
|
||||
/*
|
||||
* Wait for the target process to stop.
|
||||
* If the target is not being traced then just wait
|
||||
* to enter
|
||||
*/
|
||||
case PROCFS_CTL_WAIT:
|
||||
error = 0;
|
||||
if (p->p_flag & P_TRACED) {
|
||||
while (error == 0 &&
|
||||
(p->p_stat != SSTOP) &&
|
||||
(p->p_flag & P_TRACED) &&
|
||||
(p->p_pptr == curp)) {
|
||||
error = tsleep((caddr_t) p,
|
||||
PWAIT|PCATCH, "procfsx", 0);
|
||||
}
|
||||
if (error == 0 && !TRACE_WAIT_P(curp, p))
|
||||
error = EBUSY;
|
||||
} else {
|
||||
while (error == 0 && p->p_stat != SSTOP) {
|
||||
error = tsleep((caddr_t) p,
|
||||
PWAIT|PCATCH, "procfs", 0);
|
||||
}
|
||||
}
|
||||
return (error);
|
||||
|
||||
default:
|
||||
panic("procfs_control");
|
||||
}
|
||||
|
||||
if (p->p_stat == SSTOP)
|
||||
setrunnable(p);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
procfs_doctl(curp, p, pfs, uio)
|
||||
struct proc *curp;
|
||||
struct pfsnode *pfs;
|
||||
struct uio *uio;
|
||||
struct proc *p;
|
||||
{
|
||||
int xlen;
|
||||
int error;
|
||||
char msg[PROCFS_CTLLEN+1];
|
||||
vfs_namemap_t *nm;
|
||||
|
||||
if (uio->uio_rw != UIO_WRITE)
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
xlen = PROCFS_CTLLEN;
|
||||
error = vfs_getuserstr(uio, msg, &xlen);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Map signal names into signal generation
|
||||
* or debug control. Unknown commands and/or signals
|
||||
* return EOPNOTSUPP.
|
||||
*
|
||||
* Sending a signal while the process is being debugged
|
||||
* also has the side effect of letting the target continue
|
||||
* to run. There is no way to single-step a signal delivery.
|
||||
*/
|
||||
error = EOPNOTSUPP;
|
||||
|
||||
nm = vfs_findname(ctlnames, msg, xlen);
|
||||
if (nm) {
|
||||
error = procfs_control(curp, p, nm->nm_val);
|
||||
} else {
|
||||
nm = vfs_findname(signames, msg, xlen);
|
||||
if (nm) {
|
||||
if (TRACE_WAIT_P(curp, p)) {
|
||||
p->p_xstat = nm->nm_val;
|
||||
FIX_SSTEP(p);
|
||||
setrunnable(p);
|
||||
} else {
|
||||
psignal(p, nm->nm_val);
|
||||
}
|
||||
error = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
95
sys/miscfs/procfs/procfs_fpregs.c
Normal file
95
sys/miscfs/procfs/procfs_fpregs.c
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 1993 Jan-Simon Pendry
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)procfs_fpregs.c 8.2 (Berkeley) 6/15/94
|
||||
*
|
||||
* From:
|
||||
* $Id: procfs_regs.c,v 3.2 1993/12/15 09:40:17 jsp Exp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <machine/reg.h>
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
|
||||
int
|
||||
procfs_dofpregs(curp, p, pfs, uio)
|
||||
struct proc *curp;
|
||||
struct proc *p;
|
||||
struct pfsnode *pfs;
|
||||
struct uio *uio;
|
||||
{
|
||||
int error;
|
||||
struct fpreg r;
|
||||
char *kv;
|
||||
int kl;
|
||||
|
||||
kl = sizeof(r);
|
||||
kv = (char *) &r;
|
||||
|
||||
kv += uio->uio_offset;
|
||||
kl -= uio->uio_offset;
|
||||
if (kl > uio->uio_resid)
|
||||
kl = uio->uio_resid;
|
||||
|
||||
if (kl < 0)
|
||||
error = EINVAL;
|
||||
else
|
||||
error = procfs_read_fpregs(p, &r);
|
||||
if (error == 0)
|
||||
error = uiomove(kv, kl, uio);
|
||||
if (error == 0 && uio->uio_rw == UIO_WRITE) {
|
||||
if (p->p_stat != SSTOP)
|
||||
error = EBUSY;
|
||||
else
|
||||
error = procfs_write_fpregs(p, &r);
|
||||
}
|
||||
|
||||
uio->uio_offset = 0;
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
procfs_validfpregs(p)
|
||||
struct proc *p;
|
||||
{
|
||||
|
||||
return ((p->p_flag & P_SYSTEM) == 0);
|
||||
}
|
||||
300
sys/miscfs/procfs/procfs_mem.c
Normal file
300
sys/miscfs/procfs/procfs_mem.c
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
/*
|
||||
* Copyright (c) 1993 Jan-Simon Pendry
|
||||
* Copyright (c) 1993 Sean Eric Fagan
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Jan-Simon Pendry and Sean Eric Fagan.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)procfs_mem.c 8.5 (Berkeley) 6/15/94
|
||||
*
|
||||
* From:
|
||||
* $Id: procfs_mem.c,v 3.2 1993/12/15 09:40:17 jsp Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a lightly hacked and merged version
|
||||
* of sef's pread/pwrite functions
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_kern.h>
|
||||
#include <vm/vm_page.h>
|
||||
|
||||
static int
|
||||
procfs_rwmem(p, uio)
|
||||
struct proc *p;
|
||||
struct uio *uio;
|
||||
{
|
||||
int error;
|
||||
int writing;
|
||||
|
||||
writing = uio->uio_rw == UIO_WRITE;
|
||||
|
||||
/*
|
||||
* Only map in one page at a time. We don't have to, but it
|
||||
* makes things easier. This way is trivial - right?
|
||||
*/
|
||||
do {
|
||||
vm_map_t map, tmap;
|
||||
vm_object_t object;
|
||||
vm_offset_t kva;
|
||||
vm_offset_t uva;
|
||||
int page_offset; /* offset into page */
|
||||
vm_offset_t pageno; /* page number */
|
||||
vm_map_entry_t out_entry;
|
||||
vm_prot_t out_prot;
|
||||
vm_page_t m;
|
||||
boolean_t wired, single_use;
|
||||
vm_offset_t off;
|
||||
u_int len;
|
||||
int fix_prot;
|
||||
|
||||
uva = (vm_offset_t) uio->uio_offset;
|
||||
if (uva > VM_MAXUSER_ADDRESS) {
|
||||
error = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the page number of this segment.
|
||||
*/
|
||||
pageno = trunc_page(uva);
|
||||
page_offset = uva - pageno;
|
||||
|
||||
/*
|
||||
* How many bytes to copy
|
||||
*/
|
||||
len = min(PAGE_SIZE - page_offset, uio->uio_resid);
|
||||
|
||||
/*
|
||||
* The map we want...
|
||||
*/
|
||||
map = &p->p_vmspace->vm_map;
|
||||
|
||||
/*
|
||||
* Check the permissions for the area we're interested
|
||||
* in.
|
||||
*/
|
||||
fix_prot = 0;
|
||||
if (writing)
|
||||
fix_prot = !vm_map_check_protection(map, pageno,
|
||||
pageno + PAGE_SIZE, VM_PROT_WRITE);
|
||||
|
||||
if (fix_prot) {
|
||||
/*
|
||||
* If the page is not writable, we make it so.
|
||||
* XXX It is possible that a page may *not* be
|
||||
* read/executable, if a process changes that!
|
||||
* We will assume, for now, that a page is either
|
||||
* VM_PROT_ALL, or VM_PROT_READ|VM_PROT_EXECUTE.
|
||||
*/
|
||||
error = vm_map_protect(map, pageno,
|
||||
pageno + PAGE_SIZE, VM_PROT_ALL, 0);
|
||||
if (error)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we need to get the page. out_entry, out_prot, wired,
|
||||
* and single_use aren't used. One would think the vm code
|
||||
* would be a *bit* nicer... We use tmap because
|
||||
* vm_map_lookup() can change the map argument.
|
||||
*/
|
||||
tmap = map;
|
||||
error = vm_map_lookup(&tmap, pageno,
|
||||
writing ? VM_PROT_WRITE : VM_PROT_READ,
|
||||
&out_entry, &object, &off, &out_prot,
|
||||
&wired, &single_use);
|
||||
/*
|
||||
* We're done with tmap now.
|
||||
*/
|
||||
if (!error)
|
||||
vm_map_lookup_done(tmap, out_entry);
|
||||
|
||||
/*
|
||||
* Fault the page in...
|
||||
*/
|
||||
if (!error && writing && object->shadow) {
|
||||
m = vm_page_lookup(object, off);
|
||||
if (m == 0 || (m->flags & PG_COPYONWRITE))
|
||||
error = vm_fault(map, pageno,
|
||||
VM_PROT_WRITE, FALSE);
|
||||
}
|
||||
|
||||
/* Find space in kernel_map for the page we're interested in */
|
||||
if (!error)
|
||||
error = vm_map_find(kernel_map, object, off, &kva,
|
||||
PAGE_SIZE, 1);
|
||||
|
||||
if (!error) {
|
||||
/*
|
||||
* Neither vm_map_lookup() nor vm_map_find() appear
|
||||
* to add a reference count to the object, so we do
|
||||
* that here and now.
|
||||
*/
|
||||
vm_object_reference(object);
|
||||
|
||||
/*
|
||||
* Mark the page we just found as pageable.
|
||||
*/
|
||||
error = vm_map_pageable(kernel_map, kva,
|
||||
kva + PAGE_SIZE, 0);
|
||||
|
||||
/*
|
||||
* Now do the i/o move.
|
||||
*/
|
||||
if (!error)
|
||||
error = uiomove(kva + page_offset, len, uio);
|
||||
|
||||
vm_map_remove(kernel_map, kva, kva + PAGE_SIZE);
|
||||
}
|
||||
if (fix_prot)
|
||||
vm_map_protect(map, pageno, pageno + PAGE_SIZE,
|
||||
VM_PROT_READ|VM_PROT_EXECUTE, 0);
|
||||
} while (error == 0 && uio->uio_resid > 0);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy data in and out of the target process.
|
||||
* We do this by mapping the process's page into
|
||||
* the kernel and then doing a uiomove direct
|
||||
* from the kernel address space.
|
||||
*/
|
||||
int
|
||||
procfs_domem(curp, p, pfs, uio)
|
||||
struct proc *curp;
|
||||
struct proc *p;
|
||||
struct pfsnode *pfs;
|
||||
struct uio *uio;
|
||||
{
|
||||
|
||||
if (uio->uio_resid == 0)
|
||||
return (0);
|
||||
|
||||
return (procfs_rwmem(p, uio));
|
||||
}
|
||||
|
||||
/*
|
||||
* Given process (p), find the vnode from which
|
||||
* it's text segment is being executed.
|
||||
*
|
||||
* It would be nice to grab this information from
|
||||
* the VM system, however, there is no sure-fire
|
||||
* way of doing that. Instead, fork(), exec() and
|
||||
* wait() all maintain the p_textvp field in the
|
||||
* process proc structure which contains a held
|
||||
* reference to the exec'ed vnode.
|
||||
*/
|
||||
struct vnode *
|
||||
procfs_findtextvp(p)
|
||||
struct proc *p;
|
||||
{
|
||||
|
||||
return (p->p_textvp);
|
||||
}
|
||||
|
||||
|
||||
#ifdef probably_never
|
||||
/*
|
||||
* Given process (p), find the vnode from which
|
||||
* it's text segment is being mapped.
|
||||
*
|
||||
* (This is here, rather than in procfs_subr in order
|
||||
* to keep all the VM related code in one place.)
|
||||
*/
|
||||
struct vnode *
|
||||
procfs_findtextvp(p)
|
||||
struct proc *p;
|
||||
{
|
||||
int error;
|
||||
vm_object_t object;
|
||||
vm_offset_t pageno; /* page number */
|
||||
|
||||
/* find a vnode pager for the user address space */
|
||||
|
||||
for (pageno = VM_MIN_ADDRESS;
|
||||
pageno < VM_MAXUSER_ADDRESS;
|
||||
pageno += PAGE_SIZE) {
|
||||
vm_map_t map;
|
||||
vm_map_entry_t out_entry;
|
||||
vm_prot_t out_prot;
|
||||
boolean_t wired, single_use;
|
||||
vm_offset_t off;
|
||||
|
||||
map = &p->p_vmspace->vm_map;
|
||||
error = vm_map_lookup(&map, pageno,
|
||||
VM_PROT_READ,
|
||||
&out_entry, &object, &off, &out_prot,
|
||||
&wired, &single_use);
|
||||
|
||||
if (!error) {
|
||||
vm_pager_t pager;
|
||||
|
||||
printf("procfs: found vm object\n");
|
||||
vm_map_lookup_done(map, out_entry);
|
||||
printf("procfs: vm object = %x\n", object);
|
||||
|
||||
/*
|
||||
* At this point, assuming no errors, object
|
||||
* is the VM object mapping UVA (pageno).
|
||||
* Ensure it has a vnode pager, then grab
|
||||
* the vnode from that pager's handle.
|
||||
*/
|
||||
|
||||
pager = object->pager;
|
||||
printf("procfs: pager = %x\n", pager);
|
||||
if (pager)
|
||||
printf("procfs: found pager, type = %d\n", pager->pg_type);
|
||||
if (pager && pager->pg_type == PG_VNODE) {
|
||||
struct vnode *vp;
|
||||
|
||||
vp = (struct vnode *) pager->pg_handle;
|
||||
printf("procfs: vp = 0x%x\n", vp);
|
||||
return (vp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("procfs: text object not found\n");
|
||||
return (0);
|
||||
}
|
||||
#endif /* probably_never */
|
||||
95
sys/miscfs/procfs/procfs_regs.c
Normal file
95
sys/miscfs/procfs/procfs_regs.c
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 1993 Jan-Simon Pendry
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)procfs_regs.c 8.4 (Berkeley) 6/15/94
|
||||
*
|
||||
* From:
|
||||
* $Id: procfs_regs.c,v 3.2 1993/12/15 09:40:17 jsp Exp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <machine/reg.h>
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
|
||||
int
|
||||
procfs_doregs(curp, p, pfs, uio)
|
||||
struct proc *curp;
|
||||
struct proc *p;
|
||||
struct pfsnode *pfs;
|
||||
struct uio *uio;
|
||||
{
|
||||
int error;
|
||||
struct reg r;
|
||||
char *kv;
|
||||
int kl;
|
||||
|
||||
kl = sizeof(r);
|
||||
kv = (char *) &r;
|
||||
|
||||
kv += uio->uio_offset;
|
||||
kl -= uio->uio_offset;
|
||||
if (kl > uio->uio_resid)
|
||||
kl = uio->uio_resid;
|
||||
|
||||
if (kl < 0)
|
||||
error = EINVAL;
|
||||
else
|
||||
error = procfs_read_regs(p, &r);
|
||||
if (error == 0)
|
||||
error = uiomove(kv, kl, uio);
|
||||
if (error == 0 && uio->uio_rw == UIO_WRITE) {
|
||||
if (p->p_stat != SSTOP)
|
||||
error = EBUSY;
|
||||
else
|
||||
error = procfs_write_regs(p, &r);
|
||||
}
|
||||
|
||||
uio->uio_offset = 0;
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
procfs_validregs(p)
|
||||
struct proc *p;
|
||||
{
|
||||
|
||||
return ((p->p_flag & P_SYSTEM) == 0);
|
||||
}
|
||||
145
sys/miscfs/procfs/procfs_status.c
Normal file
145
sys/miscfs/procfs/procfs_status.c
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright (c) 1993 Jan-Simon Pendry
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)procfs_status.c 8.4 (Berkeley) 6/15/94
|
||||
*
|
||||
* From:
|
||||
* $Id: procfs_status.c,v 3.1 1993/12/15 09:40:17 jsp Exp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/tty.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/resourcevar.h>
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
|
||||
int
|
||||
procfs_dostatus(curp, p, pfs, uio)
|
||||
struct proc *curp;
|
||||
struct proc *p;
|
||||
struct pfsnode *pfs;
|
||||
struct uio *uio;
|
||||
{
|
||||
struct session *sess;
|
||||
struct tty *tp;
|
||||
struct ucred *cr;
|
||||
char *ps;
|
||||
char *sep;
|
||||
int pid, ppid, pgid, sid;
|
||||
int i;
|
||||
int xlen;
|
||||
int error;
|
||||
char psbuf[256]; /* XXX - conservative */
|
||||
|
||||
if (uio->uio_rw != UIO_READ)
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
pid = p->p_pid;
|
||||
ppid = p->p_pptr ? p->p_pptr->p_pid : 0,
|
||||
pgid = p->p_pgrp->pg_id;
|
||||
sess = p->p_pgrp->pg_session;
|
||||
sid = sess->s_leader ? sess->s_leader->p_pid : 0;
|
||||
|
||||
/* comm pid ppid pgid sid maj,min ctty,sldr start ut st wmsg uid groups ... */
|
||||
|
||||
ps = psbuf;
|
||||
bcopy(p->p_comm, ps, MAXCOMLEN);
|
||||
ps[MAXCOMLEN] = '\0';
|
||||
ps += strlen(ps);
|
||||
ps += sprintf(ps, " %d %d %d %d ", pid, ppid, pgid, sid);
|
||||
|
||||
if ((p->p_flag&P_CONTROLT) && (tp = sess->s_ttyp))
|
||||
ps += sprintf(ps, "%d,%d ", major(tp->t_dev), minor(tp->t_dev));
|
||||
else
|
||||
ps += sprintf(ps, "%d,%d ", -1, -1);
|
||||
|
||||
sep = "";
|
||||
if (sess->s_ttyvp) {
|
||||
ps += sprintf(ps, "%sctty", sep);
|
||||
sep = ",";
|
||||
}
|
||||
if (SESS_LEADER(p)) {
|
||||
ps += sprintf(ps, "%ssldr", sep);
|
||||
sep = ",";
|
||||
}
|
||||
if (*sep != ',')
|
||||
ps += sprintf(ps, "noflags");
|
||||
|
||||
if (p->p_flag & P_INMEM)
|
||||
ps += sprintf(ps, " %d,%d",
|
||||
p->p_stats->p_start.tv_sec,
|
||||
p->p_stats->p_start.tv_usec);
|
||||
else
|
||||
ps += sprintf(ps, " -1,-1");
|
||||
|
||||
{
|
||||
struct timeval ut, st;
|
||||
|
||||
calcru(p, &ut, &st, (void *) 0);
|
||||
ps += sprintf(ps, " %d,%d %d,%d",
|
||||
ut.tv_sec,
|
||||
ut.tv_usec,
|
||||
st.tv_sec,
|
||||
st.tv_usec);
|
||||
}
|
||||
|
||||
ps += sprintf(ps, " %s",
|
||||
(p->p_wchan && p->p_wmesg) ? p->p_wmesg : "nochan");
|
||||
|
||||
cr = p->p_ucred;
|
||||
|
||||
ps += sprintf(ps, " %d", cr->cr_uid);
|
||||
for (i = 0; i < cr->cr_ngroups; i++)
|
||||
ps += sprintf(ps, ",%d", cr->cr_groups[i]);
|
||||
ps += sprintf(ps, "\n");
|
||||
|
||||
xlen = ps - psbuf;
|
||||
xlen -= uio->uio_offset;
|
||||
ps = psbuf + uio->uio_offset;
|
||||
xlen = imin(xlen, uio->uio_resid);
|
||||
if (xlen <= 0)
|
||||
error = 0;
|
||||
else
|
||||
error = uiomove(ps, xlen, uio);
|
||||
|
||||
return (error);
|
||||
}
|
||||
314
sys/miscfs/procfs/procfs_subr.c
Normal file
314
sys/miscfs/procfs/procfs_subr.c
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
/*
|
||||
* Copyright (c) 1993 Jan-Simon Pendry
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)procfs_subr.c 8.6 (Berkeley) 5/14/95
|
||||
*
|
||||
* From:
|
||||
* $Id: procfs_subr.c,v 3.2 1993/12/15 09:40:17 jsp Exp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
|
||||
static struct pfsnode *pfshead;
|
||||
static int pfsvplock;
|
||||
|
||||
/*
|
||||
* allocate a pfsnode/vnode pair. the vnode is
|
||||
* referenced, but not locked.
|
||||
*
|
||||
* the pid, pfs_type, and mount point uniquely
|
||||
* identify a pfsnode. the mount point is needed
|
||||
* because someone might mount this filesystem
|
||||
* twice.
|
||||
*
|
||||
* all pfsnodes are maintained on a singly-linked
|
||||
* list. new nodes are only allocated when they cannot
|
||||
* be found on this list. entries on the list are
|
||||
* removed when the vfs reclaim entry is called.
|
||||
*
|
||||
* a single lock is kept for the entire list. this is
|
||||
* needed because the getnewvnode() function can block
|
||||
* waiting for a vnode to become free, in which case there
|
||||
* may be more than one process trying to get the same
|
||||
* vnode. this lock is only taken if we are going to
|
||||
* call getnewvnode, since the kernel itself is single-threaded.
|
||||
*
|
||||
* if an entry is found on the list, then call vget() to
|
||||
* take a reference. this is done because there may be
|
||||
* zero references to it and so it needs to removed from
|
||||
* the vnode free list.
|
||||
*/
|
||||
int
|
||||
procfs_allocvp(mp, vpp, pid, pfs_type)
|
||||
struct mount *mp;
|
||||
struct vnode **vpp;
|
||||
long pid;
|
||||
pfstype pfs_type;
|
||||
{
|
||||
struct proc *p = curproc; /* XXX */
|
||||
struct pfsnode *pfs;
|
||||
struct vnode *vp;
|
||||
struct pfsnode **pp;
|
||||
int error;
|
||||
|
||||
loop:
|
||||
for (pfs = pfshead; pfs != 0; pfs = pfs->pfs_next) {
|
||||
vp = PFSTOV(pfs);
|
||||
if (pfs->pfs_pid == pid &&
|
||||
pfs->pfs_type == pfs_type &&
|
||||
vp->v_mount == mp) {
|
||||
if (vget(vp, 0, p))
|
||||
goto loop;
|
||||
*vpp = vp;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* otherwise lock the vp list while we call getnewvnode
|
||||
* since that can block.
|
||||
*/
|
||||
if (pfsvplock & PROCFS_LOCKED) {
|
||||
pfsvplock |= PROCFS_WANT;
|
||||
sleep((caddr_t) &pfsvplock, PINOD);
|
||||
goto loop;
|
||||
}
|
||||
pfsvplock |= PROCFS_LOCKED;
|
||||
|
||||
if (error = getnewvnode(VT_PROCFS, mp, procfs_vnodeop_p, vpp))
|
||||
goto out;
|
||||
vp = *vpp;
|
||||
|
||||
MALLOC(pfs, void *, sizeof(struct pfsnode), M_TEMP, M_WAITOK);
|
||||
vp->v_data = pfs;
|
||||
|
||||
pfs->pfs_next = 0;
|
||||
pfs->pfs_pid = (pid_t) pid;
|
||||
pfs->pfs_type = pfs_type;
|
||||
pfs->pfs_vnode = vp;
|
||||
pfs->pfs_flags = 0;
|
||||
pfs->pfs_fileno = PROCFS_FILENO(pid, pfs_type);
|
||||
|
||||
switch (pfs_type) {
|
||||
case Proot: /* /proc = dr-xr-xr-x */
|
||||
pfs->pfs_mode = (VREAD|VEXEC) |
|
||||
(VREAD|VEXEC) >> 3 |
|
||||
(VREAD|VEXEC) >> 6;
|
||||
vp->v_type = VDIR;
|
||||
vp->v_flag = VROOT;
|
||||
break;
|
||||
|
||||
case Pcurproc: /* /proc/curproc = lr--r--r-- */
|
||||
pfs->pfs_mode = (VREAD) |
|
||||
(VREAD >> 3) |
|
||||
(VREAD >> 6);
|
||||
vp->v_type = VLNK;
|
||||
break;
|
||||
|
||||
case Pproc:
|
||||
pfs->pfs_mode = (VREAD|VEXEC) |
|
||||
(VREAD|VEXEC) >> 3 |
|
||||
(VREAD|VEXEC) >> 6;
|
||||
vp->v_type = VDIR;
|
||||
break;
|
||||
|
||||
case Pfile:
|
||||
case Pmem:
|
||||
case Pregs:
|
||||
case Pfpregs:
|
||||
pfs->pfs_mode = (VREAD|VWRITE);
|
||||
vp->v_type = VREG;
|
||||
break;
|
||||
|
||||
case Pctl:
|
||||
case Pnote:
|
||||
case Pnotepg:
|
||||
pfs->pfs_mode = (VWRITE);
|
||||
vp->v_type = VREG;
|
||||
break;
|
||||
|
||||
case Pstatus:
|
||||
pfs->pfs_mode = (VREAD) |
|
||||
(VREAD >> 3) |
|
||||
(VREAD >> 6);
|
||||
vp->v_type = VREG;
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("procfs_allocvp");
|
||||
}
|
||||
|
||||
/* add to procfs vnode list */
|
||||
for (pp = &pfshead; *pp; pp = &(*pp)->pfs_next)
|
||||
continue;
|
||||
*pp = pfs;
|
||||
|
||||
out:
|
||||
pfsvplock &= ~PROCFS_LOCKED;
|
||||
|
||||
if (pfsvplock & PROCFS_WANT) {
|
||||
pfsvplock &= ~PROCFS_WANT;
|
||||
wakeup((caddr_t) &pfsvplock);
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
procfs_freevp(vp)
|
||||
struct vnode *vp;
|
||||
{
|
||||
struct pfsnode **pfspp;
|
||||
struct pfsnode *pfs = VTOPFS(vp);
|
||||
|
||||
for (pfspp = &pfshead; *pfspp != 0; pfspp = &(*pfspp)->pfs_next) {
|
||||
if (*pfspp == pfs) {
|
||||
*pfspp = pfs->pfs_next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FREE(vp->v_data, M_TEMP);
|
||||
vp->v_data = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
procfs_rw(ap)
|
||||
struct vop_read_args *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct uio *uio = ap->a_uio;
|
||||
struct proc *curp = uio->uio_procp;
|
||||
struct pfsnode *pfs = VTOPFS(vp);
|
||||
struct proc *p;
|
||||
|
||||
p = PFIND(pfs->pfs_pid);
|
||||
if (p == 0)
|
||||
return (EINVAL);
|
||||
|
||||
switch (pfs->pfs_type) {
|
||||
case Pnote:
|
||||
case Pnotepg:
|
||||
return (procfs_donote(curp, p, pfs, uio));
|
||||
|
||||
case Pregs:
|
||||
return (procfs_doregs(curp, p, pfs, uio));
|
||||
|
||||
case Pfpregs:
|
||||
return (procfs_dofpregs(curp, p, pfs, uio));
|
||||
|
||||
case Pctl:
|
||||
return (procfs_doctl(curp, p, pfs, uio));
|
||||
|
||||
case Pstatus:
|
||||
return (procfs_dostatus(curp, p, pfs, uio));
|
||||
|
||||
case Pmem:
|
||||
return (procfs_domem(curp, p, pfs, uio));
|
||||
|
||||
default:
|
||||
return (EOPNOTSUPP);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a string from userland into (buf). Strip a trailing
|
||||
* nl character (to allow easy access from the shell).
|
||||
* The buffer should be *buflenp + 1 chars long. vfs_getuserstr
|
||||
* will automatically add a nul char at the end.
|
||||
*
|
||||
* Returns 0 on success or the following errors
|
||||
*
|
||||
* EINVAL: file offset is non-zero.
|
||||
* EMSGSIZE: message is longer than kernel buffer
|
||||
* EFAULT: user i/o buffer is not addressable
|
||||
*/
|
||||
int
|
||||
vfs_getuserstr(uio, buf, buflenp)
|
||||
struct uio *uio;
|
||||
char *buf;
|
||||
int *buflenp;
|
||||
{
|
||||
int xlen;
|
||||
int error;
|
||||
|
||||
if (uio->uio_offset != 0)
|
||||
return (EINVAL);
|
||||
|
||||
xlen = *buflenp;
|
||||
|
||||
/* must be able to read the whole string in one go */
|
||||
if (xlen < uio->uio_resid)
|
||||
return (EMSGSIZE);
|
||||
xlen = uio->uio_resid;
|
||||
|
||||
if (error = uiomove(buf, xlen, uio))
|
||||
return (error);
|
||||
|
||||
/* allow multiple writes without seeks */
|
||||
uio->uio_offset = 0;
|
||||
|
||||
/* cleanup string and remove trailing newline */
|
||||
buf[xlen] = '\0';
|
||||
xlen = strlen(buf);
|
||||
if (xlen > 0 && buf[xlen-1] == '\n')
|
||||
buf[--xlen] = '\0';
|
||||
*buflenp = xlen;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
vfs_namemap_t *
|
||||
vfs_findname(nm, buf, buflen)
|
||||
vfs_namemap_t *nm;
|
||||
char *buf;
|
||||
int buflen;
|
||||
{
|
||||
|
||||
for (; nm->nm_name; nm++)
|
||||
if (bcmp(buf, (char *) nm->nm_name, buflen+1) == 0)
|
||||
return (nm);
|
||||
|
||||
return (0);
|
||||
}
|
||||
193
sys/miscfs/procfs/procfs_vfsops.c
Normal file
193
sys/miscfs/procfs/procfs_vfsops.c
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* Copyright (c) 1993 Jan-Simon Pendry
|
||||
* Copyright (c) 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)procfs_vfsops.c 8.7 (Berkeley) 5/10/95
|
||||
*
|
||||
* From:
|
||||
* $Id: procfs_vfsops.c,v 3.1 1993/12/15 09:40:17 jsp Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* procfs VFS interface
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
#include <vm/vm.h> /* for PAGE_SIZE */
|
||||
|
||||
/*
|
||||
* VFS Operations.
|
||||
*
|
||||
* mount system call
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
procfs_mount(mp, path, data, ndp, p)
|
||||
struct mount *mp;
|
||||
char *path;
|
||||
caddr_t data;
|
||||
struct nameidata *ndp;
|
||||
struct proc *p;
|
||||
{
|
||||
u_int size;
|
||||
|
||||
if (UIO_MX & (UIO_MX-1)) {
|
||||
log(LOG_ERR, "procfs: invalid directory entry size");
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
if (mp->mnt_flag & MNT_UPDATE)
|
||||
return (EOPNOTSUPP);
|
||||
|
||||
mp->mnt_flag |= MNT_LOCAL;
|
||||
mp->mnt_data = 0;
|
||||
vfs_getnewfsid(mp);
|
||||
|
||||
(void) copyinstr(path, (caddr_t)mp->mnt_stat.f_mntonname, MNAMELEN, &size);
|
||||
bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
|
||||
|
||||
size = sizeof("procfs") - 1;
|
||||
bcopy("procfs", mp->mnt_stat.f_mntfromname, size);
|
||||
bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* unmount system call
|
||||
*/
|
||||
procfs_unmount(mp, mntflags, p)
|
||||
struct mount *mp;
|
||||
int mntflags;
|
||||
struct proc *p;
|
||||
{
|
||||
int error;
|
||||
int flags = 0;
|
||||
|
||||
if (mntflags & MNT_FORCE)
|
||||
flags |= FORCECLOSE;
|
||||
|
||||
if (error = vflush(mp, 0, flags))
|
||||
return (error);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
procfs_root(mp, vpp)
|
||||
struct mount *mp;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
|
||||
return (procfs_allocvp(mp, vpp, 0, Proot));
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
procfs_start(mp, flags, p)
|
||||
struct mount *mp;
|
||||
int flags;
|
||||
struct proc *p;
|
||||
{
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get file system statistics.
|
||||
*/
|
||||
procfs_statfs(mp, sbp, p)
|
||||
struct mount *mp;
|
||||
struct statfs *sbp;
|
||||
struct proc *p;
|
||||
{
|
||||
sbp->f_bsize = PAGE_SIZE;
|
||||
sbp->f_iosize = PAGE_SIZE;
|
||||
sbp->f_blocks = 1; /* avoid divide by zero in some df's */
|
||||
sbp->f_bfree = 0;
|
||||
sbp->f_bavail = 0;
|
||||
sbp->f_files = maxproc; /* approx */
|
||||
sbp->f_ffree = maxproc - nprocs; /* approx */
|
||||
|
||||
if (sbp != &mp->mnt_stat) {
|
||||
sbp->f_type = mp->mnt_vfc->vfc_typenum;
|
||||
bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
|
||||
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
|
||||
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
procfs_init(vfsp)
|
||||
struct vfsconf *vfsp;
|
||||
{
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#define procfs_fhtovp ((int (*) __P((struct mount *, struct fid *, \
|
||||
struct mbuf *, struct vnode **, int *, struct ucred **)))einval)
|
||||
#define procfs_quotactl ((int (*) __P((struct mount *, int, uid_t, caddr_t, \
|
||||
struct proc *)))eopnotsupp)
|
||||
#define procfs_sync ((int (*) __P((struct mount *, int, struct ucred *, \
|
||||
struct proc *)))nullop)
|
||||
#define procfs_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \
|
||||
size_t, struct proc *)))eopnotsupp)
|
||||
#define procfs_vget ((int (*) __P((struct mount *, ino_t, struct vnode **))) \
|
||||
eopnotsupp)
|
||||
#define procfs_vptofh ((int (*) __P((struct vnode *, struct fid *)))einval)
|
||||
|
||||
struct vfsops procfs_vfsops = {
|
||||
procfs_mount,
|
||||
procfs_start,
|
||||
procfs_unmount,
|
||||
procfs_root,
|
||||
procfs_quotactl,
|
||||
procfs_statfs,
|
||||
procfs_sync,
|
||||
procfs_vget,
|
||||
procfs_fhtovp,
|
||||
procfs_vptofh,
|
||||
procfs_init,
|
||||
procfs_sysctl,
|
||||
};
|
||||
929
sys/miscfs/procfs/procfs_vnops.c
Normal file
929
sys/miscfs/procfs/procfs_vnops.c
Normal file
|
|
@ -0,0 +1,929 @@
|
|||
/*
|
||||
* Copyright (c) 1993, 1995 Jan-Simon Pendry
|
||||
* Copyright (c) 1993, 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)procfs_vnops.c 8.18 (Berkeley) 5/21/95
|
||||
*
|
||||
* From:
|
||||
* $Id: procfs_vnops.c,v 3.2 1993/12/15 09:40:17 jsp Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* procfs vnode interface
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/dirent.h>
|
||||
#include <sys/resourcevar.h>
|
||||
#include <vm/vm.h> /* for PAGE_SIZE */
|
||||
#include <machine/reg.h>
|
||||
#include <miscfs/procfs/procfs.h>
|
||||
|
||||
/*
|
||||
* Vnode Operations.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a list of the valid names in the
|
||||
* process-specific sub-directories. It is
|
||||
* used in procfs_lookup and procfs_readdir
|
||||
*/
|
||||
struct proc_target {
|
||||
u_char pt_type;
|
||||
u_char pt_namlen;
|
||||
char *pt_name;
|
||||
pfstype pt_pfstype;
|
||||
int (*pt_valid) __P((struct proc *p));
|
||||
} proc_targets[] = {
|
||||
#define N(s) sizeof(s)-1, s
|
||||
/* name type validp */
|
||||
{ DT_DIR, N("."), Pproc, NULL },
|
||||
{ DT_DIR, N(".."), Proot, NULL },
|
||||
{ DT_REG, N("file"), Pfile, procfs_validfile },
|
||||
{ DT_REG, N("mem"), Pmem, NULL },
|
||||
{ DT_REG, N("regs"), Pregs, procfs_validregs },
|
||||
{ DT_REG, N("fpregs"), Pfpregs, procfs_validfpregs },
|
||||
{ DT_REG, N("ctl"), Pctl, NULL },
|
||||
{ DT_REG, N("status"), Pstatus, NULL },
|
||||
{ DT_REG, N("note"), Pnote, NULL },
|
||||
{ DT_REG, N("notepg"), Pnotepg, NULL },
|
||||
#undef N
|
||||
};
|
||||
static int nproc_targets = sizeof(proc_targets) / sizeof(proc_targets[0]);
|
||||
|
||||
static pid_t atopid __P((const char *, u_int));
|
||||
|
||||
/*
|
||||
* set things up for doing i/o on
|
||||
* the pfsnode (vp). (vp) is locked
|
||||
* on entry, and should be left locked
|
||||
* on exit.
|
||||
*
|
||||
* for procfs we don't need to do anything
|
||||
* in particular for i/o. all that is done
|
||||
* is to support exclusive open on process
|
||||
* memory images.
|
||||
*/
|
||||
procfs_open(ap)
|
||||
struct vop_open_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_mode;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct pfsnode *pfs = VTOPFS(ap->a_vp);
|
||||
|
||||
switch (pfs->pfs_type) {
|
||||
case Pmem:
|
||||
if (PFIND(pfs->pfs_pid) == 0)
|
||||
return (ENOENT); /* was ESRCH, jsp */
|
||||
|
||||
if ((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL) ||
|
||||
(pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE))
|
||||
return (EBUSY);
|
||||
|
||||
if (ap->a_mode & FWRITE)
|
||||
pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL);
|
||||
|
||||
return (0);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* close the pfsnode (vp) after doing i/o.
|
||||
* (vp) is not locked on entry or exit.
|
||||
*
|
||||
* nothing to do for procfs other than undo
|
||||
* any exclusive open flag (see _open above).
|
||||
*/
|
||||
procfs_close(ap)
|
||||
struct vop_close_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_fflag;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct pfsnode *pfs = VTOPFS(ap->a_vp);
|
||||
|
||||
switch (pfs->pfs_type) {
|
||||
case Pmem:
|
||||
if ((ap->a_fflag & FWRITE) && (pfs->pfs_flags & O_EXCL))
|
||||
pfs->pfs_flags &= ~(FWRITE|O_EXCL);
|
||||
break;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* do an ioctl operation on pfsnode (vp).
|
||||
* (vp) is not locked on entry or exit.
|
||||
*/
|
||||
procfs_ioctl(ap)
|
||||
struct vop_ioctl_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_command;
|
||||
caddr_t a_data;
|
||||
int a_fflag;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
return (ENOTTY);
|
||||
}
|
||||
|
||||
/*
|
||||
* do block mapping for pfsnode (vp).
|
||||
* since we don't use the buffer cache
|
||||
* for procfs this function should never
|
||||
* be called. in any case, it's not clear
|
||||
* what part of the kernel ever makes use
|
||||
* of this function. for sanity, this is the
|
||||
* usual no-op bmap, although returning
|
||||
* (EIO) would be a reasonable alternative.
|
||||
*/
|
||||
procfs_bmap(ap)
|
||||
struct vop_bmap_args /* {
|
||||
struct vnode *a_vp;
|
||||
daddr_t a_bn;
|
||||
struct vnode **a_vpp;
|
||||
daddr_t *a_bnp;
|
||||
int *a_runp;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
if (ap->a_vpp != NULL)
|
||||
*ap->a_vpp = ap->a_vp;
|
||||
if (ap->a_bnp != NULL)
|
||||
*ap->a_bnp = ap->a_bn;
|
||||
if (ap->a_runp != NULL)
|
||||
*ap->a_runp = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* procfs_inactive is called when the pfsnode
|
||||
* is vrele'd and the reference count goes
|
||||
* to zero. (vp) will be on the vnode free
|
||||
* list, so to get it back vget() must be
|
||||
* used.
|
||||
*
|
||||
* for procfs, check if the process is still
|
||||
* alive and if it isn't then just throw away
|
||||
* the vnode by calling vgone(). this may
|
||||
* be overkill and a waste of time since the
|
||||
* chances are that the process will still be
|
||||
* there and PFIND is not free.
|
||||
*
|
||||
* (vp) is locked on entry, but must be unlocked on exit.
|
||||
*/
|
||||
procfs_inactive(ap)
|
||||
struct vop_inactive_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct pfsnode *pfs = VTOPFS(vp);
|
||||
|
||||
VOP_UNLOCK(vp, 0, ap->a_p);
|
||||
if (PFIND(pfs->pfs_pid) == 0)
|
||||
vgone(vp);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* _reclaim is called when getnewvnode()
|
||||
* wants to make use of an entry on the vnode
|
||||
* free list. at this time the filesystem needs
|
||||
* to free any private data and remove the node
|
||||
* from any private lists.
|
||||
*/
|
||||
procfs_reclaim(ap)
|
||||
struct vop_reclaim_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
return (procfs_freevp(ap->a_vp));
|
||||
}
|
||||
|
||||
/*
|
||||
* Return POSIX pathconf information applicable to special devices.
|
||||
*/
|
||||
procfs_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 */
|
||||
}
|
||||
|
||||
/*
|
||||
* _print is used for debugging.
|
||||
* just print a readable description
|
||||
* of (vp).
|
||||
*/
|
||||
procfs_print(ap)
|
||||
struct vop_print_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct pfsnode *pfs = VTOPFS(ap->a_vp);
|
||||
|
||||
printf("tag VT_PROCFS, type %s, pid %d, mode %x, flags %x\n",
|
||||
pfs->pfs_type, pfs->pfs_pid, pfs->pfs_mode, pfs->pfs_flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* _abortop is called when operations such as
|
||||
* rename and create fail. this entry is responsible
|
||||
* for undoing any side-effects caused by the lookup.
|
||||
* this will always include freeing the pathname buffer.
|
||||
*/
|
||||
procfs_abortop(ap)
|
||||
struct vop_abortop_args /* {
|
||||
struct vnode *a_dvp;
|
||||
struct componentname *a_cnp;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
|
||||
FREE(ap->a_cnp->cn_pnbuf, M_NAMEI);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* generic entry point for unsupported operations
|
||||
*/
|
||||
procfs_badop()
|
||||
{
|
||||
|
||||
return (EIO);
|
||||
}
|
||||
|
||||
/*
|
||||
* Invent attributes for pfsnode (vp) and store
|
||||
* them in (vap).
|
||||
* Directories lengths are returned as zero since
|
||||
* any real length would require the genuine size
|
||||
* to be computed, and nothing cares anyway.
|
||||
*
|
||||
* this is relatively minimal for procfs.
|
||||
*/
|
||||
procfs_getattr(ap)
|
||||
struct vop_getattr_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct vattr *a_vap;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct pfsnode *pfs = VTOPFS(ap->a_vp);
|
||||
struct vattr *vap = ap->a_vap;
|
||||
struct proc *procp;
|
||||
struct timeval tv;
|
||||
int error;
|
||||
|
||||
/* first check the process still exists */
|
||||
switch (pfs->pfs_type) {
|
||||
case Proot:
|
||||
case Pcurproc:
|
||||
procp = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
procp = PFIND(pfs->pfs_pid);
|
||||
if (procp == 0)
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
error = 0;
|
||||
|
||||
/* start by zeroing out the attributes */
|
||||
VATTR_NULL(vap);
|
||||
|
||||
/* next do all the common fields */
|
||||
vap->va_type = ap->a_vp->v_type;
|
||||
vap->va_mode = pfs->pfs_mode;
|
||||
vap->va_fileid = pfs->pfs_fileno;
|
||||
vap->va_flags = 0;
|
||||
vap->va_blocksize = PAGE_SIZE;
|
||||
vap->va_bytes = vap->va_size = 0;
|
||||
|
||||
/*
|
||||
* Make all times be current TOD.
|
||||
* It would be possible to get the process start
|
||||
* time from the p_stat structure, but there's
|
||||
* no "file creation" time stamp anyway, and the
|
||||
* p_stat structure is not addressible if u. gets
|
||||
* swapped out for that process.
|
||||
*/
|
||||
microtime(&tv);
|
||||
TIMEVAL_TO_TIMESPEC(&tv, &vap->va_ctime);
|
||||
vap->va_atime = vap->va_mtime = vap->va_ctime;
|
||||
|
||||
/*
|
||||
* If the process has exercised some setuid or setgid
|
||||
* privilege, then rip away read/write permission so
|
||||
* that only root can gain access.
|
||||
*/
|
||||
switch (pfs->pfs_type) {
|
||||
case Pmem:
|
||||
case Pregs:
|
||||
case Pfpregs:
|
||||
if (procp->p_flag & P_SUGID)
|
||||
vap->va_mode &= ~((VREAD|VWRITE)|
|
||||
((VREAD|VWRITE)>>3)|
|
||||
((VREAD|VWRITE)>>6));
|
||||
case Pctl:
|
||||
case Pstatus:
|
||||
case Pnote:
|
||||
case Pnotepg:
|
||||
vap->va_nlink = 1;
|
||||
vap->va_uid = procp->p_ucred->cr_uid;
|
||||
vap->va_gid = procp->p_ucred->cr_gid;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* now do the object specific fields
|
||||
*
|
||||
* The size could be set from struct reg, but it's hardly
|
||||
* worth the trouble, and it puts some (potentially) machine
|
||||
* dependent data into this machine-independent code. If it
|
||||
* becomes important then this function should break out into
|
||||
* a per-file stat function in the corresponding .c file.
|
||||
*/
|
||||
|
||||
switch (pfs->pfs_type) {
|
||||
case Proot:
|
||||
/*
|
||||
* Set nlink to 1 to tell fts(3) we don't actually know.
|
||||
*/
|
||||
vap->va_nlink = 1;
|
||||
vap->va_uid = 0;
|
||||
vap->va_gid = 0;
|
||||
vap->va_size = vap->va_bytes = DEV_BSIZE;
|
||||
break;
|
||||
|
||||
case Pcurproc: {
|
||||
char buf[16]; /* should be enough */
|
||||
vap->va_nlink = 1;
|
||||
vap->va_uid = 0;
|
||||
vap->va_gid = 0;
|
||||
vap->va_size = vap->va_bytes =
|
||||
sprintf(buf, "%ld", (long)curproc->p_pid);
|
||||
break;
|
||||
}
|
||||
|
||||
case Pproc:
|
||||
vap->va_nlink = 2;
|
||||
vap->va_uid = procp->p_ucred->cr_uid;
|
||||
vap->va_gid = procp->p_ucred->cr_gid;
|
||||
vap->va_size = vap->va_bytes = DEV_BSIZE;
|
||||
break;
|
||||
|
||||
case Pfile:
|
||||
error = EOPNOTSUPP;
|
||||
break;
|
||||
|
||||
case Pmem:
|
||||
vap->va_bytes = vap->va_size =
|
||||
ctob(procp->p_vmspace->vm_tsize +
|
||||
procp->p_vmspace->vm_dsize +
|
||||
procp->p_vmspace->vm_ssize);
|
||||
break;
|
||||
|
||||
case Pregs:
|
||||
vap->va_bytes = vap->va_size = sizeof(struct reg);
|
||||
break;
|
||||
|
||||
case Pfpregs:
|
||||
vap->va_bytes = vap->va_size = sizeof(struct fpreg);
|
||||
break;
|
||||
|
||||
case Pctl:
|
||||
case Pstatus:
|
||||
case Pnote:
|
||||
case Pnotepg:
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("procfs_getattr");
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
procfs_setattr(ap)
|
||||
struct vop_setattr_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct vattr *a_vap;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
/*
|
||||
* just fake out attribute setting
|
||||
* it's not good to generate an error
|
||||
* return, otherwise things like creat()
|
||||
* will fail when they try to set the
|
||||
* file length to 0. worse, this means
|
||||
* that echo $note > /proc/$pid/note will fail.
|
||||
*/
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* implement access checking.
|
||||
*
|
||||
* something very similar to this code is duplicated
|
||||
* throughout the 4bsd kernel and should be moved
|
||||
* into kern/vfs_subr.c sometime.
|
||||
*
|
||||
* actually, the check for super-user is slightly
|
||||
* broken since it will allow read access to write-only
|
||||
* objects. this doesn't cause any particular trouble
|
||||
* but does mean that the i/o entry points need to check
|
||||
* that the operation really does make sense.
|
||||
*/
|
||||
procfs_access(ap)
|
||||
struct vop_access_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_mode;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vattr *vap;
|
||||
struct vattr vattr;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* If you're the super-user,
|
||||
* you always get access.
|
||||
*/
|
||||
if (ap->a_cred->cr_uid == 0)
|
||||
return (0);
|
||||
|
||||
vap = &vattr;
|
||||
if (error = VOP_GETATTR(ap->a_vp, vap, ap->a_cred, ap->a_p))
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Access check is based on only one of owner, group, public.
|
||||
* If not owner, then check group. If not a member of the
|
||||
* group, then check public access.
|
||||
*/
|
||||
if (ap->a_cred->cr_uid != vap->va_uid) {
|
||||
gid_t *gp;
|
||||
int i;
|
||||
|
||||
ap->a_mode >>= 3;
|
||||
gp = ap->a_cred->cr_groups;
|
||||
for (i = 0; i < ap->a_cred->cr_ngroups; i++, gp++)
|
||||
if (vap->va_gid == *gp)
|
||||
goto found;
|
||||
ap->a_mode >>= 3;
|
||||
found:
|
||||
;
|
||||
}
|
||||
|
||||
if ((vap->va_mode & ap->a_mode) == ap->a_mode)
|
||||
return (0);
|
||||
|
||||
return (EACCES);
|
||||
}
|
||||
|
||||
/*
|
||||
* lookup. this is incredibly complicated in the
|
||||
* general case, however for most pseudo-filesystems
|
||||
* very little needs to be done.
|
||||
*
|
||||
* unless you want to get a migraine, just make sure your
|
||||
* filesystem doesn't do any locking of its own. otherwise
|
||||
* read and inwardly digest ufs_lookup().
|
||||
*/
|
||||
procfs_lookup(ap)
|
||||
struct vop_lookup_args /* {
|
||||
struct vnode * a_dvp;
|
||||
struct vnode ** a_vpp;
|
||||
struct componentname * a_cnp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct componentname *cnp = ap->a_cnp;
|
||||
struct vnode **vpp = ap->a_vpp;
|
||||
struct vnode *dvp = ap->a_dvp;
|
||||
char *pname = cnp->cn_nameptr;
|
||||
struct proc *curp = cnp->cn_proc;
|
||||
int error = 0;
|
||||
struct proc_target *pt;
|
||||
struct vnode *fvp;
|
||||
pid_t pid;
|
||||
struct pfsnode *pfs;
|
||||
struct proc *p;
|
||||
int i;
|
||||
|
||||
*vpp = NULL;
|
||||
|
||||
if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
|
||||
return (EROFS);
|
||||
|
||||
if (cnp->cn_namelen == 1 && *pname == '.') {
|
||||
*vpp = dvp;
|
||||
VREF(dvp);
|
||||
/* vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, curp); */
|
||||
return (0);
|
||||
}
|
||||
|
||||
pfs = VTOPFS(dvp);
|
||||
switch (pfs->pfs_type) {
|
||||
case Proot:
|
||||
if (cnp->cn_flags & ISDOTDOT)
|
||||
return (EIO);
|
||||
|
||||
if (CNEQ(cnp, "curproc", 7))
|
||||
return (procfs_allocvp(dvp->v_mount, vpp, 0, Pcurproc));
|
||||
|
||||
pid = atopid(pname, cnp->cn_namelen);
|
||||
if (pid == NO_PID)
|
||||
break;
|
||||
|
||||
p = PFIND(pid);
|
||||
if (p == 0)
|
||||
break;
|
||||
|
||||
return (procfs_allocvp(dvp->v_mount, vpp, pid, Pproc));
|
||||
|
||||
case Pproc:
|
||||
if (cnp->cn_flags & ISDOTDOT)
|
||||
return (procfs_root(dvp->v_mount, vpp));
|
||||
|
||||
p = PFIND(pfs->pfs_pid);
|
||||
if (p == 0)
|
||||
break;
|
||||
|
||||
for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) {
|
||||
if (cnp->cn_namelen == pt->pt_namlen &&
|
||||
bcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 &&
|
||||
(pt->pt_valid == NULL || (*pt->pt_valid)(p)))
|
||||
goto found;
|
||||
}
|
||||
break;
|
||||
|
||||
found:
|
||||
if (pt->pt_pfstype == Pfile) {
|
||||
fvp = procfs_findtextvp(p);
|
||||
/* We already checked that it exists. */
|
||||
VREF(fvp);
|
||||
vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, curp);
|
||||
*vpp = fvp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid,
|
||||
pt->pt_pfstype));
|
||||
|
||||
default:
|
||||
return (ENOTDIR);
|
||||
}
|
||||
|
||||
return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS);
|
||||
}
|
||||
|
||||
int
|
||||
procfs_validfile(p)
|
||||
struct proc *p;
|
||||
{
|
||||
|
||||
return (procfs_findtextvp(p) != NULLVP);
|
||||
}
|
||||
|
||||
/*
|
||||
* readdir returns directory entries from pfsnode (vp).
|
||||
*
|
||||
* the strategy here with procfs is to generate a single
|
||||
* directory entry at a time (struct pfsdent) and then
|
||||
* copy that out to userland using uiomove. a more efficent
|
||||
* though more complex implementation, would try to minimize
|
||||
* the number of calls to uiomove(). for procfs, this is
|
||||
* hardly worth the added code complexity.
|
||||
*
|
||||
* this should just be done through read()
|
||||
*/
|
||||
procfs_readdir(ap)
|
||||
struct vop_readdir_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
struct ucred *a_cred;
|
||||
int *a_eofflag;
|
||||
u_long *a_cookies;
|
||||
int a_ncookies;
|
||||
} */ *ap;
|
||||
{
|
||||
struct uio *uio = ap->a_uio;
|
||||
struct pfsdent d;
|
||||
struct pfsdent *dp = &d;
|
||||
struct pfsnode *pfs;
|
||||
int error;
|
||||
int count;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* We don't allow exporting procfs mounts, and currently local
|
||||
* requests do not need cookies.
|
||||
*/
|
||||
if (ap->a_ncookies)
|
||||
panic("procfs_readdir: not hungry");
|
||||
|
||||
pfs = VTOPFS(ap->a_vp);
|
||||
|
||||
if (uio->uio_resid < UIO_MX)
|
||||
return (EINVAL);
|
||||
if (uio->uio_offset & (UIO_MX-1))
|
||||
return (EINVAL);
|
||||
if (uio->uio_offset < 0)
|
||||
return (EINVAL);
|
||||
|
||||
error = 0;
|
||||
count = 0;
|
||||
i = uio->uio_offset / UIO_MX;
|
||||
|
||||
switch (pfs->pfs_type) {
|
||||
/*
|
||||
* this is for the process-specific sub-directories.
|
||||
* all that is needed to is copy out all the entries
|
||||
* from the procent[] table (top of this file).
|
||||
*/
|
||||
case Pproc: {
|
||||
struct proc *p;
|
||||
struct proc_target *pt;
|
||||
|
||||
p = PFIND(pfs->pfs_pid);
|
||||
if (p == NULL)
|
||||
break;
|
||||
|
||||
for (pt = &proc_targets[i];
|
||||
uio->uio_resid >= UIO_MX && i < nproc_targets; pt++, i++) {
|
||||
if (pt->pt_valid && (*pt->pt_valid)(p) == 0)
|
||||
continue;
|
||||
|
||||
dp->d_reclen = UIO_MX;
|
||||
dp->d_fileno = PROCFS_FILENO(pfs->pfs_pid, pt->pt_pfstype);
|
||||
dp->d_namlen = pt->pt_namlen;
|
||||
bcopy(pt->pt_name, dp->d_name, pt->pt_namlen + 1);
|
||||
dp->d_type = pt->pt_type;
|
||||
|
||||
if (error = uiomove((caddr_t)dp, UIO_MX, uio))
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* this is for the root of the procfs filesystem
|
||||
* what is needed is a special entry for "curproc"
|
||||
* followed by an entry for each process on allproc
|
||||
#ifdef PROCFS_ZOMBIE
|
||||
* and zombproc.
|
||||
#endif
|
||||
*/
|
||||
|
||||
case Proot: {
|
||||
#ifdef PROCFS_ZOMBIE
|
||||
int doingzomb = 0;
|
||||
#endif
|
||||
int pcnt = 0;
|
||||
volatile struct proc *p = allproc.lh_first;
|
||||
|
||||
again:
|
||||
for (; p && uio->uio_resid >= UIO_MX; i++, pcnt++) {
|
||||
bzero((char *) dp, UIO_MX);
|
||||
dp->d_reclen = UIO_MX;
|
||||
|
||||
switch (i) {
|
||||
case 0: /* `.' */
|
||||
case 1: /* `..' */
|
||||
dp->d_fileno = PROCFS_FILENO(0, Proot);
|
||||
dp->d_namlen = i + 1;
|
||||
bcopy("..", dp->d_name, dp->d_namlen);
|
||||
dp->d_name[i + 1] = '\0';
|
||||
dp->d_type = DT_DIR;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
dp->d_fileno = PROCFS_FILENO(0, Pcurproc);
|
||||
dp->d_namlen = 7;
|
||||
bcopy("curproc", dp->d_name, 8);
|
||||
dp->d_type = DT_LNK;
|
||||
break;
|
||||
|
||||
default:
|
||||
while (pcnt < i) {
|
||||
pcnt++;
|
||||
p = p->p_list.le_next;
|
||||
if (!p)
|
||||
goto done;
|
||||
}
|
||||
dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc);
|
||||
dp->d_namlen = sprintf(dp->d_name, "%ld",
|
||||
(long)p->p_pid);
|
||||
dp->d_type = DT_REG;
|
||||
p = p->p_list.le_next;
|
||||
break;
|
||||
}
|
||||
|
||||
if (error = uiomove((caddr_t)dp, UIO_MX, uio))
|
||||
break;
|
||||
}
|
||||
done:
|
||||
|
||||
#ifdef PROCFS_ZOMBIE
|
||||
if (p == 0 && doingzomb == 0) {
|
||||
doingzomb = 1;
|
||||
p = zombproc.lh_first;
|
||||
goto again;
|
||||
}
|
||||
#endif
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
default:
|
||||
error = ENOTDIR;
|
||||
break;
|
||||
}
|
||||
|
||||
uio->uio_offset = i * UIO_MX;
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* readlink reads the link of `curproc'
|
||||
*/
|
||||
procfs_readlink(ap)
|
||||
struct vop_readlink_args *ap;
|
||||
{
|
||||
struct uio *uio = ap->a_uio;
|
||||
char buf[16]; /* should be enough */
|
||||
int len;
|
||||
|
||||
if (VTOPFS(ap->a_vp)->pfs_fileno != PROCFS_FILENO(0, Pcurproc))
|
||||
return (EINVAL);
|
||||
|
||||
len = sprintf(buf, "%ld", (long)curproc->p_pid);
|
||||
|
||||
return (uiomove((caddr_t)buf, len, ap->a_uio));
|
||||
}
|
||||
|
||||
/*
|
||||
* convert decimal ascii to pid_t
|
||||
*/
|
||||
static pid_t
|
||||
atopid(b, len)
|
||||
const char *b;
|
||||
u_int len;
|
||||
{
|
||||
pid_t p = 0;
|
||||
|
||||
while (len--) {
|
||||
char c = *b++;
|
||||
if (c < '0' || c > '9')
|
||||
return (NO_PID);
|
||||
p = 10 * p + (c - '0');
|
||||
if (p > PID_MAX)
|
||||
return (NO_PID);
|
||||
}
|
||||
|
||||
return (p);
|
||||
}
|
||||
|
||||
/*
|
||||
* procfs vnode operations.
|
||||
*/
|
||||
int (**procfs_vnodeop_p)();
|
||||
struct vnodeopv_entry_desc procfs_vnodeop_entries[] = {
|
||||
{ &vop_default_desc, vn_default_error },
|
||||
{ &vop_lookup_desc, procfs_lookup }, /* lookup */
|
||||
{ &vop_create_desc, procfs_create }, /* create */
|
||||
{ &vop_mknod_desc, procfs_mknod }, /* mknod */
|
||||
{ &vop_open_desc, procfs_open }, /* open */
|
||||
{ &vop_close_desc, procfs_close }, /* close */
|
||||
{ &vop_access_desc, procfs_access }, /* access */
|
||||
{ &vop_getattr_desc, procfs_getattr }, /* getattr */
|
||||
{ &vop_setattr_desc, procfs_setattr }, /* setattr */
|
||||
{ &vop_read_desc, procfs_read }, /* read */
|
||||
{ &vop_write_desc, procfs_write }, /* write */
|
||||
{ &vop_ioctl_desc, procfs_ioctl }, /* ioctl */
|
||||
{ &vop_select_desc, procfs_select }, /* select */
|
||||
{ &vop_mmap_desc, procfs_mmap }, /* mmap */
|
||||
{ &vop_revoke_desc, procfs_revoke }, /* revoke */
|
||||
{ &vop_fsync_desc, procfs_fsync }, /* fsync */
|
||||
{ &vop_seek_desc, procfs_seek }, /* seek */
|
||||
{ &vop_remove_desc, procfs_remove }, /* remove */
|
||||
{ &vop_link_desc, procfs_link }, /* link */
|
||||
{ &vop_rename_desc, procfs_rename }, /* rename */
|
||||
{ &vop_mkdir_desc, procfs_mkdir }, /* mkdir */
|
||||
{ &vop_rmdir_desc, procfs_rmdir }, /* rmdir */
|
||||
{ &vop_symlink_desc, procfs_symlink }, /* symlink */
|
||||
{ &vop_readdir_desc, procfs_readdir }, /* readdir */
|
||||
{ &vop_readlink_desc, procfs_readlink }, /* readlink */
|
||||
{ &vop_abortop_desc, procfs_abortop }, /* abortop */
|
||||
{ &vop_inactive_desc, procfs_inactive }, /* inactive */
|
||||
{ &vop_reclaim_desc, procfs_reclaim }, /* reclaim */
|
||||
{ &vop_lock_desc, procfs_lock }, /* lock */
|
||||
{ &vop_unlock_desc, procfs_unlock }, /* unlock */
|
||||
{ &vop_bmap_desc, procfs_bmap }, /* bmap */
|
||||
{ &vop_strategy_desc, procfs_strategy }, /* strategy */
|
||||
{ &vop_print_desc, procfs_print }, /* print */
|
||||
{ &vop_islocked_desc, procfs_islocked }, /* islocked */
|
||||
{ &vop_pathconf_desc, procfs_pathconf }, /* pathconf */
|
||||
{ &vop_advlock_desc, procfs_advlock }, /* advlock */
|
||||
{ &vop_blkatoff_desc, procfs_blkatoff }, /* blkatoff */
|
||||
{ &vop_valloc_desc, procfs_valloc }, /* valloc */
|
||||
{ &vop_vfree_desc, procfs_vfree }, /* vfree */
|
||||
{ &vop_truncate_desc, procfs_truncate }, /* truncate */
|
||||
{ &vop_update_desc, procfs_update }, /* update */
|
||||
{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
|
||||
};
|
||||
struct vnodeopv_desc procfs_vnodeop_opv_desc =
|
||||
{ &procfs_vnodeop_p, procfs_vnodeop_entries };
|
||||
686
sys/miscfs/specfs/spec_vnops.c
Normal file
686
sys/miscfs/specfs/spec_vnops.c
Normal file
|
|
@ -0,0 +1,686 @@
|
|||
/*
|
||||
* Copyright (c) 1989, 1993, 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.14 (Berkeley) 5/21/95
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/disklabel.h>
|
||||
#include <miscfs/specfs/specdev.h>
|
||||
|
||||
/* symbolic sleep message strings for devices */
|
||||
char devopn[] = "devopn";
|
||||
char devio[] = "devio";
|
||||
char devwait[] = "devwait";
|
||||
char devin[] = "devin";
|
||||
char devout[] = "devout";
|
||||
char devioc[] = "devioc";
|
||||
char devcls[] = "devcls";
|
||||
|
||||
int (**spec_vnodeop_p)();
|
||||
struct vnodeopv_entry_desc spec_vnodeop_entries[] = {
|
||||
{ &vop_default_desc, vn_default_error },
|
||||
{ &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_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_write_desc, spec_write }, /* write */
|
||||
{ &vop_lease_desc, spec_lease_check }, /* lease */
|
||||
{ &vop_ioctl_desc, spec_ioctl }, /* ioctl */
|
||||
{ &vop_select_desc, spec_select }, /* select */
|
||||
{ &vop_revoke_desc, spec_revoke }, /* revoke */
|
||||
{ &vop_mmap_desc, spec_mmap }, /* mmap */
|
||||
{ &vop_fsync_desc, spec_fsync }, /* fsync */
|
||||
{ &vop_seek_desc, spec_seek }, /* seek */
|
||||
{ &vop_remove_desc, spec_remove }, /* remove */
|
||||
{ &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_symlink_desc, spec_symlink }, /* symlink */
|
||||
{ &vop_readdir_desc, spec_readdir }, /* readdir */
|
||||
{ &vop_readlink_desc, spec_readlink }, /* readlink */
|
||||
{ &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_unlock_desc, spec_unlock }, /* unlock */
|
||||
{ &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_pathconf_desc, spec_pathconf }, /* pathconf */
|
||||
{ &vop_advlock_desc, spec_advlock }, /* advlock */
|
||||
{ &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */
|
||||
{ &vop_valloc_desc, spec_valloc }, /* valloc */
|
||||
{ &vop_vfree_desc, spec_vfree }, /* vfree */
|
||||
{ &vop_truncate_desc, spec_truncate }, /* truncate */
|
||||
{ &vop_update_desc, spec_update }, /* update */
|
||||
{ &vop_bwrite_desc, spec_bwrite }, /* bwrite */
|
||||
{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
|
||||
};
|
||||
struct vnodeopv_desc spec_vnodeop_opv_desc =
|
||||
{ &spec_vnodeop_p, spec_vnodeop_entries };
|
||||
|
||||
/*
|
||||
* Trivial lookup routine that always fails.
|
||||
*/
|
||||
int
|
||||
spec_lookup(ap)
|
||||
struct vop_lookup_args /* {
|
||||
struct vnode *a_dvp;
|
||||
struct vnode **a_vpp;
|
||||
struct componentname *a_cnp;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
*ap->a_vpp = NULL;
|
||||
return (ENOTDIR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open a special file.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
spec_open(ap)
|
||||
struct vop_open_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_mode;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct proc *p = ap->a_p;
|
||||
struct vnode *bvp, *vp = ap->a_vp;
|
||||
dev_t bdev, dev = (dev_t)vp->v_rdev;
|
||||
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);
|
||||
|
||||
switch (vp->v_type) {
|
||||
|
||||
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 && cdevsw[maj].d_type == D_DISK)
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (cdevsw[maj].d_type == D_TTY)
|
||||
vp->v_flag |= VISTTY;
|
||||
VOP_UNLOCK(vp, 0, p);
|
||||
error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, p);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
return (error);
|
||||
|
||||
case VBLK:
|
||||
if ((u_int)maj >= nblkdev)
|
||||
return (ENXIO);
|
||||
/*
|
||||
* 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) && bdevsw[maj].d_type == D_DISK)
|
||||
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, p));
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Vnode op for read
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
spec_read(ap)
|
||||
struct vop_read_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
int a_ioflag;
|
||||
struct ucred *a_cred;
|
||||
} */ *ap;
|
||||
{
|
||||
register struct vnode *vp = ap->a_vp;
|
||||
register struct uio *uio = ap->a_uio;
|
||||
struct proc *p = uio->uio_procp;
|
||||
struct buf *bp;
|
||||
daddr_t bn, nextbn;
|
||||
long bsize, bscale;
|
||||
struct partinfo dpart;
|
||||
int n, on, majordev, (*ioctl)();
|
||||
int error = 0;
|
||||
dev_t dev;
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
if (uio->uio_rw != UIO_READ)
|
||||
panic("spec_read mode");
|
||||
if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
|
||||
panic("spec_read proc");
|
||||
#endif
|
||||
if (uio->uio_resid == 0)
|
||||
return (0);
|
||||
|
||||
switch (vp->v_type) {
|
||||
|
||||
case VCHR:
|
||||
VOP_UNLOCK(vp, 0, p);
|
||||
error = (*cdevsw[major(vp->v_rdev)].d_read)
|
||||
(vp->v_rdev, uio, ap->a_ioflag);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
return (error);
|
||||
|
||||
case VBLK:
|
||||
if (uio->uio_offset < 0)
|
||||
return (EINVAL);
|
||||
bsize = BLKDEV_IOSIZE;
|
||||
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);
|
||||
on = uio->uio_offset % bsize;
|
||||
n = min((unsigned)(bsize - on), uio->uio_resid);
|
||||
if (vp->v_lastr + bscale == bn) {
|
||||
nextbn = bn + bscale;
|
||||
error = breadn(vp, bn, (int)bsize, &nextbn,
|
||||
(int *)&bsize, 1, NOCRED, &bp);
|
||||
} else
|
||||
error = bread(vp, bn, (int)bsize, NOCRED, &bp);
|
||||
vp->v_lastr = bn;
|
||||
n = min(n, bsize - bp->b_resid);
|
||||
if (error) {
|
||||
brelse(bp);
|
||||
return (error);
|
||||
}
|
||||
error = uiomove((char *)bp->b_data + on, n, uio);
|
||||
if (n + on == bsize)
|
||||
bp->b_flags |= B_AGE;
|
||||
brelse(bp);
|
||||
} while (error == 0 && uio->uio_resid > 0 && n != 0);
|
||||
return (error);
|
||||
|
||||
default:
|
||||
panic("spec_read type");
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
* Vnode op for write
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
spec_write(ap)
|
||||
struct vop_write_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct uio *a_uio;
|
||||
int a_ioflag;
|
||||
struct ucred *a_cred;
|
||||
} */ *ap;
|
||||
{
|
||||
register struct vnode *vp = ap->a_vp;
|
||||
register struct uio *uio = ap->a_uio;
|
||||
struct proc *p = uio->uio_procp;
|
||||
struct buf *bp;
|
||||
daddr_t bn;
|
||||
int bsize, blkmask;
|
||||
struct partinfo dpart;
|
||||
register int n, on;
|
||||
int error = 0;
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
if (uio->uio_rw != UIO_WRITE)
|
||||
panic("spec_write mode");
|
||||
if (uio->uio_segflg == UIO_USERSPACE && uio->uio_procp != curproc)
|
||||
panic("spec_write proc");
|
||||
#endif
|
||||
|
||||
switch (vp->v_type) {
|
||||
|
||||
case VCHR:
|
||||
VOP_UNLOCK(vp, 0, p);
|
||||
error = (*cdevsw[major(vp->v_rdev)].d_write)
|
||||
(vp->v_rdev, uio, ap->a_ioflag);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
return (error);
|
||||
|
||||
case VBLK:
|
||||
if (uio->uio_resid == 0)
|
||||
return (0);
|
||||
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;
|
||||
}
|
||||
blkmask = (bsize / DEV_BSIZE) - 1;
|
||||
do {
|
||||
bn = (uio->uio_offset / DEV_BSIZE) &~ blkmask;
|
||||
on = uio->uio_offset % bsize;
|
||||
n = min((unsigned)(bsize - on), uio->uio_resid);
|
||||
if (n == bsize)
|
||||
bp = getblk(vp, bn, bsize, 0, 0);
|
||||
else
|
||||
error = bread(vp, bn, bsize, NOCRED, &bp);
|
||||
n = min(n, bsize - bp->b_resid);
|
||||
if (error) {
|
||||
brelse(bp);
|
||||
return (error);
|
||||
}
|
||||
error = uiomove((char *)bp->b_data + on, n, uio);
|
||||
if (n + on == bsize) {
|
||||
bp->b_flags |= B_AGE;
|
||||
bawrite(bp);
|
||||
} else
|
||||
bdwrite(bp);
|
||||
} while (error == 0 && uio->uio_resid > 0 && n != 0);
|
||||
return (error);
|
||||
|
||||
default:
|
||||
panic("spec_write type");
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/*
|
||||
* Device ioctl operation.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
spec_ioctl(ap)
|
||||
struct vop_ioctl_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_command;
|
||||
caddr_t a_data;
|
||||
int a_fflag;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
dev_t dev = ap->a_vp->v_rdev;
|
||||
|
||||
switch (ap->a_vp->v_type) {
|
||||
|
||||
case VCHR:
|
||||
return ((*cdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data,
|
||||
ap->a_fflag, ap->a_p));
|
||||
|
||||
case VBLK:
|
||||
if (ap->a_command == 0 && (int)ap->a_data == B_TAPE)
|
||||
if (bdevsw[major(dev)].d_type == D_TAPE)
|
||||
return (0);
|
||||
else
|
||||
return (1);
|
||||
return ((*bdevsw[major(dev)].d_ioctl)(dev, ap->a_command, ap->a_data,
|
||||
ap->a_fflag, ap->a_p));
|
||||
|
||||
default:
|
||||
panic("spec_ioctl");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
spec_select(ap)
|
||||
struct vop_select_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_which;
|
||||
int a_fflags;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
register dev_t dev;
|
||||
|
||||
switch (ap->a_vp->v_type) {
|
||||
|
||||
default:
|
||||
return (1); /* XXX */
|
||||
|
||||
case VCHR:
|
||||
dev = ap->a_vp->v_rdev;
|
||||
return (*cdevsw[major(dev)].d_select)(dev, ap->a_which, ap->a_p);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Synch buffers associated with a block device
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
int
|
||||
spec_fsync(ap)
|
||||
struct vop_fsync_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct ucred *a_cred;
|
||||
int a_waitfor;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
register struct vnode *vp = ap->a_vp;
|
||||
register struct buf *bp;
|
||||
struct buf *nbp;
|
||||
int s;
|
||||
|
||||
if (vp->v_type == VCHR)
|
||||
return (0);
|
||||
/*
|
||||
* Flush all dirty buffers associated with a block device.
|
||||
*/
|
||||
loop:
|
||||
s = splbio();
|
||||
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)
|
||||
panic("spec_fsync: not dirty");
|
||||
bremfree(bp);
|
||||
bp->b_flags |= B_BUSY;
|
||||
splx(s);
|
||||
bawrite(bp);
|
||||
goto loop;
|
||||
}
|
||||
if (ap->a_waitfor == MNT_WAIT) {
|
||||
while (vp->v_numoutput) {
|
||||
vp->v_flag |= VBWAIT;
|
||||
sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1);
|
||||
}
|
||||
#ifdef DIAGNOSTIC
|
||||
if (vp->v_dirtyblkhd.lh_first) {
|
||||
vprint("spec_fsync: dirty", vp);
|
||||
goto loop;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
splx(s);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
spec_inactive(ap)
|
||||
struct vop_inactive_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Just call the device strategy routine
|
||||
*/
|
||||
spec_strategy(ap)
|
||||
struct vop_strategy_args /* {
|
||||
struct buf *a_bp;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
(*bdevsw[major(ap->a_bp->b_dev)].d_strategy)(ap->a_bp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a noop, simply returning what one has been given.
|
||||
*/
|
||||
spec_bmap(ap)
|
||||
struct vop_bmap_args /* {
|
||||
struct vnode *a_vp;
|
||||
daddr_t a_bn;
|
||||
struct vnode **a_vpp;
|
||||
daddr_t *a_bnp;
|
||||
int *a_runp;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
if (ap->a_vpp != NULL)
|
||||
*ap->a_vpp = ap->a_vp;
|
||||
if (ap->a_bnp != NULL)
|
||||
*ap->a_bnp = ap->a_bn;
|
||||
if (ap->a_runp != NULL)
|
||||
*ap->a_runp = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Device close routine
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
spec_close(ap)
|
||||
struct vop_close_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_fflag;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
register struct vnode *vp = ap->a_vp;
|
||||
dev_t dev = vp->v_rdev;
|
||||
int (*devclose) __P((dev_t, int, int, struct proc *));
|
||||
int mode, error;
|
||||
|
||||
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
|
||||
* close on last reference.
|
||||
*/
|
||||
if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
|
||||
return (0);
|
||||
devclose = cdevsw[major(dev)].d_close;
|
||||
mode = S_IFCHR;
|
||||
break;
|
||||
|
||||
case VBLK:
|
||||
/*
|
||||
* On last close of a block device (that isn't mounted)
|
||||
* we must invalidate any in core blocks, so that
|
||||
* we can, for instance, change floppy disks.
|
||||
*/
|
||||
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
|
||||
* is still in use unless we are trying to close it
|
||||
* forcibly. Since every use (buffer, vnode, swap, cmap)
|
||||
* holds a reference to the vnode, and because we mark
|
||||
* any other vnodes that alias this device, when the
|
||||
* sum of the reference counts on all the aliased
|
||||
* vnodes descends to one, we are on last close.
|
||||
*/
|
||||
if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
|
||||
return (0);
|
||||
devclose = bdevsw[major(dev)].d_close;
|
||||
mode = S_IFBLK;
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("spec_close: not special");
|
||||
}
|
||||
|
||||
return ((*devclose)(dev, ap->a_fflag, mode, ap->a_p));
|
||||
}
|
||||
|
||||
/*
|
||||
* Print out the contents of a special device vnode.
|
||||
*/
|
||||
spec_print(ap)
|
||||
struct vop_print_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
printf("tag VT_NON, dev %d, %d\n", major(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.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
spec_advlock(ap)
|
||||
struct vop_advlock_args /* {
|
||||
struct vnode *a_vp;
|
||||
caddr_t a_id;
|
||||
int a_op;
|
||||
struct flock *a_fl;
|
||||
int a_flags;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
return (EOPNOTSUPP);
|
||||
}
|
||||
|
||||
/*
|
||||
* Special device failed operation
|
||||
*/
|
||||
spec_ebadf()
|
||||
{
|
||||
|
||||
return (EBADF);
|
||||
}
|
||||
|
||||
/*
|
||||
* Special device bad operation
|
||||
*/
|
||||
spec_badop()
|
||||
{
|
||||
|
||||
panic("spec_badop called");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
129
sys/miscfs/specfs/specdev.h
Normal file
129
sys/miscfs/specfs/specdev.h
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)specdev.h 8.6 (Berkeley) 5/21/95
|
||||
*/
|
||||
|
||||
/*
|
||||
* This structure defines the information maintained about
|
||||
* special devices. It is allocated in checkalias and freed
|
||||
* in vgone.
|
||||
*/
|
||||
struct specinfo {
|
||||
struct vnode **si_hashchain;
|
||||
struct vnode *si_specnext;
|
||||
long si_flags;
|
||||
dev_t si_rdev;
|
||||
};
|
||||
/*
|
||||
* Exported shorthand
|
||||
*/
|
||||
#define v_rdev v_specinfo->si_rdev
|
||||
#define v_hashchain v_specinfo->si_hashchain
|
||||
#define v_specnext v_specinfo->si_specnext
|
||||
#define v_specflags v_specinfo->si_flags
|
||||
|
||||
/*
|
||||
* Flags for specinfo
|
||||
*/
|
||||
#define SI_MOUNTEDON 0x0001 /* block special device is mounted on */
|
||||
|
||||
/*
|
||||
* Special device management
|
||||
*/
|
||||
#define SPECHSZ 64
|
||||
#if ((SPECHSZ&(SPECHSZ-1)) == 0)
|
||||
#define SPECHASH(rdev) (((rdev>>5)+(rdev))&(SPECHSZ-1))
|
||||
#else
|
||||
#define SPECHASH(rdev) (((unsigned)((rdev>>5)+(rdev)))%SPECHSZ)
|
||||
#endif
|
||||
|
||||
struct vnode *speclisth[SPECHSZ];
|
||||
|
||||
/*
|
||||
* Prototypes for special file operations on vnodes.
|
||||
*/
|
||||
extern int (**spec_vnodeop_p)();
|
||||
struct nameidata;
|
||||
struct componentname;
|
||||
struct ucred;
|
||||
struct flock;
|
||||
struct buf;
|
||||
struct uio;
|
||||
|
||||
int spec_badop(),
|
||||
spec_ebadf();
|
||||
|
||||
int spec_lookup __P((struct vop_lookup_args *));
|
||||
#define spec_create ((int (*) __P((struct vop_create_args *)))spec_badop)
|
||||
#define spec_mknod ((int (*) __P((struct vop_mknod_args *)))spec_badop)
|
||||
int spec_open __P((struct vop_open_args *));
|
||||
int spec_close __P((struct vop_close_args *));
|
||||
#define spec_access ((int (*) __P((struct vop_access_args *)))spec_ebadf)
|
||||
#define spec_getattr ((int (*) __P((struct vop_getattr_args *)))spec_ebadf)
|
||||
#define spec_setattr ((int (*) __P((struct vop_setattr_args *)))spec_ebadf)
|
||||
int spec_read __P((struct vop_read_args *));
|
||||
int spec_write __P((struct vop_write_args *));
|
||||
#define spec_lease_check ((int (*) __P((struct vop_lease_args *)))nullop)
|
||||
int spec_ioctl __P((struct vop_ioctl_args *));
|
||||
int spec_select __P((struct vop_select_args *));
|
||||
#define spec_revoke vop_revoke
|
||||
#define spec_mmap ((int (*) __P((struct vop_mmap_args *)))spec_badop)
|
||||
int spec_fsync __P((struct vop_fsync_args *));
|
||||
#define spec_seek ((int (*) __P((struct vop_seek_args *)))spec_badop)
|
||||
#define spec_remove ((int (*) __P((struct vop_remove_args *)))spec_badop)
|
||||
#define spec_link ((int (*) __P((struct vop_link_args *)))spec_badop)
|
||||
#define spec_rename ((int (*) __P((struct vop_rename_args *)))spec_badop)
|
||||
#define spec_mkdir ((int (*) __P((struct vop_mkdir_args *)))spec_badop)
|
||||
#define spec_rmdir ((int (*) __P((struct vop_rmdir_args *)))spec_badop)
|
||||
#define spec_symlink ((int (*) __P((struct vop_symlink_args *)))spec_badop)
|
||||
#define spec_readdir ((int (*) __P((struct vop_readdir_args *)))spec_badop)
|
||||
#define spec_readlink ((int (*) __P((struct vop_readlink_args *)))spec_badop)
|
||||
#define spec_abortop ((int (*) __P((struct vop_abortop_args *)))spec_badop)
|
||||
int spec_inactive __P((struct vop_inactive_args *));
|
||||
#define spec_reclaim ((int (*) __P((struct vop_reclaim_args *)))nullop)
|
||||
#define spec_lock ((int (*) __P((struct vop_lock_args *)))vop_nolock)
|
||||
#define spec_unlock ((int (*) __P((struct vop_unlock_args *)))vop_nounlock)
|
||||
int spec_bmap __P((struct vop_bmap_args *));
|
||||
int spec_strategy __P((struct vop_strategy_args *));
|
||||
int spec_print __P((struct vop_print_args *));
|
||||
#define spec_islocked ((int(*) __P((struct vop_islocked_args *)))vop_noislocked)
|
||||
int spec_pathconf __P((struct vop_pathconf_args *));
|
||||
int spec_advlock __P((struct vop_advlock_args *));
|
||||
#define spec_blkatoff ((int (*) __P((struct vop_blkatoff_args *)))spec_badop)
|
||||
#define spec_valloc ((int (*) __P((struct vop_valloc_args *)))spec_badop)
|
||||
#define spec_reallocblks \
|
||||
((int (*) __P((struct vop_reallocblks_args *)))spec_badop)
|
||||
#define spec_vfree ((int (*) __P((struct vop_vfree_args *)))spec_badop)
|
||||
#define spec_truncate ((int (*) __P((struct vop_truncate_args *)))nullop)
|
||||
#define spec_update ((int (*) __P((struct vop_update_args *)))nullop)
|
||||
#define spec_bwrite ((int (*) __P((struct vop_bwrite_args *)))nullop)
|
||||
91
sys/miscfs/umapfs/umap.h
Normal file
91
sys/miscfs/umapfs/umap.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* the UCLA Ficus project.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)umap.h 8.4 (Berkeley) 8/20/94
|
||||
*
|
||||
* @(#)null_vnops.c 1.5 (Berkeley) 7/10/92
|
||||
*/
|
||||
|
||||
#define MAPFILEENTRIES 64
|
||||
#define GMAPFILEENTRIES 16
|
||||
#define NOBODY 32767
|
||||
#define NULLGROUP 65534
|
||||
|
||||
struct umap_args {
|
||||
char *target; /* Target of loopback */
|
||||
int nentries; /* # of entries in user map array */
|
||||
int gnentries; /* # of entries in group map array */
|
||||
u_long (*mapdata)[2]; /* pointer to array of user mappings */
|
||||
u_long (*gmapdata)[2]; /* pointer to array of group mappings */
|
||||
};
|
||||
|
||||
struct umap_mount {
|
||||
struct mount *umapm_vfs;
|
||||
struct vnode *umapm_rootvp; /* Reference to root umap_node */
|
||||
int info_nentries; /* number of uid mappings */
|
||||
int info_gnentries; /* number of gid mappings */
|
||||
u_long info_mapdata[MAPFILEENTRIES][2]; /* mapping data for
|
||||
user mapping in ficus */
|
||||
u_long info_gmapdata[GMAPFILEENTRIES][2]; /*mapping data for
|
||||
group mapping in ficus */
|
||||
};
|
||||
|
||||
#ifdef KERNEL
|
||||
/*
|
||||
* A cache of vnode references
|
||||
*/
|
||||
struct umap_node {
|
||||
LIST_ENTRY(umap_node) umap_hash; /* Hash list */
|
||||
struct vnode *umap_lowervp; /* Aliased vnode - VREFed once */
|
||||
struct vnode *umap_vnode; /* Back pointer to vnode/umap_node */
|
||||
};
|
||||
|
||||
extern int umap_node_create __P((struct mount *mp, struct vnode *target, struct vnode **vpp));
|
||||
extern u_long umap_reverse_findid __P((u_long id, u_long map[][2], int nentries));
|
||||
extern void umap_mapids __P((struct mount *v_mount, struct ucred *credp));
|
||||
|
||||
#define MOUNTTOUMAPMOUNT(mp) ((struct umap_mount *)((mp)->mnt_data))
|
||||
#define VTOUMAP(vp) ((struct umap_node *)(vp)->v_data)
|
||||
#define UMAPTOV(xp) ((xp)->umap_vnode)
|
||||
#ifdef UMAPFS_DIAGNOSTIC
|
||||
extern struct vnode *umap_checkvp __P((struct vnode *vp, char *fil, int lno));
|
||||
#define UMAPVPTOLOWERVP(vp) umap_checkvp((vp), __FILE__, __LINE__)
|
||||
#else
|
||||
#define UMAPVPTOLOWERVP(vp) (VTOUMAP(vp)->umap_lowervp)
|
||||
#endif
|
||||
|
||||
extern int (**umap_vnodeop_p)();
|
||||
extern struct vfsops umap_vfsops;
|
||||
#endif /* KERNEL */
|
||||
380
sys/miscfs/umapfs/umap_subr.c
Normal file
380
sys/miscfs/umapfs/umap_subr.c
Normal file
|
|
@ -0,0 +1,380 @@
|
|||
/*
|
||||
* Copyright (c) 1992, 1993, 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)umap_subr.c 8.9 (Berkeley) 5/14/95
|
||||
*
|
||||
* From: $Id: lofs_subr.c, v 1.11 1992/05/30 10:05:43 jsp Exp jsp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <miscfs/umapfs/umap.h>
|
||||
|
||||
#define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */
|
||||
#define NUMAPNODECACHE 16
|
||||
|
||||
/*
|
||||
* Null layer cache:
|
||||
* Each cache entry holds a reference to the target vnode
|
||||
* along with a pointer to the alias vnode. When an
|
||||
* entry is added the target vnode is VREF'd. When the
|
||||
* alias is removed the target vnode is vrele'd.
|
||||
*/
|
||||
|
||||
#define UMAP_NHASH(vp) \
|
||||
(&umap_node_hashtbl[(((u_long)vp)>>LOG2_SIZEVNODE) & umap_node_hash])
|
||||
LIST_HEAD(umap_node_hashhead, umap_node) *umap_node_hashtbl;
|
||||
u_long umap_node_hash;
|
||||
|
||||
/*
|
||||
* Initialise cache headers
|
||||
*/
|
||||
umapfs_init(vfsp)
|
||||
struct vfsconf *vfsp;
|
||||
{
|
||||
|
||||
#ifdef UMAPFS_DIAGNOSTIC
|
||||
printf("umapfs_init\n"); /* printed during system boot */
|
||||
#endif
|
||||
umap_node_hashtbl = hashinit(NUMAPNODECACHE, M_CACHE, &umap_node_hash);
|
||||
}
|
||||
|
||||
/*
|
||||
* umap_findid is called by various routines in umap_vnodeops.c to
|
||||
* find a user or group id in a map.
|
||||
*/
|
||||
static u_long
|
||||
umap_findid(id, map, nentries)
|
||||
u_long id;
|
||||
u_long map[][2];
|
||||
int nentries;
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Find uid entry in map */
|
||||
i = 0;
|
||||
while ((i<nentries) && ((map[i][0]) != id))
|
||||
i++;
|
||||
|
||||
if (i < nentries)
|
||||
return (map[i][1]);
|
||||
else
|
||||
return (-1);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* umap_reverse_findid is called by umap_getattr() in umap_vnodeops.c to
|
||||
* find a user or group id in a map, in reverse.
|
||||
*/
|
||||
u_long
|
||||
umap_reverse_findid(id, map, nentries)
|
||||
u_long id;
|
||||
u_long map[][2];
|
||||
int nentries;
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Find uid entry in map */
|
||||
i = 0;
|
||||
while ((i<nentries) && ((map[i][1]) != id))
|
||||
i++;
|
||||
|
||||
if (i < nentries)
|
||||
return (map[i][0]);
|
||||
else
|
||||
return (-1);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Return alias for target vnode if already exists, else 0.
|
||||
*/
|
||||
static struct vnode *
|
||||
umap_node_find(mp, targetvp)
|
||||
struct mount *mp;
|
||||
struct vnode *targetvp;
|
||||
{
|
||||
struct proc *p = curproc; /* XXX */
|
||||
struct umap_node_hashhead *hd;
|
||||
struct umap_node *a;
|
||||
struct vnode *vp;
|
||||
|
||||
#ifdef UMAPFS_DIAGNOSTIC
|
||||
printf("umap_node_find(mp = %x, target = %x)\n", mp, targetvp);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Find hash base, and then search the (two-way) linked
|
||||
* list looking for a umap_node structure which is referencing
|
||||
* the target vnode. If found, the increment the umap_node
|
||||
* reference count (but NOT the target vnode's VREF counter).
|
||||
*/
|
||||
hd = UMAP_NHASH(targetvp);
|
||||
loop:
|
||||
for (a = hd->lh_first; a != 0; a = a->umap_hash.le_next) {
|
||||
if (a->umap_lowervp == targetvp &&
|
||||
a->umap_vnode->v_mount == mp) {
|
||||
vp = UMAPTOV(a);
|
||||
/*
|
||||
* We need vget for the VXLOCK
|
||||
* stuff, but we don't want to lock
|
||||
* the lower node.
|
||||
*/
|
||||
if (vget(vp, 0, p)) {
|
||||
#ifdef UMAPFS_DIAGNOSTIC
|
||||
printf ("umap_node_find: vget failed.\n");
|
||||
#endif
|
||||
goto loop;
|
||||
}
|
||||
return (vp);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UMAPFS_DIAGNOSTIC
|
||||
printf("umap_node_find(%x, %x): NOT found\n", mp, targetvp);
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a new umap_node node.
|
||||
* Vp is the alias vnode, lofsvp is the target vnode.
|
||||
* Maintain a reference to (targetvp).
|
||||
*/
|
||||
static int
|
||||
umap_node_alloc(mp, lowervp, vpp)
|
||||
struct mount *mp;
|
||||
struct vnode *lowervp;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
struct umap_node_hashhead *hd;
|
||||
struct umap_node *xp;
|
||||
struct vnode *othervp, *vp;
|
||||
int error;
|
||||
|
||||
if (error = getnewvnode(VT_UMAP, mp, umap_vnodeop_p, vpp))
|
||||
return (error);
|
||||
vp = *vpp;
|
||||
|
||||
MALLOC(xp, struct umap_node *, sizeof(struct umap_node),
|
||||
M_TEMP, M_WAITOK);
|
||||
vp->v_type = lowervp->v_type;
|
||||
xp->umap_vnode = vp;
|
||||
vp->v_data = xp;
|
||||
xp->umap_lowervp = lowervp;
|
||||
/*
|
||||
* Before we insert our new node onto the hash chains,
|
||||
* check to see if someone else has beaten us to it.
|
||||
* (We could have slept in MALLOC.)
|
||||
*/
|
||||
if (othervp = umap_node_find(lowervp)) {
|
||||
FREE(xp, M_TEMP);
|
||||
vp->v_type = VBAD; /* node is discarded */
|
||||
vp->v_usecount = 0; /* XXX */
|
||||
*vpp = othervp;
|
||||
return (0);
|
||||
}
|
||||
VREF(lowervp); /* Extra VREF will be vrele'd in umap_node_create */
|
||||
hd = UMAP_NHASH(lowervp);
|
||||
LIST_INSERT_HEAD(hd, xp, umap_hash);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Try to find an existing umap_node vnode refering
|
||||
* to it, otherwise make a new umap_node vnode which
|
||||
* contains a reference to the target vnode.
|
||||
*/
|
||||
int
|
||||
umap_node_create(mp, targetvp, newvpp)
|
||||
struct mount *mp;
|
||||
struct vnode *targetvp;
|
||||
struct vnode **newvpp;
|
||||
{
|
||||
struct vnode *aliasvp;
|
||||
|
||||
if (aliasvp = umap_node_find(mp, targetvp)) {
|
||||
/*
|
||||
* Take another reference to the alias vnode
|
||||
*/
|
||||
#ifdef UMAPFS_DIAGNOSTIC
|
||||
vprint("umap_node_create: exists", ap->umap_vnode);
|
||||
#endif
|
||||
/* VREF(aliasvp); */
|
||||
} else {
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Get new vnode.
|
||||
*/
|
||||
#ifdef UMAPFS_DIAGNOSTIC
|
||||
printf("umap_node_create: create new alias vnode\n");
|
||||
#endif
|
||||
/*
|
||||
* Make new vnode reference the umap_node.
|
||||
*/
|
||||
if (error = umap_node_alloc(mp, targetvp, &aliasvp))
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* aliasvp is already VREF'd by getnewvnode()
|
||||
*/
|
||||
}
|
||||
|
||||
vrele(targetvp);
|
||||
|
||||
#ifdef UMAPFS_DIAGNOSTIC
|
||||
vprint("umap_node_create: alias", aliasvp);
|
||||
vprint("umap_node_create: target", targetvp);
|
||||
#endif
|
||||
|
||||
*newvpp = aliasvp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef UMAPFS_DIAGNOSTIC
|
||||
int umap_checkvp_barrier = 1;
|
||||
struct vnode *
|
||||
umap_checkvp(vp, fil, lno)
|
||||
struct vnode *vp;
|
||||
char *fil;
|
||||
int lno;
|
||||
{
|
||||
struct umap_node *a = VTOUMAP(vp);
|
||||
#if 0
|
||||
/*
|
||||
* Can't do this check because vop_reclaim runs
|
||||
* with funny vop vector.
|
||||
*/
|
||||
if (vp->v_op != umap_vnodeop_p) {
|
||||
printf ("umap_checkvp: on non-umap-node\n");
|
||||
while (umap_checkvp_barrier) /*WAIT*/ ;
|
||||
panic("umap_checkvp");
|
||||
}
|
||||
#endif
|
||||
if (a->umap_lowervp == NULL) {
|
||||
/* Should never happen */
|
||||
int i; u_long *p;
|
||||
printf("vp = %x, ZERO ptr\n", vp);
|
||||
for (p = (u_long *) a, i = 0; i < 8; i++)
|
||||
printf(" %x", p[i]);
|
||||
printf("\n");
|
||||
/* wait for debugger */
|
||||
while (umap_checkvp_barrier) /*WAIT*/ ;
|
||||
panic("umap_checkvp");
|
||||
}
|
||||
if (a->umap_lowervp->v_usecount < 1) {
|
||||
int i; u_long *p;
|
||||
printf("vp = %x, unref'ed lowervp\n", vp);
|
||||
for (p = (u_long *) a, i = 0; i < 8; i++)
|
||||
printf(" %x", p[i]);
|
||||
printf("\n");
|
||||
/* wait for debugger */
|
||||
while (umap_checkvp_barrier) /*WAIT*/ ;
|
||||
panic ("umap with unref'ed lowervp");
|
||||
}
|
||||
#if 0
|
||||
printf("umap %x/%d -> %x/%d [%s, %d]\n",
|
||||
a->umap_vnode, a->umap_vnode->v_usecount,
|
||||
a->umap_lowervp, a->umap_lowervp->v_usecount,
|
||||
fil, lno);
|
||||
#endif
|
||||
return (a->umap_lowervp);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* umap_mapids maps all of the ids in a credential, both user and group. */
|
||||
|
||||
void
|
||||
umap_mapids(v_mount, credp)
|
||||
struct mount *v_mount;
|
||||
struct ucred *credp;
|
||||
{
|
||||
int i, unentries, gnentries;
|
||||
u_long *groupmap, *usermap;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
|
||||
unentries = MOUNTTOUMAPMOUNT(v_mount)->info_nentries;
|
||||
usermap = &(MOUNTTOUMAPMOUNT(v_mount)->info_mapdata[0][0]);
|
||||
gnentries = MOUNTTOUMAPMOUNT(v_mount)->info_gnentries;
|
||||
groupmap = &(MOUNTTOUMAPMOUNT(v_mount)->info_gmapdata[0][0]);
|
||||
|
||||
/* Find uid entry in map */
|
||||
|
||||
uid = (uid_t) umap_findid(credp->cr_uid, usermap, unentries);
|
||||
|
||||
if (uid != -1)
|
||||
credp->cr_uid = uid;
|
||||
else
|
||||
credp->cr_uid = (uid_t) NOBODY;
|
||||
|
||||
#ifdef notdef
|
||||
/* cr_gid is the same as cr_groups[0] in 4BSD */
|
||||
|
||||
/* Find gid entry in map */
|
||||
|
||||
gid = (gid_t) umap_findid(credp->cr_gid, groupmap, gnentries);
|
||||
|
||||
if (gid != -1)
|
||||
credp->cr_gid = gid;
|
||||
else
|
||||
credp->cr_gid = NULLGROUP;
|
||||
#endif
|
||||
|
||||
/* Now we must map each of the set of groups in the cr_groups
|
||||
structure. */
|
||||
|
||||
i = 0;
|
||||
while (credp->cr_groups[i] != 0) {
|
||||
gid = (gid_t) umap_findid(credp->cr_groups[i],
|
||||
groupmap, gnentries);
|
||||
|
||||
if (gid != -1)
|
||||
credp->cr_groups[i++] = gid;
|
||||
else
|
||||
credp->cr_groups[i++] = NULLGROUP;
|
||||
}
|
||||
}
|
||||
407
sys/miscfs/umapfs/umap_vfsops.c
Normal file
407
sys/miscfs/umapfs/umap_vfsops.c
Normal file
|
|
@ -0,0 +1,407 @@
|
|||
/*
|
||||
* Copyright (c) 1992, 1993, 1995
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* the UCLA Ficus project.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)umap_vfsops.c 8.8 (Berkeley) 5/14/95
|
||||
*
|
||||
* @(#)null_vfsops.c 1.5 (Berkeley) 7/10/92
|
||||
*/
|
||||
|
||||
/*
|
||||
* Umap Layer
|
||||
* (See mount_umap(8) for a description of this layer.)
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <miscfs/umapfs/umap.h>
|
||||
|
||||
/*
|
||||
* Mount umap layer
|
||||
*/
|
||||
int
|
||||
umapfs_mount(mp, path, data, ndp, p)
|
||||
struct mount *mp;
|
||||
char *path;
|
||||
caddr_t data;
|
||||
struct nameidata *ndp;
|
||||
struct proc *p;
|
||||
{
|
||||
struct umap_args args;
|
||||
struct vnode *lowerrootvp, *vp;
|
||||
struct vnode *umapm_rootvp;
|
||||
struct umap_mount *amp;
|
||||
u_int size;
|
||||
int error;
|
||||
|
||||
#ifdef UMAPFS_DIAGNOSTIC
|
||||
printf("umapfs_mount(mp = %x)\n", mp);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Update is a no-op
|
||||
*/
|
||||
if (mp->mnt_flag & MNT_UPDATE) {
|
||||
return (EOPNOTSUPP);
|
||||
/* return (VFS_MOUNT(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, path, data, ndp, p));*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Get argument
|
||||
*/
|
||||
if (error = copyin(data, (caddr_t)&args, sizeof(struct umap_args)))
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Find lower node
|
||||
*/
|
||||
NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF,
|
||||
UIO_USERSPACE, args.target, p);
|
||||
if (error = namei(ndp))
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Sanity check on lower vnode
|
||||
*/
|
||||
lowerrootvp = ndp->ni_vp;
|
||||
#ifdef UMAPFS_DIAGNOSTIC
|
||||
printf("vp = %x, check for VDIR...\n", lowerrootvp);
|
||||
#endif
|
||||
vrele(ndp->ni_dvp);
|
||||
ndp->ni_dvp = 0;
|
||||
|
||||
if (lowerrootvp->v_type != VDIR) {
|
||||
vput(lowerrootvp);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
#ifdef UMAPFS_DIAGNOSTIC
|
||||
printf("mp = %x\n", mp);
|
||||
#endif
|
||||
|
||||
amp = (struct umap_mount *) malloc(sizeof(struct umap_mount),
|
||||
M_UFSMNT, M_WAITOK); /* XXX */
|
||||
|
||||
/*
|
||||
* Save reference to underlying FS
|
||||
*/
|
||||
amp->umapm_vfs = lowerrootvp->v_mount;
|
||||
|
||||
/*
|
||||
* Now copy in the number of entries and maps for umap mapping.
|
||||
*/
|
||||
amp->info_nentries = args.nentries;
|
||||
amp->info_gnentries = args.gnentries;
|
||||
error = copyin(args.mapdata, (caddr_t)amp->info_mapdata,
|
||||
2*sizeof(u_long)*args.nentries);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
#ifdef UMAP_DIAGNOSTIC
|
||||
printf("umap_mount:nentries %d\n",args.nentries);
|
||||
for (i = 0; i < args.nentries; i++)
|
||||
printf(" %d maps to %d\n", amp->info_mapdata[i][0],
|
||||
amp->info_mapdata[i][1]);
|
||||
#endif
|
||||
|
||||
error = copyin(args.gmapdata, (caddr_t)amp->info_gmapdata,
|
||||
2*sizeof(u_long)*args.nentries);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
#ifdef UMAP_DIAGNOSTIC
|
||||
printf("umap_mount:gnentries %d\n",args.gnentries);
|
||||
for (i = 0; i < args.gnentries; i++)
|
||||
printf(" group %d maps to %d\n",
|
||||
amp->info_gmapdata[i][0],
|
||||
amp->info_gmapdata[i][1]);
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Save reference. Each mount also holds
|
||||
* a reference on the root vnode.
|
||||
*/
|
||||
error = umap_node_create(mp, lowerrootvp, &vp);
|
||||
/*
|
||||
* Unlock the node (either the lower or the alias)
|
||||
*/
|
||||
VOP_UNLOCK(vp, 0, p);
|
||||
/*
|
||||
* Make sure the node alias worked
|
||||
*/
|
||||
if (error) {
|
||||
vrele(lowerrootvp);
|
||||
free(amp, M_UFSMNT); /* XXX */
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Keep a held reference to the root vnode.
|
||||
* It is vrele'd in umapfs_unmount.
|
||||
*/
|
||||
umapm_rootvp = vp;
|
||||
umapm_rootvp->v_flag |= VROOT;
|
||||
amp->umapm_rootvp = umapm_rootvp;
|
||||
if (UMAPVPTOLOWERVP(umapm_rootvp)->v_mount->mnt_flag & MNT_LOCAL)
|
||||
mp->mnt_flag |= MNT_LOCAL;
|
||||
mp->mnt_data = (qaddr_t) amp;
|
||||
vfs_getnewfsid(mp);
|
||||
|
||||
(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
|
||||
bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
|
||||
(void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
|
||||
&size);
|
||||
bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
|
||||
#ifdef UMAPFS_DIAGNOSTIC
|
||||
printf("umapfs_mount: lower %s, alias at %s\n",
|
||||
mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* VFS start. Nothing needed here - the start routine
|
||||
* on the underlying filesystem will have been called
|
||||
* when that filesystem was mounted.
|
||||
*/
|
||||
int
|
||||
umapfs_start(mp, flags, p)
|
||||
struct mount *mp;
|
||||
int flags;
|
||||
struct proc *p;
|
||||
{
|
||||
return (0);
|
||||
/* return (VFS_START(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, flags, p)); */
|
||||
}
|
||||
|
||||
/*
|
||||
* Free reference to umap layer
|
||||
*/
|
||||
int
|
||||
umapfs_unmount(mp, mntflags, p)
|
||||
struct mount *mp;
|
||||
int mntflags;
|
||||
struct proc *p;
|
||||
{
|
||||
struct vnode *umapm_rootvp = MOUNTTOUMAPMOUNT(mp)->umapm_rootvp;
|
||||
int error;
|
||||
int flags = 0;
|
||||
|
||||
#ifdef UMAPFS_DIAGNOSTIC
|
||||
printf("umapfs_unmount(mp = %x)\n", mp);
|
||||
#endif
|
||||
|
||||
if (mntflags & MNT_FORCE)
|
||||
flags |= FORCECLOSE;
|
||||
|
||||
/*
|
||||
* Clear out buffer cache. I don't think we
|
||||
* ever get anything cached at this level at the
|
||||
* moment, but who knows...
|
||||
*/
|
||||
#ifdef notyet
|
||||
mntflushbuf(mp, 0);
|
||||
if (mntinvalbuf(mp, 1))
|
||||
return (EBUSY);
|
||||
#endif
|
||||
if (umapm_rootvp->v_usecount > 1)
|
||||
return (EBUSY);
|
||||
if (error = vflush(mp, umapm_rootvp, flags))
|
||||
return (error);
|
||||
|
||||
#ifdef UMAPFS_DIAGNOSTIC
|
||||
vprint("alias root of lower", umapm_rootvp);
|
||||
#endif
|
||||
/*
|
||||
* Release reference on underlying root vnode
|
||||
*/
|
||||
vrele(umapm_rootvp);
|
||||
/*
|
||||
* And blow it away for future re-use
|
||||
*/
|
||||
vgone(umapm_rootvp);
|
||||
/*
|
||||
* Finally, throw away the umap_mount structure
|
||||
*/
|
||||
free(mp->mnt_data, M_UFSMNT); /* XXX */
|
||||
mp->mnt_data = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
umapfs_root(mp, vpp)
|
||||
struct mount *mp;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
struct proc *p = curproc; /* XXX */
|
||||
struct vnode *vp;
|
||||
|
||||
#ifdef UMAPFS_DIAGNOSTIC
|
||||
printf("umapfs_root(mp = %x, vp = %x->%x)\n", mp,
|
||||
MOUNTTOUMAPMOUNT(mp)->umapm_rootvp,
|
||||
UMAPVPTOLOWERVP(MOUNTTOUMAPMOUNT(mp)->umapm_rootvp)
|
||||
);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Return locked reference to root.
|
||||
*/
|
||||
vp = MOUNTTOUMAPMOUNT(mp)->umapm_rootvp;
|
||||
VREF(vp);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
*vpp = vp;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
umapfs_quotactl(mp, cmd, uid, arg, p)
|
||||
struct mount *mp;
|
||||
int cmd;
|
||||
uid_t uid;
|
||||
caddr_t arg;
|
||||
struct proc *p;
|
||||
{
|
||||
return (VFS_QUOTACTL(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, cmd, uid, arg, p));
|
||||
}
|
||||
|
||||
int
|
||||
umapfs_statfs(mp, sbp, p)
|
||||
struct mount *mp;
|
||||
struct statfs *sbp;
|
||||
struct proc *p;
|
||||
{
|
||||
int error;
|
||||
struct statfs mstat;
|
||||
|
||||
#ifdef UMAPFS_DIAGNOSTIC
|
||||
printf("umapfs_statfs(mp = %x, vp = %x->%x)\n", mp,
|
||||
MOUNTTOUMAPMOUNT(mp)->umapm_rootvp,
|
||||
UMAPVPTOLOWERVP(MOUNTTOUMAPMOUNT(mp)->umapm_rootvp)
|
||||
);
|
||||
#endif
|
||||
|
||||
bzero(&mstat, sizeof(mstat));
|
||||
|
||||
error = VFS_STATFS(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, &mstat, p);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* now copy across the "interesting" information and fake the rest */
|
||||
sbp->f_type = mstat.f_type;
|
||||
sbp->f_flags = mstat.f_flags;
|
||||
sbp->f_bsize = mstat.f_bsize;
|
||||
sbp->f_iosize = mstat.f_iosize;
|
||||
sbp->f_blocks = mstat.f_blocks;
|
||||
sbp->f_bfree = mstat.f_bfree;
|
||||
sbp->f_bavail = mstat.f_bavail;
|
||||
sbp->f_files = mstat.f_files;
|
||||
sbp->f_ffree = mstat.f_ffree;
|
||||
if (sbp != &mp->mnt_stat) {
|
||||
bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
|
||||
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
|
||||
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
umapfs_sync(mp, waitfor, cred, p)
|
||||
struct mount *mp;
|
||||
int waitfor;
|
||||
struct ucred *cred;
|
||||
struct proc *p;
|
||||
{
|
||||
/*
|
||||
* XXX - Assumes no data cached at umap layer.
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
umapfs_vget(mp, ino, vpp)
|
||||
struct mount *mp;
|
||||
ino_t ino;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
|
||||
return (VFS_VGET(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, ino, vpp));
|
||||
}
|
||||
|
||||
int
|
||||
umapfs_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp)
|
||||
struct mount *mp;
|
||||
struct fid *fidp;
|
||||
struct mbuf *nam;
|
||||
struct vnode **vpp;
|
||||
int *exflagsp;
|
||||
struct ucred**credanonp;
|
||||
{
|
||||
|
||||
return (VFS_FHTOVP(MOUNTTOUMAPMOUNT(mp)->umapm_vfs, fidp, nam, vpp, exflagsp,credanonp));
|
||||
}
|
||||
|
||||
int
|
||||
umapfs_vptofh(vp, fhp)
|
||||
struct vnode *vp;
|
||||
struct fid *fhp;
|
||||
{
|
||||
return (VFS_VPTOFH(UMAPVPTOLOWERVP(vp), fhp));
|
||||
}
|
||||
|
||||
int umapfs_init __P((struct vfsconf *));
|
||||
#define umapfs_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \
|
||||
size_t, struct proc *)))eopnotsupp)
|
||||
|
||||
struct vfsops umap_vfsops = {
|
||||
umapfs_mount,
|
||||
umapfs_start,
|
||||
umapfs_unmount,
|
||||
umapfs_root,
|
||||
umapfs_quotactl,
|
||||
umapfs_statfs,
|
||||
umapfs_sync,
|
||||
umapfs_vget,
|
||||
umapfs_fhtovp,
|
||||
umapfs_vptofh,
|
||||
umapfs_init,
|
||||
umapfs_sysctl,
|
||||
};
|
||||
533
sys/miscfs/umapfs/umap_vnops.c
Normal file
533
sys/miscfs/umapfs/umap_vnops.c
Normal file
|
|
@ -0,0 +1,533 @@
|
|||
/*
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* the UCLA Ficus project.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)umap_vnops.c 8.6 (Berkeley) 5/22/95
|
||||
*/
|
||||
|
||||
/*
|
||||
* Umap Layer
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/buf.h>
|
||||
#include <miscfs/umapfs/umap.h>
|
||||
|
||||
|
||||
int umap_bug_bypass = 0; /* for debugging: enables bypass printf'ing */
|
||||
|
||||
/*
|
||||
* This is the 10-Apr-92 bypass routine.
|
||||
* See null_vnops.c:null_bypass for more details.
|
||||
*/
|
||||
int
|
||||
umap_bypass(ap)
|
||||
struct vop_generic_args /* {
|
||||
struct vnodeop_desc *a_desc;
|
||||
<other random data follows, presumably>
|
||||
} */ *ap;
|
||||
{
|
||||
extern int (**umap_vnodeop_p)(); /* not extern, really "forward" */
|
||||
struct ucred **credpp = 0, *credp = 0;
|
||||
struct ucred *savecredp, *savecompcredp = 0;
|
||||
struct ucred *compcredp = 0;
|
||||
struct vnode **this_vp_p;
|
||||
int error;
|
||||
struct vnode *old_vps[VDESC_MAX_VPS];
|
||||
struct vnode *vp1 = 0;
|
||||
struct vnode **vps_p[VDESC_MAX_VPS];
|
||||
struct vnode ***vppp;
|
||||
struct vnodeop_desc *descp = ap->a_desc;
|
||||
int reles, i;
|
||||
struct componentname **compnamepp = 0;
|
||||
|
||||
if (umap_bug_bypass)
|
||||
printf ("umap_bypass: %s\n", descp->vdesc_name);
|
||||
|
||||
#ifdef SAFETY
|
||||
/*
|
||||
* We require at least one vp.
|
||||
*/
|
||||
if (descp->vdesc_vp_offsets == NULL ||
|
||||
descp->vdesc_vp_offsets[0] == VDESC_NO_OFFSET)
|
||||
panic ("umap_bypass: no vp's in map.\n");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Map the vnodes going in.
|
||||
* Later, we'll invoke the operation based on
|
||||
* the first mapped vnode's operation vector.
|
||||
*/
|
||||
reles = descp->vdesc_flags;
|
||||
for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) {
|
||||
if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET)
|
||||
break; /* bail out at end of list */
|
||||
vps_p[i] = this_vp_p =
|
||||
VOPARG_OFFSETTO(struct vnode**, descp->vdesc_vp_offsets[i], ap);
|
||||
|
||||
if (i == 0) {
|
||||
vp1 = *vps_p[0];
|
||||
}
|
||||
|
||||
/*
|
||||
* We're not guaranteed that any but the first vnode
|
||||
* are of our type. Check for and don't map any
|
||||
* that aren't. (Must map first vp or vclean fails.)
|
||||
*/
|
||||
|
||||
if (i && (*this_vp_p)->v_op != umap_vnodeop_p) {
|
||||
old_vps[i] = NULL;
|
||||
} else {
|
||||
old_vps[i] = *this_vp_p;
|
||||
*(vps_p[i]) = UMAPVPTOLOWERVP(*this_vp_p);
|
||||
if (reles & 1)
|
||||
VREF(*this_vp_p);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Fix the credentials. (That's the purpose of this layer.)
|
||||
*/
|
||||
|
||||
if (descp->vdesc_cred_offset != VDESC_NO_OFFSET) {
|
||||
|
||||
credpp = VOPARG_OFFSETTO(struct ucred**,
|
||||
descp->vdesc_cred_offset, ap);
|
||||
|
||||
/* Save old values */
|
||||
|
||||
savecredp = (*credpp);
|
||||
(*credpp) = crdup(savecredp);
|
||||
credp = *credpp;
|
||||
|
||||
if (umap_bug_bypass && credp->cr_uid != 0)
|
||||
printf("umap_bypass: user was %d, group %d\n",
|
||||
credp->cr_uid, credp->cr_gid);
|
||||
|
||||
/* Map all ids in the credential structure. */
|
||||
|
||||
umap_mapids(vp1->v_mount, credp);
|
||||
|
||||
if (umap_bug_bypass && credp->cr_uid != 0)
|
||||
printf("umap_bypass: user now %d, group %d\n",
|
||||
credp->cr_uid, credp->cr_gid);
|
||||
}
|
||||
|
||||
/* BSD often keeps a credential in the componentname structure
|
||||
* for speed. If there is one, it better get mapped, too.
|
||||
*/
|
||||
|
||||
if (descp->vdesc_componentname_offset != VDESC_NO_OFFSET) {
|
||||
|
||||
compnamepp = VOPARG_OFFSETTO(struct componentname**,
|
||||
descp->vdesc_componentname_offset, ap);
|
||||
|
||||
compcredp = (*compnamepp)->cn_cred;
|
||||
savecompcredp = compcredp;
|
||||
compcredp = (*compnamepp)->cn_cred = crdup(savecompcredp);
|
||||
|
||||
if (umap_bug_bypass && compcredp->cr_uid != 0)
|
||||
printf("umap_bypass: component credit user was %d, group %d\n",
|
||||
compcredp->cr_uid, compcredp->cr_gid);
|
||||
|
||||
/* Map all ids in the credential structure. */
|
||||
|
||||
umap_mapids(vp1->v_mount, compcredp);
|
||||
|
||||
if (umap_bug_bypass && compcredp->cr_uid != 0)
|
||||
printf("umap_bypass: component credit user now %d, group %d\n",
|
||||
compcredp->cr_uid, compcredp->cr_gid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Call the operation on the lower layer
|
||||
* with the modified argument structure.
|
||||
*/
|
||||
error = VCALL(*(vps_p[0]), descp->vdesc_offset, ap);
|
||||
|
||||
/*
|
||||
* Maintain the illusion of call-by-value
|
||||
* by restoring vnodes in the argument structure
|
||||
* to their original value.
|
||||
*/
|
||||
reles = descp->vdesc_flags;
|
||||
for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) {
|
||||
if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET)
|
||||
break; /* bail out at end of list */
|
||||
if (old_vps[i]) {
|
||||
*(vps_p[i]) = old_vps[i];
|
||||
if (reles & 1)
|
||||
vrele(*(vps_p[i]));
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* Map the possible out-going vpp
|
||||
* (Assumes that the lower layer always returns
|
||||
* a VREF'ed vpp unless it gets an error.)
|
||||
*/
|
||||
if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET &&
|
||||
!(descp->vdesc_flags & VDESC_NOMAP_VPP) &&
|
||||
!error) {
|
||||
if (descp->vdesc_flags & VDESC_VPP_WILLRELE)
|
||||
goto out;
|
||||
vppp = VOPARG_OFFSETTO(struct vnode***,
|
||||
descp->vdesc_vpp_offset, ap);
|
||||
error = umap_node_create(old_vps[0]->v_mount, **vppp, *vppp);
|
||||
};
|
||||
|
||||
out:
|
||||
/*
|
||||
* Free duplicate cred structure and restore old one.
|
||||
*/
|
||||
if (descp->vdesc_cred_offset != VDESC_NO_OFFSET) {
|
||||
if (umap_bug_bypass && credp && credp->cr_uid != 0)
|
||||
printf("umap_bypass: returning-user was %d\n",
|
||||
credp->cr_uid);
|
||||
|
||||
crfree(credp);
|
||||
(*credpp) = savecredp;
|
||||
if (umap_bug_bypass && credpp && (*credpp)->cr_uid != 0)
|
||||
printf("umap_bypass: returning-user now %d\n\n",
|
||||
(*credpp)->cr_uid);
|
||||
}
|
||||
|
||||
if (descp->vdesc_componentname_offset != VDESC_NO_OFFSET) {
|
||||
if (umap_bug_bypass && compcredp && compcredp->cr_uid != 0)
|
||||
printf("umap_bypass: returning-component-user was %d\n",
|
||||
compcredp->cr_uid);
|
||||
|
||||
crfree(compcredp);
|
||||
(*compnamepp)->cn_cred = savecompcredp;
|
||||
if (umap_bug_bypass && credpp && (*credpp)->cr_uid != 0)
|
||||
printf("umap_bypass: returning-component-user now %d\n",
|
||||
compcredp->cr_uid);
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* We handle getattr to change the fsid.
|
||||
*/
|
||||
int
|
||||
umap_getattr(ap)
|
||||
struct vop_getattr_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct vattr *a_vap;
|
||||
struct ucred *a_cred;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
short uid, gid;
|
||||
int error, tmpid, nentries, gnentries;
|
||||
u_long (*mapdata)[2], (*gmapdata)[2];
|
||||
struct vnode **vp1p;
|
||||
struct vnodeop_desc *descp = ap->a_desc;
|
||||
|
||||
if (error = umap_bypass(ap))
|
||||
return (error);
|
||||
/* Requires that arguments be restored. */
|
||||
ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
|
||||
|
||||
/*
|
||||
* Umap needs to map the uid and gid returned by a stat
|
||||
* into the proper values for this site. This involves
|
||||
* finding the returned uid in the mapping information,
|
||||
* translating it into the uid on the other end,
|
||||
* and filling in the proper field in the vattr
|
||||
* structure pointed to by ap->a_vap. The group
|
||||
* is easier, since currently all groups will be
|
||||
* translate to the NULLGROUP.
|
||||
*/
|
||||
|
||||
/* Find entry in map */
|
||||
|
||||
uid = ap->a_vap->va_uid;
|
||||
gid = ap->a_vap->va_gid;
|
||||
if (umap_bug_bypass)
|
||||
printf("umap_getattr: mapped uid = %d, mapped gid = %d\n", uid,
|
||||
gid);
|
||||
|
||||
vp1p = VOPARG_OFFSETTO(struct vnode**, descp->vdesc_vp_offsets[0], ap);
|
||||
nentries = MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_nentries;
|
||||
mapdata = (MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_mapdata);
|
||||
gnentries = MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_gnentries;
|
||||
gmapdata = (MOUNTTOUMAPMOUNT((*vp1p)->v_mount)->info_gmapdata);
|
||||
|
||||
/* Reverse map the uid for the vnode. Since it's a reverse
|
||||
map, we can't use umap_mapids() to do it. */
|
||||
|
||||
tmpid = umap_reverse_findid(uid, mapdata, nentries);
|
||||
|
||||
if (tmpid != -1) {
|
||||
|
||||
ap->a_vap->va_uid = (uid_t) tmpid;
|
||||
if (umap_bug_bypass)
|
||||
printf("umap_getattr: original uid = %d\n", uid);
|
||||
} else
|
||||
ap->a_vap->va_uid = (uid_t) NOBODY;
|
||||
|
||||
/* Reverse map the gid for the vnode. */
|
||||
|
||||
tmpid = umap_reverse_findid(gid, gmapdata, gnentries);
|
||||
|
||||
if (tmpid != -1) {
|
||||
|
||||
ap->a_vap->va_gid = (gid_t) tmpid;
|
||||
if (umap_bug_bypass)
|
||||
printf("umap_getattr: original gid = %d\n", gid);
|
||||
} else
|
||||
ap->a_vap->va_gid = (gid_t) NULLGROUP;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to process our own vnode lock and then clear the
|
||||
* interlock flag as it applies only to our vnode, not the
|
||||
* vnodes below us on the stack.
|
||||
*/
|
||||
int
|
||||
umap_lock(ap)
|
||||
struct vop_lock_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_flags;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
|
||||
vop_nolock(ap);
|
||||
if ((ap->a_flags & LK_TYPE_MASK) == LK_DRAIN)
|
||||
return (0);
|
||||
ap->a_flags &= ~LK_INTERLOCK;
|
||||
return (null_bypass(ap));
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to process our own vnode unlock and then clear the
|
||||
* interlock flag as it applies only to our vnode, not the
|
||||
* vnodes below us on the stack.
|
||||
*/
|
||||
int
|
||||
umap_unlock(ap)
|
||||
struct vop_unlock_args /* {
|
||||
struct vnode *a_vp;
|
||||
int a_flags;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
|
||||
vop_nounlock(ap);
|
||||
ap->a_flags &= ~LK_INTERLOCK;
|
||||
return (null_bypass(ap));
|
||||
}
|
||||
|
||||
int
|
||||
umap_inactive(ap)
|
||||
struct vop_inactive_args /* {
|
||||
struct vnode *a_vp;
|
||||
struct proc *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
/*
|
||||
* Do nothing (and _don't_ bypass).
|
||||
* Wait to vrele lowervp until reclaim,
|
||||
* so that until then our umap_node is in the
|
||||
* cache and reusable.
|
||||
*
|
||||
*/
|
||||
VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
umap_reclaim(ap)
|
||||
struct vop_reclaim_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct umap_node *xp = VTOUMAP(vp);
|
||||
struct vnode *lowervp = xp->umap_lowervp;
|
||||
|
||||
/* After this assignment, this node will not be re-used. */
|
||||
xp->umap_lowervp = NULL;
|
||||
LIST_REMOVE(xp, umap_hash);
|
||||
FREE(vp->v_data, M_TEMP);
|
||||
vp->v_data = NULL;
|
||||
vrele(lowervp);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
umap_strategy(ap)
|
||||
struct vop_strategy_args /* {
|
||||
struct buf *a_bp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct buf *bp = ap->a_bp;
|
||||
int error;
|
||||
struct vnode *savedvp;
|
||||
|
||||
savedvp = bp->b_vp;
|
||||
bp->b_vp = UMAPVPTOLOWERVP(bp->b_vp);
|
||||
|
||||
error = VOP_STRATEGY(ap->a_bp);
|
||||
|
||||
bp->b_vp = savedvp;
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
umap_bwrite(ap)
|
||||
struct vop_bwrite_args /* {
|
||||
struct buf *a_bp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct buf *bp = ap->a_bp;
|
||||
int error;
|
||||
struct vnode *savedvp;
|
||||
|
||||
savedvp = bp->b_vp;
|
||||
bp->b_vp = UMAPVPTOLOWERVP(bp->b_vp);
|
||||
|
||||
error = VOP_BWRITE(ap->a_bp);
|
||||
|
||||
bp->b_vp = savedvp;
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
umap_print(ap)
|
||||
struct vop_print_args /* {
|
||||
struct vnode *a_vp;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
printf("\ttag VT_UMAPFS, vp=%x, lowervp=%x\n", vp, UMAPVPTOLOWERVP(vp));
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
umap_rename(ap)
|
||||
struct vop_rename_args /* {
|
||||
struct vnode *a_fdvp;
|
||||
struct vnode *a_fvp;
|
||||
struct componentname *a_fcnp;
|
||||
struct vnode *a_tdvp;
|
||||
struct vnode *a_tvp;
|
||||
struct componentname *a_tcnp;
|
||||
} */ *ap;
|
||||
{
|
||||
int error;
|
||||
struct componentname *compnamep;
|
||||
struct ucred *compcredp, *savecompcredp;
|
||||
struct vnode *vp;
|
||||
|
||||
/*
|
||||
* Rename is irregular, having two componentname structures.
|
||||
* We need to map the cre in the second structure,
|
||||
* and then bypass takes care of the rest.
|
||||
*/
|
||||
|
||||
vp = ap->a_fdvp;
|
||||
compnamep = ap->a_tcnp;
|
||||
compcredp = compnamep->cn_cred;
|
||||
|
||||
savecompcredp = compcredp;
|
||||
compcredp = compnamep->cn_cred = crdup(savecompcredp);
|
||||
|
||||
if (umap_bug_bypass && compcredp->cr_uid != 0)
|
||||
printf("umap_rename: rename component credit user was %d, group %d\n",
|
||||
compcredp->cr_uid, compcredp->cr_gid);
|
||||
|
||||
/* Map all ids in the credential structure. */
|
||||
|
||||
umap_mapids(vp->v_mount, compcredp);
|
||||
|
||||
if (umap_bug_bypass && compcredp->cr_uid != 0)
|
||||
printf("umap_rename: rename component credit user now %d, group %d\n",
|
||||
compcredp->cr_uid, compcredp->cr_gid);
|
||||
|
||||
error = umap_bypass(ap);
|
||||
|
||||
/* Restore the additional mapped componentname cred structure. */
|
||||
|
||||
crfree(compcredp);
|
||||
compnamep->cn_cred = savecompcredp;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Global vfs data structures
|
||||
*/
|
||||
/*
|
||||
* XXX - strategy, bwrite are hand coded currently. They should
|
||||
* go away with a merged buffer/block cache.
|
||||
*
|
||||
*/
|
||||
int (**umap_vnodeop_p)();
|
||||
struct vnodeopv_entry_desc umap_vnodeop_entries[] = {
|
||||
{ &vop_default_desc, umap_bypass },
|
||||
|
||||
{ &vop_getattr_desc, umap_getattr },
|
||||
{ &vop_lock_desc, umap_lock },
|
||||
{ &vop_unlock_desc, umap_unlock },
|
||||
{ &vop_inactive_desc, umap_inactive },
|
||||
{ &vop_reclaim_desc, umap_reclaim },
|
||||
{ &vop_print_desc, umap_print },
|
||||
{ &vop_rename_desc, umap_rename },
|
||||
|
||||
{ &vop_strategy_desc, umap_strategy },
|
||||
{ &vop_bwrite_desc, umap_bwrite },
|
||||
|
||||
{ (struct vnodeop_desc*) NULL, (int(*)()) NULL }
|
||||
};
|
||||
struct vnodeopv_desc umap_vnodeop_opv_desc =
|
||||
{ &umap_vnodeop_p, umap_vnodeop_entries };
|
||||
8
sys/miscfs/union/README
Normal file
8
sys/miscfs/union/README
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
If you plan on using union mounts, then you should consider replacing
|
||||
three files in "libc/gen" in the C library with the files in "libc"
|
||||
in this directory. The replacement version of opendir() automatically
|
||||
removes duplicate names when a union stack is encountered. The other
|
||||
two files do special handling of whiteouts. You will then need to
|
||||
rebuild the C library and all commands.
|
||||
|
||||
@(#)README 8.2 (Berkeley) 11/4/94
|
||||
995
sys/miscfs/union/libc.fts.c
Normal file
995
sys/miscfs/union/libc.fts.c
Normal file
|
|
@ -0,0 +1,995 @@
|
|||
/*-
|
||||
* Copyright (c) 1990, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <fts.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static FTSENT *fts_alloc __P((FTS *, char *, int));
|
||||
static FTSENT *fts_build __P((FTS *, int));
|
||||
static void fts_lfree __P((FTSENT *));
|
||||
static void fts_load __P((FTS *, FTSENT *));
|
||||
static size_t fts_maxarglen __P((char * const *));
|
||||
static void fts_padjust __P((FTS *, void *));
|
||||
static int fts_palloc __P((FTS *, size_t));
|
||||
static FTSENT *fts_sort __P((FTS *, FTSENT *, int));
|
||||
static u_short fts_stat __P((FTS *, FTSENT *, int));
|
||||
|
||||
#define ISDOT(a) (a[0] == '.' && (!a[1] || a[1] == '.' && !a[2]))
|
||||
|
||||
#define ISSET(opt) (sp->fts_options & opt)
|
||||
#define SET(opt) (sp->fts_options |= opt)
|
||||
|
||||
#define CHDIR(sp, path) (!ISSET(FTS_NOCHDIR) && chdir(path))
|
||||
#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd))
|
||||
|
||||
/* fts_build flags */
|
||||
#define BCHILD 1 /* fts_children */
|
||||
#define BNAMES 2 /* fts_children, names only */
|
||||
#define BREAD 3 /* fts_read */
|
||||
|
||||
FTS *
|
||||
fts_open(argv, options, compar)
|
||||
char * const *argv;
|
||||
register int options;
|
||||
int (*compar)();
|
||||
{
|
||||
register FTS *sp;
|
||||
register FTSENT *p, *root;
|
||||
register int nitems;
|
||||
FTSENT *parent, *tmp;
|
||||
int len;
|
||||
|
||||
/* Options check. */
|
||||
if (options & ~FTS_OPTIONMASK) {
|
||||
errno = EINVAL;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Allocate/initialize the stream */
|
||||
if ((sp = malloc((u_int)sizeof(FTS))) == NULL)
|
||||
return (NULL);
|
||||
memset(sp, 0, sizeof(FTS));
|
||||
sp->fts_compar = compar;
|
||||
sp->fts_options = options;
|
||||
|
||||
/* Logical walks turn on NOCHDIR; symbolic links are too hard. */
|
||||
if (ISSET(FTS_LOGICAL))
|
||||
SET(FTS_NOCHDIR);
|
||||
|
||||
/*
|
||||
* Start out with 1K of path space, and enough, in any case,
|
||||
* to hold the user's paths.
|
||||
*/
|
||||
if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN)))
|
||||
goto mem1;
|
||||
|
||||
/* Allocate/initialize root's parent. */
|
||||
if ((parent = fts_alloc(sp, "", 0)) == NULL)
|
||||
goto mem2;
|
||||
parent->fts_level = FTS_ROOTPARENTLEVEL;
|
||||
|
||||
/* Allocate/initialize root(s). */
|
||||
for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) {
|
||||
/* Don't allow zero-length paths. */
|
||||
if ((len = strlen(*argv)) == 0) {
|
||||
errno = ENOENT;
|
||||
goto mem3;
|
||||
}
|
||||
|
||||
p = fts_alloc(sp, *argv, len);
|
||||
p->fts_level = FTS_ROOTLEVEL;
|
||||
p->fts_parent = parent;
|
||||
p->fts_accpath = p->fts_name;
|
||||
p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW));
|
||||
|
||||
/* Command-line "." and ".." are real directories. */
|
||||
if (p->fts_info == FTS_DOT)
|
||||
p->fts_info = FTS_D;
|
||||
|
||||
/*
|
||||
* If comparison routine supplied, traverse in sorted
|
||||
* order; otherwise traverse in the order specified.
|
||||
*/
|
||||
if (compar) {
|
||||
p->fts_link = root;
|
||||
root = p;
|
||||
} else {
|
||||
p->fts_link = NULL;
|
||||
if (root == NULL)
|
||||
tmp = root = p;
|
||||
else {
|
||||
tmp->fts_link = p;
|
||||
tmp = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (compar && nitems > 1)
|
||||
root = fts_sort(sp, root, nitems);
|
||||
|
||||
/*
|
||||
* Allocate a dummy pointer and make fts_read think that we've just
|
||||
* finished the node before the root(s); set p->fts_info to FTS_INIT
|
||||
* so that everything about the "current" node is ignored.
|
||||
*/
|
||||
if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
|
||||
goto mem3;
|
||||
sp->fts_cur->fts_link = root;
|
||||
sp->fts_cur->fts_info = FTS_INIT;
|
||||
|
||||
/*
|
||||
* If using chdir(2), grab a file descriptor pointing to dot to insure
|
||||
* that we can get back here; this could be avoided for some paths,
|
||||
* but almost certainly not worth the effort. Slashes, symbolic links,
|
||||
* and ".." are all fairly nasty problems. Note, if we can't get the
|
||||
* descriptor we run anyway, just more slowly.
|
||||
*/
|
||||
if (!ISSET(FTS_NOCHDIR) && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0)
|
||||
SET(FTS_NOCHDIR);
|
||||
|
||||
return (sp);
|
||||
|
||||
mem3: fts_lfree(root);
|
||||
free(parent);
|
||||
mem2: free(sp->fts_path);
|
||||
mem1: free(sp);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
fts_load(sp, p)
|
||||
FTS *sp;
|
||||
register FTSENT *p;
|
||||
{
|
||||
register int len;
|
||||
register char *cp;
|
||||
|
||||
/*
|
||||
* Load the stream structure for the next traversal. Since we don't
|
||||
* actually enter the directory until after the preorder visit, set
|
||||
* the fts_accpath field specially so the chdir gets done to the right
|
||||
* place and the user can access the first node. From fts_open it's
|
||||
* known that the path will fit.
|
||||
*/
|
||||
len = p->fts_pathlen = p->fts_namelen;
|
||||
memmove(sp->fts_path, p->fts_name, len + 1);
|
||||
if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
|
||||
len = strlen(++cp);
|
||||
memmove(p->fts_name, cp, len + 1);
|
||||
p->fts_namelen = len;
|
||||
}
|
||||
p->fts_accpath = p->fts_path = sp->fts_path;
|
||||
sp->fts_dev = p->fts_dev;
|
||||
}
|
||||
|
||||
int
|
||||
fts_close(sp)
|
||||
FTS *sp;
|
||||
{
|
||||
register FTSENT *freep, *p;
|
||||
int saved_errno;
|
||||
|
||||
/*
|
||||
* This still works if we haven't read anything -- the dummy structure
|
||||
* points to the root list, so we step through to the end of the root
|
||||
* list which has a valid parent pointer.
|
||||
*/
|
||||
if (sp->fts_cur) {
|
||||
for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
|
||||
freep = p;
|
||||
p = p->fts_link ? p->fts_link : p->fts_parent;
|
||||
free(freep);
|
||||
}
|
||||
free(p);
|
||||
}
|
||||
|
||||
/* Free up child linked list, sort array, path buffer. */
|
||||
if (sp->fts_child)
|
||||
fts_lfree(sp->fts_child);
|
||||
if (sp->fts_array)
|
||||
free(sp->fts_array);
|
||||
free(sp->fts_path);
|
||||
|
||||
/* Return to original directory, save errno if necessary. */
|
||||
if (!ISSET(FTS_NOCHDIR)) {
|
||||
saved_errno = fchdir(sp->fts_rfd) ? errno : 0;
|
||||
(void)close(sp->fts_rfd);
|
||||
}
|
||||
|
||||
/* Free up the stream pointer. */
|
||||
free(sp);
|
||||
|
||||
/* Set errno and return. */
|
||||
if (!ISSET(FTS_NOCHDIR) && saved_errno) {
|
||||
errno = saved_errno;
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Special case a root of "/" so that slashes aren't appended which would
|
||||
* cause paths to be written as "//foo".
|
||||
*/
|
||||
#define NAPPEND(p) \
|
||||
(p->fts_level == FTS_ROOTLEVEL && p->fts_pathlen == 1 && \
|
||||
p->fts_path[0] == '/' ? 0 : p->fts_pathlen)
|
||||
|
||||
FTSENT *
|
||||
fts_read(sp)
|
||||
register FTS *sp;
|
||||
{
|
||||
register FTSENT *p, *tmp;
|
||||
register int instr;
|
||||
register char *t;
|
||||
int saved_errno;
|
||||
|
||||
/* If finished or unrecoverable error, return NULL. */
|
||||
if (sp->fts_cur == NULL || ISSET(FTS_STOP))
|
||||
return (NULL);
|
||||
|
||||
/* Set current node pointer. */
|
||||
p = sp->fts_cur;
|
||||
|
||||
/* Save and zero out user instructions. */
|
||||
instr = p->fts_instr;
|
||||
p->fts_instr = FTS_NOINSTR;
|
||||
|
||||
/* Any type of file may be re-visited; re-stat and re-turn. */
|
||||
if (instr == FTS_AGAIN) {
|
||||
p->fts_info = fts_stat(sp, p, 0);
|
||||
return (p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Following a symlink -- SLNONE test allows application to see
|
||||
* SLNONE and recover. If indirecting through a symlink, have
|
||||
* keep a pointer to current location. If unable to get that
|
||||
* pointer, follow fails.
|
||||
*/
|
||||
if (instr == FTS_FOLLOW &&
|
||||
(p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
|
||||
p->fts_info = fts_stat(sp, p, 1);
|
||||
if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR))
|
||||
if ((p->fts_symfd = open(".", O_RDONLY, 0)) < 0) {
|
||||
p->fts_errno = errno;
|
||||
p->fts_info = FTS_ERR;
|
||||
} else
|
||||
p->fts_flags |= FTS_SYMFOLLOW;
|
||||
return (p);
|
||||
}
|
||||
|
||||
/* Directory in pre-order. */
|
||||
if (p->fts_info == FTS_D) {
|
||||
/* If skipped or crossed mount point, do post-order visit. */
|
||||
if (instr == FTS_SKIP ||
|
||||
ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev) {
|
||||
if (p->fts_flags & FTS_SYMFOLLOW)
|
||||
(void)close(p->fts_symfd);
|
||||
if (sp->fts_child) {
|
||||
fts_lfree(sp->fts_child);
|
||||
sp->fts_child = NULL;
|
||||
}
|
||||
p->fts_info = FTS_DP;
|
||||
return (p);
|
||||
}
|
||||
|
||||
/* Rebuild if only read the names and now traversing. */
|
||||
if (sp->fts_child && sp->fts_options & FTS_NAMEONLY) {
|
||||
sp->fts_options &= ~FTS_NAMEONLY;
|
||||
fts_lfree(sp->fts_child);
|
||||
sp->fts_child = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cd to the subdirectory.
|
||||
*
|
||||
* If have already read and now fail to chdir, whack the list
|
||||
* to make the names come out right, and set the parent errno
|
||||
* so the application will eventually get an error condition.
|
||||
* Set the FTS_DONTCHDIR flag so that when we logically change
|
||||
* directories back to the parent we don't do a chdir.
|
||||
*
|
||||
* If haven't read do so. If the read fails, fts_build sets
|
||||
* FTS_STOP or the fts_info field of the node.
|
||||
*/
|
||||
if (sp->fts_child) {
|
||||
if (CHDIR(sp, p->fts_accpath)) {
|
||||
p->fts_errno = errno;
|
||||
p->fts_flags |= FTS_DONTCHDIR;
|
||||
for (p = sp->fts_child; p; p = p->fts_link)
|
||||
p->fts_accpath =
|
||||
p->fts_parent->fts_accpath;
|
||||
}
|
||||
} else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
|
||||
if (ISSET(FTS_STOP))
|
||||
return (NULL);
|
||||
return (p);
|
||||
}
|
||||
p = sp->fts_child;
|
||||
sp->fts_child = NULL;
|
||||
goto name;
|
||||
}
|
||||
|
||||
/* Move to the next node on this level. */
|
||||
next: tmp = p;
|
||||
if (p = p->fts_link) {
|
||||
free(tmp);
|
||||
|
||||
/*
|
||||
* If reached the top, return to the original directory, and
|
||||
* load the paths for the next root.
|
||||
*/
|
||||
if (p->fts_level == FTS_ROOTLEVEL) {
|
||||
if (!ISSET(FTS_NOCHDIR) && FCHDIR(sp, sp->fts_rfd)) {
|
||||
SET(FTS_STOP);
|
||||
return (NULL);
|
||||
}
|
||||
fts_load(sp, p);
|
||||
return (sp->fts_cur = p);
|
||||
}
|
||||
|
||||
/*
|
||||
* User may have called fts_set on the node. If skipped,
|
||||
* ignore. If followed, get a file descriptor so we can
|
||||
* get back if necessary.
|
||||
*/
|
||||
if (p->fts_instr == FTS_SKIP)
|
||||
goto next;
|
||||
if (p->fts_instr == FTS_FOLLOW) {
|
||||
p->fts_info = fts_stat(sp, p, 1);
|
||||
if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR))
|
||||
if ((p->fts_symfd =
|
||||
open(".", O_RDONLY, 0)) < 0) {
|
||||
p->fts_errno = errno;
|
||||
p->fts_info = FTS_ERR;
|
||||
} else
|
||||
p->fts_flags |= FTS_SYMFOLLOW;
|
||||
p->fts_instr = FTS_NOINSTR;
|
||||
}
|
||||
|
||||
name: t = sp->fts_path + NAPPEND(p->fts_parent);
|
||||
*t++ = '/';
|
||||
memmove(t, p->fts_name, p->fts_namelen + 1);
|
||||
return (sp->fts_cur = p);
|
||||
}
|
||||
|
||||
/* Move up to the parent node. */
|
||||
p = tmp->fts_parent;
|
||||
free(tmp);
|
||||
|
||||
if (p->fts_level == FTS_ROOTPARENTLEVEL) {
|
||||
/*
|
||||
* Done; free everything up and set errno to 0 so the user
|
||||
* can distinguish between error and EOF.
|
||||
*/
|
||||
free(p);
|
||||
errno = 0;
|
||||
return (sp->fts_cur = NULL);
|
||||
}
|
||||
|
||||
/* Nul terminate the pathname. */
|
||||
sp->fts_path[p->fts_pathlen] = '\0';
|
||||
|
||||
/*
|
||||
* Return to the parent directory. If at a root node or came through
|
||||
* a symlink, go back through the file descriptor. Otherwise, cd up
|
||||
* one directory.
|
||||
*/
|
||||
if (p->fts_level == FTS_ROOTLEVEL) {
|
||||
if (!ISSET(FTS_NOCHDIR) && FCHDIR(sp, sp->fts_rfd)) {
|
||||
SET(FTS_STOP);
|
||||
return (NULL);
|
||||
}
|
||||
} else if (p->fts_flags & FTS_SYMFOLLOW) {
|
||||
if (FCHDIR(sp, p->fts_symfd)) {
|
||||
saved_errno = errno;
|
||||
(void)close(p->fts_symfd);
|
||||
errno = saved_errno;
|
||||
SET(FTS_STOP);
|
||||
return (NULL);
|
||||
}
|
||||
(void)close(p->fts_symfd);
|
||||
} else if (!(p->fts_flags & FTS_DONTCHDIR)) {
|
||||
if (CHDIR(sp, "..")) {
|
||||
SET(FTS_STOP);
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
|
||||
return (sp->fts_cur = p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fts_set takes the stream as an argument although it's not used in this
|
||||
* implementation; it would be necessary if anyone wanted to add global
|
||||
* semantics to fts using fts_set. An error return is allowed for similar
|
||||
* reasons.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
int
|
||||
fts_set(sp, p, instr)
|
||||
FTS *sp;
|
||||
FTSENT *p;
|
||||
int instr;
|
||||
{
|
||||
if (instr && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
|
||||
instr != FTS_NOINSTR && instr != FTS_SKIP) {
|
||||
errno = EINVAL;
|
||||
return (1);
|
||||
}
|
||||
p->fts_instr = instr;
|
||||
return (0);
|
||||
}
|
||||
|
||||
FTSENT *
|
||||
fts_children(sp, instr)
|
||||
register FTS *sp;
|
||||
int instr;
|
||||
{
|
||||
register FTSENT *p;
|
||||
int fd;
|
||||
|
||||
if (instr && instr != FTS_NAMEONLY) {
|
||||
errno = EINVAL;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Set current node pointer. */
|
||||
p = sp->fts_cur;
|
||||
|
||||
/*
|
||||
* Errno set to 0 so user can distinguish empty directory from
|
||||
* an error.
|
||||
*/
|
||||
errno = 0;
|
||||
|
||||
/* Fatal errors stop here. */
|
||||
if (ISSET(FTS_STOP))
|
||||
return (NULL);
|
||||
|
||||
/* Return logical hierarchy of user's arguments. */
|
||||
if (p->fts_info == FTS_INIT)
|
||||
return (p->fts_link);
|
||||
|
||||
/*
|
||||
* If not a directory being visited in pre-order, stop here. Could
|
||||
* allow FTS_DNR, assuming the user has fixed the problem, but the
|
||||
* same effect is available with FTS_AGAIN.
|
||||
*/
|
||||
if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
|
||||
return (NULL);
|
||||
|
||||
/* Free up any previous child list. */
|
||||
if (sp->fts_child)
|
||||
fts_lfree(sp->fts_child);
|
||||
|
||||
if (instr == FTS_NAMEONLY) {
|
||||
sp->fts_options |= FTS_NAMEONLY;
|
||||
instr = BNAMES;
|
||||
} else
|
||||
instr = BCHILD;
|
||||
|
||||
/*
|
||||
* If using chdir on a relative path and called BEFORE fts_read does
|
||||
* its chdir to the root of a traversal, we can lose -- we need to
|
||||
* chdir into the subdirectory, and we don't know where the current
|
||||
* directory is, so we can't get back so that the upcoming chdir by
|
||||
* fts_read will work.
|
||||
*/
|
||||
if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
|
||||
ISSET(FTS_NOCHDIR))
|
||||
return (sp->fts_child = fts_build(sp, instr));
|
||||
|
||||
if ((fd = open(".", O_RDONLY, 0)) < 0)
|
||||
return (NULL);
|
||||
sp->fts_child = fts_build(sp, instr);
|
||||
if (fchdir(fd))
|
||||
return (NULL);
|
||||
(void)close(fd);
|
||||
return (sp->fts_child);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the tricky part -- do not casually change *anything* in here. The
|
||||
* idea is to build the linked list of entries that are used by fts_children
|
||||
* and fts_read. There are lots of special cases.
|
||||
*
|
||||
* The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is
|
||||
* set and it's a physical walk (so that symbolic links can't be directories),
|
||||
* we can do things quickly. First, if it's a 4.4BSD file system, the type
|
||||
* of the file is in the directory entry. Otherwise, we assume that the number
|
||||
* of subdirectories in a node is equal to the number of links to the parent.
|
||||
* The former skips all stat calls. The latter skips stat calls in any leaf
|
||||
* directories and for any files after the subdirectories in the directory have
|
||||
* been found, cutting the stat calls by about 2/3.
|
||||
*/
|
||||
static FTSENT *
|
||||
fts_build(sp, type)
|
||||
register FTS *sp;
|
||||
int type;
|
||||
{
|
||||
register struct dirent *dp;
|
||||
register FTSENT *p, *head;
|
||||
register int nitems;
|
||||
FTSENT *cur, *tail;
|
||||
DIR *dirp;
|
||||
void *adjaddr;
|
||||
int cderrno, descend, len, level, maxlen, nlinks, oflag, saved_errno;
|
||||
char *cp;
|
||||
|
||||
/* Set current node pointer. */
|
||||
cur = sp->fts_cur;
|
||||
|
||||
/*
|
||||
* Open the directory for reading. If this fails, we're done.
|
||||
* If being called from fts_read, set the fts_info field.
|
||||
*/
|
||||
#ifdef FTS_WHITEOUT
|
||||
if (ISSET(FTS_WHITEOUT))
|
||||
oflag = DTF_NODUP|DTF_REWIND;
|
||||
else
|
||||
oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND;
|
||||
#else
|
||||
#define __opendir2(path, flag) opendir(path)
|
||||
#endif
|
||||
if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) {
|
||||
if (type == BREAD) {
|
||||
cur->fts_info = FTS_DNR;
|
||||
cur->fts_errno = errno;
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Nlinks is the number of possible entries of type directory in the
|
||||
* directory if we're cheating on stat calls, 0 if we're not doing
|
||||
* any stat calls at all, -1 if we're doing stats on everything.
|
||||
*/
|
||||
if (type == BNAMES)
|
||||
nlinks = 0;
|
||||
else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL))
|
||||
nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
|
||||
else
|
||||
nlinks = -1;
|
||||
|
||||
#ifdef notdef
|
||||
(void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);
|
||||
(void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
|
||||
ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
|
||||
#endif
|
||||
/*
|
||||
* If we're going to need to stat anything or we want to descend
|
||||
* and stay in the directory, chdir. If this fails we keep going,
|
||||
* but set a flag so we don't chdir after the post-order visit.
|
||||
* We won't be able to stat anything, but we can still return the
|
||||
* names themselves. Note, that since fts_read won't be able to
|
||||
* chdir into the directory, it will have to return different path
|
||||
* names than before, i.e. "a/b" instead of "b". Since the node
|
||||
* has already been visited in pre-order, have to wait until the
|
||||
* post-order visit to return the error. There is a special case
|
||||
* here, if there was nothing to stat then it's not an error to
|
||||
* not be able to stat. This is all fairly nasty. If a program
|
||||
* needed sorted entries or stat information, they had better be
|
||||
* checking FTS_NS on the returned nodes.
|
||||
*/
|
||||
cderrno = 0;
|
||||
if (nlinks || type == BREAD)
|
||||
if (FCHDIR(sp, dirfd(dirp))) {
|
||||
if (nlinks && type == BREAD)
|
||||
cur->fts_errno = errno;
|
||||
cur->fts_flags |= FTS_DONTCHDIR;
|
||||
descend = 0;
|
||||
cderrno = errno;
|
||||
} else
|
||||
descend = 1;
|
||||
else
|
||||
descend = 0;
|
||||
|
||||
/*
|
||||
* Figure out the max file name length that can be stored in the
|
||||
* current path -- the inner loop allocates more path as necessary.
|
||||
* We really wouldn't have to do the maxlen calculations here, we
|
||||
* could do them in fts_read before returning the path, but it's a
|
||||
* lot easier here since the length is part of the dirent structure.
|
||||
*
|
||||
* If not changing directories set a pointer so that can just append
|
||||
* each new name into the path.
|
||||
*/
|
||||
maxlen = sp->fts_pathlen - cur->fts_pathlen - 1;
|
||||
len = NAPPEND(cur);
|
||||
if (ISSET(FTS_NOCHDIR)) {
|
||||
cp = sp->fts_path + len;
|
||||
*cp++ = '/';
|
||||
}
|
||||
|
||||
level = cur->fts_level + 1;
|
||||
|
||||
/* Read the directory, attaching each entry to the `link' pointer. */
|
||||
adjaddr = NULL;
|
||||
for (head = tail = NULL, nitems = 0; dp = readdir(dirp);) {
|
||||
if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
|
||||
continue;
|
||||
|
||||
if ((p = fts_alloc(sp, dp->d_name, (int)dp->d_namlen)) == NULL)
|
||||
goto mem1;
|
||||
if (dp->d_namlen > maxlen) {
|
||||
if (fts_palloc(sp, (size_t)dp->d_namlen)) {
|
||||
/*
|
||||
* No more memory for path or structures. Save
|
||||
* errno, free up the current structure and the
|
||||
* structures already allocated.
|
||||
*/
|
||||
mem1: saved_errno = errno;
|
||||
if (p)
|
||||
free(p);
|
||||
fts_lfree(head);
|
||||
(void)closedir(dirp);
|
||||
errno = saved_errno;
|
||||
cur->fts_info = FTS_ERR;
|
||||
SET(FTS_STOP);
|
||||
return (NULL);
|
||||
}
|
||||
adjaddr = sp->fts_path;
|
||||
maxlen = sp->fts_pathlen - sp->fts_cur->fts_pathlen - 1;
|
||||
}
|
||||
|
||||
p->fts_pathlen = len + dp->d_namlen + 1;
|
||||
p->fts_parent = sp->fts_cur;
|
||||
p->fts_level = level;
|
||||
|
||||
#ifdef FTS_WHITEOUT
|
||||
if (dp->d_type == DT_WHT)
|
||||
p->fts_flags |= FTS_ISW;
|
||||
#endif
|
||||
|
||||
if (cderrno) {
|
||||
if (nlinks) {
|
||||
p->fts_info = FTS_NS;
|
||||
p->fts_errno = cderrno;
|
||||
} else
|
||||
p->fts_info = FTS_NSOK;
|
||||
p->fts_accpath = cur->fts_accpath;
|
||||
} else if (nlinks == 0
|
||||
#ifdef DT_DIR
|
||||
|| nlinks > 0 &&
|
||||
dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN
|
||||
#endif
|
||||
) {
|
||||
p->fts_accpath =
|
||||
ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
|
||||
p->fts_info = FTS_NSOK;
|
||||
} else {
|
||||
/* Build a file name for fts_stat to stat. */
|
||||
if (ISSET(FTS_NOCHDIR)) {
|
||||
p->fts_accpath = p->fts_path;
|
||||
memmove(cp, p->fts_name, p->fts_namelen + 1);
|
||||
} else
|
||||
p->fts_accpath = p->fts_name;
|
||||
/* Stat it. */
|
||||
p->fts_info = fts_stat(sp, p, 0);
|
||||
|
||||
/* Decrement link count if applicable. */
|
||||
if (nlinks > 0 && (p->fts_info == FTS_D ||
|
||||
p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
|
||||
--nlinks;
|
||||
}
|
||||
|
||||
/* We walk in directory order so "ls -f" doesn't get upset. */
|
||||
p->fts_link = NULL;
|
||||
if (head == NULL)
|
||||
head = tail = p;
|
||||
else {
|
||||
tail->fts_link = p;
|
||||
tail = p;
|
||||
}
|
||||
++nitems;
|
||||
}
|
||||
(void)closedir(dirp);
|
||||
|
||||
/*
|
||||
* If had to realloc the path, adjust the addresses for the rest
|
||||
* of the tree.
|
||||
*/
|
||||
if (adjaddr)
|
||||
fts_padjust(sp, adjaddr);
|
||||
|
||||
/*
|
||||
* If not changing directories, reset the path back to original
|
||||
* state.
|
||||
*/
|
||||
if (ISSET(FTS_NOCHDIR)) {
|
||||
if (cp - 1 > sp->fts_path)
|
||||
--cp;
|
||||
*cp = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* If descended after called from fts_children or after called from
|
||||
* fts_read and nothing found, get back. At the root level we use
|
||||
* the saved fd; if one of fts_open()'s arguments is a relative path
|
||||
* to an empty directory, we wind up here with no other way back. If
|
||||
* can't get back, we're done.
|
||||
*/
|
||||
if (descend && (type == BCHILD || !nitems) &&
|
||||
(cur->fts_level == FTS_ROOTLEVEL ?
|
||||
FCHDIR(sp, sp->fts_rfd) : CHDIR(sp, ".."))) {
|
||||
cur->fts_info = FTS_ERR;
|
||||
SET(FTS_STOP);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* If didn't find anything, return NULL. */
|
||||
if (!nitems) {
|
||||
if (type == BREAD)
|
||||
cur->fts_info = FTS_DP;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Sort the entries. */
|
||||
if (sp->fts_compar && nitems > 1)
|
||||
head = fts_sort(sp, head, nitems);
|
||||
return (head);
|
||||
}
|
||||
|
||||
static u_short
|
||||
fts_stat(sp, p, follow)
|
||||
FTS *sp;
|
||||
register FTSENT *p;
|
||||
int follow;
|
||||
{
|
||||
register FTSENT *t;
|
||||
register dev_t dev;
|
||||
register ino_t ino;
|
||||
struct stat *sbp, sb;
|
||||
int saved_errno;
|
||||
|
||||
/* If user needs stat info, stat buffer already allocated. */
|
||||
sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
|
||||
|
||||
#ifdef FTS_WHITEOUT
|
||||
/* check for whiteout */
|
||||
if (p->fts_flags & FTS_ISW) {
|
||||
if (sbp != &sb) {
|
||||
memset(sbp, '\0', sizeof (*sbp));
|
||||
sbp->st_mode = S_IFWHT;
|
||||
}
|
||||
return (FTS_W);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If doing a logical walk, or application requested FTS_FOLLOW, do
|
||||
* a stat(2). If that fails, check for a non-existent symlink. If
|
||||
* fail, set the errno from the stat call.
|
||||
*/
|
||||
if (ISSET(FTS_LOGICAL) || follow) {
|
||||
if (stat(p->fts_accpath, sbp)) {
|
||||
saved_errno = errno;
|
||||
if (!lstat(p->fts_accpath, sbp)) {
|
||||
errno = 0;
|
||||
return (FTS_SLNONE);
|
||||
}
|
||||
p->fts_errno = saved_errno;
|
||||
goto err;
|
||||
}
|
||||
} else if (lstat(p->fts_accpath, sbp)) {
|
||||
p->fts_errno = errno;
|
||||
err: memset(sbp, 0, sizeof(struct stat));
|
||||
return (FTS_NS);
|
||||
}
|
||||
|
||||
if (S_ISDIR(sbp->st_mode)) {
|
||||
/*
|
||||
* Set the device/inode. Used to find cycles and check for
|
||||
* crossing mount points. Also remember the link count, used
|
||||
* in fts_build to limit the number of stat calls. It is
|
||||
* understood that these fields are only referenced if fts_info
|
||||
* is set to FTS_D.
|
||||
*/
|
||||
dev = p->fts_dev = sbp->st_dev;
|
||||
ino = p->fts_ino = sbp->st_ino;
|
||||
p->fts_nlink = sbp->st_nlink;
|
||||
|
||||
if (ISDOT(p->fts_name))
|
||||
return (FTS_DOT);
|
||||
|
||||
/*
|
||||
* Cycle detection is done by brute force when the directory
|
||||
* is first encountered. If the tree gets deep enough or the
|
||||
* number of symbolic links to directories is high enough,
|
||||
* something faster might be worthwhile.
|
||||
*/
|
||||
for (t = p->fts_parent;
|
||||
t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
|
||||
if (ino == t->fts_ino && dev == t->fts_dev) {
|
||||
p->fts_cycle = t;
|
||||
return (FTS_DC);
|
||||
}
|
||||
return (FTS_D);
|
||||
}
|
||||
if (S_ISLNK(sbp->st_mode))
|
||||
return (FTS_SL);
|
||||
if (S_ISREG(sbp->st_mode))
|
||||
return (FTS_F);
|
||||
return (FTS_DEFAULT);
|
||||
}
|
||||
|
||||
static FTSENT *
|
||||
fts_sort(sp, head, nitems)
|
||||
FTS *sp;
|
||||
FTSENT *head;
|
||||
register int nitems;
|
||||
{
|
||||
register FTSENT **ap, *p;
|
||||
|
||||
/*
|
||||
* Construct an array of pointers to the structures and call qsort(3).
|
||||
* Reassemble the array in the order returned by qsort. If unable to
|
||||
* sort for memory reasons, return the directory entries in their
|
||||
* current order. Allocate enough space for the current needs plus
|
||||
* 40 so don't realloc one entry at a time.
|
||||
*/
|
||||
if (nitems > sp->fts_nitems) {
|
||||
sp->fts_nitems = nitems + 40;
|
||||
if ((sp->fts_array = realloc(sp->fts_array,
|
||||
(size_t)(sp->fts_nitems * sizeof(FTSENT *)))) == NULL) {
|
||||
sp->fts_nitems = 0;
|
||||
return (head);
|
||||
}
|
||||
}
|
||||
for (ap = sp->fts_array, p = head; p; p = p->fts_link)
|
||||
*ap++ = p;
|
||||
qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar);
|
||||
for (head = *(ap = sp->fts_array); --nitems; ++ap)
|
||||
ap[0]->fts_link = ap[1];
|
||||
ap[0]->fts_link = NULL;
|
||||
return (head);
|
||||
}
|
||||
|
||||
static FTSENT *
|
||||
fts_alloc(sp, name, namelen)
|
||||
FTS *sp;
|
||||
char *name;
|
||||
register int namelen;
|
||||
{
|
||||
register FTSENT *p;
|
||||
size_t len;
|
||||
|
||||
/*
|
||||
* The file name is a variable length array and no stat structure is
|
||||
* necessary if the user has set the nostat bit. Allocate the FTSENT
|
||||
* structure, the file name and the stat structure in one chunk, but
|
||||
* be careful that the stat structure is reasonably aligned. Since the
|
||||
* fts_name field is declared to be of size 1, the fts_name pointer is
|
||||
* namelen + 2 before the first possible address of the stat structure.
|
||||
*/
|
||||
len = sizeof(FTSENT) + namelen;
|
||||
if (!ISSET(FTS_NOSTAT))
|
||||
len += sizeof(struct stat) + ALIGNBYTES;
|
||||
if ((p = malloc(len)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
/* Copy the name plus the trailing NULL. */
|
||||
memmove(p->fts_name, name, namelen + 1);
|
||||
|
||||
if (!ISSET(FTS_NOSTAT))
|
||||
p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2);
|
||||
p->fts_namelen = namelen;
|
||||
p->fts_path = sp->fts_path;
|
||||
p->fts_errno = 0;
|
||||
p->fts_flags = 0;
|
||||
p->fts_instr = FTS_NOINSTR;
|
||||
p->fts_number = 0;
|
||||
p->fts_pointer = NULL;
|
||||
return (p);
|
||||
}
|
||||
|
||||
static void
|
||||
fts_lfree(head)
|
||||
register FTSENT *head;
|
||||
{
|
||||
register FTSENT *p;
|
||||
|
||||
/* Free a linked list of structures. */
|
||||
while (p = head) {
|
||||
head = head->fts_link;
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow essentially unlimited paths; find, rm, ls should all work on any tree.
|
||||
* Most systems will allow creation of paths much longer than MAXPATHLEN, even
|
||||
* though the kernel won't resolve them. Add the size (not just what's needed)
|
||||
* plus 256 bytes so don't realloc the path 2 bytes at a time.
|
||||
*/
|
||||
static int
|
||||
fts_palloc(sp, more)
|
||||
FTS *sp;
|
||||
size_t more;
|
||||
{
|
||||
sp->fts_pathlen += more + 256;
|
||||
sp->fts_path = realloc(sp->fts_path, (size_t)sp->fts_pathlen);
|
||||
return (sp->fts_path == NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* When the path is realloc'd, have to fix all of the pointers in structures
|
||||
* already returned.
|
||||
*/
|
||||
static void
|
||||
fts_padjust(sp, addr)
|
||||
FTS *sp;
|
||||
void *addr;
|
||||
{
|
||||
FTSENT *p;
|
||||
|
||||
#define ADJUST(p) { \
|
||||
(p)->fts_accpath = \
|
||||
(char *)addr + ((p)->fts_accpath - (p)->fts_path); \
|
||||
(p)->fts_path = addr; \
|
||||
}
|
||||
/* Adjust the current set of children. */
|
||||
for (p = sp->fts_child; p; p = p->fts_link)
|
||||
ADJUST(p);
|
||||
|
||||
/* Adjust the rest of the tree. */
|
||||
for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
|
||||
ADJUST(p);
|
||||
p = p->fts_link ? p->fts_link : p->fts_parent;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t
|
||||
fts_maxarglen(argv)
|
||||
char * const *argv;
|
||||
{
|
||||
size_t len, max;
|
||||
|
||||
for (max = 0; *argv; ++argv)
|
||||
if ((len = strlen(*argv)) > max)
|
||||
max = len;
|
||||
return (max);
|
||||
}
|
||||
255
sys/miscfs/union/libc.opendir.c
Normal file
255
sys/miscfs/union/libc.opendir.c
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* Copyright (c) 1983, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)opendir.c 8.6 (Berkeley) 8/14/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
* Open a directory.
|
||||
*/
|
||||
DIR *
|
||||
opendir(name)
|
||||
const char *name;
|
||||
{
|
||||
|
||||
return (__opendir2(name, DTF_HIDEW|DTF_NODUP));
|
||||
}
|
||||
|
||||
DIR *
|
||||
__opendir2(name, flags)
|
||||
const char *name;
|
||||
int flags;
|
||||
{
|
||||
DIR *dirp;
|
||||
int fd;
|
||||
int incr;
|
||||
int unionstack;
|
||||
|
||||
if ((fd = open(name, O_RDONLY)) == -1)
|
||||
return (NULL);
|
||||
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1 ||
|
||||
(dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
|
||||
close(fd);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* If CLBYTES is an exact multiple of DIRBLKSIZ, use a CLBYTES
|
||||
* buffer that it cluster boundary aligned.
|
||||
* Hopefully this can be a big win someday by allowing page
|
||||
* trades to user space to be done by getdirentries()
|
||||
*/
|
||||
if ((CLBYTES % DIRBLKSIZ) == 0)
|
||||
incr = CLBYTES;
|
||||
else
|
||||
incr = DIRBLKSIZ;
|
||||
|
||||
/*
|
||||
* Determine whether this directory is the top of a union stack.
|
||||
*/
|
||||
if (flags & DTF_NODUP) {
|
||||
struct statfs sfb;
|
||||
|
||||
if (fstatfs(fd, &sfb) < 0) {
|
||||
free(dirp);
|
||||
close(fd);
|
||||
return (NULL);
|
||||
}
|
||||
unionstack = (sfb.f_type == MOUNT_UNION);
|
||||
} else {
|
||||
unionstack = 0;
|
||||
}
|
||||
|
||||
if (unionstack) {
|
||||
int len = 0;
|
||||
int space = 0;
|
||||
char *buf = 0;
|
||||
char *ddptr = 0;
|
||||
int n;
|
||||
struct dirent **dpv;
|
||||
|
||||
/*
|
||||
* The strategy here is to read all the directory
|
||||
* entries into a buffer, sort the buffer, and
|
||||
* remove duplicate entries by setting the inode
|
||||
* number to zero.
|
||||
*/
|
||||
|
||||
do {
|
||||
/*
|
||||
* Always make at least DIRBLKSIZ bytes
|
||||
* available to getdirentries
|
||||
*/
|
||||
if (space < DIRBLKSIZ) {
|
||||
space += incr;
|
||||
len += incr;
|
||||
buf = realloc(buf, len);
|
||||
if (buf == NULL) {
|
||||
free(dirp);
|
||||
close(fd);
|
||||
return (NULL);
|
||||
}
|
||||
ddptr = buf + (len - space);
|
||||
}
|
||||
|
||||
n = getdirentries(fd, ddptr, space, &dirp->dd_seek);
|
||||
if (n > 0) {
|
||||
ddptr += n;
|
||||
space -= n;
|
||||
}
|
||||
} while (n > 0);
|
||||
|
||||
flags |= __DTF_READALL;
|
||||
|
||||
/*
|
||||
* Re-open the directory.
|
||||
* This has the effect of rewinding back to the
|
||||
* top of the union stack and is needed by
|
||||
* programs which plan to fchdir to a descriptor
|
||||
* which has also been read -- see fts.c.
|
||||
*/
|
||||
if (flags & DTF_REWIND) {
|
||||
(void) close(fd);
|
||||
if ((fd = open(name, O_RDONLY)) == -1) {
|
||||
free(buf);
|
||||
free(dirp);
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* There is now a buffer full of (possibly) duplicate
|
||||
* names.
|
||||
*/
|
||||
dirp->dd_buf = buf;
|
||||
|
||||
/*
|
||||
* Go round this loop twice...
|
||||
*
|
||||
* Scan through the buffer, counting entries.
|
||||
* On the second pass, save pointers to each one.
|
||||
* Then sort the pointers and remove duplicate names.
|
||||
*/
|
||||
for (dpv = 0;;) {
|
||||
n = 0;
|
||||
ddptr = buf;
|
||||
while (ddptr < buf + len) {
|
||||
struct dirent *dp;
|
||||
|
||||
dp = (struct dirent *) ddptr;
|
||||
if ((int)dp & 03)
|
||||
break;
|
||||
if ((dp->d_reclen <= 0) ||
|
||||
(dp->d_reclen > (buf + len + 1 - ddptr)))
|
||||
break;
|
||||
ddptr += dp->d_reclen;
|
||||
if (dp->d_fileno) {
|
||||
if (dpv)
|
||||
dpv[n] = dp;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
if (dpv) {
|
||||
struct dirent *xp;
|
||||
|
||||
/*
|
||||
* This sort must be stable.
|
||||
*/
|
||||
mergesort(dpv, n, sizeof(*dpv), alphasort);
|
||||
|
||||
dpv[n] = NULL;
|
||||
xp = NULL;
|
||||
|
||||
/*
|
||||
* Scan through the buffer in sort order,
|
||||
* zapping the inode number of any
|
||||
* duplicate names.
|
||||
*/
|
||||
for (n = 0; dpv[n]; n++) {
|
||||
struct dirent *dp = dpv[n];
|
||||
|
||||
if ((xp == NULL) ||
|
||||
strcmp(dp->d_name, xp->d_name)) {
|
||||
xp = dp;
|
||||
} else {
|
||||
dp->d_fileno = 0;
|
||||
}
|
||||
if (dp->d_type == DT_WHT &&
|
||||
(flags & DTF_HIDEW))
|
||||
dp->d_fileno = 0;
|
||||
}
|
||||
|
||||
free(dpv);
|
||||
break;
|
||||
} else {
|
||||
dpv = malloc((n+1) * sizeof(struct dirent *));
|
||||
if (dpv == NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dirp->dd_len = len;
|
||||
dirp->dd_size = ddptr - dirp->dd_buf;
|
||||
} else {
|
||||
dirp->dd_len = incr;
|
||||
dirp->dd_buf = malloc(dirp->dd_len);
|
||||
if (dirp->dd_buf == NULL) {
|
||||
free(dirp);
|
||||
close (fd);
|
||||
return (NULL);
|
||||
}
|
||||
dirp->dd_seek = 0;
|
||||
flags &= ~DTF_REWIND;
|
||||
}
|
||||
|
||||
dirp->dd_loc = 0;
|
||||
dirp->dd_fd = fd;
|
||||
dirp->dd_flags = flags;
|
||||
|
||||
/*
|
||||
* Set up seek point for rewinddir.
|
||||
*/
|
||||
dirp->dd_rewind = telldir(dirp);
|
||||
|
||||
return (dirp);
|
||||
}
|
||||
75
sys/miscfs/union/libc.readdir.c
Normal file
75
sys/miscfs/union/libc.readdir.c
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 1983, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)readdir.c 8.3 (Berkeley) 9/29/94";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <dirent.h>
|
||||
|
||||
/*
|
||||
* get next entry in a directory.
|
||||
*/
|
||||
struct dirent *
|
||||
readdir(dirp)
|
||||
register DIR *dirp;
|
||||
{
|
||||
register struct dirent *dp;
|
||||
|
||||
for (;;) {
|
||||
if (dirp->dd_loc >= dirp->dd_size) {
|
||||
if (dirp->dd_flags & __DTF_READALL)
|
||||
return (NULL);
|
||||
dirp->dd_loc = 0;
|
||||
}
|
||||
if (dirp->dd_loc == 0 && !(dirp->dd_flags & __DTF_READALL)) {
|
||||
dirp->dd_size = getdirentries(dirp->dd_fd,
|
||||
dirp->dd_buf, dirp->dd_len, &dirp->dd_seek);
|
||||
if (dirp->dd_size <= 0)
|
||||
return (NULL);
|
||||
}
|
||||
dp = (struct dirent *)(dirp->dd_buf + dirp->dd_loc);
|
||||
if ((int)dp & 03) /* bogus pointer check */
|
||||
return (NULL);
|
||||
if (dp->d_reclen <= 0 ||
|
||||
dp->d_reclen > dirp->dd_len + 1 - dirp->dd_loc)
|
||||
return (NULL);
|
||||
dirp->dd_loc += dp->d_reclen;
|
||||
if (dp->d_ino == 0)
|
||||
continue;
|
||||
if (dp->d_type == DT_WHT && (dirp->dd_flags & DTF_HIDEW))
|
||||
continue;
|
||||
return (dp);
|
||||
}
|
||||
}
|
||||
129
sys/miscfs/union/union.h
Normal file
129
sys/miscfs/union/union.h
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright (c) 1994 The Regents of the University of California.
|
||||
* Copyright (c) 1994 Jan-Simon Pendry.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)union.h 8.9 (Berkeley) 12/10/94
|
||||
*/
|
||||
|
||||
struct union_args {
|
||||
char *target; /* Target of loopback */
|
||||
int mntflags; /* Options on the mount */
|
||||
};
|
||||
|
||||
#define UNMNT_ABOVE 0x0001 /* Target appears below mount point */
|
||||
#define UNMNT_BELOW 0x0002 /* Target appears below mount point */
|
||||
#define UNMNT_REPLACE 0x0003 /* Target replaces mount point */
|
||||
#define UNMNT_OPMASK 0x0003
|
||||
|
||||
struct union_mount {
|
||||
struct vnode *um_uppervp;
|
||||
struct vnode *um_lowervp;
|
||||
struct ucred *um_cred; /* Credentials of user calling mount */
|
||||
int um_cmode; /* cmask from mount process */
|
||||
int um_op; /* Operation mode */
|
||||
};
|
||||
|
||||
#ifdef KERNEL
|
||||
|
||||
/*
|
||||
* DEFDIRMODE is the mode bits used to create a shadow directory.
|
||||
*/
|
||||
#define VRWXMODE (VREAD|VWRITE|VEXEC)
|
||||
#define VRWMODE (VREAD|VWRITE)
|
||||
#define UN_DIRMODE ((VRWXMODE)|(VRWXMODE>>3)|(VRWXMODE>>6))
|
||||
#define UN_FILEMODE ((VRWMODE)|(VRWMODE>>3)|(VRWMODE>>6))
|
||||
|
||||
/*
|
||||
* A cache of vnode references
|
||||
*/
|
||||
struct union_node {
|
||||
LIST_ENTRY(union_node) un_cache; /* Hash chain */
|
||||
struct vnode *un_vnode; /* Back pointer */
|
||||
struct vnode *un_uppervp; /* overlaying object */
|
||||
struct vnode *un_lowervp; /* underlying object */
|
||||
struct vnode *un_dirvp; /* Parent dir of uppervp */
|
||||
struct vnode *un_pvp; /* Parent vnode */
|
||||
char *un_path; /* saved component name */
|
||||
int un_hash; /* saved un_path hash value */
|
||||
int un_openl; /* # of opens on lowervp */
|
||||
unsigned int un_flags;
|
||||
struct vnode **un_dircache; /* cached union stack */
|
||||
off_t un_uppersz; /* size of upper object */
|
||||
off_t un_lowersz; /* size of lower object */
|
||||
#ifdef DIAGNOSTIC
|
||||
pid_t un_pid;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define UN_WANT 0x01
|
||||
#define UN_LOCKED 0x02
|
||||
#define UN_ULOCK 0x04 /* Upper node is locked */
|
||||
#define UN_KLOCK 0x08 /* Keep upper node locked on vput */
|
||||
#define UN_CACHED 0x10 /* In union cache */
|
||||
|
||||
extern int union_allocvp __P((struct vnode **, struct mount *,
|
||||
struct vnode *, struct vnode *,
|
||||
struct componentname *, struct vnode *,
|
||||
struct vnode *, int));
|
||||
extern int union_copyfile __P((struct vnode *, struct vnode *,
|
||||
struct ucred *, struct proc *));
|
||||
extern int union_copyup __P((struct union_node *, int, struct ucred *,
|
||||
struct proc *));
|
||||
extern int union_dowhiteout __P((struct union_node *, struct ucred *,
|
||||
struct proc *));
|
||||
extern int union_mkshadow __P((struct union_mount *, struct vnode *,
|
||||
struct componentname *, struct vnode **));
|
||||
extern int union_mkwhiteout __P((struct union_mount *, struct vnode *,
|
||||
struct componentname *, char *));
|
||||
extern int union_vn_create __P((struct vnode **, struct union_node *,
|
||||
struct proc *));
|
||||
extern int union_cn_close __P((struct vnode *, int, struct ucred *,
|
||||
struct proc *));
|
||||
extern void union_removed_upper __P((struct union_node *un));
|
||||
extern struct vnode *union_lowervp __P((struct vnode *));
|
||||
extern void union_newlower __P((struct union_node *, struct vnode *));
|
||||
extern void union_newupper __P((struct union_node *, struct vnode *));
|
||||
extern void union_newsize __P((struct vnode *, off_t, off_t));
|
||||
|
||||
#define MOUNTTOUNIONMOUNT(mp) ((struct union_mount *)((mp)->mnt_data))
|
||||
#define VTOUNION(vp) ((struct union_node *)(vp)->v_data)
|
||||
#define UNIONTOV(un) ((un)->un_vnode)
|
||||
#define LOWERVP(vp) (VTOUNION(vp)->un_lowervp)
|
||||
#define UPPERVP(vp) (VTOUNION(vp)->un_uppervp)
|
||||
#define OTHERVP(vp) (UPPERVP(vp) ? UPPERVP(vp) : LOWERVP(vp))
|
||||
|
||||
extern int (**union_vnodeop_p)();
|
||||
extern struct vfsops union_vfsops;
|
||||
#endif /* KERNEL */
|
||||
1086
sys/miscfs/union/union_subr.c
Normal file
1086
sys/miscfs/union/union_subr.c
Normal file
File diff suppressed because it is too large
Load diff
495
sys/miscfs/union/union_vfsops.c
Normal file
495
sys/miscfs/union/union_vfsops.c
Normal file
|
|
@ -0,0 +1,495 @@
|
|||
/*
|
||||
* Copyright (c) 1994, 1995 The Regents of the University of California.
|
||||
* Copyright (c) 1994, 1995 Jan-Simon Pendry.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software donated to Berkeley by
|
||||
* Jan-Simon Pendry.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @(#)union_vfsops.c 8.20 (Berkeley) 5/20/95
|
||||
*/
|
||||
|
||||
/*
|
||||
* Union Layer
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/vnode.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/namei.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/filedesc.h>
|
||||
#include <sys/queue.h>
|
||||
#include <miscfs/union/union.h>
|
||||
|
||||
/*
|
||||
* Mount union filesystem
|
||||
*/
|
||||
int
|
||||
union_mount(mp, path, data, ndp, p)
|
||||
struct mount *mp;
|
||||
char *path;
|
||||
caddr_t data;
|
||||
struct nameidata *ndp;
|
||||
struct proc *p;
|
||||
{
|
||||
int error = 0;
|
||||
struct union_args args;
|
||||
struct vnode *lowerrootvp = NULLVP;
|
||||
struct vnode *upperrootvp = NULLVP;
|
||||
struct union_mount *um = 0;
|
||||
struct ucred *cred = 0;
|
||||
struct ucred *scred;
|
||||
struct vattr va;
|
||||
char *cp;
|
||||
int len;
|
||||
u_int size;
|
||||
|
||||
#ifdef UNION_DIAGNOSTIC
|
||||
printf("union_mount(mp = %x)\n", mp);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Update is a no-op
|
||||
*/
|
||||
if (mp->mnt_flag & MNT_UPDATE) {
|
||||
/*
|
||||
* Need to provide.
|
||||
* 1. a way to convert between rdonly and rdwr mounts.
|
||||
* 2. support for nfs exports.
|
||||
*/
|
||||
error = EOPNOTSUPP;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get argument
|
||||
*/
|
||||
if (error = copyin(data, (caddr_t)&args, sizeof(struct union_args)))
|
||||
goto bad;
|
||||
|
||||
lowerrootvp = mp->mnt_vnodecovered;
|
||||
VREF(lowerrootvp);
|
||||
|
||||
/*
|
||||
* Find upper node.
|
||||
*/
|
||||
NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT,
|
||||
UIO_USERSPACE, args.target, p);
|
||||
|
||||
if (error = namei(ndp))
|
||||
goto bad;
|
||||
|
||||
upperrootvp = ndp->ni_vp;
|
||||
vrele(ndp->ni_dvp);
|
||||
ndp->ni_dvp = NULL;
|
||||
|
||||
if (upperrootvp->v_type != VDIR) {
|
||||
error = EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
um = (struct union_mount *) malloc(sizeof(struct union_mount),
|
||||
M_UFSMNT, M_WAITOK); /* XXX */
|
||||
|
||||
/*
|
||||
* Keep a held reference to the target vnodes.
|
||||
* They are vrele'd in union_unmount.
|
||||
*
|
||||
* Depending on the _BELOW flag, the filesystems are
|
||||
* viewed in a different order. In effect, this is the
|
||||
* same as providing a mount under option to the mount syscall.
|
||||
*/
|
||||
|
||||
um->um_op = args.mntflags & UNMNT_OPMASK;
|
||||
switch (um->um_op) {
|
||||
case UNMNT_ABOVE:
|
||||
um->um_lowervp = lowerrootvp;
|
||||
um->um_uppervp = upperrootvp;
|
||||
break;
|
||||
|
||||
case UNMNT_BELOW:
|
||||
um->um_lowervp = upperrootvp;
|
||||
um->um_uppervp = lowerrootvp;
|
||||
break;
|
||||
|
||||
case UNMNT_REPLACE:
|
||||
vrele(lowerrootvp);
|
||||
lowerrootvp = NULLVP;
|
||||
um->um_uppervp = upperrootvp;
|
||||
um->um_lowervp = lowerrootvp;
|
||||
break;
|
||||
|
||||
default:
|
||||
error = EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unless the mount is readonly, ensure that the top layer
|
||||
* supports whiteout operations
|
||||
*/
|
||||
if ((mp->mnt_flag & MNT_RDONLY) == 0) {
|
||||
error = VOP_WHITEOUT(um->um_uppervp, (struct componentname *) 0, LOOKUP);
|
||||
if (error)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
um->um_cred = p->p_ucred;
|
||||
crhold(um->um_cred);
|
||||
um->um_cmode = UN_DIRMODE &~ p->p_fd->fd_cmask;
|
||||
|
||||
/*
|
||||
* Depending on what you think the MNT_LOCAL flag might mean,
|
||||
* you may want the && to be || on the conditional below.
|
||||
* At the moment it has been defined that the filesystem is
|
||||
* only local if it is all local, ie the MNT_LOCAL flag implies
|
||||
* that the entire namespace is local. If you think the MNT_LOCAL
|
||||
* flag implies that some of the files might be stored locally
|
||||
* then you will want to change the conditional.
|
||||
*/
|
||||
if (um->um_op == UNMNT_ABOVE) {
|
||||
if (((um->um_lowervp == NULLVP) ||
|
||||
(um->um_lowervp->v_mount->mnt_flag & MNT_LOCAL)) &&
|
||||
(um->um_uppervp->v_mount->mnt_flag & MNT_LOCAL))
|
||||
mp->mnt_flag |= MNT_LOCAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy in the upper layer's RDONLY flag. This is for the benefit
|
||||
* of lookup() which explicitly checks the flag, rather than asking
|
||||
* the filesystem for it's own opinion. This means, that an update
|
||||
* mount of the underlying filesystem to go from rdonly to rdwr
|
||||
* will leave the unioned view as read-only.
|
||||
*/
|
||||
mp->mnt_flag |= (um->um_uppervp->v_mount->mnt_flag & MNT_RDONLY);
|
||||
|
||||
mp->mnt_data = (qaddr_t) um;
|
||||
vfs_getnewfsid(mp);
|
||||
|
||||
(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
|
||||
bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
|
||||
|
||||
switch (um->um_op) {
|
||||
case UNMNT_ABOVE:
|
||||
cp = "<above>:";
|
||||
break;
|
||||
case UNMNT_BELOW:
|
||||
cp = "<below>:";
|
||||
break;
|
||||
case UNMNT_REPLACE:
|
||||
cp = "";
|
||||
break;
|
||||
}
|
||||
len = strlen(cp);
|
||||
bcopy(cp, mp->mnt_stat.f_mntfromname, len);
|
||||
|
||||
cp = mp->mnt_stat.f_mntfromname + len;
|
||||
len = MNAMELEN - len;
|
||||
|
||||
(void) copyinstr(args.target, cp, len - 1, &size);
|
||||
bzero(cp + size, len - size);
|
||||
|
||||
#ifdef UNION_DIAGNOSTIC
|
||||
printf("union_mount: from %s, on %s\n",
|
||||
mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
|
||||
#endif
|
||||
return (0);
|
||||
|
||||
bad:
|
||||
if (um)
|
||||
free(um, M_UFSMNT);
|
||||
if (cred)
|
||||
crfree(cred);
|
||||
if (upperrootvp)
|
||||
vrele(upperrootvp);
|
||||
if (lowerrootvp)
|
||||
vrele(lowerrootvp);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* VFS start. Nothing needed here - the start routine
|
||||
* on the underlying filesystem(s) will have been called
|
||||
* when that filesystem was mounted.
|
||||
*/
|
||||
int
|
||||
union_start(mp, flags, p)
|
||||
struct mount *mp;
|
||||
int flags;
|
||||
struct proc *p;
|
||||
{
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free reference to union layer
|
||||
*/
|
||||
int
|
||||
union_unmount(mp, mntflags, p)
|
||||
struct mount *mp;
|
||||
int mntflags;
|
||||
struct proc *p;
|
||||
{
|
||||
struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
|
||||
struct vnode *um_rootvp;
|
||||
int error;
|
||||
int freeing;
|
||||
int flags = 0;
|
||||
|
||||
#ifdef UNION_DIAGNOSTIC
|
||||
printf("union_unmount(mp = %x)\n", mp);
|
||||
#endif
|
||||
|
||||
if (mntflags & MNT_FORCE)
|
||||
flags |= FORCECLOSE;
|
||||
|
||||
if (error = union_root(mp, &um_rootvp))
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Keep flushing vnodes from the mount list.
|
||||
* This is needed because of the un_pvp held
|
||||
* reference to the parent vnode.
|
||||
* If more vnodes have been freed on a given pass,
|
||||
* the try again. The loop will iterate at most
|
||||
* (d) times, where (d) is the maximum tree depth
|
||||
* in the filesystem.
|
||||
*/
|
||||
for (freeing = 0; vflush(mp, um_rootvp, flags) != 0;) {
|
||||
struct vnode *vp;
|
||||
int n;
|
||||
|
||||
/* count #vnodes held on mount list */
|
||||
for (n = 0, vp = mp->mnt_vnodelist.lh_first;
|
||||
vp != NULLVP;
|
||||
vp = vp->v_mntvnodes.le_next)
|
||||
n++;
|
||||
|
||||
/* if this is unchanged then stop */
|
||||
if (n == freeing)
|
||||
break;
|
||||
|
||||
/* otherwise try once more time */
|
||||
freeing = n;
|
||||
}
|
||||
|
||||
/* At this point the root vnode should have a single reference */
|
||||
if (um_rootvp->v_usecount > 1) {
|
||||
vput(um_rootvp);
|
||||
return (EBUSY);
|
||||
}
|
||||
|
||||
#ifdef UNION_DIAGNOSTIC
|
||||
vprint("union root", um_rootvp);
|
||||
#endif
|
||||
/*
|
||||
* Discard references to upper and lower target vnodes.
|
||||
*/
|
||||
if (um->um_lowervp)
|
||||
vrele(um->um_lowervp);
|
||||
vrele(um->um_uppervp);
|
||||
crfree(um->um_cred);
|
||||
/*
|
||||
* Release reference on underlying root vnode
|
||||
*/
|
||||
vput(um_rootvp);
|
||||
/*
|
||||
* And blow it away for future re-use
|
||||
*/
|
||||
vgone(um_rootvp);
|
||||
/*
|
||||
* Finally, throw away the union_mount structure
|
||||
*/
|
||||
free(mp->mnt_data, M_UFSMNT); /* XXX */
|
||||
mp->mnt_data = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
union_root(mp, vpp)
|
||||
struct mount *mp;
|
||||
struct vnode **vpp;
|
||||
{
|
||||
struct proc *p = curproc; /* XXX */
|
||||
struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
|
||||
int error;
|
||||
int loselock;
|
||||
|
||||
/*
|
||||
* Return locked reference to root.
|
||||
*/
|
||||
VREF(um->um_uppervp);
|
||||
if ((um->um_op == UNMNT_BELOW) &&
|
||||
VOP_ISLOCKED(um->um_uppervp)) {
|
||||
loselock = 1;
|
||||
} else {
|
||||
vn_lock(um->um_uppervp, LK_EXCLUSIVE | LK_RETRY, p);
|
||||
loselock = 0;
|
||||
}
|
||||
if (um->um_lowervp)
|
||||
VREF(um->um_lowervp);
|
||||
error = union_allocvp(vpp, mp,
|
||||
(struct vnode *) 0,
|
||||
(struct vnode *) 0,
|
||||
(struct componentname *) 0,
|
||||
um->um_uppervp,
|
||||
um->um_lowervp,
|
||||
1);
|
||||
|
||||
if (error) {
|
||||
if (loselock)
|
||||
vrele(um->um_uppervp);
|
||||
else
|
||||
vput(um->um_uppervp);
|
||||
if (um->um_lowervp)
|
||||
vrele(um->um_lowervp);
|
||||
} else {
|
||||
if (loselock)
|
||||
VTOUNION(*vpp)->un_flags &= ~UN_ULOCK;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
union_statfs(mp, sbp, p)
|
||||
struct mount *mp;
|
||||
struct statfs *sbp;
|
||||
struct proc *p;
|
||||
{
|
||||
int error;
|
||||
struct union_mount *um = MOUNTTOUNIONMOUNT(mp);
|
||||
struct statfs mstat;
|
||||
int lbsize;
|
||||
|
||||
#ifdef UNION_DIAGNOSTIC
|
||||
printf("union_statfs(mp = %x, lvp = %x, uvp = %x)\n", mp,
|
||||
um->um_lowervp,
|
||||
um->um_uppervp);
|
||||
#endif
|
||||
|
||||
bzero(&mstat, sizeof(mstat));
|
||||
|
||||
if (um->um_lowervp) {
|
||||
error = VFS_STATFS(um->um_lowervp->v_mount, &mstat, p);
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* now copy across the "interesting" information and fake the rest */
|
||||
#if 0
|
||||
sbp->f_type = mstat.f_type;
|
||||
sbp->f_flags = mstat.f_flags;
|
||||
sbp->f_bsize = mstat.f_bsize;
|
||||
sbp->f_iosize = mstat.f_iosize;
|
||||
#endif
|
||||
lbsize = mstat.f_bsize;
|
||||
sbp->f_blocks = mstat.f_blocks;
|
||||
sbp->f_bfree = mstat.f_bfree;
|
||||
sbp->f_bavail = mstat.f_bavail;
|
||||
sbp->f_files = mstat.f_files;
|
||||
sbp->f_ffree = mstat.f_ffree;
|
||||
|
||||
error = VFS_STATFS(um->um_uppervp->v_mount, &mstat, p);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
sbp->f_flags = mstat.f_flags;
|
||||
sbp->f_bsize = mstat.f_bsize;
|
||||
sbp->f_iosize = mstat.f_iosize;
|
||||
|
||||
/*
|
||||
* if the lower and upper blocksizes differ, then frig the
|
||||
* block counts so that the sizes reported by df make some
|
||||
* kind of sense. none of this makes sense though.
|
||||
*/
|
||||
|
||||
if (mstat.f_bsize != lbsize)
|
||||
sbp->f_blocks = sbp->f_blocks * lbsize / mstat.f_bsize;
|
||||
|
||||
/*
|
||||
* The "total" fields count total resources in all layers,
|
||||
* the "free" fields count only those resources which are
|
||||
* free in the upper layer (since only the upper layer
|
||||
* is writeable).
|
||||
*/
|
||||
sbp->f_blocks += mstat.f_blocks;
|
||||
sbp->f_bfree = mstat.f_bfree;
|
||||
sbp->f_bavail = mstat.f_bavail;
|
||||
sbp->f_files += mstat.f_files;
|
||||
sbp->f_ffree = mstat.f_ffree;
|
||||
|
||||
if (sbp != &mp->mnt_stat) {
|
||||
sbp->f_type = mp->mnt_vfc->vfc_typenum;
|
||||
bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
|
||||
bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
|
||||
bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX - Assumes no data cached at union layer.
|
||||
*/
|
||||
#define union_sync ((int (*) __P((struct mount *, int, struct ucred *, \
|
||||
struct proc *)))nullop)
|
||||
|
||||
#define union_fhtovp ((int (*) __P((struct mount *, struct fid *, \
|
||||
struct mbuf *, struct vnode **, int *, struct ucred **)))eopnotsupp)
|
||||
int union_init __P((struct vfsconf *));
|
||||
#define union_quotactl ((int (*) __P((struct mount *, int, uid_t, caddr_t, \
|
||||
struct proc *)))eopnotsupp)
|
||||
#define union_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \
|
||||
size_t, struct proc *)))eopnotsupp)
|
||||
#define union_vget ((int (*) __P((struct mount *, ino_t, struct vnode **))) \
|
||||
eopnotsupp)
|
||||
#define union_vptofh ((int (*) __P((struct vnode *, struct fid *)))eopnotsupp)
|
||||
|
||||
struct vfsops union_vfsops = {
|
||||
union_mount,
|
||||
union_start,
|
||||
union_unmount,
|
||||
union_root,
|
||||
union_quotactl,
|
||||
union_statfs,
|
||||
union_sync,
|
||||
union_vget,
|
||||
union_fhtovp,
|
||||
union_vptofh,
|
||||
union_init,
|
||||
union_sysctl,
|
||||
};
|
||||
1657
sys/miscfs/union/union_vnops.c
Normal file
1657
sys/miscfs/union/union_vnops.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue