diff options
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; +} | 
