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*67367Smckusick * @(#)procfs_vnops.c 8.7 (Berkeley) 06/04/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 */ 5265924Spendry { N("file"), Pfile }, 5365924Spendry { N("mem"), Pmem }, 5465924Spendry { N("regs"), Pregs }, 5565924Spendry { N("fpregs"), Pfpregs }, 5665924Spendry { N("ctl"), Pctl }, 5765924Spendry { N("status"), Pstatus }, 5865924Spendry { N("note"), Pnote }, 5965924Spendry { 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) 78*67367Smckusick struct vop_open_args /* { 79*67367Smckusick struct vnode *a_vp; 80*67367Smckusick int a_mode; 81*67367Smckusick struct ucred *a_cred; 82*67367Smckusick struct proc *a_p; 83*67367Smckusick } */ *ap; 8465524Spendry { 8565524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 8665524Spendry 8765524Spendry switch (pfs->pfs_type) { 8865524Spendry case Pmem: 8965524Spendry if (PFIND(pfs->pfs_pid) == 0) 9065524Spendry return (ENOENT); /* was ESRCH, jsp */ 9165524Spendry 9265524Spendry if ((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL) || 9365524Spendry (pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE)) 9465524Spendry return (EBUSY); 9565524Spendry 9665524Spendry 9765524Spendry if (ap->a_mode & FWRITE) 9865524Spendry pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL); 9965524Spendry 10065524Spendry return (0); 10165524Spendry 10265524Spendry default: 10365524Spendry break; 10465524Spendry } 10565524Spendry 10665524Spendry return (0); 10765524Spendry } 10865524Spendry 10965524Spendry /* 11065524Spendry * close the pfsnode (vp) after doing i/o. 11165524Spendry * (vp) is not locked on entry or exit. 11265524Spendry * 11365524Spendry * nothing to do for procfs other than undo 11465524Spendry * any exclusive open flag (see _open above). 11565524Spendry */ 11665524Spendry procfs_close(ap) 117*67367Smckusick struct vop_close_args /* { 118*67367Smckusick struct vnode *a_vp; 119*67367Smckusick int a_fflag; 120*67367Smckusick struct ucred *a_cred; 121*67367Smckusick struct proc *a_p; 122*67367Smckusick } */ *ap; 12365524Spendry { 12465524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 12565524Spendry 12665524Spendry switch (pfs->pfs_type) { 12765524Spendry case Pmem: 12865524Spendry if ((ap->a_fflag & FWRITE) && (pfs->pfs_flags & O_EXCL)) 12965524Spendry pfs->pfs_flags &= ~(FWRITE|O_EXCL); 13065524Spendry break; 13165524Spendry } 13265524Spendry 13365524Spendry return (0); 13465524Spendry } 13565524Spendry 13665524Spendry /* 13765524Spendry * do an ioctl operation on pfsnode (vp). 13865524Spendry * (vp) is not locked on entry or exit. 13965524Spendry */ 14065524Spendry procfs_ioctl(ap) 141*67367Smckusick struct vop_ioctl_args /* { 142*67367Smckusick struct vnode *a_vp; 143*67367Smckusick int a_command; 144*67367Smckusick caddr_t a_data; 145*67367Smckusick int a_fflag; 146*67367Smckusick struct ucred *a_cred; 147*67367Smckusick struct proc *a_p; 148*67367Smckusick } */ *ap; 14965524Spendry { 15065524Spendry 15165524Spendry return (ENOTTY); 15265524Spendry } 15365524Spendry 15465524Spendry /* 15565524Spendry * do block mapping for pfsnode (vp). 15665524Spendry * since we don't use the buffer cache 15765524Spendry * for procfs this function should never 15865524Spendry * be called. in any case, it's not clear 15965524Spendry * what part of the kernel ever makes use 16065524Spendry * of this function. for sanity, this is the 16165524Spendry * usual no-op bmap, although returning 16265524Spendry * (EIO) would be a reasonable alternative. 16365524Spendry */ 16465524Spendry procfs_bmap(ap) 165*67367Smckusick struct vop_bmap_args /* { 166*67367Smckusick struct vnode *a_vp; 167*67367Smckusick daddr_t a_bn; 168*67367Smckusick struct vnode **a_vpp; 169*67367Smckusick daddr_t *a_bnp; 170*67367Smckusick } */ *ap; 17165524Spendry { 17265524Spendry 17365524Spendry if (ap->a_vpp != NULL) 17465524Spendry *ap->a_vpp = ap->a_vp; 17565524Spendry if (ap->a_bnp != NULL) 17665524Spendry *ap->a_bnp = ap->a_bn; 17765524Spendry return (0); 17865524Spendry } 17965524Spendry 18065524Spendry /* 18165524Spendry * _inactive is called when the pfsnode 18265524Spendry * is vrele'd and the reference count goes 18365524Spendry * to zero. (vp) will be on the vnode free 18465524Spendry * list, so to get it back vget() must be 18565524Spendry * used. 18665524Spendry * 18765524Spendry * for procfs, check if the process is still 18865524Spendry * alive and if it isn't then just throw away 18965524Spendry * the vnode by calling vgone(). this may 19065524Spendry * be overkill and a waste of time since the 19165524Spendry * chances are that the process will still be 19265524Spendry * there and PFIND is not free. 19365524Spendry * 19465524Spendry * (vp) is not locked on entry or exit. 19565524Spendry */ 19665524Spendry procfs_inactive(ap) 197*67367Smckusick struct vop_inactive_args /* { 198*67367Smckusick struct vnode *a_vp; 199*67367Smckusick } */ *ap; 20065524Spendry { 20165524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 20265524Spendry 20365524Spendry if (PFIND(pfs->pfs_pid) == 0) 20465524Spendry vgone(ap->a_vp); 20565524Spendry 20665524Spendry return (0); 20765524Spendry } 20865524Spendry 20965524Spendry /* 21065524Spendry * _reclaim is called when getnewvnode() 21165524Spendry * wants to make use of an entry on the vnode 21265524Spendry * free list. at this time the filesystem needs 21365524Spendry * to free any private data and remove the node 21465524Spendry * from any private lists. 21565524Spendry */ 21665524Spendry procfs_reclaim(ap) 217*67367Smckusick struct vop_reclaim_args /* { 218*67367Smckusick struct vnode *a_vp; 219*67367Smckusick } */ *ap; 22065524Spendry { 22165524Spendry int error; 22265524Spendry 22365524Spendry error = procfs_freevp(ap->a_vp); 22465524Spendry return (error); 22565524Spendry } 22665524Spendry 22765524Spendry /* 22865743Spendry * Return POSIX pathconf information applicable to special devices. 22965743Spendry */ 23065743Spendry procfs_pathconf(ap) 23165743Spendry struct vop_pathconf_args /* { 23265743Spendry struct vnode *a_vp; 23365743Spendry int a_name; 23465743Spendry int *a_retval; 23565743Spendry } */ *ap; 23665743Spendry { 23765743Spendry 23865743Spendry switch (ap->a_name) { 23965743Spendry case _PC_LINK_MAX: 24065743Spendry *ap->a_retval = LINK_MAX; 24165743Spendry return (0); 24265743Spendry case _PC_MAX_CANON: 24365743Spendry *ap->a_retval = MAX_CANON; 24465743Spendry return (0); 24565743Spendry case _PC_MAX_INPUT: 24665743Spendry *ap->a_retval = MAX_INPUT; 24765743Spendry return (0); 24865743Spendry case _PC_PIPE_BUF: 24965743Spendry *ap->a_retval = PIPE_BUF; 25065743Spendry return (0); 25165743Spendry case _PC_CHOWN_RESTRICTED: 25265743Spendry *ap->a_retval = 1; 25365743Spendry return (0); 25465743Spendry case _PC_VDISABLE: 25565743Spendry *ap->a_retval = _POSIX_VDISABLE; 25665743Spendry return (0); 25765743Spendry default: 25865743Spendry return (EINVAL); 25965743Spendry } 26065743Spendry /* NOTREACHED */ 26165743Spendry } 26265743Spendry 26365743Spendry /* 26465524Spendry * _print is used for debugging. 26565524Spendry * just print a readable description 26665524Spendry * of (vp). 26765524Spendry */ 26865524Spendry procfs_print(ap) 269*67367Smckusick struct vop_print_args /* { 270*67367Smckusick struct vnode *a_vp; 271*67367Smckusick } */ *ap; 27265524Spendry { 27365524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 27465524Spendry 27565524Spendry printf("tag VT_PROCFS, pid %d, mode %x, flags %x\n", 27665524Spendry pfs->pfs_pid, 27765524Spendry pfs->pfs_mode, pfs->pfs_flags); 27865524Spendry } 27965524Spendry 28065524Spendry /* 28165524Spendry * _abortop is called when operations such as 28265524Spendry * rename and create fail. this entry is responsible 28365524Spendry * for undoing any side-effects caused by the lookup. 28465524Spendry * this will always include freeing the pathname buffer. 28565524Spendry */ 28665524Spendry procfs_abortop(ap) 287*67367Smckusick struct vop_abortop_args /* { 288*67367Smckusick struct vnode *a_dvp; 289*67367Smckusick struct componentname *a_cnp; 290*67367Smckusick } */ *ap; 29165524Spendry { 29265524Spendry 29365524Spendry if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) 29465524Spendry FREE(ap->a_cnp->cn_pnbuf, M_NAMEI); 29565524Spendry return (0); 29665524Spendry } 29765524Spendry 29865524Spendry /* 29965524Spendry * generic entry point for unsupported operations 30065524Spendry */ 30165524Spendry procfs_badop() 30265524Spendry { 30365524Spendry 30465524Spendry return (EIO); 30565524Spendry } 30665524Spendry 30765524Spendry /* 30865524Spendry * Invent attributes for pfsnode (vp) and store 30965524Spendry * them in (vap). 31065524Spendry * Directories lengths are returned as zero since 31165524Spendry * any real length would require the genuine size 31265524Spendry * to be computed, and nothing cares anyway. 31365524Spendry * 31465524Spendry * this is relatively minimal for procfs. 31565524Spendry */ 31665524Spendry procfs_getattr(ap) 317*67367Smckusick struct vop_getattr_args /* { 318*67367Smckusick struct vnode *a_vp; 319*67367Smckusick struct vattr *a_vap; 320*67367Smckusick struct ucred *a_cred; 321*67367Smckusick struct proc *a_p; 322*67367Smckusick } */ *ap; 32365524Spendry { 32465524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 32565536Spendry struct vattr *vap = ap->a_vap; 32665524Spendry struct proc *procp; 32765524Spendry int error; 32865524Spendry 32965524Spendry /* first check the process still exists */ 33066025Spendry switch (pfs->pfs_type) { 33166025Spendry case Proot: 33266025Spendry procp = 0; 33366025Spendry break; 33465524Spendry 33566025Spendry default: 33666025Spendry procp = PFIND(pfs->pfs_pid); 33766025Spendry if (procp == 0) 33866025Spendry return (ENOENT); 33966025Spendry } 34066025Spendry 34165524Spendry error = 0; 34265524Spendry 34365524Spendry /* start by zeroing out the attributes */ 34465536Spendry VATTR_NULL(vap); 34565524Spendry 34665524Spendry /* next do all the common fields */ 34765536Spendry vap->va_type = ap->a_vp->v_type; 34865536Spendry vap->va_mode = pfs->pfs_mode; 34965536Spendry vap->va_fileid = pfs->pfs_fileno; 35065536Spendry vap->va_flags = 0; 35165536Spendry vap->va_blocksize = PAGE_SIZE; 35265536Spendry vap->va_bytes = vap->va_size = 0; 35365524Spendry 35465524Spendry /* 35566025Spendry * If the process has exercised some setuid or setgid 35666025Spendry * privilege, then rip away read/write permission so 35766025Spendry * that only root can gain access. 35866025Spendry */ 35966025Spendry switch (pfs->pfs_type) { 36066025Spendry case Pregs: 36166025Spendry case Pfpregs: 36266025Spendry case Pmem: 36366025Spendry if (procp->p_flag & P_SUGID) 36466025Spendry vap->va_mode &= ~((VREAD|VWRITE)| 36566025Spendry ((VREAD|VWRITE)>>3)| 36666025Spendry ((VREAD|VWRITE)>>6)); 36766025Spendry break; 36866025Spendry } 36966025Spendry 37066025Spendry /* 37165524Spendry * Make all times be current TOD. 37265524Spendry * It would be possible to get the process start 37365524Spendry * time from the p_stat structure, but there's 37465524Spendry * no "file creation" time stamp anyway, and the 37565524Spendry * p_stat structure is not addressible if u. gets 37665524Spendry * swapped out for that process. 37765524Spendry */ 37865536Spendry microtime(&vap->va_ctime); 37965536Spendry vap->va_atime = vap->va_mtime = vap->va_ctime; 38065524Spendry 38165524Spendry /* 38265524Spendry * now do the object specific fields 38365524Spendry * 38465524Spendry * The size could be set from struct reg, but it's hardly 38565524Spendry * worth the trouble, and it puts some (potentially) machine 38665524Spendry * dependent data into this machine-independent code. If it 38765524Spendry * becomes important then this function should break out into 38865524Spendry * a per-file stat function in the corresponding .c file. 38965524Spendry */ 39065524Spendry 39165524Spendry switch (pfs->pfs_type) { 39265524Spendry case Proot: 39365536Spendry vap->va_nlink = 2; 39465536Spendry vap->va_uid = 0; 39565536Spendry vap->va_gid = 0; 39665524Spendry break; 39765524Spendry 39865524Spendry case Pproc: 39965536Spendry vap->va_nlink = 2; 40065536Spendry vap->va_uid = procp->p_ucred->cr_uid; 40165536Spendry vap->va_gid = procp->p_ucred->cr_gid; 40265524Spendry break; 40365524Spendry 40465524Spendry case Pfile: 40565524Spendry error = EOPNOTSUPP; 40665524Spendry break; 40765524Spendry 40865524Spendry case Pmem: 40965536Spendry vap->va_nlink = 1; 41065536Spendry vap->va_bytes = vap->va_size = 41165524Spendry ctob(procp->p_vmspace->vm_tsize + 41265524Spendry procp->p_vmspace->vm_dsize + 41365524Spendry procp->p_vmspace->vm_ssize); 41465536Spendry vap->va_uid = procp->p_ucred->cr_uid; 41565536Spendry vap->va_gid = procp->p_ucred->cr_gid; 41665524Spendry break; 41765524Spendry 41865524Spendry case Pregs: 41965924Spendry case Pfpregs: 42065524Spendry case Pctl: 42165524Spendry case Pstatus: 42265524Spendry case Pnote: 42365524Spendry case Pnotepg: 42465536Spendry vap->va_nlink = 1; 42565536Spendry vap->va_uid = procp->p_ucred->cr_uid; 42665536Spendry vap->va_gid = procp->p_ucred->cr_gid; 42765524Spendry break; 42865524Spendry 42965524Spendry default: 43065524Spendry panic("procfs_getattr"); 43165524Spendry } 43265524Spendry 43365524Spendry return (error); 43465524Spendry } 43565524Spendry 43665524Spendry procfs_setattr(ap) 437*67367Smckusick struct vop_setattr_args /* { 438*67367Smckusick struct vnode *a_vp; 439*67367Smckusick struct vattr *a_vap; 440*67367Smckusick struct ucred *a_cred; 441*67367Smckusick struct proc *a_p; 442*67367Smckusick } */ *ap; 44365524Spendry { 44465524Spendry /* 44565524Spendry * just fake out attribute setting 44665524Spendry * it's not good to generate an error 44765524Spendry * return, otherwise things like creat() 44865524Spendry * will fail when they try to set the 44965524Spendry * file length to 0. worse, this means 45065524Spendry * that echo $note > /proc/$pid/note will fail. 45165524Spendry */ 45265524Spendry 45365524Spendry return (0); 45465524Spendry } 45565524Spendry 45665524Spendry /* 45765524Spendry * implement access checking. 45865524Spendry * 45965524Spendry * something very similar to this code is duplicated 46065524Spendry * throughout the 4bsd kernel and should be moved 46165524Spendry * into kern/vfs_subr.c sometime. 46265524Spendry * 46365524Spendry * actually, the check for super-user is slightly 46465524Spendry * broken since it will allow read access to write-only 46565524Spendry * objects. this doesn't cause any particular trouble 46665524Spendry * but does mean that the i/o entry points need to check 46765524Spendry * that the operation really does make sense. 46865524Spendry */ 46965524Spendry procfs_access(ap) 470*67367Smckusick struct vop_access_args /* { 471*67367Smckusick struct vnode *a_vp; 472*67367Smckusick int a_mode; 473*67367Smckusick struct ucred *a_cred; 474*67367Smckusick struct proc *a_p; 475*67367Smckusick } */ *ap; 47665524Spendry { 47765524Spendry struct vattr *vap; 47865524Spendry struct vattr vattr; 47965524Spendry int error; 48065524Spendry 48165524Spendry /* 48265524Spendry * If you're the super-user, 48365524Spendry * you always get access. 48465524Spendry */ 48565524Spendry if (ap->a_cred->cr_uid == (uid_t) 0) 48665524Spendry return (0); 48765524Spendry vap = &vattr; 48865524Spendry if (error = VOP_GETATTR(ap->a_vp, vap, ap->a_cred, ap->a_p)) 48965524Spendry return (error); 49065524Spendry 49165524Spendry /* 49265524Spendry * Access check is based on only one of owner, group, public. 49365524Spendry * If not owner, then check group. If not a member of the 49465524Spendry * group, then check public access. 49565524Spendry */ 49665524Spendry if (ap->a_cred->cr_uid != vap->va_uid) { 49765524Spendry gid_t *gp; 49865524Spendry int i; 49965524Spendry 50065524Spendry (ap->a_mode) >>= 3; 50165524Spendry gp = ap->a_cred->cr_groups; 50265524Spendry for (i = 0; i < ap->a_cred->cr_ngroups; i++, gp++) 50365524Spendry if (vap->va_gid == *gp) 50465524Spendry goto found; 50565524Spendry ap->a_mode >>= 3; 50665524Spendry found: 50765524Spendry ; 50865524Spendry } 50965524Spendry 51065524Spendry if ((vap->va_mode & ap->a_mode) == ap->a_mode) 51165524Spendry return (0); 51265524Spendry 51365524Spendry return (EACCES); 51465524Spendry } 51565524Spendry 51665524Spendry /* 51765524Spendry * lookup. this is incredibly complicated in the 51865524Spendry * general case, however for most pseudo-filesystems 51965524Spendry * very little needs to be done. 52065524Spendry * 52165524Spendry * unless you want to get a migraine, just make sure your 52265524Spendry * filesystem doesn't do any locking of its own. otherwise 52365524Spendry * read and inwardly digest ufs_lookup(). 52465524Spendry */ 52565524Spendry procfs_lookup(ap) 526*67367Smckusick struct vop_lookup_args /* { 527*67367Smckusick struct vnode * a_dvp; 528*67367Smckusick struct vnode ** a_vpp; 529*67367Smckusick struct componentname * a_cnp; 530*67367Smckusick } */ *ap; 53165524Spendry { 53265524Spendry struct componentname *cnp = ap->a_cnp; 53365524Spendry struct vnode **vpp = ap->a_vpp; 53465524Spendry struct vnode *dvp = ap->a_dvp; 53565524Spendry char *pname = cnp->cn_nameptr; 53665524Spendry int error = 0; 53765524Spendry pid_t pid; 53865524Spendry struct vnode *nvp; 53965524Spendry struct pfsnode *pfs; 54065524Spendry struct proc *procp; 54165524Spendry pfstype pfs_type; 54265524Spendry int i; 54365524Spendry 54465524Spendry if (cnp->cn_namelen == 1 && *pname == '.') { 54565524Spendry *vpp = dvp; 54665524Spendry VREF(dvp); 54765524Spendry /*VOP_LOCK(dvp);*/ 54865524Spendry return (0); 54965524Spendry } 55065524Spendry 55165524Spendry *vpp = NULL; 55265524Spendry 55365524Spendry pfs = VTOPFS(dvp); 55465524Spendry switch (pfs->pfs_type) { 55565524Spendry case Proot: 55665524Spendry if (cnp->cn_flags & ISDOTDOT) 55765524Spendry return (EIO); 55865524Spendry 55965524Spendry if (CNEQ(cnp, "curproc", 7)) 56065524Spendry pid = cnp->cn_proc->p_pid; 56165524Spendry else 56265524Spendry pid = atopid(pname, cnp->cn_namelen); 56365524Spendry if (pid == NO_PID) 56465524Spendry return (ENOENT); 56565524Spendry 56665524Spendry procp = PFIND(pid); 56765524Spendry if (procp == 0) 56865524Spendry return (ENOENT); 56965524Spendry 57065524Spendry error = procfs_allocvp(dvp->v_mount, &nvp, pid, Pproc); 57165524Spendry if (error) 57265524Spendry return (error); 57365524Spendry 57465524Spendry nvp->v_type = VDIR; 57565524Spendry pfs = VTOPFS(nvp); 57665524Spendry 57765524Spendry *vpp = nvp; 57865524Spendry return (0); 57965524Spendry 58065524Spendry case Pproc: 58165524Spendry if (cnp->cn_flags & ISDOTDOT) { 58265524Spendry error = procfs_root(dvp->v_mount, vpp); 58365524Spendry return (error); 58465524Spendry } 58565524Spendry 58665524Spendry procp = PFIND(pfs->pfs_pid); 58765524Spendry if (procp == 0) 58865524Spendry return (ENOENT); 58965524Spendry 59065524Spendry for (i = 0; i < Nprocent; i++) { 59165524Spendry struct pfsnames *dp = &procent[i]; 59265524Spendry 59365524Spendry if (cnp->cn_namelen == dp->d_namlen && 59465524Spendry bcmp(pname, dp->d_name, dp->d_namlen) == 0) { 59565524Spendry pfs_type = dp->d_pfstype; 59665524Spendry goto found; 59765524Spendry } 59865524Spendry } 59965524Spendry return (ENOENT); 60065524Spendry 60165524Spendry found: 60265524Spendry if (pfs_type == Pfile) { 60365524Spendry nvp = procfs_findtextvp(procp); 60465524Spendry if (nvp) { 60565524Spendry VREF(nvp); 60665524Spendry VOP_LOCK(nvp); 60765524Spendry } else { 60865524Spendry error = ENXIO; 60965524Spendry } 61065524Spendry } else { 61165524Spendry error = procfs_allocvp(dvp->v_mount, &nvp, 61265524Spendry pfs->pfs_pid, pfs_type); 61365524Spendry if (error) 61465524Spendry return (error); 61565524Spendry 61665524Spendry nvp->v_type = VREG; 61765524Spendry pfs = VTOPFS(nvp); 61865524Spendry } 61965524Spendry *vpp = nvp; 62065524Spendry return (error); 62165524Spendry 62265524Spendry default: 62365524Spendry return (ENOTDIR); 62465524Spendry } 62565524Spendry } 62665524Spendry 62765524Spendry /* 62865524Spendry * readdir returns directory entries from pfsnode (vp). 62965524Spendry * 63065524Spendry * the strategy here with procfs is to generate a single 63165524Spendry * directory entry at a time (struct pfsdent) and then 63265524Spendry * copy that out to userland using uiomove. a more efficent 63365524Spendry * though more complex implementation, would try to minimize 63465524Spendry * the number of calls to uiomove(). for procfs, this is 63565524Spendry * hardly worth the added code complexity. 63665524Spendry * 63765524Spendry * this should just be done through read() 63865524Spendry */ 63965524Spendry procfs_readdir(ap) 640*67367Smckusick struct vop_readdir_args /* { 641*67367Smckusick struct vnode *a_vp; 642*67367Smckusick struct uio *a_uio; 643*67367Smckusick struct ucred *a_cred; 644*67367Smckusick int *a_eofflag; 645*67367Smckusick u_long *a_cookies; 646*67367Smckusick int a_ncookies; 647*67367Smckusick } */ *ap; 64865524Spendry { 64965524Spendry struct uio *uio = ap->a_uio; 65065524Spendry struct pfsdent d; 65165524Spendry struct pfsdent *dp = &d; 65265524Spendry struct pfsnode *pfs; 65365524Spendry int error; 65465524Spendry int count; 65565524Spendry int i; 65665524Spendry 657*67367Smckusick /* 658*67367Smckusick * We don't allow exporting procfs mounts, and currently local 659*67367Smckusick * requests do not need cookies. 660*67367Smckusick */ 661*67367Smckusick if (ap->a_ncookies) 662*67367Smckusick panic("procfs_readdir: not hungry"); 663*67367Smckusick 66465524Spendry pfs = VTOPFS(ap->a_vp); 66565524Spendry 66665524Spendry if (uio->uio_resid < UIO_MX) 66765524Spendry return (EINVAL); 66865524Spendry if (uio->uio_offset & (UIO_MX-1)) 66965524Spendry return (EINVAL); 67065524Spendry if (uio->uio_offset < 0) 67165524Spendry return (EINVAL); 67265524Spendry 67365524Spendry error = 0; 67465524Spendry count = 0; 67565524Spendry i = uio->uio_offset / UIO_MX; 67665524Spendry 67765524Spendry switch (pfs->pfs_type) { 67865524Spendry /* 67965524Spendry * this is for the process-specific sub-directories. 68065524Spendry * all that is needed to is copy out all the entries 68165524Spendry * from the procent[] table (top of this file). 68265524Spendry */ 68365524Spendry case Pproc: { 68465524Spendry while (uio->uio_resid >= UIO_MX) { 68565524Spendry struct pfsnames *dt; 68665524Spendry 68765524Spendry if (i >= Nprocent) 68865524Spendry break; 68965524Spendry 69065524Spendry dt = &procent[i]; 69165524Spendry 69265524Spendry dp->d_reclen = UIO_MX; 69365524Spendry dp->d_fileno = PROCFS_FILENO(pfs->pfs_pid, dt->d_pfstype); 69465524Spendry dp->d_type = DT_REG; 69565524Spendry dp->d_namlen = dt->d_namlen; 69665524Spendry bcopy(dt->d_name, dp->d_name, sizeof(dt->d_name)-1); 69765524Spendry error = uiomove((caddr_t) dp, UIO_MX, uio); 69865524Spendry if (error) 69965524Spendry break; 70065524Spendry count += UIO_MX; 70165524Spendry i++; 70265524Spendry } 70365524Spendry 70465524Spendry break; 70565524Spendry 70665524Spendry } 70765524Spendry 70865524Spendry /* 70965524Spendry * this is for the root of the procfs filesystem 71065524Spendry * what is needed is a special entry for "curproc" 71165524Spendry * followed by an entry for each process on allproc 71265524Spendry #ifdef PROCFS_ZOMBIE 71365524Spendry * and zombproc. 71465524Spendry #endif 71565524Spendry */ 71665524Spendry 71765524Spendry case Proot: { 71865524Spendry int pcnt; 71965524Spendry #ifdef PROCFS_ZOMBIE 72065524Spendry int doingzomb = 0; 72165524Spendry #endif 72265524Spendry volatile struct proc *p; 72365524Spendry 72465524Spendry p = allproc; 72565524Spendry 72665524Spendry #define PROCFS_XFILES 1 /* number of other entries, like "curproc" */ 72765524Spendry pcnt = PROCFS_XFILES; 72865524Spendry 72965524Spendry while (p && uio->uio_resid >= UIO_MX) { 73065524Spendry bzero((char *) dp, UIO_MX); 73165524Spendry dp->d_type = DT_DIR; 73265524Spendry dp->d_reclen = UIO_MX; 73365524Spendry 73465524Spendry switch (i) { 73565524Spendry case 0: 73665524Spendry /* ship out entry for "curproc" */ 73765524Spendry dp->d_fileno = PROCFS_FILENO(PID_MAX+1, Pproc); 73865536Spendry dp->d_namlen = sprintf(dp->d_name, "curproc"); 73965524Spendry break; 74065524Spendry 74165524Spendry default: 74265524Spendry if (pcnt >= i) { 74365524Spendry dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc); 74465524Spendry dp->d_namlen = sprintf(dp->d_name, "%ld", (long) p->p_pid); 74565524Spendry } 74665524Spendry 74765524Spendry p = p->p_next; 74865524Spendry 74965524Spendry #ifdef PROCFS_ZOMBIE 75065524Spendry if (p == 0 && doingzomb == 0) { 75165524Spendry doingzomb = 1; 75265524Spendry p = zombproc; 75365524Spendry } 75465524Spendry #endif 75565524Spendry 75665524Spendry if (pcnt++ < i) 75765524Spendry continue; 75865524Spendry 75965524Spendry break; 76065524Spendry } 76165524Spendry error = uiomove((caddr_t) dp, UIO_MX, uio); 76265524Spendry if (error) 76365524Spendry break; 76465524Spendry count += UIO_MX; 76565524Spendry i++; 76665524Spendry } 76765524Spendry 76865524Spendry break; 76965524Spendry 77065524Spendry } 77165524Spendry 77265524Spendry default: 77365524Spendry error = ENOTDIR; 77465524Spendry break; 77565524Spendry } 77665524Spendry 77765524Spendry uio->uio_offset = i * UIO_MX; 77865524Spendry 77965524Spendry return (error); 78065524Spendry } 78165524Spendry 78265524Spendry /* 78365524Spendry * convert decimal ascii to pid_t 78465524Spendry */ 78565524Spendry static pid_t 78665524Spendry atopid(b, len) 78765524Spendry const char *b; 78865524Spendry u_int len; 78965524Spendry { 79065524Spendry pid_t p = 0; 79165524Spendry 79265524Spendry while (len--) { 79365524Spendry char c = *b++; 79465524Spendry if (c < '0' || c > '9') 79565524Spendry return (NO_PID); 79665524Spendry p = 10 * p + (c - '0'); 79765524Spendry if (p > PID_MAX) 79865524Spendry return (NO_PID); 79965524Spendry } 80065524Spendry 80165524Spendry return (p); 80265524Spendry } 80365524Spendry 80465524Spendry /* 80565524Spendry * procfs vnode operations. 80665524Spendry */ 80765524Spendry int (**procfs_vnodeop_p)(); 80865524Spendry struct vnodeopv_entry_desc procfs_vnodeop_entries[] = { 80965524Spendry { &vop_default_desc, vn_default_error }, 81065524Spendry { &vop_lookup_desc, procfs_lookup }, /* lookup */ 81165524Spendry { &vop_create_desc, procfs_create }, /* create */ 81265524Spendry { &vop_mknod_desc, procfs_mknod }, /* mknod */ 81365524Spendry { &vop_open_desc, procfs_open }, /* open */ 81465524Spendry { &vop_close_desc, procfs_close }, /* close */ 81565524Spendry { &vop_access_desc, procfs_access }, /* access */ 81665524Spendry { &vop_getattr_desc, procfs_getattr }, /* getattr */ 81765524Spendry { &vop_setattr_desc, procfs_setattr }, /* setattr */ 81865524Spendry { &vop_read_desc, procfs_read }, /* read */ 81965524Spendry { &vop_write_desc, procfs_write }, /* write */ 82065524Spendry { &vop_ioctl_desc, procfs_ioctl }, /* ioctl */ 82165524Spendry { &vop_select_desc, procfs_select }, /* select */ 82265524Spendry { &vop_mmap_desc, procfs_mmap }, /* mmap */ 82365524Spendry { &vop_fsync_desc, procfs_fsync }, /* fsync */ 82465524Spendry { &vop_seek_desc, procfs_seek }, /* seek */ 82565524Spendry { &vop_remove_desc, procfs_remove }, /* remove */ 82665524Spendry { &vop_link_desc, procfs_link }, /* link */ 82765524Spendry { &vop_rename_desc, procfs_rename }, /* rename */ 82865524Spendry { &vop_mkdir_desc, procfs_mkdir }, /* mkdir */ 82965524Spendry { &vop_rmdir_desc, procfs_rmdir }, /* rmdir */ 83065524Spendry { &vop_symlink_desc, procfs_symlink }, /* symlink */ 83165524Spendry { &vop_readdir_desc, procfs_readdir }, /* readdir */ 83265524Spendry { &vop_readlink_desc, procfs_readlink }, /* readlink */ 83365524Spendry { &vop_abortop_desc, procfs_abortop }, /* abortop */ 83465524Spendry { &vop_inactive_desc, procfs_inactive }, /* inactive */ 83565524Spendry { &vop_reclaim_desc, procfs_reclaim }, /* reclaim */ 83665524Spendry { &vop_lock_desc, procfs_lock }, /* lock */ 83765524Spendry { &vop_unlock_desc, procfs_unlock }, /* unlock */ 83865524Spendry { &vop_bmap_desc, procfs_bmap }, /* bmap */ 83965524Spendry { &vop_strategy_desc, procfs_strategy }, /* strategy */ 84065524Spendry { &vop_print_desc, procfs_print }, /* print */ 84165524Spendry { &vop_islocked_desc, procfs_islocked }, /* islocked */ 84265524Spendry { &vop_pathconf_desc, procfs_pathconf }, /* pathconf */ 84365524Spendry { &vop_advlock_desc, procfs_advlock }, /* advlock */ 84465524Spendry { &vop_blkatoff_desc, procfs_blkatoff }, /* blkatoff */ 84565524Spendry { &vop_valloc_desc, procfs_valloc }, /* valloc */ 84665524Spendry { &vop_vfree_desc, procfs_vfree }, /* vfree */ 84765524Spendry { &vop_truncate_desc, procfs_truncate }, /* truncate */ 84865524Spendry { &vop_update_desc, procfs_update }, /* update */ 84965524Spendry { (struct vnodeop_desc*)NULL, (int(*)())NULL } 85065524Spendry }; 85165524Spendry struct vnodeopv_desc procfs_vnodeop_opv_desc = 85265524Spendry { &procfs_vnodeop_p, procfs_vnodeop_entries }; 853