165524Spendry /* 265524Spendry * Copyright (c) 1993 The Regents of the University of California. 365524Spendry * Copyright (c) 1993 Jan-Simon Pendry 465524Spendry * All rights reserved. 565524Spendry * 665524Spendry * This code is derived from software contributed to Berkeley by 765524Spendry * Jan-Simon Pendry. 865524Spendry * 965524Spendry * %sccs.include.redist.c% 1065524Spendry * 11*65536Spendry * @(#)procfs_vnops.c 8.2 (Berkeley) 01/06/94 1265524Spendry * 1365524Spendry * From: 1465524Spendry * $Id: procfs_vnops.c,v 3.2 1993/12/15 09:40:17 jsp Exp $ 1565524Spendry */ 1665524Spendry 1765524Spendry /* 1865524Spendry * procfs vnode interface 1965524Spendry */ 2065524Spendry 2165524Spendry #include <sys/param.h> 2265524Spendry #include <sys/systm.h> 2365524Spendry #include <sys/time.h> 2465524Spendry #include <sys/kernel.h> 2565524Spendry #include <sys/file.h> 2665524Spendry #include <sys/proc.h> 2765524Spendry #include <sys/vnode.h> 2865524Spendry #include <sys/namei.h> 2965524Spendry #include <sys/malloc.h> 3065524Spendry #include <sys/dirent.h> 3165524Spendry #include <sys/resourcevar.h> 3265524Spendry #include <miscfs/procfs/procfs.h> 3365524Spendry #include <vm/vm.h> /* for PAGE_SIZE */ 3465524Spendry 3565524Spendry /* 3665524Spendry * Vnode Operations. 3765524Spendry * 3865524Spendry */ 3965524Spendry 4065524Spendry /* 4165524Spendry * This is a list of the valid names in the 4265524Spendry * process-specific sub-directories. It is 4365524Spendry * used in procfs_lookup and procfs_readdir 4465524Spendry */ 4565524Spendry static struct pfsnames { 4665524Spendry u_short d_namlen; 4765524Spendry char d_name[PROCFS_NAMELEN]; 4865524Spendry pfstype d_pfstype; 4965524Spendry } procent[] = { 5065524Spendry #define N(s) sizeof(s)-1, s 5165524Spendry /* namlen, nam, type */ 5265524Spendry { N("file"), Pfile }, 5365524Spendry { N("mem"), Pmem }, 5465524Spendry { N("regs"), Pregs }, 5565524Spendry { N("ctl"), Pctl }, 5665524Spendry { N("status"), Pstatus }, 5765524Spendry { N("note"), Pnote }, 5865524Spendry { N("notepg"), Pnotepg }, 5965524Spendry #undef N 6065524Spendry }; 6165524Spendry #define Nprocent (sizeof(procent)/sizeof(procent[0])) 6265524Spendry 6365524Spendry static pid_t atopid __P((const char *, u_int)); 6465524Spendry 6565524Spendry /* 6665524Spendry * set things up for doing i/o on 6765524Spendry * the pfsnode (vp). (vp) is locked 6865524Spendry * on entry, and should be left locked 6965524Spendry * on exit. 7065524Spendry * 7165524Spendry * for procfs we don't need to do anything 7265524Spendry * in particular for i/o. all that is done 7365524Spendry * is to support exclusive open on process 7465524Spendry * memory images. 7565524Spendry */ 7665524Spendry procfs_open(ap) 7765524Spendry struct vop_open_args *ap; 7865524Spendry { 7965524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 8065524Spendry 8165524Spendry switch (pfs->pfs_type) { 8265524Spendry case Pmem: 8365524Spendry if (PFIND(pfs->pfs_pid) == 0) 8465524Spendry return (ENOENT); /* was ESRCH, jsp */ 8565524Spendry 8665524Spendry if ((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL) || 8765524Spendry (pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE)) 8865524Spendry return (EBUSY); 8965524Spendry 9065524Spendry 9165524Spendry if (ap->a_mode & FWRITE) 9265524Spendry pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL); 9365524Spendry 9465524Spendry return (0); 9565524Spendry 9665524Spendry default: 9765524Spendry break; 9865524Spendry } 9965524Spendry 10065524Spendry return (0); 10165524Spendry } 10265524Spendry 10365524Spendry /* 10465524Spendry * close the pfsnode (vp) after doing i/o. 10565524Spendry * (vp) is not locked on entry or exit. 10665524Spendry * 10765524Spendry * nothing to do for procfs other than undo 10865524Spendry * any exclusive open flag (see _open above). 10965524Spendry */ 11065524Spendry procfs_close(ap) 11165524Spendry struct vop_close_args *ap; 11265524Spendry { 11365524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 11465524Spendry 11565524Spendry switch (pfs->pfs_type) { 11665524Spendry case Pmem: 11765524Spendry if ((ap->a_fflag & FWRITE) && (pfs->pfs_flags & O_EXCL)) 11865524Spendry pfs->pfs_flags &= ~(FWRITE|O_EXCL); 11965524Spendry break; 12065524Spendry } 12165524Spendry 12265524Spendry return (0); 12365524Spendry } 12465524Spendry 12565524Spendry /* 12665524Spendry * do an ioctl operation on pfsnode (vp). 12765524Spendry * (vp) is not locked on entry or exit. 12865524Spendry */ 12965524Spendry procfs_ioctl(ap) 13065524Spendry struct vop_ioctl_args *ap; 13165524Spendry { 13265524Spendry 13365524Spendry return (ENOTTY); 13465524Spendry } 13565524Spendry 13665524Spendry /* 13765524Spendry * do block mapping for pfsnode (vp). 13865524Spendry * since we don't use the buffer cache 13965524Spendry * for procfs this function should never 14065524Spendry * be called. in any case, it's not clear 14165524Spendry * what part of the kernel ever makes use 14265524Spendry * of this function. for sanity, this is the 14365524Spendry * usual no-op bmap, although returning 14465524Spendry * (EIO) would be a reasonable alternative. 14565524Spendry */ 14665524Spendry procfs_bmap(ap) 14765524Spendry struct vop_bmap_args *ap; 14865524Spendry { 14965524Spendry 15065524Spendry if (ap->a_vpp != NULL) 15165524Spendry *ap->a_vpp = ap->a_vp; 15265524Spendry if (ap->a_bnp != NULL) 15365524Spendry *ap->a_bnp = ap->a_bn; 15465524Spendry return (0); 15565524Spendry } 15665524Spendry 15765524Spendry /* 15865524Spendry * _inactive is called when the pfsnode 15965524Spendry * is vrele'd and the reference count goes 16065524Spendry * to zero. (vp) will be on the vnode free 16165524Spendry * list, so to get it back vget() must be 16265524Spendry * used. 16365524Spendry * 16465524Spendry * for procfs, check if the process is still 16565524Spendry * alive and if it isn't then just throw away 16665524Spendry * the vnode by calling vgone(). this may 16765524Spendry * be overkill and a waste of time since the 16865524Spendry * chances are that the process will still be 16965524Spendry * there and PFIND is not free. 17065524Spendry * 17165524Spendry * (vp) is not locked on entry or exit. 17265524Spendry */ 17365524Spendry procfs_inactive(ap) 17465524Spendry struct vop_inactive_args *ap; 17565524Spendry { 17665524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 17765524Spendry 17865524Spendry if (PFIND(pfs->pfs_pid) == 0) 17965524Spendry vgone(ap->a_vp); 18065524Spendry 18165524Spendry return (0); 18265524Spendry } 18365524Spendry 18465524Spendry /* 18565524Spendry * _reclaim is called when getnewvnode() 18665524Spendry * wants to make use of an entry on the vnode 18765524Spendry * free list. at this time the filesystem needs 18865524Spendry * to free any private data and remove the node 18965524Spendry * from any private lists. 19065524Spendry */ 19165524Spendry procfs_reclaim(ap) 19265524Spendry struct vop_reclaim_args *ap; 19365524Spendry { 19465524Spendry int error; 19565524Spendry 19665524Spendry error = procfs_freevp(ap->a_vp); 19765524Spendry return (error); 19865524Spendry } 19965524Spendry 20065524Spendry /* 20165524Spendry * _print is used for debugging. 20265524Spendry * just print a readable description 20365524Spendry * of (vp). 20465524Spendry */ 20565524Spendry procfs_print(ap) 20665524Spendry struct vop_print_args *ap; 20765524Spendry { 20865524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 20965524Spendry 21065524Spendry printf("tag VT_PROCFS, pid %d, mode %x, flags %x\n", 21165524Spendry pfs->pfs_pid, 21265524Spendry pfs->pfs_mode, pfs->pfs_flags); 21365524Spendry } 21465524Spendry 21565524Spendry /* 21665524Spendry * _abortop is called when operations such as 21765524Spendry * rename and create fail. this entry is responsible 21865524Spendry * for undoing any side-effects caused by the lookup. 21965524Spendry * this will always include freeing the pathname buffer. 22065524Spendry */ 22165524Spendry procfs_abortop(ap) 22265524Spendry struct vop_abortop_args *ap; 22365524Spendry { 22465524Spendry 22565524Spendry if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) 22665524Spendry FREE(ap->a_cnp->cn_pnbuf, M_NAMEI); 22765524Spendry return (0); 22865524Spendry } 22965524Spendry 23065524Spendry /* 23165524Spendry * generic entry point for unsupported operations 23265524Spendry */ 23365524Spendry procfs_badop() 23465524Spendry { 23565524Spendry 23665524Spendry return (EIO); 23765524Spendry } 23865524Spendry 23965524Spendry /* 24065524Spendry * Invent attributes for pfsnode (vp) and store 24165524Spendry * them in (vap). 24265524Spendry * Directories lengths are returned as zero since 24365524Spendry * any real length would require the genuine size 24465524Spendry * to be computed, and nothing cares anyway. 24565524Spendry * 24665524Spendry * this is relatively minimal for procfs. 24765524Spendry */ 24865524Spendry procfs_getattr(ap) 24965524Spendry struct vop_getattr_args *ap; 25065524Spendry { 25165524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 252*65536Spendry struct vattr *vap = ap->a_vap; 25365524Spendry struct proc *procp; 25465524Spendry int error; 25565524Spendry 25665524Spendry /* first check the process still exists */ 25765524Spendry procp = PFIND(pfs->pfs_pid); 25865524Spendry if (procp == 0) 25965524Spendry return (ENOENT); 26065524Spendry 26165524Spendry error = 0; 26265524Spendry 26365524Spendry /* start by zeroing out the attributes */ 264*65536Spendry VATTR_NULL(vap); 26565524Spendry 26665524Spendry /* next do all the common fields */ 267*65536Spendry vap->va_type = ap->a_vp->v_type; 268*65536Spendry vap->va_mode = pfs->pfs_mode; 269*65536Spendry vap->va_fileid = pfs->pfs_fileno; 270*65536Spendry vap->va_flags = 0; 271*65536Spendry vap->va_blocksize = PAGE_SIZE; 272*65536Spendry vap->va_bytes = vap->va_size = 0; 27365524Spendry 27465524Spendry /* 27565524Spendry * Make all times be current TOD. 27665524Spendry * It would be possible to get the process start 27765524Spendry * time from the p_stat structure, but there's 27865524Spendry * no "file creation" time stamp anyway, and the 27965524Spendry * p_stat structure is not addressible if u. gets 28065524Spendry * swapped out for that process. 28165524Spendry */ 282*65536Spendry microtime(&vap->va_ctime); 283*65536Spendry vap->va_atime = vap->va_mtime = vap->va_ctime; 28465524Spendry 28565524Spendry /* 28665524Spendry * now do the object specific fields 28765524Spendry * 28865524Spendry * The size could be set from struct reg, but it's hardly 28965524Spendry * worth the trouble, and it puts some (potentially) machine 29065524Spendry * dependent data into this machine-independent code. If it 29165524Spendry * becomes important then this function should break out into 29265524Spendry * a per-file stat function in the corresponding .c file. 29365524Spendry */ 29465524Spendry 29565524Spendry switch (pfs->pfs_type) { 29665524Spendry case Proot: 297*65536Spendry vap->va_nlink = 2; 298*65536Spendry vap->va_uid = 0; 299*65536Spendry vap->va_gid = 0; 30065524Spendry break; 30165524Spendry 30265524Spendry case Pproc: 303*65536Spendry vap->va_nlink = 2; 304*65536Spendry vap->va_uid = procp->p_ucred->cr_uid; 305*65536Spendry vap->va_gid = procp->p_ucred->cr_gid; 30665524Spendry break; 30765524Spendry 30865524Spendry case Pfile: 30965524Spendry error = EOPNOTSUPP; 31065524Spendry break; 31165524Spendry 31265524Spendry case Pmem: 313*65536Spendry vap->va_nlink = 1; 314*65536Spendry vap->va_bytes = vap->va_size = 31565524Spendry ctob(procp->p_vmspace->vm_tsize + 31665524Spendry procp->p_vmspace->vm_dsize + 31765524Spendry procp->p_vmspace->vm_ssize); 318*65536Spendry vap->va_uid = procp->p_ucred->cr_uid; 319*65536Spendry vap->va_gid = procp->p_ucred->cr_gid; 32065524Spendry break; 32165524Spendry 32265524Spendry case Pregs: 32365524Spendry case Pctl: 32465524Spendry case Pstatus: 32565524Spendry case Pnote: 32665524Spendry case Pnotepg: 327*65536Spendry vap->va_nlink = 1; 328*65536Spendry vap->va_uid = procp->p_ucred->cr_uid; 329*65536Spendry vap->va_gid = procp->p_ucred->cr_gid; 33065524Spendry break; 33165524Spendry 33265524Spendry default: 33365524Spendry panic("procfs_getattr"); 33465524Spendry } 33565524Spendry 33665524Spendry return (error); 33765524Spendry } 33865524Spendry 33965524Spendry procfs_setattr(ap) 34065524Spendry struct vop_setattr_args *ap; 34165524Spendry { 34265524Spendry /* 34365524Spendry * just fake out attribute setting 34465524Spendry * it's not good to generate an error 34565524Spendry * return, otherwise things like creat() 34665524Spendry * will fail when they try to set the 34765524Spendry * file length to 0. worse, this means 34865524Spendry * that echo $note > /proc/$pid/note will fail. 34965524Spendry */ 35065524Spendry 35165524Spendry return (0); 35265524Spendry } 35365524Spendry 35465524Spendry /* 35565524Spendry * implement access checking. 35665524Spendry * 35765524Spendry * something very similar to this code is duplicated 35865524Spendry * throughout the 4bsd kernel and should be moved 35965524Spendry * into kern/vfs_subr.c sometime. 36065524Spendry * 36165524Spendry * actually, the check for super-user is slightly 36265524Spendry * broken since it will allow read access to write-only 36365524Spendry * objects. this doesn't cause any particular trouble 36465524Spendry * but does mean that the i/o entry points need to check 36565524Spendry * that the operation really does make sense. 36665524Spendry */ 36765524Spendry procfs_access(ap) 36865524Spendry struct vop_access_args *ap; 36965524Spendry { 37065524Spendry struct vattr *vap; 37165524Spendry struct vattr vattr; 37265524Spendry int error; 37365524Spendry 37465524Spendry /* 37565524Spendry * If you're the super-user, 37665524Spendry * you always get access. 37765524Spendry */ 37865524Spendry if (ap->a_cred->cr_uid == (uid_t) 0) 37965524Spendry return (0); 38065524Spendry vap = &vattr; 38165524Spendry if (error = VOP_GETATTR(ap->a_vp, vap, ap->a_cred, ap->a_p)) 38265524Spendry return (error); 38365524Spendry 38465524Spendry /* 38565524Spendry * Access check is based on only one of owner, group, public. 38665524Spendry * If not owner, then check group. If not a member of the 38765524Spendry * group, then check public access. 38865524Spendry */ 38965524Spendry if (ap->a_cred->cr_uid != vap->va_uid) { 39065524Spendry gid_t *gp; 39165524Spendry int i; 39265524Spendry 39365524Spendry (ap->a_mode) >>= 3; 39465524Spendry gp = ap->a_cred->cr_groups; 39565524Spendry for (i = 0; i < ap->a_cred->cr_ngroups; i++, gp++) 39665524Spendry if (vap->va_gid == *gp) 39765524Spendry goto found; 39865524Spendry ap->a_mode >>= 3; 39965524Spendry found: 40065524Spendry ; 40165524Spendry } 40265524Spendry 40365524Spendry if ((vap->va_mode & ap->a_mode) == ap->a_mode) 40465524Spendry return (0); 40565524Spendry 40665524Spendry return (EACCES); 40765524Spendry } 40865524Spendry 40965524Spendry /* 41065524Spendry * lookup. this is incredibly complicated in the 41165524Spendry * general case, however for most pseudo-filesystems 41265524Spendry * very little needs to be done. 41365524Spendry * 41465524Spendry * unless you want to get a migraine, just make sure your 41565524Spendry * filesystem doesn't do any locking of its own. otherwise 41665524Spendry * read and inwardly digest ufs_lookup(). 41765524Spendry */ 41865524Spendry procfs_lookup(ap) 41965524Spendry struct vop_lookup_args *ap; 42065524Spendry { 42165524Spendry struct componentname *cnp = ap->a_cnp; 42265524Spendry struct vnode **vpp = ap->a_vpp; 42365524Spendry struct vnode *dvp = ap->a_dvp; 42465524Spendry char *pname = cnp->cn_nameptr; 42565524Spendry int error = 0; 42665524Spendry int flag; 42765524Spendry pid_t pid; 42865524Spendry struct vnode *nvp; 42965524Spendry struct pfsnode *pfs; 43065524Spendry struct proc *procp; 43165524Spendry int mode; 43265524Spendry pfstype pfs_type; 43365524Spendry int i; 43465524Spendry 43565524Spendry if (cnp->cn_namelen == 1 && *pname == '.') { 43665524Spendry *vpp = dvp; 43765524Spendry VREF(dvp); 43865524Spendry /*VOP_LOCK(dvp);*/ 43965524Spendry return (0); 44065524Spendry } 44165524Spendry 44265524Spendry *vpp = NULL; 44365524Spendry 44465524Spendry pfs = VTOPFS(dvp); 44565524Spendry switch (pfs->pfs_type) { 44665524Spendry case Proot: 44765524Spendry if (cnp->cn_flags & ISDOTDOT) 44865524Spendry return (EIO); 44965524Spendry 45065524Spendry if (CNEQ(cnp, "curproc", 7)) 45165524Spendry pid = cnp->cn_proc->p_pid; 45265524Spendry else 45365524Spendry pid = atopid(pname, cnp->cn_namelen); 45465524Spendry if (pid == NO_PID) 45565524Spendry return (ENOENT); 45665524Spendry 45765524Spendry procp = PFIND(pid); 45865524Spendry if (procp == 0) 45965524Spendry return (ENOENT); 46065524Spendry 46165524Spendry error = procfs_allocvp(dvp->v_mount, &nvp, pid, Pproc); 46265524Spendry if (error) 46365524Spendry return (error); 46465524Spendry 46565524Spendry nvp->v_type = VDIR; 46665524Spendry pfs = VTOPFS(nvp); 46765524Spendry 46865524Spendry *vpp = nvp; 46965524Spendry return (0); 47065524Spendry 47165524Spendry case Pproc: 47265524Spendry if (cnp->cn_flags & ISDOTDOT) { 47365524Spendry error = procfs_root(dvp->v_mount, vpp); 47465524Spendry return (error); 47565524Spendry } 47665524Spendry 47765524Spendry procp = PFIND(pfs->pfs_pid); 47865524Spendry if (procp == 0) 47965524Spendry return (ENOENT); 48065524Spendry 48165524Spendry for (i = 0; i < Nprocent; i++) { 48265524Spendry struct pfsnames *dp = &procent[i]; 48365524Spendry 48465524Spendry if (cnp->cn_namelen == dp->d_namlen && 48565524Spendry bcmp(pname, dp->d_name, dp->d_namlen) == 0) { 48665524Spendry pfs_type = dp->d_pfstype; 48765524Spendry goto found; 48865524Spendry } 48965524Spendry } 49065524Spendry return (ENOENT); 49165524Spendry 49265524Spendry found: 49365524Spendry if (pfs_type == Pfile) { 49465524Spendry nvp = procfs_findtextvp(procp); 49565524Spendry if (nvp) { 49665524Spendry VREF(nvp); 49765524Spendry VOP_LOCK(nvp); 49865524Spendry } else { 49965524Spendry error = ENXIO; 50065524Spendry } 50165524Spendry } else { 50265524Spendry error = procfs_allocvp(dvp->v_mount, &nvp, 50365524Spendry pfs->pfs_pid, pfs_type); 50465524Spendry if (error) 50565524Spendry return (error); 50665524Spendry 50765524Spendry nvp->v_type = VREG; 50865524Spendry pfs = VTOPFS(nvp); 50965524Spendry } 51065524Spendry *vpp = nvp; 51165524Spendry return (error); 51265524Spendry 51365524Spendry default: 51465524Spendry return (ENOTDIR); 51565524Spendry } 51665524Spendry } 51765524Spendry 51865524Spendry /* 51965524Spendry * readdir returns directory entries from pfsnode (vp). 52065524Spendry * 52165524Spendry * the strategy here with procfs is to generate a single 52265524Spendry * directory entry at a time (struct pfsdent) and then 52365524Spendry * copy that out to userland using uiomove. a more efficent 52465524Spendry * though more complex implementation, would try to minimize 52565524Spendry * the number of calls to uiomove(). for procfs, this is 52665524Spendry * hardly worth the added code complexity. 52765524Spendry * 52865524Spendry * this should just be done through read() 52965524Spendry */ 53065524Spendry procfs_readdir(ap) 53165524Spendry struct vop_readdir_args *ap; 53265524Spendry { 53365524Spendry struct uio *uio = ap->a_uio; 53465524Spendry struct pfsdent d; 53565524Spendry struct pfsdent *dp = &d; 53665524Spendry struct pfsnode *pfs; 53765524Spendry int error; 53865524Spendry int count; 53965524Spendry int i; 54065524Spendry 54165524Spendry pfs = VTOPFS(ap->a_vp); 54265524Spendry 54365524Spendry if (uio->uio_resid < UIO_MX) 54465524Spendry return (EINVAL); 54565524Spendry if (uio->uio_offset & (UIO_MX-1)) 54665524Spendry return (EINVAL); 54765524Spendry if (uio->uio_offset < 0) 54865524Spendry return (EINVAL); 54965524Spendry 55065524Spendry error = 0; 55165524Spendry count = 0; 55265524Spendry i = uio->uio_offset / UIO_MX; 55365524Spendry 55465524Spendry switch (pfs->pfs_type) { 55565524Spendry /* 55665524Spendry * this is for the process-specific sub-directories. 55765524Spendry * all that is needed to is copy out all the entries 55865524Spendry * from the procent[] table (top of this file). 55965524Spendry */ 56065524Spendry case Pproc: { 56165524Spendry while (uio->uio_resid >= UIO_MX) { 56265524Spendry struct pfsnames *dt; 56365524Spendry 56465524Spendry if (i >= Nprocent) 56565524Spendry break; 56665524Spendry 56765524Spendry dt = &procent[i]; 56865524Spendry 56965524Spendry dp->d_reclen = UIO_MX; 57065524Spendry dp->d_fileno = PROCFS_FILENO(pfs->pfs_pid, dt->d_pfstype); 57165524Spendry dp->d_type = DT_REG; 57265524Spendry dp->d_namlen = dt->d_namlen; 57365524Spendry bcopy(dt->d_name, dp->d_name, sizeof(dt->d_name)-1); 57465524Spendry error = uiomove((caddr_t) dp, UIO_MX, uio); 57565524Spendry if (error) 57665524Spendry break; 57765524Spendry count += UIO_MX; 57865524Spendry i++; 57965524Spendry } 58065524Spendry 58165524Spendry break; 58265524Spendry 58365524Spendry } 58465524Spendry 58565524Spendry /* 58665524Spendry * this is for the root of the procfs filesystem 58765524Spendry * what is needed is a special entry for "curproc" 58865524Spendry * followed by an entry for each process on allproc 58965524Spendry #ifdef PROCFS_ZOMBIE 59065524Spendry * and zombproc. 59165524Spendry #endif 59265524Spendry */ 59365524Spendry 59465524Spendry case Proot: { 59565524Spendry int pcnt; 59665524Spendry #ifdef PROCFS_ZOMBIE 59765524Spendry int doingzomb = 0; 59865524Spendry #endif 59965524Spendry volatile struct proc *p; 60065524Spendry 60165524Spendry p = allproc; 60265524Spendry 60365524Spendry #define PROCFS_XFILES 1 /* number of other entries, like "curproc" */ 60465524Spendry pcnt = PROCFS_XFILES; 60565524Spendry 60665524Spendry while (p && uio->uio_resid >= UIO_MX) { 60765524Spendry bzero((char *) dp, UIO_MX); 60865524Spendry dp->d_type = DT_DIR; 60965524Spendry dp->d_reclen = UIO_MX; 61065524Spendry 61165524Spendry switch (i) { 61265524Spendry case 0: 61365524Spendry /* ship out entry for "curproc" */ 61465524Spendry dp->d_fileno = PROCFS_FILENO(PID_MAX+1, Pproc); 615*65536Spendry dp->d_namlen = sprintf(dp->d_name, "curproc"); 61665524Spendry break; 61765524Spendry 61865524Spendry default: 61965524Spendry if (pcnt >= i) { 62065524Spendry dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc); 62165524Spendry dp->d_namlen = sprintf(dp->d_name, "%ld", (long) p->p_pid); 62265524Spendry } 62365524Spendry 62465524Spendry p = p->p_next; 62565524Spendry 62665524Spendry #ifdef PROCFS_ZOMBIE 62765524Spendry if (p == 0 && doingzomb == 0) { 62865524Spendry doingzomb = 1; 62965524Spendry p = zombproc; 63065524Spendry } 63165524Spendry #endif 63265524Spendry 63365524Spendry if (pcnt++ < i) 63465524Spendry continue; 63565524Spendry 63665524Spendry break; 63765524Spendry } 63865524Spendry error = uiomove((caddr_t) dp, UIO_MX, uio); 63965524Spendry if (error) 64065524Spendry break; 64165524Spendry count += UIO_MX; 64265524Spendry i++; 64365524Spendry } 64465524Spendry 64565524Spendry break; 64665524Spendry 64765524Spendry } 64865524Spendry 64965524Spendry default: 65065524Spendry error = ENOTDIR; 65165524Spendry break; 65265524Spendry } 65365524Spendry 65465524Spendry uio->uio_offset = i * UIO_MX; 65565524Spendry 65665524Spendry return (error); 65765524Spendry } 65865524Spendry 65965524Spendry /* 66065524Spendry * convert decimal ascii to pid_t 66165524Spendry */ 66265524Spendry static pid_t 66365524Spendry atopid(b, len) 66465524Spendry const char *b; 66565524Spendry u_int len; 66665524Spendry { 66765524Spendry pid_t p = 0; 66865524Spendry 66965524Spendry while (len--) { 67065524Spendry char c = *b++; 67165524Spendry if (c < '0' || c > '9') 67265524Spendry return (NO_PID); 67365524Spendry p = 10 * p + (c - '0'); 67465524Spendry if (p > PID_MAX) 67565524Spendry return (NO_PID); 67665524Spendry } 67765524Spendry 67865524Spendry return (p); 67965524Spendry } 68065524Spendry 68165524Spendry /* 68265524Spendry * procfs vnode operations. 68365524Spendry */ 68465524Spendry int (**procfs_vnodeop_p)(); 68565524Spendry struct vnodeopv_entry_desc procfs_vnodeop_entries[] = { 68665524Spendry { &vop_default_desc, vn_default_error }, 68765524Spendry { &vop_lookup_desc, procfs_lookup }, /* lookup */ 68865524Spendry { &vop_create_desc, procfs_create }, /* create */ 68965524Spendry { &vop_mknod_desc, procfs_mknod }, /* mknod */ 69065524Spendry { &vop_open_desc, procfs_open }, /* open */ 69165524Spendry { &vop_close_desc, procfs_close }, /* close */ 69265524Spendry { &vop_access_desc, procfs_access }, /* access */ 69365524Spendry { &vop_getattr_desc, procfs_getattr }, /* getattr */ 69465524Spendry { &vop_setattr_desc, procfs_setattr }, /* setattr */ 69565524Spendry { &vop_read_desc, procfs_read }, /* read */ 69665524Spendry { &vop_write_desc, procfs_write }, /* write */ 69765524Spendry { &vop_ioctl_desc, procfs_ioctl }, /* ioctl */ 69865524Spendry { &vop_select_desc, procfs_select }, /* select */ 69965524Spendry { &vop_mmap_desc, procfs_mmap }, /* mmap */ 70065524Spendry { &vop_fsync_desc, procfs_fsync }, /* fsync */ 70165524Spendry { &vop_seek_desc, procfs_seek }, /* seek */ 70265524Spendry { &vop_remove_desc, procfs_remove }, /* remove */ 70365524Spendry { &vop_link_desc, procfs_link }, /* link */ 70465524Spendry { &vop_rename_desc, procfs_rename }, /* rename */ 70565524Spendry { &vop_mkdir_desc, procfs_mkdir }, /* mkdir */ 70665524Spendry { &vop_rmdir_desc, procfs_rmdir }, /* rmdir */ 70765524Spendry { &vop_symlink_desc, procfs_symlink }, /* symlink */ 70865524Spendry { &vop_readdir_desc, procfs_readdir }, /* readdir */ 70965524Spendry { &vop_readlink_desc, procfs_readlink }, /* readlink */ 71065524Spendry { &vop_abortop_desc, procfs_abortop }, /* abortop */ 71165524Spendry { &vop_inactive_desc, procfs_inactive }, /* inactive */ 71265524Spendry { &vop_reclaim_desc, procfs_reclaim }, /* reclaim */ 71365524Spendry { &vop_lock_desc, procfs_lock }, /* lock */ 71465524Spendry { &vop_unlock_desc, procfs_unlock }, /* unlock */ 71565524Spendry { &vop_bmap_desc, procfs_bmap }, /* bmap */ 71665524Spendry { &vop_strategy_desc, procfs_strategy }, /* strategy */ 71765524Spendry { &vop_print_desc, procfs_print }, /* print */ 71865524Spendry { &vop_islocked_desc, procfs_islocked }, /* islocked */ 71965524Spendry { &vop_pathconf_desc, procfs_pathconf }, /* pathconf */ 72065524Spendry { &vop_advlock_desc, procfs_advlock }, /* advlock */ 72165524Spendry { &vop_blkatoff_desc, procfs_blkatoff }, /* blkatoff */ 72265524Spendry { &vop_valloc_desc, procfs_valloc }, /* valloc */ 72365524Spendry { &vop_vfree_desc, procfs_vfree }, /* vfree */ 72465524Spendry { &vop_truncate_desc, procfs_truncate }, /* truncate */ 72565524Spendry { &vop_update_desc, procfs_update }, /* update */ 72665524Spendry { (struct vnodeop_desc*)NULL, (int(*)())NULL } 72765524Spendry }; 72865524Spendry struct vnodeopv_desc procfs_vnodeop_opv_desc = 72965524Spendry { &procfs_vnodeop_p, procfs_vnodeop_entries }; 730