aboutsummaryrefslogtreecommitdiff
path: root/sys/procfs
diff options
context:
space:
mode:
authorsvn2git <svn2git@FreeBSD.org>1994-05-01 08:00:00 +0000
committersvn2git <svn2git@FreeBSD.org>1994-05-01 08:00:00 +0000
commita16f65c7d117419bd266c28a1901ef129a337569 (patch)
tree2626602f66dc3551e7a7c7bc9ad763c3bc7ab40a /sys/procfs
parent8503f4f13f77abf7adc8f7e329c6f9c1d52b6a20 (diff)
Diffstat (limited to 'sys/procfs')
-rw-r--r--sys/procfs/pfsnode.h217
-rw-r--r--sys/procfs/procfs_subr.c429
-rw-r--r--sys/procfs/procfs_vfsops.c280
-rw-r--r--sys/procfs/procfs_vnops.c708
4 files changed, 1634 insertions, 0 deletions
diff --git a/sys/procfs/pfsnode.h b/sys/procfs/pfsnode.h
new file mode 100644
index 000000000000..6979e493e8cc
--- /dev/null
+++ b/sys/procfs/pfsnode.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 1993 Paul Kranenburg
+ * 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 Paul Kranenburg.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: pfsnode.h,v 1.1 1993/12/12 12:26:39 davidg Exp $
+ */
+
+/*
+ * This structure defines the 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 */
+ pid_t pfs_pid; /* associated process */
+ u_short pfs_mode; /* mode bits for stat() */
+ uid_t pfs_uid; /* process' owner */
+ gid_t pfs_gid; /* process' group */
+ u_long pfs_vflags; /* chflags() flags */
+ u_long pfs_flags; /* open flags */
+ struct vmspace *pfs_vs;
+};
+
+struct pfsnode *pfshead;
+
+/*
+ * Format of a directory entry in /proc
+ */
+struct pfsdent {
+ unsigned long d_fileno;
+ unsigned short d_reclen;
+ unsigned short d_namlen;
+ char d_nam[8];
+};
+#define PFSDENTSIZE (sizeof(struct direct) - MAXNAMELEN + 8)
+
+#ifndef DIRBLKSIZ
+#define DIRBLKSIZ DEV_BSIZE
+#endif
+
+#ifdef DEBUG
+int pfs_debug;
+#endif
+
+/*
+ * Convert between pfsnode pointers and vnode pointers
+ */
+#define VTOPFS(vp) ((struct pfsnode *)(vp)->v_data)
+#define PFSTOV(pfsp) ((pfsp)->pfs_vnode)
+
+/*
+ * Prototypes for PFS operations on vnodes.
+ */
+int pfs_badop();
+int pfs_doio();
+int pfs_lookup __P(( \
+ struct vnode *vp, \
+ struct nameidata *ndp, \
+ struct proc *p));
+#define pfs_create ((int (*) __P(( \
+ struct nameidata *ndp, \
+ struct vattr *vap, \
+ struct proc *p))) pfs_badop)
+#define pfs_mknod ((int (*) __P(( \
+ struct nameidata *ndp, \
+ struct vattr *vap, \
+ struct ucred *cred, \
+ struct proc *p))) pfs_badop)
+int pfs_open __P((
+ struct vnode *vp,
+ int mode,
+ struct ucred *cred,
+ struct proc *p));
+int pfs_close __P((
+ struct vnode *vp,
+ int fflag,
+ struct ucred *cred,
+ struct proc *p));
+int pfs_access __P((
+ struct vnode *vp,
+ int mode,
+ struct ucred *cred,
+ struct proc *p));
+int pfs_getattr __P((
+ struct vnode *vp,
+ struct vattr *vap,
+ struct ucred *cred,
+ struct proc *p));
+int pfs_setattr __P((
+ struct vnode *vp,
+ struct vattr *vap,
+ struct ucred *cred,
+ struct proc *p));
+#define pfs_read ((int (*) __P(( \
+ struct vnode *vp, \
+ struct uio *uio, \
+ int ioflag, \
+ struct ucred *cred))) pfs_doio)
+#define pfs_write ((int (*) __P(( \
+ struct vnode *vp, \
+ struct uio *uio, \
+ int ioflag, \
+ struct ucred *cred))) pfs_doio)
+int pfs_ioctl __P((
+ struct vnode *vp,
+ int command,
+ caddr_t data,
+ int fflag,
+ struct ucred *cred,
+ struct proc *p));
+#define pfs_select ((int (*) __P(( \
+ struct vnode *vp, \
+ int which, \
+ int fflags, \
+ struct ucred *cred, \
+ struct proc *p))) pfs_badop)
+#define pfs_mmap ((int (*) __P(( \
+ struct vnode *vp, \
+ int fflags, \
+ struct ucred *cred, \
+ struct proc *p))) pfs_badop)
+#define pfs_fsync ((int (*) __P(( \
+ struct vnode *vp, \
+ int fflags, \
+ struct ucred *cred, \
+ int waitfor, \
+ struct proc *p))) pfs_badop)
+#define pfs_seek ((int (*) __P(( \
+ struct vnode *vp, \
+ off_t oldoff, \
+ off_t newoff, \
+ struct ucred *cred))) pfs_badop)
+#define pfs_remove ((int (*) __P(( \
+ struct nameidata *ndp, \
+ struct proc *p))) pfs_badop)
+#define pfs_link ((int (*) __P(( \
+ struct vnode *vp, \
+ struct nameidata *ndp, \
+ struct proc *p))) pfs_badop)
+#define pfs_rename ((int (*) __P(( \
+ struct nameidata *fndp, \
+ struct nameidata *tdnp, \
+ struct proc *p))) pfs_badop)
+#define pfs_mkdir ((int (*) __P(( \
+ struct nameidata *ndp, \
+ struct vattr *vap, \
+ struct proc *p))) pfs_badop)
+#define pfs_rmdir ((int (*) __P(( \
+ struct nameidata *ndp, \
+ struct proc *p))) pfs_badop)
+#define pfs_symlink ((int (*) __P(( \
+ struct nameidata *ndp, \
+ struct vattr *vap, \
+ char *target, \
+ struct proc *p))) pfs_badop)
+int pfs_readdir __P((
+ struct vnode *vp,
+ struct uio *uio,
+ struct ucred *cred,
+ int *eofflagp));
+#define pfs_readlink ((int (*) __P(( \
+ struct vnode *vp, \
+ struct uio *uio, \
+ struct ucred *cred))) pfs_badop)
+#define pfs_abortop ((int (*) __P(( \
+ struct nameidata *ndp))) pfs_badop)
+int pfs_inactive __P((
+ struct vnode *vp,
+ struct proc *p));
+int pfs_reclaim __P((
+ struct vnode *vp));
+#define pfs_lock ((int (*) __P(( \
+ struct vnode *vp))) nullop)
+#define pfs_unlock ((int (*) __P(( \
+ struct vnode *vp))) nullop)
+int pfs_bmap __P((
+ struct vnode *vp,
+ daddr_t bn,
+ struct vnode **vpp,
+ daddr_t *bnp));
+int pfs_strategy __P((
+ struct buf *bp));
+void pfs_print __P((
+ struct vnode *vp));
+#define pfs_islocked ((int (*) __P(( \
+ struct vnode *vp))) nullop)
+#define pfs_advlock ((int (*) __P(( \
+ struct vnode *vp, \
+ caddr_t id, \
+ int op, \
+ struct flock *fl, \
+ int flags))) pfs_badop)
diff --git a/sys/procfs/procfs_subr.c b/sys/procfs/procfs_subr.c
new file mode 100644
index 000000000000..94f5e8e5e253
--- /dev/null
+++ b/sys/procfs/procfs_subr.c
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 1993 Paul Kranenburg
+ * 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 Paul Kranenburg.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: procfs_subr.c,v 1.4 1994/01/14 16:25:04 davidg Exp $
+ */
+#include "param.h"
+#include "systm.h"
+#include "time.h"
+#include "kernel.h"
+#include "ioctl.h"
+#include "proc.h"
+#include "buf.h"
+#include "vnode.h"
+#include "file.h"
+#include "resourcevar.h"
+#include "vm/vm.h"
+#include "vm/vm_page.h"
+#include "vm/vm_kern.h"
+#include "vm/vm_user.h"
+#include "kinfo.h"
+#include "kinfo_proc.h"
+#include "machine/pmap.h"
+
+#include "procfs.h"
+#include "pfsnode.h"
+
+#include "machine/vmparam.h"
+
+/*
+ * Get process address map (PIOCGMAP)
+ */
+int
+pfs_vmmap(procp, pfsp, pmapp)
+struct proc *procp;
+struct nfsnode *pfsp;
+struct procmap *pmapp;
+{
+ int error = 0;
+ vm_map_t map;
+ vm_map_entry_t entry;
+ struct procmap prmap;
+
+ map = &procp->p_vmspace->vm_map;
+ vm_map_lock(map);
+ entry = map->header.next;
+
+ while (entry != &map->header) {
+ if (entry->is_a_map) {
+ vm_map_t submap = entry->object.share_map;
+ vm_map_entry_t subentry;
+
+ vm_map_lock(submap);
+ subentry = submap->header.next;
+ while (subentry != &submap->header) {
+ prmap.vaddr = subentry->start;
+ prmap.size = subentry->end - subentry->start;
+ prmap.offset = subentry->offset;
+ prmap.prot = subentry->protection;
+ error = copyout(&prmap, pmapp, sizeof(prmap));
+ if (error)
+ break;
+ pmapp++;
+ subentry = subentry->next;
+ }
+ vm_map_unlock(submap);
+ if (error)
+ break;
+ }
+ prmap.vaddr = entry->start;
+ prmap.size = entry->end - entry->start;
+ prmap.offset = entry->offset;
+ prmap.prot = entry->protection;
+ error = copyout(&prmap, pmapp, sizeof(prmap));
+ if (error)
+ break;
+ pmapp++;
+ entry = entry->next;
+ }
+
+ vm_map_unlock(map);
+ return error;
+}
+
+/*
+ * Count number of VM entries of process (PIOCNMAP)
+ */
+int
+pfs_vm_nentries(procp, pfsp)
+struct proc *procp;
+struct nfsnode *pfsp;
+{
+ int count = 0;
+ vm_map_t map;
+ vm_map_entry_t entry;
+
+ map = &procp->p_vmspace->vm_map;
+ vm_map_lock(map);
+ entry = map->header.next;
+
+ while (entry != &map->header) {
+ if (entry->is_a_map)
+ count += entry->object.share_map->nentries;
+ else
+ count++;
+ entry = entry->next;
+ }
+
+ vm_map_unlock(map);
+ return count;
+}
+
+/*
+ * Map process mapped file to file descriptor (PIOCGMAPFD)
+ */
+int
+pfs_vmfd(procp, pfsp, vmfdp, p)
+struct proc *procp;
+struct pfsnode *pfsp;
+struct vmfd *vmfdp;
+struct proc *p;
+{
+ int rv;
+ vm_map_t map;
+ vm_offset_t addr;
+ vm_size_t size;
+ vm_prot_t prot, maxprot;
+ vm_inherit_t inherit;
+ boolean_t shared;
+ vm_object_t object;
+ vm_offset_t objoff;
+ struct vnode *vp;
+ struct file *fp;
+ extern struct fileops vnops;
+
+ map = &procp->p_vmspace->vm_map;
+
+ addr = vmfdp->vaddr;
+ rv = vm_region(map, &addr, &size, &prot, &maxprot,
+ &inherit, &shared, &object, &objoff);
+
+ if (rv != KERN_SUCCESS)
+ return EINVAL;
+
+ while (object != NULL && object->pager == NULL)
+ object = object->shadow;
+
+ if (object == NULL || object->pager == NULL
+ /* Nobody seems to care || !object->pager_ready */ )
+ return ENOENT;
+
+ if (object->pager->pg_type != PG_VNODE)
+ return ENOENT;
+
+ /* We have a vnode pager, allocate file descriptor */
+ vp = (struct vnode *)object->pager->pg_handle;
+ if (VOP_ACCESS(vp, VREAD, p->p_ucred, p)) {
+ rv = EACCES;
+ goto out;
+ }
+ rv = falloc(p, &fp, &vmfdp->fd);
+ if (rv)
+ goto out;
+
+ VREF(vp);
+ fp->f_type = DTYPE_VNODE;
+ fp->f_ops = &vnops;
+ fp->f_data = (caddr_t)vp;
+ fp->f_flag = FREAD;
+
+out:
+ vm_object_unlock(object);
+ return rv;
+}
+
+
+/*
+ * Vnode op for reading/writing.
+ */
+/* ARGSUSED */
+int
+pfs_doio(vp, uio, ioflag, cred)
+ struct vnode *vp;
+ register struct uio *uio;
+ int ioflag;
+ struct ucred *cred;
+{
+ struct pfsnode *pfsp = VTOPFS(vp);
+ struct proc *procp;
+ int error = 0;
+ long n, on;
+ vm_offset_t kva, kbuf;
+ int pflag;
+
+#ifdef DEBUG
+ if (pfs_debug)
+ printf("pfs_doio(%s): vp 0x%x, proc %x, offset %d\n",
+ uio->uio_rw==UIO_READ?"R":"W", vp, uio->uio_procp, uio->uio_offset);
+#endif
+
+#ifdef DIAGNOSTIC
+ if (vp->v_type != VPROC)
+ panic("pfs_doio vtype");
+#endif
+ procp = pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0;
+ if (!procp)
+ return ESRCH;
+
+ if (procp->p_flag & SSYS)
+ return EACCES;
+
+ if (uio->uio_resid == 0) {
+ return (0);
+ }
+ /* allocate a bounce buffer */
+ /* notice that this bounce buffer bogosity is due to
+ a problem with wiring/unwiring procs pages, so
+ rather than wire the destination procs data pages
+ I used a kernel bounce buffer
+ */
+ kbuf = kmem_alloc(kernel_map, NBPG);
+ if( !kbuf)
+ return ENOMEM;
+
+ /* allocate a kva */
+ kva = kmem_alloc_pageable(kernel_map, NBPG);
+ if( !kva) {
+ kmem_free(kernel_map, kbuf, NBPG);
+ return ENOMEM;
+ }
+
+ pflag = procp->p_flag & SKEEP;
+ procp->p_flag |= SKEEP;
+
+ do { /* One page at a time */
+ int rv;
+ vm_map_t map;
+ vm_offset_t offset, v, pa;
+ vm_prot_t oldprot = 0, prot, maxprot;
+ vm_inherit_t inherit;
+ boolean_t shared;
+ vm_object_t object;
+ vm_offset_t objoff;
+ vm_page_t m;
+ vm_offset_t size;
+ int s;
+
+
+ on = uio->uio_offset - trunc_page(uio->uio_offset);
+ n = MIN(NBPG-on, uio->uio_resid);
+
+ /* Map page into kernel space */
+
+ /* printf("rw: offset: %d, n: %d, resid: %d\n",
+ uio->uio_offset, n, uio->uio_resid); */
+ if (procp->p_vmspace != pfsp->pfs_vs) {
+ error = EFAULT;
+ break;
+ }
+
+ map = &procp->p_vmspace->vm_map;
+
+ offset = trunc_page((vm_offset_t)uio->uio_offset);
+
+/*
+ * This code *fakes* the existance of the UPAGES at the address USRSTACK
+ * in the process address space for versions of the kernel where the
+ * UPAGES do not exist in the process map.
+ */
+#if 0
+#ifndef FULLSWAP
+ if( offset >= USRSTACK) {
+ caddr_t paddr;
+ if( offset >= USRSTACK + NBPG*UPAGES) {
+ error = EINVAL;
+ break;
+ }
+ paddr = (caddr_t) procp->p_addr;
+ error = uiomove(paddr + (offset - USRSTACK), (int)n, uio);
+ continue;
+ }
+#endif
+#endif
+
+ /* make sure that the offset exists in the procs map */
+ rv = vm_region(map, &offset, &size, &prot, &maxprot,
+ &inherit, &shared, &object, &objoff);
+ if (rv != KERN_SUCCESS) {
+ error = EINVAL;
+ break;
+ }
+
+
+ /* change protections if need be */
+ if (uio->uio_rw == UIO_WRITE && (prot & VM_PROT_WRITE) == 0) {
+ oldprot = prot;
+ prot |= VM_PROT_WRITE;
+ rv = vm_protect(map, offset, NBPG, FALSE, prot);
+ if (rv != KERN_SUCCESS) {
+ error = EPERM;
+ break;
+ }
+ }
+
+ if( uio->uio_rw != UIO_WRITE) {
+ prot &= ~VM_PROT_WRITE;
+ }
+
+ /* check for stack area -- don't fault in unused pages */
+ if( (caddr_t) offset >= procp->p_vmspace->vm_maxsaddr &&
+ offset < USRSTACK) {
+ if( (caddr_t) offset <
+ ((procp->p_vmspace->vm_maxsaddr + MAXSSIZ) - ctob( procp->p_vmspace->vm_ssize))) {
+ error = EFAULT;
+ goto reprot;
+ }
+ if( (caddr_t) offset >=
+ ((procp->p_vmspace->vm_maxsaddr + MAXSSIZ))) {
+ error = EFAULT;
+ goto reprot;
+ }
+ }
+
+ /* wire the page table page */
+ v = trunc_page(((vm_offset_t)vtopte( offset)));
+ vm_map_pageable(map, v, round_page(v+1), FALSE);
+
+ if( uio->uio_rw == UIO_READ) {
+ /* Now just fault the page table and the page */
+ rv = vm_fault(map, offset, VM_PROT_READ, FALSE);
+
+ if (rv != KERN_SUCCESS) {
+ procp->p_flag = (procp->p_flag & ~SKEEP) | pflag;
+ vm_map_pageable(map, v, round_page(v+1), TRUE);
+ error = EFAULT;
+ goto reprot;
+ }
+
+
+ /* get the physical address of the page */
+ pa = pmap_extract( vm_map_pmap(map), offset);
+
+ if( !pa) {
+ printf("pfs: cannot get pa -- read\n");
+ } else {
+ /* enter the physical address into the kernel pmap */
+ pmap_enter(vm_map_pmap(kernel_map), kva, pa, prot, TRUE);
+ /* copy the data */
+ bcopy( (caddr_t)kva, (caddr_t)kbuf, NBPG);
+ /* remove the physical address from the kernel pmap */
+ pmap_remove(vm_map_pmap(kernel_map), kva, round_page(kva + 1));
+ }
+ }
+
+ error = uiomove((caddr_t)(kbuf + on), (int)n, uio);
+
+ if( !error && uio->uio_rw == UIO_WRITE) {
+ /* Now just fault the page table and the page */
+ rv = vm_fault(map, offset, VM_PROT_READ|VM_PROT_WRITE, FALSE);
+
+ if (rv != KERN_SUCCESS) {
+ procp->p_flag = (procp->p_flag & ~SKEEP) | pflag;
+ vm_map_pageable(map, v, round_page(v+1), TRUE);
+ error = EFAULT;
+ goto reprot;
+ }
+
+ /* get the physical address of the page */
+ pa = pmap_extract( vm_map_pmap(map), offset);
+
+ if( !pa) {
+ printf("pfs: cannot get pa -- write\n");
+ } else {
+ /* enter the physical address into the kernel pmap */
+ pmap_enter(vm_map_pmap(kernel_map), kva, pa, prot, TRUE);
+ /* copy the data */
+ bcopy( (caddr_t)kbuf, (caddr_t)kva + on, n);
+ /* remove the physical address from the kernel pmap */
+ pmap_remove(vm_map_pmap(kernel_map), kva, round_page(kva + 1));
+ }
+ }
+
+ /* unwire the page table page */
+ vm_map_pageable(map, v, round_page(v+1), TRUE);
+
+ reprot:
+
+ if (oldprot) {
+ rv = vm_protect(map, offset, NBPG, FALSE, oldprot);
+ if (rv != KERN_SUCCESS && error == 0) {
+ error = EPERM;
+ break;
+ }
+ }
+
+ } while (error == 0 && uio->uio_resid > 0);
+
+ procp->p_flag = (procp->p_flag & ~SKEEP) | pflag;
+/* free the kva and bounce buffer */
+ kmem_free_wakeup(kernel_map, kva, NBPG);
+ kmem_free(kernel_map, kbuf, NBPG);
+
+ return (error);
+}
diff --git a/sys/procfs/procfs_vfsops.c b/sys/procfs/procfs_vfsops.c
new file mode 100644
index 000000000000..16d0b30d3a12
--- /dev/null
+++ b/sys/procfs/procfs_vfsops.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 1993 Paul Kranenburg
+ * 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 Paul Kranenburg.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: procfs_vfsops.c,v 1.2 1993/12/31 17:42:56 davidg Exp $
+ */
+
+/*
+ * PROCFS VFS interface routines
+ */
+
+#include "param.h"
+#include "time.h"
+#include "kernel.h"
+#include "proc.h"
+#include "buf.h"
+#include "mount.h"
+#include "signalvar.h"
+#include "vnode.h"
+
+#include "pfsnode.h"
+
+extern struct vnodeops pfs_vnodeops;
+
+/*
+ * mfs vfs operations.
+ */
+int pfs_mount();
+int pfs_start();
+int pfs_unmount();
+int pfs_root();
+int pfs_quotactl();
+int pfs_statfs();
+int pfs_sync();
+int pfs_fhtovp();
+int pfs_vptofh();
+void pfs_init();
+
+struct vfsops procfs_vfsops = {
+ pfs_mount,
+ pfs_start,
+ pfs_unmount,
+ pfs_root,
+ pfs_quotactl,
+ pfs_statfs,
+ pfs_sync,
+ pfs_fhtovp,
+ pfs_vptofh,
+ pfs_init,
+};
+
+/*
+ * VFS Operations.
+ *
+ * mount system call
+ */
+/* ARGSUSED */
+int
+pfs_mount(mp, path, data, ndp, p)
+ register struct mount *mp;
+ char *path;
+ caddr_t data;
+ struct nameidata *ndp;
+ struct proc *p;
+{
+#if 0
+ struct pfs_args args;
+#endif
+ struct vnode *pvp;
+ u_int size;
+ int error;
+
+ if (mp->mnt_flag & MNT_UPDATE) {
+ return (0);
+ }
+
+#if 0
+ if (error = copyin(data, (caddr_t)&args, sizeof (struct pfs_args)))
+ return (error);
+#endif
+ (void) copyinstr(path, (caddr_t)mp->mnt_stat.f_mntonname, MNAMELEN, &size);
+ bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
+
+ size = sizeof("proc") - 1;
+ bcopy("proc", mp->mnt_stat.f_mntfromname, size);
+ bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
+
+ (void) pfs_statfs(mp, &mp->mnt_stat, p);
+ return (0);
+}
+
+/*
+ * unmount system call
+ */
+int
+pfs_unmount(mp, mntflags, p)
+ struct mount *mp;
+ int mntflags;
+ struct proc *p;
+{
+ return (0);
+}
+
+#if 0
+int
+pfs_root(mp, vpp)
+ struct mount *mp;
+ struct vnode **vpp;
+{
+ struct vnode *vp;
+ struct pfsnode *pfsp, **pp;
+ int error;
+
+ /* Look in "cache" first */
+ for (pfsp = pfshead; pfsp != NULL; pfsp = pfsp->pfs_next) {
+ if (pfsp->pfs_vnode->v_flag & VROOT) {
+ *vpp = pfsp->pfs_vnode;
+ vref(*vpp);
+ return 0;
+ }
+ }
+
+ /* Not on list, allocate new vnode */
+ error = getnewvnode(VT_PROCFS, mp, &pfs_vnodeops, &vp);
+ if (error)
+ return error;
+
+ vp->v_type = VDIR;
+ vp->v_flag = VROOT;
+ pfsp = VTOPFS(vp);
+ pfsp->pfs_next = NULL;
+ pfsp->pfs_pid = 0;
+ pfsp->pfs_vnode = vp;
+ pfsp->pfs_flags = 0;
+ pfsp->pfs_vflags = 0;
+ pfsp->pfs_uid = 0;
+ pfsp->pfs_gid = 2; /* XXX group kmem */
+ pfsp->pfs_mode = 0750; /* /proc = drwxr-x--- */
+
+ /* Append to pfs node list */
+
+ pfsp->pfs_next = pfshead;
+ pfshead = pfsp;
+
+ *vpp = vp;
+ return 0;
+}
+#endif
+
+
+int
+pfs_root(mp, vpp)
+ struct mount *mp;
+ struct vnode **vpp;
+{
+ struct vnode *vp;
+ struct pfsnode *pfsp;
+ int error;
+
+ error = getnewvnode(VT_PROCFS, mp, &pfs_vnodeops, &vp);
+ if (error)
+ return error;
+
+ vp->v_type = VDIR;
+ vp->v_flag = VROOT;
+ pfsp = VTOPFS(vp);
+ pfsp->pfs_vnode = vp;
+ pfsp->pfs_pid = 0;
+ pfsp->pfs_pid = 0;
+ pfsp->pfs_flags = 0;
+ pfsp->pfs_vflags = 0;
+ pfsp->pfs_uid = 0;
+ pfsp->pfs_gid = 2; /* XXX group kmem */
+ pfsp->pfs_mode = 0750; /* /proc = drwxr-x--- */
+
+ *vpp = vp;
+ return 0;
+}
+
+/*
+ */
+/* ARGSUSED */
+int
+pfs_start(mp, flags, p)
+ struct mount *mp;
+ int flags;
+ struct proc *p;
+{
+ return 0;
+}
+
+/*
+ * Get file system statistics.
+ */
+int
+pfs_statfs(mp, sbp, p)
+ struct mount *mp;
+ struct statfs *sbp;
+ struct proc *p;
+{
+
+ sbp->f_type = MOUNT_PROCFS;
+ sbp->f_fsize = 512;
+ sbp->f_bsize = NBPG;
+ sbp->f_blocks = maxproc;
+ sbp->f_bfree = maxproc - nprocs;
+ sbp->f_bavail = sbp->f_bfree;
+ sbp->f_files = maxproc; /* plus . and .. */
+ sbp->f_ffree = maxproc - nprocs;
+
+ return 0;
+}
+
+
+int
+pfs_quotactl(mp, cmds, uid, arg, p)
+ struct mount *mp;
+ int cmds;
+ uid_t uid;
+ caddr_t arg;
+ struct proc *p;
+{
+ return EOPNOTSUPP;
+}
+
+int
+pfs_sync(mp, waitfor)
+ struct mount *mp;
+ int waitfor;
+{
+ return 0;
+}
+
+int
+pfs_fhtovp(mp, fhp, vpp)
+ register struct mount *mp;
+ struct fid *fhp;
+ struct vnode **vpp;
+{
+ return EINVAL;
+}
+
+int
+pfs_vptofh(vp, fhp)
+ struct vnode *vp;
+ struct fid *fhp;
+{
+ return EINVAL;
+}
+
+void
+pfs_init()
+{
+ return;
+}
diff --git a/sys/procfs/procfs_vnops.c b/sys/procfs/procfs_vnops.c
new file mode 100644
index 000000000000..90d524cb474f
--- /dev/null
+++ b/sys/procfs/procfs_vnops.c
@@ -0,0 +1,708 @@
+/*
+ * Copyright (c) 1993 Paul Kranenburg
+ * 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 Paul Kranenburg.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: procfs_vnops.c,v 1.6 1994/01/31 04:19:20 davidg Exp $
+ */
+
+/*
+ * PROCFS vnode interface routines
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "time.h"
+#include "kernel.h"
+#include "ioctl.h"
+#include "file.h"
+#include "proc.h"
+#include "buf.h"
+#include "vnode.h"
+#include "namei.h"
+#include "resourcevar.h"
+#include "vm/vm.h"
+#include "kinfo.h"
+#include "kinfo_proc.h"
+
+#include "sys/procfs.h"
+#include "pfsnode.h"
+
+#include "machine/vmparam.h"
+
+/*
+ * procfs vnode operations.
+ */
+struct vnodeops pfs_vnodeops = {
+ pfs_lookup, /* lookup */
+ pfs_create, /* create */
+ pfs_mknod, /* mknod */
+ pfs_open, /* open */
+ pfs_close, /* close */
+ pfs_access, /* access */
+ pfs_getattr, /* getattr */
+ pfs_setattr, /* setattr */
+ pfs_read, /* read */
+ pfs_write, /* write */
+ pfs_ioctl, /* ioctl */
+ pfs_select, /* select */
+ pfs_mmap, /* mmap */
+ pfs_fsync, /* fsync */
+ pfs_seek, /* seek */
+ pfs_remove, /* remove */
+ pfs_link, /* link */
+ pfs_rename, /* rename */
+ pfs_mkdir, /* mkdir */
+ pfs_rmdir, /* rmdir */
+ pfs_symlink, /* symlink */
+ pfs_readdir, /* readdir */
+ pfs_readlink, /* readlink */
+ pfs_abortop, /* abortop */
+ pfs_inactive, /* inactive */
+ pfs_reclaim, /* reclaim */
+ pfs_lock, /* lock */
+ pfs_unlock, /* unlock */
+ pfs_bmap, /* bmap */
+ pfs_strategy, /* strategy */
+ pfs_print, /* print */
+ pfs_islocked, /* islocked */
+ pfs_advlock, /* advlock */
+};
+
+/*
+ * Vnode Operations.
+ *
+ */
+/* ARGSUSED */
+int
+pfs_open(vp, mode, cred, p)
+ register struct vnode *vp;
+ int mode;
+ struct ucred *cred;
+ struct proc *p;
+{
+ struct pfsnode *pfsp = VTOPFS(vp);
+ struct proc *procp;
+
+#ifdef DEBUG
+ if (pfs_debug)
+ printf("pfs_open: vp 0x%x, proc %d\n", vp, p->p_pid);
+#endif
+
+ if ( (procp = (pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0)) == NULL)
+ return ESRCH;
+
+ if ( (pfsp->pfs_flags & FWRITE) && (mode & O_EXCL) ||
+ (pfsp->pfs_flags & O_EXCL) && (mode & FWRITE) )
+ return EBUSY;
+
+
+ if (mode & FWRITE)
+ pfsp->pfs_flags = (mode & (FWRITE|O_EXCL));
+
+ procp->p_vmspace->vm_refcnt++;
+ pfsp->pfs_vs = procp->p_vmspace;
+ return 0;
+}
+
+/*
+ * /proc filesystem close routine
+ */
+/* ARGSUSED */
+int
+pfs_close(vp, flag, cred, p)
+ register struct vnode *vp;
+ int flag;
+ struct ucred *cred;
+ struct proc *p;
+{
+ struct pfsnode *pfsp = VTOPFS(vp);
+
+#ifdef DEBUG
+ if (pfs_debug)
+ printf("pfs_close: vp 0x%x proc %d\n", vp, p->p_pid);
+#endif
+ if ((flag & FWRITE) && (pfsp->pfs_flags & O_EXCL))
+ pfsp->pfs_flags &= ~(FWRITE|O_EXCL);
+
+ vmspace_free(pfsp->pfs_vs);
+ return (0);
+}
+
+/*
+ * Ioctl operation.
+ */
+/* ARGSUSED */
+int
+pfs_ioctl(vp, com, data, fflag, cred, p)
+ struct vnode *vp;
+ int com;
+ caddr_t data;
+ int fflag;
+ struct ucred *cred;
+ struct proc *p;
+{
+ int error = 0;
+ struct proc *procp;
+ struct pfsnode *pfsp = VTOPFS(vp);
+
+ procp = pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0;
+ if (!procp)
+ return ESRCH;
+
+ switch (com) {
+
+ case PIOCGPINFO: {
+ int copysize = sizeof(struct kinfo_proc), needed;
+ kinfo_doproc(KINFO_PROC_PID, data, &copysize,
+ pfsp->pfs_pid, &needed);
+ break;
+ }
+
+#ifdef notyet /* Changes to proc.h needed */
+ case PIOCGSIGSET:
+ procp->p_psigset = *(sigset_t *)data;
+ break;
+
+ case PIOCSSIGSET:
+ *(sigset_t *)data = procp->p_psigset;
+ break;
+
+ case PIOCGFLTSET:
+ procp->p_pfltset = *(sigflt_t *)data;
+ break;
+
+ case PIOCSFLTSET:
+ *(fltset_t *)data = procp->p_pfltset;
+ break;
+#endif
+
+ case PIOCGMAPFD:
+ error = pfs_vmfd(procp, pfsp, (struct vmfd *)data, p);
+ break;
+
+ case PIOCGNMAP:
+ *(int *)data = pfs_vm_nentries(procp, pfsp);
+ break;
+
+ case PIOCGMAP:
+ error = pfs_vmmap(procp, pfsp, *(struct procmap *)data);
+ break;
+
+ default:
+ error = EIO;
+ break;
+ }
+ return error;
+}
+
+/*
+ * Pass I/O requests to the memory filesystem process.
+ */
+int
+pfs_strategy(bp)
+ register struct buf *bp;
+{
+ struct vnode *vp;
+ struct proc *p = curproc; /* XXX */
+
+ return (0);
+}
+
+/*
+ * This is a noop, simply returning what one has been given.
+ */
+int
+pfs_bmap(vp, bn, vpp, bnp)
+ struct vnode *vp;
+ daddr_t bn;
+ struct vnode **vpp;
+ daddr_t *bnp;
+{
+
+ if (vpp != NULL)
+ *vpp = vp;
+ if (bnp != NULL)
+ *bnp = bn;
+ return (0);
+}
+
+/*
+ * /proc filesystem inactive routine
+ */
+/* ARGSUSED */
+int
+pfs_inactive(vp, p)
+ struct vnode *vp;
+ struct proc *p;
+{
+ struct pfsnode *pfsp = VTOPFS(vp);
+
+ if ((pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0) == NULL
+ && vp->v_usecount == 0)
+ vgone(vp);
+
+ return 0;
+}
+
+/*
+ * /proc filesystem reclaim routine
+ */
+/* ARGSUSED */
+int
+pfs_reclaim(vp)
+ struct vnode *vp;
+{
+ struct pfsnode **pp, *pfsp = VTOPFS(vp);
+
+ for (pp = &pfshead; *pp; pp = &(*pp)->pfs_next) {
+ if (*pp == pfsp) {
+ *pp = pfsp->pfs_next;
+ break;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Print out the contents of an pfsnode.
+ */
+void
+pfs_print(vp)
+ struct vnode *vp;
+{
+ struct pfsnode *pfsp = VTOPFS(vp);
+
+ printf("tag VT_PROCFS, pid %d, uid %d, gid %d, mode %x, flags %x\n",
+ pfsp->pfs_pid,
+ pfsp->pfs_uid, pfsp->pfs_gid,
+ pfsp->pfs_mode, pfsp->pfs_flags);
+
+ return;
+}
+
+/*
+ * /proc bad operation
+ */
+int
+pfs_badop()
+{
+ printf("pfs_badop called\n");
+ return EIO;
+}
+
+/*
+ * Make up some attributes for a process file
+ */
+int
+pfs_getattr (vp, vap, cred, p)
+ struct vnode *vp;
+ struct vattr *vap;
+ struct ucred *cred;
+ struct proc *p;
+{
+ struct pfsnode *pfsp = VTOPFS(vp);
+ struct proc *procp;
+
+ VATTR_NULL(vap);
+ vap->va_type = vp->v_type;
+ vap->va_flags = pfsp->pfs_vflags;
+
+ if (vp->v_flag & VROOT) {
+ vap->va_mode = 0750; /* /proc = rwxr-x--- */
+ vap->va_nlink = 2;
+ vap->va_size =
+ roundup((2+nprocs)*sizeof(struct pfsdent), DIRBLKSIZ);
+ vap->va_size_rsv = 0;
+ vap->va_uid = 0;
+ vap->va_gid = 2; /* XXX group kmem */
+ vap->va_bytes = 0;
+ vap->va_atime = vap->va_mtime = vap->va_ctime = time; /*XXX*/
+ vap->va_rdev = makedev(255, 255);
+ return 0;
+ }
+
+
+ vap->va_rdev = makedev(255, pfsp->pfs_pid);
+ vap->va_mode = 0644;
+ procp = pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0;
+ if (!procp)
+ return ESRCH;
+
+ vap->va_nlink = 1;
+ vap->va_size = ctob( procp->p_vmspace->vm_tsize +
+ procp->p_vmspace->vm_dsize +
+ procp->p_vmspace->vm_ssize);
+ vap->va_bytes = 0;
+ vap->va_size_rsv = 0;
+ vap->va_blocksize = PAGE_SIZE;
+ vap->va_uid = procp->p_ucred->cr_uid;
+ vap->va_gid = procp->p_ucred->cr_gid;
+ if (vap->va_uid != procp->p_cred->p_ruid)
+ vap->va_mode |= VSUID;
+ if (vap->va_gid != procp->p_cred->p_rgid)
+ vap->va_mode |= VSGID;
+ if (procp->p_flag & SLOAD) {
+ vap->va_atime = vap->va_mtime = vap->va_ctime =
+ procp->p_stats->p_start;
+ }
+
+ return 0;
+}
+
+/*
+ * Set some attributes for a process file
+ */
+int
+pfs_setattr (vp, vap, cred, p)
+ struct vnode *vp;
+ struct vattr *vap;
+ struct ucred *cred;
+ struct proc *p;
+{
+ struct pfsnode *pfsp = VTOPFS(vp);
+ struct proc *procp;
+ int error = 0;
+
+ procp = pfsp->pfs_pid?pfind(pfsp->pfs_pid):&proc0;
+ if (!procp)
+ return ESRCH;
+
+ /*
+ * Check for unsetable attributes.
+ */
+ if ((vap->va_type != VNON) || (vap->va_nlink != (short)VNOVAL) ||
+ (vap->va_fsid != (long)VNOVAL) ||
+ (vap->va_fileid != (long)VNOVAL) ||
+ (vap->va_blocksize != (long)VNOVAL) ||
+ (vap->va_rdev != (dev_t)VNOVAL) ||
+ ((int)vap->va_bytes != (u_long)VNOVAL) ||
+ ((int)vap->va_bytes_rsv != (u_long)VNOVAL) ||
+ ((int)vap->va_size != (u_long)VNOVAL) ||
+ ((int)vap->va_size_rsv != (u_long)VNOVAL) ||
+ (vap->va_gen != (long)VNOVAL) ||
+ ((int)vap->va_atime.tv_sec != (u_long)VNOVAL) ||
+ ((int)vap->va_mtime.tv_sec != (u_long)VNOVAL) ||
+ ((int)vap->va_ctime.tv_sec != (u_long)VNOVAL) ||
+ (( (vap->va_uid != (uid_t)VNOVAL) ||
+ (vap->va_gid != (gid_t)VNOVAL)) && !(vp->v_flag & VROOT)) ) {
+ return (EINVAL);
+ }
+
+ /* set mode bits, only rwx bits are modified */
+ if (vap->va_mode != (u_short)VNOVAL) {
+ if (cred->cr_uid != pfsp->pfs_uid &&
+ (error = suser(cred, &p->p_acflag)))
+ return (error);
+ pfsp->pfs_mode = vap->va_mode & 0777;
+ }
+
+ /* For now, only allow to change ownership of "/proc" itself */
+ if ((vp->v_flag & VROOT) && vap->va_uid != (uid_t)VNOVAL) {
+ if ((error = suser(cred, &p->p_acflag)))
+ return (error);
+ pfsp->pfs_uid = vap->va_uid;
+ }
+
+ if ((vp->v_flag & VROOT) && vap->va_gid != (gid_t)VNOVAL) {
+ if ((cred->cr_uid != pfsp->pfs_uid ||
+ !groupmember(vap->va_gid, cred)) &&
+ (error = suser(cred, &p->p_acflag)))
+ return error;
+
+ pfsp->pfs_gid = vap->va_gid;
+ }
+
+ /* chflags() */
+ if (vap->va_flags != (u_long)VNOVAL) {
+ if (cred->cr_uid != pfsp->pfs_uid &&
+ (error = suser(cred, &p->p_acflag)))
+ return (error);
+ if (cred->cr_uid == 0) {
+ pfsp->pfs_vflags = vap->va_flags;
+ } else {
+ pfsp->pfs_vflags &= 0xffff0000ul;
+ pfsp->pfs_vflags |= (vap->va_flags & 0xffff);
+ }
+ }
+ return 0;
+}
+
+int
+pfs_access (vp, mode, cred, p)
+ struct vnode *vp;
+ int mode;
+ struct ucred *cred;
+ struct proc *p;
+{
+ register struct vattr *vap;
+ register gid_t *gp;
+ struct vattr vattr;
+ register int i;
+ int error;
+
+ /*
+ * If you're the super-user,
+ * you always get access.
+ */
+ if (cred->cr_uid == (uid_t)0)
+ return (0);
+ vap = &vattr;
+ if (error = pfs_getattr(vp, vap, cred, 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 (cred->cr_uid != vap->va_uid) {
+ mode >>= 3;
+ gp = cred->cr_groups;
+ for (i = 0; i < cred->cr_ngroups; i++, gp++)
+ if (vap->va_gid == *gp)
+ goto found;
+ mode >>= 3;
+found:
+ ;
+ }
+ if ((vap->va_mode & mode) != 0)
+ return (0);
+ return (EACCES);
+}
+
+/*
+ * /proc lookup
+ */
+int
+pfs_lookup(vp, ndp, p)
+ register struct vnode *vp;
+ register struct nameidata *ndp;
+ struct proc *p;
+{
+ int lockparent, wantparent, flag, error = 0;
+ pid_t pid;
+ struct vnode *nvp;
+ struct pfsnode *pfsp;
+ struct proc *procp;
+
+#ifdef DEBUG
+ if (pfs_debug)
+ printf("pfs_lookup: vp 0x%x name %s proc %d\n",
+ vp, ndp->ni_ptr, p->p_pid);
+#endif
+
+ ndp->ni_dvp = vp;
+ ndp->ni_vp = NULL;
+ if (vp->v_type != VDIR)
+ return (ENOTDIR);
+
+ lockparent = ndp->ni_nameiop & LOCKPARENT;
+ flag = ndp->ni_nameiop & OPMASK;
+ wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT);
+ if (flag != LOOKUP)
+ return EACCES;
+ if (ndp->ni_isdotdot) {
+ /* Should not happen */
+ printf("pfs_lookup: vp 0x%x: dotdot\n", vp);
+ return EIO;
+ }
+ if (ndp->ni_namelen == 1 && *ndp->ni_ptr == '.') {
+ VREF(vp);
+ ndp->ni_vp = vp;
+ return 0;
+ }
+
+ pid = (pid_t)atoi(ndp->ni_ptr, ndp->ni_namelen);
+ if (pid == (pid_t)-1)
+ return ENOENT;
+
+ if ((procp = pid?pfind(pid):&proc0) == NULL)
+ return ENOENT;
+
+loop:
+ /* Search pfs node list first */
+ for (pfsp = pfshead; pfsp != NULL; pfsp = pfsp->pfs_next) {
+ if (pfsp->pfs_pid == pid)
+ break;
+ }
+
+ if (pfsp == NULL) {
+ struct pfsnode **pp;
+ error = getnewvnode(VT_PROCFS, vp->v_mount, &pfs_vnodeops, &nvp);
+ if (error)
+ return error;
+
+ nvp->v_type = VPROC;
+ pfsp = VTOPFS(nvp);
+ pfsp->pfs_next = NULL;
+ pfsp->pfs_pid = pid;
+ pfsp->pfs_vnode = nvp;
+ pfsp->pfs_flags = 0;
+ pfsp->pfs_vflags = 0;
+ pfsp->pfs_uid = procp->p_ucred->cr_uid;
+ pfsp->pfs_gid = procp->p_ucred->cr_gid;
+ pfsp->pfs_mode = 0700; /* Initial access bits */
+
+ /* Append to pfs node list */
+ pfsp->pfs_next = pfshead;
+ pfshead = pfsp;
+
+ } else {
+ if (vget(pfsp->pfs_vnode))
+ goto loop;
+ VOP_UNLOCK(pfsp->pfs_vnode);
+ }
+ ndp->ni_vp = pfsp->pfs_vnode;
+
+ return (error);
+}
+
+int
+pfs_readdir(vp, uio, cred, eofflagp)
+ struct vnode *vp;
+ register struct uio *uio;
+ struct ucred *cred;
+ int *eofflagp;
+{
+ int error = 0;
+ int count, lost, pcnt, skipcnt, doingzomb = 0;
+ struct proc *p;
+ struct pfsdent dent;
+
+#ifdef DEBUG
+ if (pfs_debug)
+ printf("pfs_readdir: vp 0x%x proc %d\n",
+ vp, uio->uio_procp->p_pid);
+#endif
+ count = uio->uio_resid;
+ count &= ~(DIRBLKSIZ - 1);
+ lost = uio->uio_resid - count;
+ if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1)))
+ return (EINVAL);
+ uio->uio_resid = count;
+ uio->uio_iov->iov_len = count;
+ *eofflagp = 1;
+ skipcnt = uio->uio_offset / sizeof(struct pfsdent);
+
+ count = 0;
+ if (skipcnt == 0) {
+ /* Fake "." and ".." entries? */
+#if 0
+ dent.d_fileno = 2; /* XXX - Filesystem root */
+ dent.d_reclen = sizeof(struct pfsdent);
+
+ dent.d_namlen = 1;
+ dent.d_nam[0] = '.';
+ dent.d_nam[1] = '\0';
+ error = uiomove((char *)&dent, sizeof(struct pfsdent) , uio);
+ if (error)
+ return error;
+
+ dent.d_fileno = 2;
+ dent.d_namlen = 2;
+ dent.d_nam[1] = '.';
+ dent.d_nam[2] = '\0';
+ error = uiomove((char *)&dent, sizeof(struct pfsdent) , uio);
+ if (error)
+ return error;
+#endif
+ count += 2*dent.d_reclen;
+ }
+
+ p = (struct proc *)allproc;
+ for (pcnt = 0; p && uio->uio_resid; pcnt++) {
+ if (pcnt < skipcnt) {
+ p = p->p_nxt;
+ if (p == NULL && doingzomb == 0) {
+ doingzomb = 1;
+ p = zombproc;
+ }
+ continue;
+ }
+ *eofflagp = 0;
+
+ /* "inode" is process slot (actually position on list) */
+ dent.d_fileno = (unsigned long)(pcnt+1);
+ dent.d_namlen = itos((unsigned int)p->p_pid, dent.d_nam);
+ dent.d_nam[dent.d_namlen] = '\0';
+
+ p = p->p_nxt;
+ if (p == NULL && doingzomb == 0) {
+ doingzomb = 1;
+ p = zombproc;
+ }
+ if (p == NULL) {
+ /* Extend 'reclen' to end of block */;
+ dent.d_reclen = DIRBLKSIZ - (count & (DIRBLKSIZ - 1));
+ } else
+ dent.d_reclen = sizeof(struct pfsdent);
+ count += dent.d_reclen;
+ error = uiomove((char *)&dent, dent.d_reclen, uio);
+ if (error)
+ break;
+ }
+ if (count == 0)
+ *eofflagp = 1;
+
+ uio->uio_resid += lost;
+ return error;
+}
+
+/*
+ * convert n to decimal representation in character array b
+ * return number of decimal digits produced.
+ */
+int
+itos(n, b)
+unsigned int n;
+char *b;
+{
+#define BASE 10
+ int m = (n<BASE)?0:itos(n/BASE, b);
+
+ *(b+m) = "0123456789abcdef"[n%BASE];
+ return m+1;
+}
+
+/*
+ * convert decimal ascii representation in b of length len to integer
+ */
+int
+atoi(b, len)
+char *b;
+unsigned int len;
+{
+ int n = 0;
+
+ while (len--) {
+ register char c = *b++;
+ if (c < '0' || c > '9')
+ return -1;
+ n = 10 * n + (c - '0');
+ }
+ return n;
+}