diff options
Diffstat (limited to 'sys/miscfs/kernfs')
-rw-r--r-- | sys/miscfs/kernfs/kernfs.h | 57 | ||||
-rw-r--r-- | sys/miscfs/kernfs/kernfs_vfsops.c | 342 | ||||
-rw-r--r-- | sys/miscfs/kernfs/kernfs_vnops.c | 777 |
3 files changed, 1176 insertions, 0 deletions
diff --git a/sys/miscfs/kernfs/kernfs.h b/sys/miscfs/kernfs/kernfs.h new file mode 100644 index 0000000..2def608 --- /dev/null +++ b/sys/miscfs/kernfs/kernfs.h @@ -0,0 +1,57 @@ +/* + * 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.4 (Berkeley) 1/21/94 + * $Id$ + */ + +#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) + +extern int (**kernfs_vnodeop_p)(); +extern struct vfsops kernfs_vfsops; +extern struct vnode *rrootvp; +#endif /* KERNEL */ diff --git a/sys/miscfs/kernfs/kernfs_vfsops.c b/sys/miscfs/kernfs/kernfs_vfsops.c new file mode 100644 index 0000000..be0f7a9 --- /dev/null +++ b/sys/miscfs/kernfs/kernfs_vfsops.c @@ -0,0 +1,342 @@ +/* + * 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_vfsops.c 8.4 (Berkeley) 1/21/94 + * $Id$ + */ + +/* + * 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> + +struct vnode *rrootvp; + +/* + * Create a vnode for a character device. + */ +int +cdevvp(dev, vpp) + dev_t dev; + struct vnode **vpp; +{ + register struct vnode *vp; + struct vnode *nvp; + int error; + + if (dev == NODEV) + return (0); + error = getnewvnode(VT_NON, (struct mount *)0, spec_vnodeop_p, &nvp); + if (error) { + *vpp = 0; + return (error); + } + vp = nvp; + vp->v_type = VCHR; + if (nvp = checkalias(vp, dev, (struct mount *)0)) { + vput(vp); + vp = nvp; + } + *vpp = vp; + return (0); +} + +int +kernfs_init() +{ + int cmaj; + int bmaj = major(rootdev); + int error = ENXIO; + +#ifdef KERNFS_DIAGNOSTIC + printf("kernfs_init\n"); /* printed during system boot */ +#endif + + for (cmaj = 0; cmaj < nchrdev; cmaj++) { + if (cdevsw[cmaj].d_open == bdevsw[bmaj].d_open) { + dev_t cdev = makedev(cmaj, minor(rootdev)); + error = cdevvp(cdev, &rrootvp); + if (error == 0) + break; + } + } + + if (error) { + printf("kernfs: no raw boot device\n"); + rrootvp = 0; + } + return (0); +} + +/* + * Mount the Kernel params filesystem + */ +int +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; + getnewfsid(mp, MOUNT_KERNFS); + + (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 + return (0); +} + +int +kernfs_start(mp, flags, p) + struct mount *mp; + int flags; + struct proc *p; +{ + return (0); +} + +int +kernfs_unmount(mp, mntflags, p) + struct mount *mp; + int mntflags; + struct proc *p; +{ + int error; + int flags = 0; + extern int doforce; + struct vnode *rootvp = VFSTOKERNFS(mp)->kf_root; + +#ifdef KERNFS_DIAGNOSTIC + printf("kernfs_unmount(mp = %x)\n", mp); +#endif + + if (mntflags & MNT_FORCE) { + /* kernfs can never be rootfs so don't check for it */ + if (!doforce) + return (EINVAL); + 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; +} + +int +kernfs_root(mp, vpp) + struct mount *mp; + struct vnode **vpp; +{ + 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); + VOP_LOCK(vp); + *vpp = vp; + return (0); +} + +int +kernfs_quotactl(mp, cmd, uid, arg, p) + struct mount *mp; + int cmd; + uid_t uid; + caddr_t arg; + struct proc *p; +{ + return (EOPNOTSUPP); +} + +int +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_type = MOUNT_KERNFS; + 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) { + 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 +kernfs_sync(mp, waitfor) + struct mount *mp; + int waitfor; +{ + return (0); +} + +/* + * Kernfs flat namespace lookup. + * Currently unsupported. + */ +int +kernfs_vget(mp, ino, vpp) + struct mount *mp; + ino_t ino; + struct vnode **vpp; +{ + + return (EOPNOTSUPP); +} + + +int +kernfs_fhtovp(mp, fhp, setgen, vpp) + struct mount *mp; + struct fid *fhp; + int setgen; + struct vnode **vpp; +{ + return (EOPNOTSUPP); +} + +int +kernfs_vptofh(vp, fhp) + struct vnode *vp; + struct fid *fhp; +{ + return (EOPNOTSUPP); +} + +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, +}; diff --git a/sys/miscfs/kernfs/kernfs_vnops.c b/sys/miscfs/kernfs/kernfs_vnops.c new file mode 100644 index 0000000..b1166d1 --- /dev/null +++ b/sys/miscfs/kernfs/kernfs_vnops.c @@ -0,0 +1,777 @@ +/* + * 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.6 (Berkeley) 2/10/94 + * $Id: kernfs_vnops.c,v 1.3 1994/08/02 07:45:04 davidg Exp $ + */ + +/* + * 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 { + 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 + int kt_tag; + int kt_rw; + int kt_vtype; +} kern_targets[] = { +/* NOTE: The name must be less than UIO_MX-16 chars in length */ + /* name data tag ro/rw */ + { ".", 0, KTT_NULL, VREAD, VDIR }, + { "..", 0, KTT_NULL, VREAD, VDIR }, + { "boottime", &boottime.tv_sec, KTT_INT, VREAD, VREG }, + { "copyright", copyright, KTT_STRING, VREAD, VREG }, + { "hostname", 0, KTT_HOSTNAME, VREAD|VWRITE, VREG }, + { "hz", &hz, KTT_INT, VREAD, VREG }, + { "loadavg", 0, KTT_AVENRUN, VREAD, VREG }, + { "pagesize", &cnt.v_page_size, KTT_INT, VREAD, VREG }, + { "physmem", &physmem, KTT_INT, VREAD, VREG }, +#if 0 + { "root", 0, KTT_NULL, VREAD, VDIR }, +#endif + { "rootdev", 0, KTT_NULL, VREAD, VBLK }, + { "rrootdev", 0, KTT_NULL, VREAD, VCHR }, + { "time", 0, KTT_TIME, VREAD, VREG }, + { "version", version, KTT_STRING, VREAD, VREG }, +}; + +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 (EINVAL); + } + + *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... + */ +int +kernfs_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; + struct vnode *fvp; + int error, i; + char *pname; + +#ifdef KERNFS_DIAGNOSTIC + printf("kernfs_lookup(%x)\n", ap); + printf("kernfs_lookup(dp = %x, vpp = %x, cnp = %x)\n", dvp, vpp, ap->a_cnp); +#endif + pname = cnp->cn_nameptr; +#ifdef KERNFS_DIAGNOSTIC + printf("kernfs_lookup(%s)\n", pname); +#endif + if (cnp->cn_namelen == 1 && *pname == '.') { + *vpp = dvp; + VREF(dvp); + /*VOP_LOCK(dvp);*/ + return (0); + } + +#if 0 + if (cnp->cn_namelen == 4 && bcmp(pname, "root", 4) == 0) { + *vpp = rootdir; + VREF(rootdir); + VOP_LOCK(rootdir); + return (0); + } +#endif + + /* + * /kern/rootdev is the root device + */ + if (cnp->cn_namelen == 7 && bcmp(pname, "rootdev", 7) == 0) { + *vpp = rootvp; + VREF(rootvp); + VOP_LOCK(rootvp); + return (0); + } + + /* + * /kern/rrootdev is the raw root device + */ + if (cnp->cn_namelen == 8 && bcmp(pname, "rrootdev", 8) == 0) { + if (rrootvp) { + *vpp = rrootvp; + VREF(rrootvp); + VOP_LOCK(rrootvp); + return (0); + } + error = ENXIO; + goto bad; + } + + error = ENOENT; + + for (i = 0; i < nkern_targets; i++) { + struct kern_target *kt = &kern_targets[i]; + if (cnp->cn_namelen == strlen(kt->kt_name) && + bcmp(kt->kt_name, pname, cnp->cn_namelen) == 0) { + error = 0; + break; + } + } + +#ifdef KERNFS_DIAGNOSTIC + printf("kernfs_lookup: i = %d, error = %d\n", i, error); +#endif + + if (error) + goto bad; + +#ifdef KERNFS_DIAGNOSTIC + printf("kernfs_lookup: allocate new vnode\n"); +#endif + error = getnewvnode(VT_KERNFS, dvp->v_mount, kernfs_vnodeop_p, &fvp); + if (error) + goto bad; + MALLOC(fvp->v_data, void *, sizeof(struct kernfs_node), M_TEMP, M_WAITOK); + VTOKERN(fvp)->kf_kt = &kern_targets[i]; + fvp->v_type = VTOKERN(fvp)->kf_kt->kt_vtype; + *vpp = fvp; +#ifdef KERNFS_DIAGNOSTIC + printf("kernfs_lookup: newvp = %x\n", fvp); +#endif + return (0); + +bad:; + *vpp = NULL; +#ifdef KERNFS_DIAGNOSTIC + printf("kernfs_lookup: error = %d\n", error); +#endif + return (error); +} + +int +kernfs_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; + + /* + * Can always open the root (modulo perms) + */ + if (vp->v_flag & VROOT) + return (0); + +#ifdef KERNFS_DIAGNOSTIC + printf("kernfs_open, mode = %x, file = %s\n", + ap->a_mode, VTOKERN(vp)->kf_kt->kt_name); +#endif + + if ((ap->a_mode & FWRITE) && !(VTOKERN(vp)->kf_kt->kt_rw & VWRITE)) + return (EOPNOTSUPP); + + 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; +{ + struct vnode *vp = ap->a_vp; + struct ucred *cred = ap->a_cred; + mode_t mode = ap->a_mode; + + if (mode & VEXEC) { + if (vp->v_flag & VROOT) + return (0); + return (EACCES); + } + + if (cred->cr_uid == 0) { + if ((vp->v_flag & VROOT) == 0) { + struct kern_target *kt = VTOKERN(vp)->kf_kt; + + if ((mode & VWRITE) && !(kt->kt_rw & VWRITE)) + return (EROFS); + } + return (0); + } + + if (mode & VWRITE) + return (EACCES); + + return (0); +} + + +int +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; + 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_qsize = 0; */ + vap->va_blocksize = DEV_BSIZE; + { + struct timeval tv; + 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; + + 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_rw & VWRITE ? WRITE_MODE : READ_MODE); + vap->va_nlink = 1; + vap->va_fileid = 3 + (kt - kern_targets) / sizeof(*kt); + error = kernfs_xread(kt, strbuf, sizeof(strbuf), &nbytes); + vap->va_size = nbytes; + } + + vp->v_type = vap->va_type; +#ifdef KERNFS_DIAGNOSTIC + printf("kernfs_getattr: return error %d\n", error); +#endif + return (error); +} + +int +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_flag & VROOT) + return (EOPNOTSUPP); + + kt = VTOKERN(vp)->kf_kt; + +#ifdef KERNFS_DIAGNOSTIC + printf("kern_read %s\n", kt->kt_name); +#endif + + len = 0; + error = kernfs_xread(kt, strbuf, sizeof(strbuf), &len); + if (error) + return (error); + cp = strbuf + off; + len -= off; + return (uiomove(cp, len, 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_flag & VROOT) + return (0); + + kt = VTOKERN(vp)->kf_kt; + + if (uio->uio_offset != 0) + return (EINVAL); + + xlen = min(uio->uio_resid, KSTRING-1); + error = uiomove(strbuf, xlen, uio); + if (error) + return (error); + + if (uio->uio_resid != 0) + return (EIO); + + strbuf[xlen] = '\0'; + xlen = strlen(strbuf); + return (kernfs_xwrite(kt, strbuf, xlen)); +} + + +int +kernfs_readdir(ap) + struct vop_readdir_args /* { + struct vnode *a_vp; + struct uio *a_uio; + struct ucred *a_cred; + } */ *ap; +{ + struct uio *uio = ap->a_uio; + int i; + int error; + + i = uio->uio_offset / UIO_MX; + error = 0; + while (uio->uio_resid > 0 && i < nkern_targets) { + struct dirent d; + struct dirent *dp = &d; + struct kern_target *kt = &kern_targets[i]; +#ifdef KERNFS_DIAGNOSTIC + printf("kernfs_readdir: i = %d\n", i); +#endif + + bzero((caddr_t) dp, UIO_MX); + + dp->d_namlen = strlen(kt->kt_name); + bcopy(kt->kt_name, dp->d_name, dp->d_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 = DT_UNKNOWN; /* XXX */ + /* + * 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 +kernfs_inactive(ap) + struct vop_inactive_args /* { + struct vnode *a_vp; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + + /* + * Clear out the v_type field to avoid + * nasty things happening in vgone(). + */ + vp->v_type = VNON; +#ifdef KERNFS_DIAGNOSTIC + printf("kernfs_inactive(%x)\n", vp); +#endif + return (0); +} + +int +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. + */ +int +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 */ +int +kernfs_print(ap) + struct vop_print_args /* { + struct vnode *a_vp; + } */ *ap; +{ + + printf("tag VT_KERNFS, kernfs vnode\n"); + return (0); +} + +/*void*/ +int +kernfs_vfree(ap) + struct vop_vfree_args /* { + struct vnode *a_pvp; + ino_t a_ino; + int a_mode; + } */ *ap; +{ + + return (0); +} + +/* + * /dev/fd vnode unsupported operation + */ +int +kernfs_enotsupp() +{ + + return (EOPNOTSUPP); +} + +/* + * /dev/fd "should never get here" operation + */ +int +kernfs_badop() +{ + + panic("kernfs: bad op"); + /* NOTREACHED */ +} + +/* + * kernfs vnode null operation + */ +int +kernfs_nullop() +{ + + return (0); +} + +#define kernfs_create ((int (*) __P((struct vop_create_args *)))kernfs_enotsupp) +#define kernfs_mknod ((int (*) __P((struct vop_mknod_args *)))kernfs_enotsupp) +#define kernfs_close ((int (*) __P((struct vop_close_args *)))nullop) +#define kernfs_ioctl ((int (*) __P((struct vop_ioctl_args *)))kernfs_enotsupp) +#define kernfs_select ((int (*) __P((struct vop_select_args *)))kernfs_enotsupp) +#define kernfs_mmap ((int (*) __P((struct vop_mmap_args *)))kernfs_enotsupp) +#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 *)))kernfs_enotsupp) +#define kernfs_link ((int (*) __P((struct vop_link_args *)))kernfs_enotsupp) +#define kernfs_rename ((int (*) __P((struct vop_rename_args *)))kernfs_enotsupp) +#define kernfs_mkdir ((int (*) __P((struct vop_mkdir_args *)))kernfs_enotsupp) +#define kernfs_rmdir ((int (*) __P((struct vop_rmdir_args *)))kernfs_enotsupp) +#define kernfs_symlink ((int (*) __P((struct vop_symlink_args *)))kernfs_enotsupp) +#define kernfs_readlink \ + ((int (*) __P((struct vop_readlink_args *)))kernfs_enotsupp) +#define kernfs_abortop ((int (*) __P((struct vop_abortop_args *)))nullop) +#define kernfs_lock ((int (*) __P((struct vop_lock_args *)))nullop) +#define kernfs_unlock ((int (*) __P((struct vop_unlock_args *)))nullop) +#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 *)))nullop) +#define kernfs_advlock ((int (*) __P((struct vop_advlock_args *)))kernfs_enotsupp) +#define kernfs_blkatoff \ + ((int (*) __P((struct vop_blkatoff_args *)))kernfs_enotsupp) +#define kernfs_valloc ((int(*) __P(( \ + struct vnode *pvp, \ + int mode, \ + struct ucred *cred, \ + struct vnode **vpp))) kernfs_enotsupp) +#define kernfs_truncate \ + ((int (*) __P((struct vop_truncate_args *)))kernfs_enotsupp) +#define kernfs_update ((int (*) __P((struct vop_update_args *)))kernfs_enotsupp) +#define kernfs_bwrite ((int (*) __P((struct vop_bwrite_args *)))kernfs_enotsupp) + +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_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 }; |