diff options
| author | svn2git <svn2git@FreeBSD.org> | 1994-05-01 08:00:00 +0000 |
|---|---|---|
| committer | svn2git <svn2git@FreeBSD.org> | 1994-05-01 08:00:00 +0000 |
| commit | a16f65c7d117419bd266c28a1901ef129a337569 (patch) | |
| tree | 2626602f66dc3551e7a7c7bc9ad763c3bc7ab40a /sys/procfs | |
| parent | 8503f4f13f77abf7adc8f7e329c6f9c1d52b6a20 (diff) | |
Diffstat (limited to 'sys/procfs')
| -rw-r--r-- | sys/procfs/pfsnode.h | 217 | ||||
| -rw-r--r-- | sys/procfs/procfs_subr.c | 429 | ||||
| -rw-r--r-- | sys/procfs/procfs_vfsops.c | 280 | ||||
| -rw-r--r-- | sys/procfs/procfs_vnops.c | 708 |
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, ©size, + 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; +} |
