165524Spendry /* 265524Spendry * Copyright (c) 1993 Jan-Simon Pendry 365808Sbostic * Copyright (c) 1993 465808Sbostic * The Regents of the University of California. 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*65924Spendry * @(#)procfs_vnops.c 8.5 (Berkeley) 01/27/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 */ 52*65924Spendry { N("file"), Pfile }, 53*65924Spendry { N("mem"), Pmem }, 54*65924Spendry { N("regs"), Pregs }, 55*65924Spendry { N("fpregs"), Pfpregs }, 56*65924Spendry { N("ctl"), Pctl }, 57*65924Spendry { N("status"), Pstatus }, 58*65924Spendry { N("note"), Pnote }, 59*65924Spendry { N("notepg"), Pnotepg }, 6065524Spendry #undef N 6165524Spendry }; 6265524Spendry #define Nprocent (sizeof(procent)/sizeof(procent[0])) 6365524Spendry 6465524Spendry static pid_t atopid __P((const char *, u_int)); 6565524Spendry 6665524Spendry /* 6765524Spendry * set things up for doing i/o on 6865524Spendry * the pfsnode (vp). (vp) is locked 6965524Spendry * on entry, and should be left locked 7065524Spendry * on exit. 7165524Spendry * 7265524Spendry * for procfs we don't need to do anything 7365524Spendry * in particular for i/o. all that is done 7465524Spendry * is to support exclusive open on process 7565524Spendry * memory images. 7665524Spendry */ 7765524Spendry procfs_open(ap) 7865524Spendry struct vop_open_args *ap; 7965524Spendry { 8065524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 8165524Spendry 8265524Spendry switch (pfs->pfs_type) { 8365524Spendry case Pmem: 8465524Spendry if (PFIND(pfs->pfs_pid) == 0) 8565524Spendry return (ENOENT); /* was ESRCH, jsp */ 8665524Spendry 8765524Spendry if ((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL) || 8865524Spendry (pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE)) 8965524Spendry return (EBUSY); 9065524Spendry 9165524Spendry 9265524Spendry if (ap->a_mode & FWRITE) 9365524Spendry pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL); 9465524Spendry 9565524Spendry return (0); 9665524Spendry 9765524Spendry default: 9865524Spendry break; 9965524Spendry } 10065524Spendry 10165524Spendry return (0); 10265524Spendry } 10365524Spendry 10465524Spendry /* 10565524Spendry * close the pfsnode (vp) after doing i/o. 10665524Spendry * (vp) is not locked on entry or exit. 10765524Spendry * 10865524Spendry * nothing to do for procfs other than undo 10965524Spendry * any exclusive open flag (see _open above). 11065524Spendry */ 11165524Spendry procfs_close(ap) 11265524Spendry struct vop_close_args *ap; 11365524Spendry { 11465524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 11565524Spendry 11665524Spendry switch (pfs->pfs_type) { 11765524Spendry case Pmem: 11865524Spendry if ((ap->a_fflag & FWRITE) && (pfs->pfs_flags & O_EXCL)) 11965524Spendry pfs->pfs_flags &= ~(FWRITE|O_EXCL); 12065524Spendry break; 12165524Spendry } 12265524Spendry 12365524Spendry return (0); 12465524Spendry } 12565524Spendry 12665524Spendry /* 12765524Spendry * do an ioctl operation on pfsnode (vp). 12865524Spendry * (vp) is not locked on entry or exit. 12965524Spendry */ 13065524Spendry procfs_ioctl(ap) 13165524Spendry struct vop_ioctl_args *ap; 13265524Spendry { 13365524Spendry 13465524Spendry return (ENOTTY); 13565524Spendry } 13665524Spendry 13765524Spendry /* 13865524Spendry * do block mapping for pfsnode (vp). 13965524Spendry * since we don't use the buffer cache 14065524Spendry * for procfs this function should never 14165524Spendry * be called. in any case, it's not clear 14265524Spendry * what part of the kernel ever makes use 14365524Spendry * of this function. for sanity, this is the 14465524Spendry * usual no-op bmap, although returning 14565524Spendry * (EIO) would be a reasonable alternative. 14665524Spendry */ 14765524Spendry procfs_bmap(ap) 14865524Spendry struct vop_bmap_args *ap; 14965524Spendry { 15065524Spendry 15165524Spendry if (ap->a_vpp != NULL) 15265524Spendry *ap->a_vpp = ap->a_vp; 15365524Spendry if (ap->a_bnp != NULL) 15465524Spendry *ap->a_bnp = ap->a_bn; 15565524Spendry return (0); 15665524Spendry } 15765524Spendry 15865524Spendry /* 15965524Spendry * _inactive is called when the pfsnode 16065524Spendry * is vrele'd and the reference count goes 16165524Spendry * to zero. (vp) will be on the vnode free 16265524Spendry * list, so to get it back vget() must be 16365524Spendry * used. 16465524Spendry * 16565524Spendry * for procfs, check if the process is still 16665524Spendry * alive and if it isn't then just throw away 16765524Spendry * the vnode by calling vgone(). this may 16865524Spendry * be overkill and a waste of time since the 16965524Spendry * chances are that the process will still be 17065524Spendry * there and PFIND is not free. 17165524Spendry * 17265524Spendry * (vp) is not locked on entry or exit. 17365524Spendry */ 17465524Spendry procfs_inactive(ap) 17565524Spendry struct vop_inactive_args *ap; 17665524Spendry { 17765524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 17865524Spendry 17965524Spendry if (PFIND(pfs->pfs_pid) == 0) 18065524Spendry vgone(ap->a_vp); 18165524Spendry 18265524Spendry return (0); 18365524Spendry } 18465524Spendry 18565524Spendry /* 18665524Spendry * _reclaim is called when getnewvnode() 18765524Spendry * wants to make use of an entry on the vnode 18865524Spendry * free list. at this time the filesystem needs 18965524Spendry * to free any private data and remove the node 19065524Spendry * from any private lists. 19165524Spendry */ 19265524Spendry procfs_reclaim(ap) 19365524Spendry struct vop_reclaim_args *ap; 19465524Spendry { 19565524Spendry int error; 19665524Spendry 19765524Spendry error = procfs_freevp(ap->a_vp); 19865524Spendry return (error); 19965524Spendry } 20065524Spendry 20165524Spendry /* 20265743Spendry * Return POSIX pathconf information applicable to special devices. 20365743Spendry */ 20465743Spendry procfs_pathconf(ap) 20565743Spendry struct vop_pathconf_args /* { 20665743Spendry struct vnode *a_vp; 20765743Spendry int a_name; 20865743Spendry int *a_retval; 20965743Spendry } */ *ap; 21065743Spendry { 21165743Spendry 21265743Spendry switch (ap->a_name) { 21365743Spendry case _PC_LINK_MAX: 21465743Spendry *ap->a_retval = LINK_MAX; 21565743Spendry return (0); 21665743Spendry case _PC_MAX_CANON: 21765743Spendry *ap->a_retval = MAX_CANON; 21865743Spendry return (0); 21965743Spendry case _PC_MAX_INPUT: 22065743Spendry *ap->a_retval = MAX_INPUT; 22165743Spendry return (0); 22265743Spendry case _PC_PIPE_BUF: 22365743Spendry *ap->a_retval = PIPE_BUF; 22465743Spendry return (0); 22565743Spendry case _PC_CHOWN_RESTRICTED: 22665743Spendry *ap->a_retval = 1; 22765743Spendry return (0); 22865743Spendry case _PC_VDISABLE: 22965743Spendry *ap->a_retval = _POSIX_VDISABLE; 23065743Spendry return (0); 23165743Spendry default: 23265743Spendry return (EINVAL); 23365743Spendry } 23465743Spendry /* NOTREACHED */ 23565743Spendry } 23665743Spendry 23765743Spendry /* 23865524Spendry * _print is used for debugging. 23965524Spendry * just print a readable description 24065524Spendry * of (vp). 24165524Spendry */ 24265524Spendry procfs_print(ap) 24365524Spendry struct vop_print_args *ap; 24465524Spendry { 24565524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 24665524Spendry 24765524Spendry printf("tag VT_PROCFS, pid %d, mode %x, flags %x\n", 24865524Spendry pfs->pfs_pid, 24965524Spendry pfs->pfs_mode, pfs->pfs_flags); 25065524Spendry } 25165524Spendry 25265524Spendry /* 25365524Spendry * _abortop is called when operations such as 25465524Spendry * rename and create fail. this entry is responsible 25565524Spendry * for undoing any side-effects caused by the lookup. 25665524Spendry * this will always include freeing the pathname buffer. 25765524Spendry */ 25865524Spendry procfs_abortop(ap) 25965524Spendry struct vop_abortop_args *ap; 26065524Spendry { 26165524Spendry 26265524Spendry if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) 26365524Spendry FREE(ap->a_cnp->cn_pnbuf, M_NAMEI); 26465524Spendry return (0); 26565524Spendry } 26665524Spendry 26765524Spendry /* 26865524Spendry * generic entry point for unsupported operations 26965524Spendry */ 27065524Spendry procfs_badop() 27165524Spendry { 27265524Spendry 27365524Spendry return (EIO); 27465524Spendry } 27565524Spendry 27665524Spendry /* 27765524Spendry * Invent attributes for pfsnode (vp) and store 27865524Spendry * them in (vap). 27965524Spendry * Directories lengths are returned as zero since 28065524Spendry * any real length would require the genuine size 28165524Spendry * to be computed, and nothing cares anyway. 28265524Spendry * 28365524Spendry * this is relatively minimal for procfs. 28465524Spendry */ 28565524Spendry procfs_getattr(ap) 28665524Spendry struct vop_getattr_args *ap; 28765524Spendry { 28865524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 28965536Spendry struct vattr *vap = ap->a_vap; 29065524Spendry struct proc *procp; 29165524Spendry int error; 29265524Spendry 29365524Spendry /* first check the process still exists */ 29465524Spendry procp = PFIND(pfs->pfs_pid); 29565524Spendry if (procp == 0) 29665524Spendry return (ENOENT); 29765524Spendry 29865524Spendry error = 0; 29965524Spendry 30065524Spendry /* start by zeroing out the attributes */ 30165536Spendry VATTR_NULL(vap); 30265524Spendry 30365524Spendry /* next do all the common fields */ 30465536Spendry vap->va_type = ap->a_vp->v_type; 30565536Spendry vap->va_mode = pfs->pfs_mode; 30665536Spendry vap->va_fileid = pfs->pfs_fileno; 30765536Spendry vap->va_flags = 0; 30865536Spendry vap->va_blocksize = PAGE_SIZE; 30965536Spendry vap->va_bytes = vap->va_size = 0; 31065524Spendry 31165524Spendry /* 31265524Spendry * Make all times be current TOD. 31365524Spendry * It would be possible to get the process start 31465524Spendry * time from the p_stat structure, but there's 31565524Spendry * no "file creation" time stamp anyway, and the 31665524Spendry * p_stat structure is not addressible if u. gets 31765524Spendry * swapped out for that process. 31865524Spendry */ 31965536Spendry microtime(&vap->va_ctime); 32065536Spendry vap->va_atime = vap->va_mtime = vap->va_ctime; 32165524Spendry 32265524Spendry /* 32365524Spendry * now do the object specific fields 32465524Spendry * 32565524Spendry * The size could be set from struct reg, but it's hardly 32665524Spendry * worth the trouble, and it puts some (potentially) machine 32765524Spendry * dependent data into this machine-independent code. If it 32865524Spendry * becomes important then this function should break out into 32965524Spendry * a per-file stat function in the corresponding .c file. 33065524Spendry */ 33165524Spendry 33265524Spendry switch (pfs->pfs_type) { 33365524Spendry case Proot: 33465536Spendry vap->va_nlink = 2; 33565536Spendry vap->va_uid = 0; 33665536Spendry vap->va_gid = 0; 33765524Spendry break; 33865524Spendry 33965524Spendry case Pproc: 34065536Spendry vap->va_nlink = 2; 34165536Spendry vap->va_uid = procp->p_ucred->cr_uid; 34265536Spendry vap->va_gid = procp->p_ucred->cr_gid; 34365524Spendry break; 34465524Spendry 34565524Spendry case Pfile: 34665524Spendry error = EOPNOTSUPP; 34765524Spendry break; 34865524Spendry 34965524Spendry case Pmem: 35065536Spendry vap->va_nlink = 1; 35165536Spendry vap->va_bytes = vap->va_size = 35265524Spendry ctob(procp->p_vmspace->vm_tsize + 35365524Spendry procp->p_vmspace->vm_dsize + 35465524Spendry procp->p_vmspace->vm_ssize); 35565536Spendry vap->va_uid = procp->p_ucred->cr_uid; 35665536Spendry vap->va_gid = procp->p_ucred->cr_gid; 35765524Spendry break; 35865524Spendry 35965524Spendry case Pregs: 360*65924Spendry case Pfpregs: 36165524Spendry case Pctl: 36265524Spendry case Pstatus: 36365524Spendry case Pnote: 36465524Spendry case Pnotepg: 36565536Spendry vap->va_nlink = 1; 36665536Spendry vap->va_uid = procp->p_ucred->cr_uid; 36765536Spendry vap->va_gid = procp->p_ucred->cr_gid; 36865524Spendry break; 36965524Spendry 37065524Spendry default: 37165524Spendry panic("procfs_getattr"); 37265524Spendry } 37365524Spendry 37465524Spendry return (error); 37565524Spendry } 37665524Spendry 37765524Spendry procfs_setattr(ap) 37865524Spendry struct vop_setattr_args *ap; 37965524Spendry { 38065524Spendry /* 38165524Spendry * just fake out attribute setting 38265524Spendry * it's not good to generate an error 38365524Spendry * return, otherwise things like creat() 38465524Spendry * will fail when they try to set the 38565524Spendry * file length to 0. worse, this means 38665524Spendry * that echo $note > /proc/$pid/note will fail. 38765524Spendry */ 38865524Spendry 38965524Spendry return (0); 39065524Spendry } 39165524Spendry 39265524Spendry /* 39365524Spendry * implement access checking. 39465524Spendry * 39565524Spendry * something very similar to this code is duplicated 39665524Spendry * throughout the 4bsd kernel and should be moved 39765524Spendry * into kern/vfs_subr.c sometime. 39865524Spendry * 39965524Spendry * actually, the check for super-user is slightly 40065524Spendry * broken since it will allow read access to write-only 40165524Spendry * objects. this doesn't cause any particular trouble 40265524Spendry * but does mean that the i/o entry points need to check 40365524Spendry * that the operation really does make sense. 40465524Spendry */ 40565524Spendry procfs_access(ap) 40665524Spendry struct vop_access_args *ap; 40765524Spendry { 40865524Spendry struct vattr *vap; 40965524Spendry struct vattr vattr; 41065524Spendry int error; 41165524Spendry 41265524Spendry /* 41365524Spendry * If you're the super-user, 41465524Spendry * you always get access. 41565524Spendry */ 41665524Spendry if (ap->a_cred->cr_uid == (uid_t) 0) 41765524Spendry return (0); 41865524Spendry vap = &vattr; 41965524Spendry if (error = VOP_GETATTR(ap->a_vp, vap, ap->a_cred, ap->a_p)) 42065524Spendry return (error); 42165524Spendry 42265524Spendry /* 42365524Spendry * Access check is based on only one of owner, group, public. 42465524Spendry * If not owner, then check group. If not a member of the 42565524Spendry * group, then check public access. 42665524Spendry */ 42765524Spendry if (ap->a_cred->cr_uid != vap->va_uid) { 42865524Spendry gid_t *gp; 42965524Spendry int i; 43065524Spendry 43165524Spendry (ap->a_mode) >>= 3; 43265524Spendry gp = ap->a_cred->cr_groups; 43365524Spendry for (i = 0; i < ap->a_cred->cr_ngroups; i++, gp++) 43465524Spendry if (vap->va_gid == *gp) 43565524Spendry goto found; 43665524Spendry ap->a_mode >>= 3; 43765524Spendry found: 43865524Spendry ; 43965524Spendry } 44065524Spendry 44165524Spendry if ((vap->va_mode & ap->a_mode) == ap->a_mode) 44265524Spendry return (0); 44365524Spendry 44465524Spendry return (EACCES); 44565524Spendry } 44665524Spendry 44765524Spendry /* 44865524Spendry * lookup. this is incredibly complicated in the 44965524Spendry * general case, however for most pseudo-filesystems 45065524Spendry * very little needs to be done. 45165524Spendry * 45265524Spendry * unless you want to get a migraine, just make sure your 45365524Spendry * filesystem doesn't do any locking of its own. otherwise 45465524Spendry * read and inwardly digest ufs_lookup(). 45565524Spendry */ 45665524Spendry procfs_lookup(ap) 45765524Spendry struct vop_lookup_args *ap; 45865524Spendry { 45965524Spendry struct componentname *cnp = ap->a_cnp; 46065524Spendry struct vnode **vpp = ap->a_vpp; 46165524Spendry struct vnode *dvp = ap->a_dvp; 46265524Spendry char *pname = cnp->cn_nameptr; 46365524Spendry int error = 0; 46465524Spendry pid_t pid; 46565524Spendry struct vnode *nvp; 46665524Spendry struct pfsnode *pfs; 46765524Spendry struct proc *procp; 46865524Spendry pfstype pfs_type; 46965524Spendry int i; 47065524Spendry 47165524Spendry if (cnp->cn_namelen == 1 && *pname == '.') { 47265524Spendry *vpp = dvp; 47365524Spendry VREF(dvp); 47465524Spendry /*VOP_LOCK(dvp);*/ 47565524Spendry return (0); 47665524Spendry } 47765524Spendry 47865524Spendry *vpp = NULL; 47965524Spendry 48065524Spendry pfs = VTOPFS(dvp); 48165524Spendry switch (pfs->pfs_type) { 48265524Spendry case Proot: 48365524Spendry if (cnp->cn_flags & ISDOTDOT) 48465524Spendry return (EIO); 48565524Spendry 48665524Spendry if (CNEQ(cnp, "curproc", 7)) 48765524Spendry pid = cnp->cn_proc->p_pid; 48865524Spendry else 48965524Spendry pid = atopid(pname, cnp->cn_namelen); 49065524Spendry if (pid == NO_PID) 49165524Spendry return (ENOENT); 49265524Spendry 49365524Spendry procp = PFIND(pid); 49465524Spendry if (procp == 0) 49565524Spendry return (ENOENT); 49665524Spendry 49765524Spendry error = procfs_allocvp(dvp->v_mount, &nvp, pid, Pproc); 49865524Spendry if (error) 49965524Spendry return (error); 50065524Spendry 50165524Spendry nvp->v_type = VDIR; 50265524Spendry pfs = VTOPFS(nvp); 50365524Spendry 50465524Spendry *vpp = nvp; 50565524Spendry return (0); 50665524Spendry 50765524Spendry case Pproc: 50865524Spendry if (cnp->cn_flags & ISDOTDOT) { 50965524Spendry error = procfs_root(dvp->v_mount, vpp); 51065524Spendry return (error); 51165524Spendry } 51265524Spendry 51365524Spendry procp = PFIND(pfs->pfs_pid); 51465524Spendry if (procp == 0) 51565524Spendry return (ENOENT); 51665524Spendry 51765524Spendry for (i = 0; i < Nprocent; i++) { 51865524Spendry struct pfsnames *dp = &procent[i]; 51965524Spendry 52065524Spendry if (cnp->cn_namelen == dp->d_namlen && 52165524Spendry bcmp(pname, dp->d_name, dp->d_namlen) == 0) { 52265524Spendry pfs_type = dp->d_pfstype; 52365524Spendry goto found; 52465524Spendry } 52565524Spendry } 52665524Spendry return (ENOENT); 52765524Spendry 52865524Spendry found: 52965524Spendry if (pfs_type == Pfile) { 53065524Spendry nvp = procfs_findtextvp(procp); 53165524Spendry if (nvp) { 53265524Spendry VREF(nvp); 53365524Spendry VOP_LOCK(nvp); 53465524Spendry } else { 53565524Spendry error = ENXIO; 53665524Spendry } 53765524Spendry } else { 53865524Spendry error = procfs_allocvp(dvp->v_mount, &nvp, 53965524Spendry pfs->pfs_pid, pfs_type); 54065524Spendry if (error) 54165524Spendry return (error); 54265524Spendry 54365524Spendry nvp->v_type = VREG; 54465524Spendry pfs = VTOPFS(nvp); 54565524Spendry } 54665524Spendry *vpp = nvp; 54765524Spendry return (error); 54865524Spendry 54965524Spendry default: 55065524Spendry return (ENOTDIR); 55165524Spendry } 55265524Spendry } 55365524Spendry 55465524Spendry /* 55565524Spendry * readdir returns directory entries from pfsnode (vp). 55665524Spendry * 55765524Spendry * the strategy here with procfs is to generate a single 55865524Spendry * directory entry at a time (struct pfsdent) and then 55965524Spendry * copy that out to userland using uiomove. a more efficent 56065524Spendry * though more complex implementation, would try to minimize 56165524Spendry * the number of calls to uiomove(). for procfs, this is 56265524Spendry * hardly worth the added code complexity. 56365524Spendry * 56465524Spendry * this should just be done through read() 56565524Spendry */ 56665524Spendry procfs_readdir(ap) 56765524Spendry struct vop_readdir_args *ap; 56865524Spendry { 56965524Spendry struct uio *uio = ap->a_uio; 57065524Spendry struct pfsdent d; 57165524Spendry struct pfsdent *dp = &d; 57265524Spendry struct pfsnode *pfs; 57365524Spendry int error; 57465524Spendry int count; 57565524Spendry int i; 57665524Spendry 57765524Spendry pfs = VTOPFS(ap->a_vp); 57865524Spendry 57965524Spendry if (uio->uio_resid < UIO_MX) 58065524Spendry return (EINVAL); 58165524Spendry if (uio->uio_offset & (UIO_MX-1)) 58265524Spendry return (EINVAL); 58365524Spendry if (uio->uio_offset < 0) 58465524Spendry return (EINVAL); 58565524Spendry 58665524Spendry error = 0; 58765524Spendry count = 0; 58865524Spendry i = uio->uio_offset / UIO_MX; 58965524Spendry 59065524Spendry switch (pfs->pfs_type) { 59165524Spendry /* 59265524Spendry * this is for the process-specific sub-directories. 59365524Spendry * all that is needed to is copy out all the entries 59465524Spendry * from the procent[] table (top of this file). 59565524Spendry */ 59665524Spendry case Pproc: { 59765524Spendry while (uio->uio_resid >= UIO_MX) { 59865524Spendry struct pfsnames *dt; 59965524Spendry 60065524Spendry if (i >= Nprocent) 60165524Spendry break; 60265524Spendry 60365524Spendry dt = &procent[i]; 60465524Spendry 60565524Spendry dp->d_reclen = UIO_MX; 60665524Spendry dp->d_fileno = PROCFS_FILENO(pfs->pfs_pid, dt->d_pfstype); 60765524Spendry dp->d_type = DT_REG; 60865524Spendry dp->d_namlen = dt->d_namlen; 60965524Spendry bcopy(dt->d_name, dp->d_name, sizeof(dt->d_name)-1); 61065524Spendry error = uiomove((caddr_t) dp, UIO_MX, uio); 61165524Spendry if (error) 61265524Spendry break; 61365524Spendry count += UIO_MX; 61465524Spendry i++; 61565524Spendry } 61665524Spendry 61765524Spendry break; 61865524Spendry 61965524Spendry } 62065524Spendry 62165524Spendry /* 62265524Spendry * this is for the root of the procfs filesystem 62365524Spendry * what is needed is a special entry for "curproc" 62465524Spendry * followed by an entry for each process on allproc 62565524Spendry #ifdef PROCFS_ZOMBIE 62665524Spendry * and zombproc. 62765524Spendry #endif 62865524Spendry */ 62965524Spendry 63065524Spendry case Proot: { 63165524Spendry int pcnt; 63265524Spendry #ifdef PROCFS_ZOMBIE 63365524Spendry int doingzomb = 0; 63465524Spendry #endif 63565524Spendry volatile struct proc *p; 63665524Spendry 63765524Spendry p = allproc; 63865524Spendry 63965524Spendry #define PROCFS_XFILES 1 /* number of other entries, like "curproc" */ 64065524Spendry pcnt = PROCFS_XFILES; 64165524Spendry 64265524Spendry while (p && uio->uio_resid >= UIO_MX) { 64365524Spendry bzero((char *) dp, UIO_MX); 64465524Spendry dp->d_type = DT_DIR; 64565524Spendry dp->d_reclen = UIO_MX; 64665524Spendry 64765524Spendry switch (i) { 64865524Spendry case 0: 64965524Spendry /* ship out entry for "curproc" */ 65065524Spendry dp->d_fileno = PROCFS_FILENO(PID_MAX+1, Pproc); 65165536Spendry dp->d_namlen = sprintf(dp->d_name, "curproc"); 65265524Spendry break; 65365524Spendry 65465524Spendry default: 65565524Spendry if (pcnt >= i) { 65665524Spendry dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc); 65765524Spendry dp->d_namlen = sprintf(dp->d_name, "%ld", (long) p->p_pid); 65865524Spendry } 65965524Spendry 66065524Spendry p = p->p_next; 66165524Spendry 66265524Spendry #ifdef PROCFS_ZOMBIE 66365524Spendry if (p == 0 && doingzomb == 0) { 66465524Spendry doingzomb = 1; 66565524Spendry p = zombproc; 66665524Spendry } 66765524Spendry #endif 66865524Spendry 66965524Spendry if (pcnt++ < i) 67065524Spendry continue; 67165524Spendry 67265524Spendry break; 67365524Spendry } 67465524Spendry error = uiomove((caddr_t) dp, UIO_MX, uio); 67565524Spendry if (error) 67665524Spendry break; 67765524Spendry count += UIO_MX; 67865524Spendry i++; 67965524Spendry } 68065524Spendry 68165524Spendry break; 68265524Spendry 68365524Spendry } 68465524Spendry 68565524Spendry default: 68665524Spendry error = ENOTDIR; 68765524Spendry break; 68865524Spendry } 68965524Spendry 69065524Spendry uio->uio_offset = i * UIO_MX; 69165524Spendry 69265524Spendry return (error); 69365524Spendry } 69465524Spendry 69565524Spendry /* 69665524Spendry * convert decimal ascii to pid_t 69765524Spendry */ 69865524Spendry static pid_t 69965524Spendry atopid(b, len) 70065524Spendry const char *b; 70165524Spendry u_int len; 70265524Spendry { 70365524Spendry pid_t p = 0; 70465524Spendry 70565524Spendry while (len--) { 70665524Spendry char c = *b++; 70765524Spendry if (c < '0' || c > '9') 70865524Spendry return (NO_PID); 70965524Spendry p = 10 * p + (c - '0'); 71065524Spendry if (p > PID_MAX) 71165524Spendry return (NO_PID); 71265524Spendry } 71365524Spendry 71465524Spendry return (p); 71565524Spendry } 71665524Spendry 71765524Spendry /* 71865524Spendry * procfs vnode operations. 71965524Spendry */ 72065524Spendry int (**procfs_vnodeop_p)(); 72165524Spendry struct vnodeopv_entry_desc procfs_vnodeop_entries[] = { 72265524Spendry { &vop_default_desc, vn_default_error }, 72365524Spendry { &vop_lookup_desc, procfs_lookup }, /* lookup */ 72465524Spendry { &vop_create_desc, procfs_create }, /* create */ 72565524Spendry { &vop_mknod_desc, procfs_mknod }, /* mknod */ 72665524Spendry { &vop_open_desc, procfs_open }, /* open */ 72765524Spendry { &vop_close_desc, procfs_close }, /* close */ 72865524Spendry { &vop_access_desc, procfs_access }, /* access */ 72965524Spendry { &vop_getattr_desc, procfs_getattr }, /* getattr */ 73065524Spendry { &vop_setattr_desc, procfs_setattr }, /* setattr */ 73165524Spendry { &vop_read_desc, procfs_read }, /* read */ 73265524Spendry { &vop_write_desc, procfs_write }, /* write */ 73365524Spendry { &vop_ioctl_desc, procfs_ioctl }, /* ioctl */ 73465524Spendry { &vop_select_desc, procfs_select }, /* select */ 73565524Spendry { &vop_mmap_desc, procfs_mmap }, /* mmap */ 73665524Spendry { &vop_fsync_desc, procfs_fsync }, /* fsync */ 73765524Spendry { &vop_seek_desc, procfs_seek }, /* seek */ 73865524Spendry { &vop_remove_desc, procfs_remove }, /* remove */ 73965524Spendry { &vop_link_desc, procfs_link }, /* link */ 74065524Spendry { &vop_rename_desc, procfs_rename }, /* rename */ 74165524Spendry { &vop_mkdir_desc, procfs_mkdir }, /* mkdir */ 74265524Spendry { &vop_rmdir_desc, procfs_rmdir }, /* rmdir */ 74365524Spendry { &vop_symlink_desc, procfs_symlink }, /* symlink */ 74465524Spendry { &vop_readdir_desc, procfs_readdir }, /* readdir */ 74565524Spendry { &vop_readlink_desc, procfs_readlink }, /* readlink */ 74665524Spendry { &vop_abortop_desc, procfs_abortop }, /* abortop */ 74765524Spendry { &vop_inactive_desc, procfs_inactive }, /* inactive */ 74865524Spendry { &vop_reclaim_desc, procfs_reclaim }, /* reclaim */ 74965524Spendry { &vop_lock_desc, procfs_lock }, /* lock */ 75065524Spendry { &vop_unlock_desc, procfs_unlock }, /* unlock */ 75165524Spendry { &vop_bmap_desc, procfs_bmap }, /* bmap */ 75265524Spendry { &vop_strategy_desc, procfs_strategy }, /* strategy */ 75365524Spendry { &vop_print_desc, procfs_print }, /* print */ 75465524Spendry { &vop_islocked_desc, procfs_islocked }, /* islocked */ 75565524Spendry { &vop_pathconf_desc, procfs_pathconf }, /* pathconf */ 75665524Spendry { &vop_advlock_desc, procfs_advlock }, /* advlock */ 75765524Spendry { &vop_blkatoff_desc, procfs_blkatoff }, /* blkatoff */ 75865524Spendry { &vop_valloc_desc, procfs_valloc }, /* valloc */ 75965524Spendry { &vop_vfree_desc, procfs_vfree }, /* vfree */ 76065524Spendry { &vop_truncate_desc, procfs_truncate }, /* truncate */ 76165524Spendry { &vop_update_desc, procfs_update }, /* update */ 76265524Spendry { (struct vnodeop_desc*)NULL, (int(*)())NULL } 76365524Spendry }; 76465524Spendry struct vnodeopv_desc procfs_vnodeop_opv_desc = 76565524Spendry { &procfs_vnodeop_p, procfs_vnodeop_entries }; 766