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*65743Spendry * @(#)procfs_vnops.c 8.3 (Berkeley) 01/14/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 /* 201*65743Spendry * Return POSIX pathconf information applicable to special devices. 202*65743Spendry */ 203*65743Spendry procfs_pathconf(ap) 204*65743Spendry struct vop_pathconf_args /* { 205*65743Spendry struct vnode *a_vp; 206*65743Spendry int a_name; 207*65743Spendry int *a_retval; 208*65743Spendry } */ *ap; 209*65743Spendry { 210*65743Spendry 211*65743Spendry switch (ap->a_name) { 212*65743Spendry case _PC_LINK_MAX: 213*65743Spendry *ap->a_retval = LINK_MAX; 214*65743Spendry return (0); 215*65743Spendry case _PC_MAX_CANON: 216*65743Spendry *ap->a_retval = MAX_CANON; 217*65743Spendry return (0); 218*65743Spendry case _PC_MAX_INPUT: 219*65743Spendry *ap->a_retval = MAX_INPUT; 220*65743Spendry return (0); 221*65743Spendry case _PC_PIPE_BUF: 222*65743Spendry *ap->a_retval = PIPE_BUF; 223*65743Spendry return (0); 224*65743Spendry case _PC_CHOWN_RESTRICTED: 225*65743Spendry *ap->a_retval = 1; 226*65743Spendry return (0); 227*65743Spendry case _PC_VDISABLE: 228*65743Spendry *ap->a_retval = _POSIX_VDISABLE; 229*65743Spendry return (0); 230*65743Spendry default: 231*65743Spendry return (EINVAL); 232*65743Spendry } 233*65743Spendry /* NOTREACHED */ 234*65743Spendry } 235*65743Spendry 236*65743Spendry /* 23765524Spendry * _print is used for debugging. 23865524Spendry * just print a readable description 23965524Spendry * of (vp). 24065524Spendry */ 24165524Spendry procfs_print(ap) 24265524Spendry struct vop_print_args *ap; 24365524Spendry { 24465524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 24565524Spendry 24665524Spendry printf("tag VT_PROCFS, pid %d, mode %x, flags %x\n", 24765524Spendry pfs->pfs_pid, 24865524Spendry pfs->pfs_mode, pfs->pfs_flags); 24965524Spendry } 25065524Spendry 25165524Spendry /* 25265524Spendry * _abortop is called when operations such as 25365524Spendry * rename and create fail. this entry is responsible 25465524Spendry * for undoing any side-effects caused by the lookup. 25565524Spendry * this will always include freeing the pathname buffer. 25665524Spendry */ 25765524Spendry procfs_abortop(ap) 25865524Spendry struct vop_abortop_args *ap; 25965524Spendry { 26065524Spendry 26165524Spendry if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) 26265524Spendry FREE(ap->a_cnp->cn_pnbuf, M_NAMEI); 26365524Spendry return (0); 26465524Spendry } 26565524Spendry 26665524Spendry /* 26765524Spendry * generic entry point for unsupported operations 26865524Spendry */ 26965524Spendry procfs_badop() 27065524Spendry { 27165524Spendry 27265524Spendry return (EIO); 27365524Spendry } 27465524Spendry 27565524Spendry /* 27665524Spendry * Invent attributes for pfsnode (vp) and store 27765524Spendry * them in (vap). 27865524Spendry * Directories lengths are returned as zero since 27965524Spendry * any real length would require the genuine size 28065524Spendry * to be computed, and nothing cares anyway. 28165524Spendry * 28265524Spendry * this is relatively minimal for procfs. 28365524Spendry */ 28465524Spendry procfs_getattr(ap) 28565524Spendry struct vop_getattr_args *ap; 28665524Spendry { 28765524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 28865536Spendry struct vattr *vap = ap->a_vap; 28965524Spendry struct proc *procp; 29065524Spendry int error; 29165524Spendry 29265524Spendry /* first check the process still exists */ 29365524Spendry procp = PFIND(pfs->pfs_pid); 29465524Spendry if (procp == 0) 29565524Spendry return (ENOENT); 29665524Spendry 29765524Spendry error = 0; 29865524Spendry 29965524Spendry /* start by zeroing out the attributes */ 30065536Spendry VATTR_NULL(vap); 30165524Spendry 30265524Spendry /* next do all the common fields */ 30365536Spendry vap->va_type = ap->a_vp->v_type; 30465536Spendry vap->va_mode = pfs->pfs_mode; 30565536Spendry vap->va_fileid = pfs->pfs_fileno; 30665536Spendry vap->va_flags = 0; 30765536Spendry vap->va_blocksize = PAGE_SIZE; 30865536Spendry vap->va_bytes = vap->va_size = 0; 30965524Spendry 31065524Spendry /* 31165524Spendry * Make all times be current TOD. 31265524Spendry * It would be possible to get the process start 31365524Spendry * time from the p_stat structure, but there's 31465524Spendry * no "file creation" time stamp anyway, and the 31565524Spendry * p_stat structure is not addressible if u. gets 31665524Spendry * swapped out for that process. 31765524Spendry */ 31865536Spendry microtime(&vap->va_ctime); 31965536Spendry vap->va_atime = vap->va_mtime = vap->va_ctime; 32065524Spendry 32165524Spendry /* 32265524Spendry * now do the object specific fields 32365524Spendry * 32465524Spendry * The size could be set from struct reg, but it's hardly 32565524Spendry * worth the trouble, and it puts some (potentially) machine 32665524Spendry * dependent data into this machine-independent code. If it 32765524Spendry * becomes important then this function should break out into 32865524Spendry * a per-file stat function in the corresponding .c file. 32965524Spendry */ 33065524Spendry 33165524Spendry switch (pfs->pfs_type) { 33265524Spendry case Proot: 33365536Spendry vap->va_nlink = 2; 33465536Spendry vap->va_uid = 0; 33565536Spendry vap->va_gid = 0; 33665524Spendry break; 33765524Spendry 33865524Spendry case Pproc: 33965536Spendry vap->va_nlink = 2; 34065536Spendry vap->va_uid = procp->p_ucred->cr_uid; 34165536Spendry vap->va_gid = procp->p_ucred->cr_gid; 34265524Spendry break; 34365524Spendry 34465524Spendry case Pfile: 34565524Spendry error = EOPNOTSUPP; 34665524Spendry break; 34765524Spendry 34865524Spendry case Pmem: 34965536Spendry vap->va_nlink = 1; 35065536Spendry vap->va_bytes = vap->va_size = 35165524Spendry ctob(procp->p_vmspace->vm_tsize + 35265524Spendry procp->p_vmspace->vm_dsize + 35365524Spendry procp->p_vmspace->vm_ssize); 35465536Spendry vap->va_uid = procp->p_ucred->cr_uid; 35565536Spendry vap->va_gid = procp->p_ucred->cr_gid; 35665524Spendry break; 35765524Spendry 35865524Spendry case Pregs: 35965524Spendry case Pctl: 36065524Spendry case Pstatus: 36165524Spendry case Pnote: 36265524Spendry case Pnotepg: 36365536Spendry vap->va_nlink = 1; 36465536Spendry vap->va_uid = procp->p_ucred->cr_uid; 36565536Spendry vap->va_gid = procp->p_ucred->cr_gid; 36665524Spendry break; 36765524Spendry 36865524Spendry default: 36965524Spendry panic("procfs_getattr"); 37065524Spendry } 37165524Spendry 37265524Spendry return (error); 37365524Spendry } 37465524Spendry 37565524Spendry procfs_setattr(ap) 37665524Spendry struct vop_setattr_args *ap; 37765524Spendry { 37865524Spendry /* 37965524Spendry * just fake out attribute setting 38065524Spendry * it's not good to generate an error 38165524Spendry * return, otherwise things like creat() 38265524Spendry * will fail when they try to set the 38365524Spendry * file length to 0. worse, this means 38465524Spendry * that echo $note > /proc/$pid/note will fail. 38565524Spendry */ 38665524Spendry 38765524Spendry return (0); 38865524Spendry } 38965524Spendry 39065524Spendry /* 39165524Spendry * implement access checking. 39265524Spendry * 39365524Spendry * something very similar to this code is duplicated 39465524Spendry * throughout the 4bsd kernel and should be moved 39565524Spendry * into kern/vfs_subr.c sometime. 39665524Spendry * 39765524Spendry * actually, the check for super-user is slightly 39865524Spendry * broken since it will allow read access to write-only 39965524Spendry * objects. this doesn't cause any particular trouble 40065524Spendry * but does mean that the i/o entry points need to check 40165524Spendry * that the operation really does make sense. 40265524Spendry */ 40365524Spendry procfs_access(ap) 40465524Spendry struct vop_access_args *ap; 40565524Spendry { 40665524Spendry struct vattr *vap; 40765524Spendry struct vattr vattr; 40865524Spendry int error; 40965524Spendry 41065524Spendry /* 41165524Spendry * If you're the super-user, 41265524Spendry * you always get access. 41365524Spendry */ 41465524Spendry if (ap->a_cred->cr_uid == (uid_t) 0) 41565524Spendry return (0); 41665524Spendry vap = &vattr; 41765524Spendry if (error = VOP_GETATTR(ap->a_vp, vap, ap->a_cred, ap->a_p)) 41865524Spendry return (error); 41965524Spendry 42065524Spendry /* 42165524Spendry * Access check is based on only one of owner, group, public. 42265524Spendry * If not owner, then check group. If not a member of the 42365524Spendry * group, then check public access. 42465524Spendry */ 42565524Spendry if (ap->a_cred->cr_uid != vap->va_uid) { 42665524Spendry gid_t *gp; 42765524Spendry int i; 42865524Spendry 42965524Spendry (ap->a_mode) >>= 3; 43065524Spendry gp = ap->a_cred->cr_groups; 43165524Spendry for (i = 0; i < ap->a_cred->cr_ngroups; i++, gp++) 43265524Spendry if (vap->va_gid == *gp) 43365524Spendry goto found; 43465524Spendry ap->a_mode >>= 3; 43565524Spendry found: 43665524Spendry ; 43765524Spendry } 43865524Spendry 43965524Spendry if ((vap->va_mode & ap->a_mode) == ap->a_mode) 44065524Spendry return (0); 44165524Spendry 44265524Spendry return (EACCES); 44365524Spendry } 44465524Spendry 44565524Spendry /* 44665524Spendry * lookup. this is incredibly complicated in the 44765524Spendry * general case, however for most pseudo-filesystems 44865524Spendry * very little needs to be done. 44965524Spendry * 45065524Spendry * unless you want to get a migraine, just make sure your 45165524Spendry * filesystem doesn't do any locking of its own. otherwise 45265524Spendry * read and inwardly digest ufs_lookup(). 45365524Spendry */ 45465524Spendry procfs_lookup(ap) 45565524Spendry struct vop_lookup_args *ap; 45665524Spendry { 45765524Spendry struct componentname *cnp = ap->a_cnp; 45865524Spendry struct vnode **vpp = ap->a_vpp; 45965524Spendry struct vnode *dvp = ap->a_dvp; 46065524Spendry char *pname = cnp->cn_nameptr; 46165524Spendry int error = 0; 46265524Spendry pid_t pid; 46365524Spendry struct vnode *nvp; 46465524Spendry struct pfsnode *pfs; 46565524Spendry struct proc *procp; 46665524Spendry pfstype pfs_type; 46765524Spendry int i; 46865524Spendry 46965524Spendry if (cnp->cn_namelen == 1 && *pname == '.') { 47065524Spendry *vpp = dvp; 47165524Spendry VREF(dvp); 47265524Spendry /*VOP_LOCK(dvp);*/ 47365524Spendry return (0); 47465524Spendry } 47565524Spendry 47665524Spendry *vpp = NULL; 47765524Spendry 47865524Spendry pfs = VTOPFS(dvp); 47965524Spendry switch (pfs->pfs_type) { 48065524Spendry case Proot: 48165524Spendry if (cnp->cn_flags & ISDOTDOT) 48265524Spendry return (EIO); 48365524Spendry 48465524Spendry if (CNEQ(cnp, "curproc", 7)) 48565524Spendry pid = cnp->cn_proc->p_pid; 48665524Spendry else 48765524Spendry pid = atopid(pname, cnp->cn_namelen); 48865524Spendry if (pid == NO_PID) 48965524Spendry return (ENOENT); 49065524Spendry 49165524Spendry procp = PFIND(pid); 49265524Spendry if (procp == 0) 49365524Spendry return (ENOENT); 49465524Spendry 49565524Spendry error = procfs_allocvp(dvp->v_mount, &nvp, pid, Pproc); 49665524Spendry if (error) 49765524Spendry return (error); 49865524Spendry 49965524Spendry nvp->v_type = VDIR; 50065524Spendry pfs = VTOPFS(nvp); 50165524Spendry 50265524Spendry *vpp = nvp; 50365524Spendry return (0); 50465524Spendry 50565524Spendry case Pproc: 50665524Spendry if (cnp->cn_flags & ISDOTDOT) { 50765524Spendry error = procfs_root(dvp->v_mount, vpp); 50865524Spendry return (error); 50965524Spendry } 51065524Spendry 51165524Spendry procp = PFIND(pfs->pfs_pid); 51265524Spendry if (procp == 0) 51365524Spendry return (ENOENT); 51465524Spendry 51565524Spendry for (i = 0; i < Nprocent; i++) { 51665524Spendry struct pfsnames *dp = &procent[i]; 51765524Spendry 51865524Spendry if (cnp->cn_namelen == dp->d_namlen && 51965524Spendry bcmp(pname, dp->d_name, dp->d_namlen) == 0) { 52065524Spendry pfs_type = dp->d_pfstype; 52165524Spendry goto found; 52265524Spendry } 52365524Spendry } 52465524Spendry return (ENOENT); 52565524Spendry 52665524Spendry found: 52765524Spendry if (pfs_type == Pfile) { 52865524Spendry nvp = procfs_findtextvp(procp); 52965524Spendry if (nvp) { 53065524Spendry VREF(nvp); 53165524Spendry VOP_LOCK(nvp); 53265524Spendry } else { 53365524Spendry error = ENXIO; 53465524Spendry } 53565524Spendry } else { 53665524Spendry error = procfs_allocvp(dvp->v_mount, &nvp, 53765524Spendry pfs->pfs_pid, pfs_type); 53865524Spendry if (error) 53965524Spendry return (error); 54065524Spendry 54165524Spendry nvp->v_type = VREG; 54265524Spendry pfs = VTOPFS(nvp); 54365524Spendry } 54465524Spendry *vpp = nvp; 54565524Spendry return (error); 54665524Spendry 54765524Spendry default: 54865524Spendry return (ENOTDIR); 54965524Spendry } 55065524Spendry } 55165524Spendry 55265524Spendry /* 55365524Spendry * readdir returns directory entries from pfsnode (vp). 55465524Spendry * 55565524Spendry * the strategy here with procfs is to generate a single 55665524Spendry * directory entry at a time (struct pfsdent) and then 55765524Spendry * copy that out to userland using uiomove. a more efficent 55865524Spendry * though more complex implementation, would try to minimize 55965524Spendry * the number of calls to uiomove(). for procfs, this is 56065524Spendry * hardly worth the added code complexity. 56165524Spendry * 56265524Spendry * this should just be done through read() 56365524Spendry */ 56465524Spendry procfs_readdir(ap) 56565524Spendry struct vop_readdir_args *ap; 56665524Spendry { 56765524Spendry struct uio *uio = ap->a_uio; 56865524Spendry struct pfsdent d; 56965524Spendry struct pfsdent *dp = &d; 57065524Spendry struct pfsnode *pfs; 57165524Spendry int error; 57265524Spendry int count; 57365524Spendry int i; 57465524Spendry 57565524Spendry pfs = VTOPFS(ap->a_vp); 57665524Spendry 57765524Spendry if (uio->uio_resid < UIO_MX) 57865524Spendry return (EINVAL); 57965524Spendry if (uio->uio_offset & (UIO_MX-1)) 58065524Spendry return (EINVAL); 58165524Spendry if (uio->uio_offset < 0) 58265524Spendry return (EINVAL); 58365524Spendry 58465524Spendry error = 0; 58565524Spendry count = 0; 58665524Spendry i = uio->uio_offset / UIO_MX; 58765524Spendry 58865524Spendry switch (pfs->pfs_type) { 58965524Spendry /* 59065524Spendry * this is for the process-specific sub-directories. 59165524Spendry * all that is needed to is copy out all the entries 59265524Spendry * from the procent[] table (top of this file). 59365524Spendry */ 59465524Spendry case Pproc: { 59565524Spendry while (uio->uio_resid >= UIO_MX) { 59665524Spendry struct pfsnames *dt; 59765524Spendry 59865524Spendry if (i >= Nprocent) 59965524Spendry break; 60065524Spendry 60165524Spendry dt = &procent[i]; 60265524Spendry 60365524Spendry dp->d_reclen = UIO_MX; 60465524Spendry dp->d_fileno = PROCFS_FILENO(pfs->pfs_pid, dt->d_pfstype); 60565524Spendry dp->d_type = DT_REG; 60665524Spendry dp->d_namlen = dt->d_namlen; 60765524Spendry bcopy(dt->d_name, dp->d_name, sizeof(dt->d_name)-1); 60865524Spendry error = uiomove((caddr_t) dp, UIO_MX, uio); 60965524Spendry if (error) 61065524Spendry break; 61165524Spendry count += UIO_MX; 61265524Spendry i++; 61365524Spendry } 61465524Spendry 61565524Spendry break; 61665524Spendry 61765524Spendry } 61865524Spendry 61965524Spendry /* 62065524Spendry * this is for the root of the procfs filesystem 62165524Spendry * what is needed is a special entry for "curproc" 62265524Spendry * followed by an entry for each process on allproc 62365524Spendry #ifdef PROCFS_ZOMBIE 62465524Spendry * and zombproc. 62565524Spendry #endif 62665524Spendry */ 62765524Spendry 62865524Spendry case Proot: { 62965524Spendry int pcnt; 63065524Spendry #ifdef PROCFS_ZOMBIE 63165524Spendry int doingzomb = 0; 63265524Spendry #endif 63365524Spendry volatile struct proc *p; 63465524Spendry 63565524Spendry p = allproc; 63665524Spendry 63765524Spendry #define PROCFS_XFILES 1 /* number of other entries, like "curproc" */ 63865524Spendry pcnt = PROCFS_XFILES; 63965524Spendry 64065524Spendry while (p && uio->uio_resid >= UIO_MX) { 64165524Spendry bzero((char *) dp, UIO_MX); 64265524Spendry dp->d_type = DT_DIR; 64365524Spendry dp->d_reclen = UIO_MX; 64465524Spendry 64565524Spendry switch (i) { 64665524Spendry case 0: 64765524Spendry /* ship out entry for "curproc" */ 64865524Spendry dp->d_fileno = PROCFS_FILENO(PID_MAX+1, Pproc); 64965536Spendry dp->d_namlen = sprintf(dp->d_name, "curproc"); 65065524Spendry break; 65165524Spendry 65265524Spendry default: 65365524Spendry if (pcnt >= i) { 65465524Spendry dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc); 65565524Spendry dp->d_namlen = sprintf(dp->d_name, "%ld", (long) p->p_pid); 65665524Spendry } 65765524Spendry 65865524Spendry p = p->p_next; 65965524Spendry 66065524Spendry #ifdef PROCFS_ZOMBIE 66165524Spendry if (p == 0 && doingzomb == 0) { 66265524Spendry doingzomb = 1; 66365524Spendry p = zombproc; 66465524Spendry } 66565524Spendry #endif 66665524Spendry 66765524Spendry if (pcnt++ < i) 66865524Spendry continue; 66965524Spendry 67065524Spendry break; 67165524Spendry } 67265524Spendry error = uiomove((caddr_t) dp, UIO_MX, uio); 67365524Spendry if (error) 67465524Spendry break; 67565524Spendry count += UIO_MX; 67665524Spendry i++; 67765524Spendry } 67865524Spendry 67965524Spendry break; 68065524Spendry 68165524Spendry } 68265524Spendry 68365524Spendry default: 68465524Spendry error = ENOTDIR; 68565524Spendry break; 68665524Spendry } 68765524Spendry 68865524Spendry uio->uio_offset = i * UIO_MX; 68965524Spendry 69065524Spendry return (error); 69165524Spendry } 69265524Spendry 69365524Spendry /* 69465524Spendry * convert decimal ascii to pid_t 69565524Spendry */ 69665524Spendry static pid_t 69765524Spendry atopid(b, len) 69865524Spendry const char *b; 69965524Spendry u_int len; 70065524Spendry { 70165524Spendry pid_t p = 0; 70265524Spendry 70365524Spendry while (len--) { 70465524Spendry char c = *b++; 70565524Spendry if (c < '0' || c > '9') 70665524Spendry return (NO_PID); 70765524Spendry p = 10 * p + (c - '0'); 70865524Spendry if (p > PID_MAX) 70965524Spendry return (NO_PID); 71065524Spendry } 71165524Spendry 71265524Spendry return (p); 71365524Spendry } 71465524Spendry 71565524Spendry /* 71665524Spendry * procfs vnode operations. 71765524Spendry */ 71865524Spendry int (**procfs_vnodeop_p)(); 71965524Spendry struct vnodeopv_entry_desc procfs_vnodeop_entries[] = { 72065524Spendry { &vop_default_desc, vn_default_error }, 72165524Spendry { &vop_lookup_desc, procfs_lookup }, /* lookup */ 72265524Spendry { &vop_create_desc, procfs_create }, /* create */ 72365524Spendry { &vop_mknod_desc, procfs_mknod }, /* mknod */ 72465524Spendry { &vop_open_desc, procfs_open }, /* open */ 72565524Spendry { &vop_close_desc, procfs_close }, /* close */ 72665524Spendry { &vop_access_desc, procfs_access }, /* access */ 72765524Spendry { &vop_getattr_desc, procfs_getattr }, /* getattr */ 72865524Spendry { &vop_setattr_desc, procfs_setattr }, /* setattr */ 72965524Spendry { &vop_read_desc, procfs_read }, /* read */ 73065524Spendry { &vop_write_desc, procfs_write }, /* write */ 73165524Spendry { &vop_ioctl_desc, procfs_ioctl }, /* ioctl */ 73265524Spendry { &vop_select_desc, procfs_select }, /* select */ 73365524Spendry { &vop_mmap_desc, procfs_mmap }, /* mmap */ 73465524Spendry { &vop_fsync_desc, procfs_fsync }, /* fsync */ 73565524Spendry { &vop_seek_desc, procfs_seek }, /* seek */ 73665524Spendry { &vop_remove_desc, procfs_remove }, /* remove */ 73765524Spendry { &vop_link_desc, procfs_link }, /* link */ 73865524Spendry { &vop_rename_desc, procfs_rename }, /* rename */ 73965524Spendry { &vop_mkdir_desc, procfs_mkdir }, /* mkdir */ 74065524Spendry { &vop_rmdir_desc, procfs_rmdir }, /* rmdir */ 74165524Spendry { &vop_symlink_desc, procfs_symlink }, /* symlink */ 74265524Spendry { &vop_readdir_desc, procfs_readdir }, /* readdir */ 74365524Spendry { &vop_readlink_desc, procfs_readlink }, /* readlink */ 74465524Spendry { &vop_abortop_desc, procfs_abortop }, /* abortop */ 74565524Spendry { &vop_inactive_desc, procfs_inactive }, /* inactive */ 74665524Spendry { &vop_reclaim_desc, procfs_reclaim }, /* reclaim */ 74765524Spendry { &vop_lock_desc, procfs_lock }, /* lock */ 74865524Spendry { &vop_unlock_desc, procfs_unlock }, /* unlock */ 74965524Spendry { &vop_bmap_desc, procfs_bmap }, /* bmap */ 75065524Spendry { &vop_strategy_desc, procfs_strategy }, /* strategy */ 75165524Spendry { &vop_print_desc, procfs_print }, /* print */ 75265524Spendry { &vop_islocked_desc, procfs_islocked }, /* islocked */ 75365524Spendry { &vop_pathconf_desc, procfs_pathconf }, /* pathconf */ 75465524Spendry { &vop_advlock_desc, procfs_advlock }, /* advlock */ 75565524Spendry { &vop_blkatoff_desc, procfs_blkatoff }, /* blkatoff */ 75665524Spendry { &vop_valloc_desc, procfs_valloc }, /* valloc */ 75765524Spendry { &vop_vfree_desc, procfs_vfree }, /* vfree */ 75865524Spendry { &vop_truncate_desc, procfs_truncate }, /* truncate */ 75965524Spendry { &vop_update_desc, procfs_update }, /* update */ 76065524Spendry { (struct vnodeop_desc*)NULL, (int(*)())NULL } 76165524Spendry }; 76265524Spendry struct vnodeopv_desc procfs_vnodeop_opv_desc = 76365524Spendry { &procfs_vnodeop_p, procfs_vnodeop_entries }; 764