165524Spendry /* 268232Spendry * Copyright (c) 1993, 1995 Jan-Simon Pendry 368232Spendry * Copyright (c) 1993, 1995 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*69442Smckusick * @(#)procfs_vnops.c 8.17 (Berkeley) 05/14/95 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> 3267389Spendry #include <vm/vm.h> /* for PAGE_SIZE */ 3367389Spendry #include <machine/reg.h> 3465524Spendry #include <miscfs/procfs/procfs.h> 3565524Spendry 3665524Spendry /* 3765524Spendry * Vnode Operations. 3865524Spendry * 3965524Spendry */ 4065524Spendry 4165524Spendry /* 4265524Spendry * This is a list of the valid names in the 4365524Spendry * process-specific sub-directories. It is 4465524Spendry * used in procfs_lookup and procfs_readdir 4565524Spendry */ 4669351Smckusick struct proc_target { 4769351Smckusick u_char pt_type; 4869351Smckusick u_char pt_namlen; 4969351Smckusick char *pt_name; 5069351Smckusick pfstype pt_pfstype; 5169351Smckusick int (*pt_valid) __P((struct proc *p)); 5269351Smckusick } proc_targets[] = { 5365524Spendry #define N(s) sizeof(s)-1, s 5469351Smckusick /* name type validp */ 5567389Spendry { DT_DIR, N("."), Pproc, NULL }, 5667389Spendry { DT_DIR, N(".."), Proot, NULL }, 5767389Spendry { DT_REG, N("file"), Pfile, procfs_validfile }, 5867389Spendry { DT_REG, N("mem"), Pmem, NULL }, 5967389Spendry { DT_REG, N("regs"), Pregs, procfs_validregs }, 6067389Spendry { DT_REG, N("fpregs"), Pfpregs, procfs_validfpregs }, 6167389Spendry { DT_REG, N("ctl"), Pctl, NULL }, 6267389Spendry { DT_REG, N("status"), Pstatus, NULL }, 6367389Spendry { DT_REG, N("note"), Pnote, NULL }, 6467389Spendry { DT_REG, N("notepg"), Pnotepg, NULL }, 6565524Spendry #undef N 6665524Spendry }; 6769351Smckusick static int nproc_targets = sizeof(proc_targets) / sizeof(proc_targets[0]); 6865524Spendry 6965524Spendry static pid_t atopid __P((const char *, u_int)); 7065524Spendry 7165524Spendry /* 7265524Spendry * set things up for doing i/o on 7365524Spendry * the pfsnode (vp). (vp) is locked 7465524Spendry * on entry, and should be left locked 7565524Spendry * on exit. 7665524Spendry * 7765524Spendry * for procfs we don't need to do anything 7865524Spendry * in particular for i/o. all that is done 7965524Spendry * is to support exclusive open on process 8065524Spendry * memory images. 8165524Spendry */ 8265524Spendry procfs_open(ap) 8367367Smckusick struct vop_open_args /* { 8467367Smckusick struct vnode *a_vp; 8567367Smckusick int a_mode; 8667367Smckusick struct ucred *a_cred; 8767367Smckusick struct proc *a_p; 8867367Smckusick } */ *ap; 8965524Spendry { 9065524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 9165524Spendry 9265524Spendry switch (pfs->pfs_type) { 9365524Spendry case Pmem: 9465524Spendry if (PFIND(pfs->pfs_pid) == 0) 9565524Spendry return (ENOENT); /* was ESRCH, jsp */ 9665524Spendry 9765524Spendry if ((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL) || 9867389Spendry (pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE)) 9965524Spendry return (EBUSY); 10065524Spendry 10165524Spendry if (ap->a_mode & FWRITE) 10265524Spendry pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL); 10365524Spendry 10465524Spendry return (0); 10565524Spendry 10665524Spendry default: 10765524Spendry break; 10865524Spendry } 10965524Spendry 11065524Spendry return (0); 11165524Spendry } 11265524Spendry 11365524Spendry /* 11465524Spendry * close the pfsnode (vp) after doing i/o. 11565524Spendry * (vp) is not locked on entry or exit. 11665524Spendry * 11765524Spendry * nothing to do for procfs other than undo 11865524Spendry * any exclusive open flag (see _open above). 11965524Spendry */ 12065524Spendry procfs_close(ap) 12167367Smckusick struct vop_close_args /* { 12267367Smckusick struct vnode *a_vp; 12367367Smckusick int a_fflag; 12467367Smckusick struct ucred *a_cred; 12567367Smckusick struct proc *a_p; 12667367Smckusick } */ *ap; 12765524Spendry { 12865524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 12965524Spendry 13065524Spendry switch (pfs->pfs_type) { 13165524Spendry case Pmem: 13265524Spendry if ((ap->a_fflag & FWRITE) && (pfs->pfs_flags & O_EXCL)) 13365524Spendry pfs->pfs_flags &= ~(FWRITE|O_EXCL); 13465524Spendry break; 13565524Spendry } 13665524Spendry 13765524Spendry return (0); 13865524Spendry } 13965524Spendry 14065524Spendry /* 14165524Spendry * do an ioctl operation on pfsnode (vp). 14265524Spendry * (vp) is not locked on entry or exit. 14365524Spendry */ 14465524Spendry procfs_ioctl(ap) 14567367Smckusick struct vop_ioctl_args /* { 14667367Smckusick struct vnode *a_vp; 14767367Smckusick int a_command; 14867367Smckusick caddr_t a_data; 14967367Smckusick int a_fflag; 15067367Smckusick struct ucred *a_cred; 15167367Smckusick struct proc *a_p; 15267367Smckusick } */ *ap; 15365524Spendry { 15465524Spendry 15565524Spendry return (ENOTTY); 15665524Spendry } 15765524Spendry 15865524Spendry /* 15965524Spendry * do block mapping for pfsnode (vp). 16065524Spendry * since we don't use the buffer cache 16165524Spendry * for procfs this function should never 16265524Spendry * be called. in any case, it's not clear 16365524Spendry * what part of the kernel ever makes use 16465524Spendry * of this function. for sanity, this is the 16565524Spendry * usual no-op bmap, although returning 16665524Spendry * (EIO) would be a reasonable alternative. 16765524Spendry */ 16865524Spendry procfs_bmap(ap) 16967367Smckusick struct vop_bmap_args /* { 17067367Smckusick struct vnode *a_vp; 17167367Smckusick daddr_t a_bn; 17267367Smckusick struct vnode **a_vpp; 17367367Smckusick daddr_t *a_bnp; 17468232Spendry int *a_runp; 17567367Smckusick } */ *ap; 17665524Spendry { 17765524Spendry 17865524Spendry if (ap->a_vpp != NULL) 17965524Spendry *ap->a_vpp = ap->a_vp; 18065524Spendry if (ap->a_bnp != NULL) 18165524Spendry *ap->a_bnp = ap->a_bn; 18268230Spendry if (ap->a_runp != NULL) 18368230Spendry *ap->a_runp = 0; 18465524Spendry return (0); 18565524Spendry } 18665524Spendry 18765524Spendry /* 18865524Spendry * _inactive is called when the pfsnode 18965524Spendry * is vrele'd and the reference count goes 19065524Spendry * to zero. (vp) will be on the vnode free 19165524Spendry * list, so to get it back vget() must be 19265524Spendry * used. 19365524Spendry * 19465524Spendry * for procfs, check if the process is still 19565524Spendry * alive and if it isn't then just throw away 19669362Spendry * the vnode by calling vgone(). this may 19765524Spendry * be overkill and a waste of time since the 19865524Spendry * chances are that the process will still be 19965524Spendry * there and PFIND is not free. 20065524Spendry * 20165524Spendry * (vp) is not locked on entry or exit. 20265524Spendry */ 20365524Spendry procfs_inactive(ap) 20467367Smckusick struct vop_inactive_args /* { 20567367Smckusick struct vnode *a_vp; 20667367Smckusick } */ *ap; 20765524Spendry { 20865524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 20965524Spendry 21065524Spendry if (PFIND(pfs->pfs_pid) == 0) 21169362Spendry vgone(ap->a_vp); 21265524Spendry 21365524Spendry return (0); 21465524Spendry } 21565524Spendry 21665524Spendry /* 21765524Spendry * _reclaim is called when getnewvnode() 21865524Spendry * wants to make use of an entry on the vnode 21965524Spendry * free list. at this time the filesystem needs 22065524Spendry * to free any private data and remove the node 22165524Spendry * from any private lists. 22265524Spendry */ 22365524Spendry procfs_reclaim(ap) 22467367Smckusick struct vop_reclaim_args /* { 22567367Smckusick struct vnode *a_vp; 22667367Smckusick } */ *ap; 22765524Spendry { 22865524Spendry 22967389Spendry return (procfs_freevp(ap->a_vp)); 23065524Spendry } 23165524Spendry 23265524Spendry /* 23365743Spendry * Return POSIX pathconf information applicable to special devices. 23465743Spendry */ 23565743Spendry procfs_pathconf(ap) 23665743Spendry struct vop_pathconf_args /* { 23765743Spendry struct vnode *a_vp; 23865743Spendry int a_name; 23965743Spendry int *a_retval; 24065743Spendry } */ *ap; 24165743Spendry { 24265743Spendry 24365743Spendry switch (ap->a_name) { 24465743Spendry case _PC_LINK_MAX: 24565743Spendry *ap->a_retval = LINK_MAX; 24665743Spendry return (0); 24765743Spendry case _PC_MAX_CANON: 24865743Spendry *ap->a_retval = MAX_CANON; 24965743Spendry return (0); 25065743Spendry case _PC_MAX_INPUT: 25165743Spendry *ap->a_retval = MAX_INPUT; 25265743Spendry return (0); 25365743Spendry case _PC_PIPE_BUF: 25465743Spendry *ap->a_retval = PIPE_BUF; 25565743Spendry return (0); 25665743Spendry case _PC_CHOWN_RESTRICTED: 25765743Spendry *ap->a_retval = 1; 25865743Spendry return (0); 25965743Spendry case _PC_VDISABLE: 26065743Spendry *ap->a_retval = _POSIX_VDISABLE; 26165743Spendry return (0); 26265743Spendry default: 26365743Spendry return (EINVAL); 26465743Spendry } 26565743Spendry /* NOTREACHED */ 26665743Spendry } 26765743Spendry 26865743Spendry /* 26965524Spendry * _print is used for debugging. 27065524Spendry * just print a readable description 27165524Spendry * of (vp). 27265524Spendry */ 27365524Spendry procfs_print(ap) 27467367Smckusick struct vop_print_args /* { 27567367Smckusick struct vnode *a_vp; 27667367Smckusick } */ *ap; 27765524Spendry { 27865524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 27965524Spendry 28067389Spendry printf("tag VT_PROCFS, type %s, pid %d, mode %x, flags %x\n", 28167389Spendry pfs->pfs_type, pfs->pfs_pid, pfs->pfs_mode, pfs->pfs_flags); 28265524Spendry } 28365524Spendry 28465524Spendry /* 28565524Spendry * _abortop is called when operations such as 28665524Spendry * rename and create fail. this entry is responsible 28765524Spendry * for undoing any side-effects caused by the lookup. 28865524Spendry * this will always include freeing the pathname buffer. 28965524Spendry */ 29065524Spendry procfs_abortop(ap) 29167367Smckusick struct vop_abortop_args /* { 29267367Smckusick struct vnode *a_dvp; 29367367Smckusick struct componentname *a_cnp; 29467367Smckusick } */ *ap; 29565524Spendry { 29665524Spendry 29765524Spendry if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) 29865524Spendry FREE(ap->a_cnp->cn_pnbuf, M_NAMEI); 29965524Spendry return (0); 30065524Spendry } 30165524Spendry 30265524Spendry /* 30365524Spendry * generic entry point for unsupported operations 30465524Spendry */ 30565524Spendry procfs_badop() 30665524Spendry { 30765524Spendry 30865524Spendry return (EIO); 30965524Spendry } 31065524Spendry 31165524Spendry /* 31265524Spendry * Invent attributes for pfsnode (vp) and store 31365524Spendry * them in (vap). 31465524Spendry * Directories lengths are returned as zero since 31565524Spendry * any real length would require the genuine size 31665524Spendry * to be computed, and nothing cares anyway. 31765524Spendry * 31865524Spendry * this is relatively minimal for procfs. 31965524Spendry */ 32065524Spendry procfs_getattr(ap) 32167367Smckusick struct vop_getattr_args /* { 32267367Smckusick struct vnode *a_vp; 32367367Smckusick struct vattr *a_vap; 32467367Smckusick struct ucred *a_cred; 32567367Smckusick struct proc *a_p; 32667367Smckusick } */ *ap; 32765524Spendry { 32865524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 32965536Spendry struct vattr *vap = ap->a_vap; 33065524Spendry struct proc *procp; 33168174Scgd struct timeval tv; 33265524Spendry int error; 33365524Spendry 33465524Spendry /* first check the process still exists */ 33566025Spendry switch (pfs->pfs_type) { 33666025Spendry case Proot: 33767389Spendry case Pcurproc: 33866025Spendry procp = 0; 33966025Spendry break; 34065524Spendry 34166025Spendry default: 34266025Spendry procp = PFIND(pfs->pfs_pid); 34366025Spendry if (procp == 0) 34466025Spendry return (ENOENT); 34566025Spendry } 34666025Spendry 34765524Spendry error = 0; 34865524Spendry 34965524Spendry /* start by zeroing out the attributes */ 35065536Spendry VATTR_NULL(vap); 35165524Spendry 35265524Spendry /* next do all the common fields */ 35365536Spendry vap->va_type = ap->a_vp->v_type; 35465536Spendry vap->va_mode = pfs->pfs_mode; 35565536Spendry vap->va_fileid = pfs->pfs_fileno; 35665536Spendry vap->va_flags = 0; 35765536Spendry vap->va_blocksize = PAGE_SIZE; 35865536Spendry vap->va_bytes = vap->va_size = 0; 35965524Spendry 36065524Spendry /* 36167389Spendry * Make all times be current TOD. 36267389Spendry * It would be possible to get the process start 36367389Spendry * time from the p_stat structure, but there's 36467389Spendry * no "file creation" time stamp anyway, and the 36567389Spendry * p_stat structure is not addressible if u. gets 36667389Spendry * swapped out for that process. 36767389Spendry */ 36868174Scgd microtime(&tv); 36968174Scgd TIMEVAL_TO_TIMESPEC(&tv, &vap->va_ctime); 37067389Spendry vap->va_atime = vap->va_mtime = vap->va_ctime; 37167389Spendry 37267389Spendry /* 37366025Spendry * If the process has exercised some setuid or setgid 37466025Spendry * privilege, then rip away read/write permission so 37566025Spendry * that only root can gain access. 37666025Spendry */ 37766025Spendry switch (pfs->pfs_type) { 37867389Spendry case Pmem: 37966025Spendry case Pregs: 38066025Spendry case Pfpregs: 38166025Spendry if (procp->p_flag & P_SUGID) 38266025Spendry vap->va_mode &= ~((VREAD|VWRITE)| 38366025Spendry ((VREAD|VWRITE)>>3)| 38466025Spendry ((VREAD|VWRITE)>>6)); 38567389Spendry case Pctl: 38667389Spendry case Pstatus: 38767389Spendry case Pnote: 38867389Spendry case Pnotepg: 38967389Spendry vap->va_nlink = 1; 39067389Spendry vap->va_uid = procp->p_ucred->cr_uid; 39167389Spendry vap->va_gid = procp->p_ucred->cr_gid; 39266025Spendry break; 39366025Spendry } 39466025Spendry 39566025Spendry /* 39665524Spendry * now do the object specific fields 39765524Spendry * 39865524Spendry * The size could be set from struct reg, but it's hardly 39965524Spendry * worth the trouble, and it puts some (potentially) machine 40065524Spendry * dependent data into this machine-independent code. If it 40165524Spendry * becomes important then this function should break out into 40265524Spendry * a per-file stat function in the corresponding .c file. 40365524Spendry */ 40465524Spendry 40565524Spendry switch (pfs->pfs_type) { 40665524Spendry case Proot: 40767389Spendry /* 40867389Spendry * Set nlink to 1 to tell fts(3) we don't actually know. 40967389Spendry */ 41067389Spendry vap->va_nlink = 1; 41165536Spendry vap->va_uid = 0; 41265536Spendry vap->va_gid = 0; 41367389Spendry vap->va_size = vap->va_bytes = DEV_BSIZE; 41465524Spendry break; 41565524Spendry 41667389Spendry case Pcurproc: { 41767389Spendry char buf[16]; /* should be enough */ 41867389Spendry vap->va_nlink = 1; 41967389Spendry vap->va_uid = 0; 42067389Spendry vap->va_gid = 0; 42167389Spendry vap->va_size = vap->va_bytes = 42267389Spendry sprintf(buf, "%ld", (long)curproc->p_pid); 42367389Spendry break; 42467389Spendry } 42567389Spendry 42665524Spendry case Pproc: 42765536Spendry vap->va_nlink = 2; 42865536Spendry vap->va_uid = procp->p_ucred->cr_uid; 42965536Spendry vap->va_gid = procp->p_ucred->cr_gid; 43067389Spendry vap->va_size = vap->va_bytes = DEV_BSIZE; 43165524Spendry break; 43265524Spendry 43365524Spendry case Pfile: 43465524Spendry error = EOPNOTSUPP; 43565524Spendry break; 43665524Spendry 43765524Spendry case Pmem: 43865536Spendry vap->va_bytes = vap->va_size = 43965524Spendry ctob(procp->p_vmspace->vm_tsize + 44065524Spendry procp->p_vmspace->vm_dsize + 44165524Spendry procp->p_vmspace->vm_ssize); 44265524Spendry break; 44365524Spendry 44465524Spendry case Pregs: 44567389Spendry vap->va_bytes = vap->va_size = sizeof(struct reg); 44667389Spendry break; 44767389Spendry 44865924Spendry case Pfpregs: 44967389Spendry vap->va_bytes = vap->va_size = sizeof(struct fpreg); 45067389Spendry break; 45167389Spendry 45265524Spendry case Pctl: 45365524Spendry case Pstatus: 45465524Spendry case Pnote: 45565524Spendry case Pnotepg: 45665524Spendry break; 45765524Spendry 45865524Spendry default: 45965524Spendry panic("procfs_getattr"); 46065524Spendry } 46165524Spendry 46265524Spendry return (error); 46365524Spendry } 46465524Spendry 46565524Spendry procfs_setattr(ap) 46667367Smckusick struct vop_setattr_args /* { 46767367Smckusick struct vnode *a_vp; 46867367Smckusick struct vattr *a_vap; 46967367Smckusick struct ucred *a_cred; 47067367Smckusick struct proc *a_p; 47167367Smckusick } */ *ap; 47265524Spendry { 47365524Spendry /* 47465524Spendry * just fake out attribute setting 47565524Spendry * it's not good to generate an error 47665524Spendry * return, otherwise things like creat() 47765524Spendry * will fail when they try to set the 47865524Spendry * file length to 0. worse, this means 47965524Spendry * that echo $note > /proc/$pid/note will fail. 48065524Spendry */ 48165524Spendry 48265524Spendry return (0); 48365524Spendry } 48465524Spendry 48565524Spendry /* 48665524Spendry * implement access checking. 48765524Spendry * 48865524Spendry * something very similar to this code is duplicated 48965524Spendry * throughout the 4bsd kernel and should be moved 49065524Spendry * into kern/vfs_subr.c sometime. 49165524Spendry * 49265524Spendry * actually, the check for super-user is slightly 49365524Spendry * broken since it will allow read access to write-only 49465524Spendry * objects. this doesn't cause any particular trouble 49565524Spendry * but does mean that the i/o entry points need to check 49665524Spendry * that the operation really does make sense. 49765524Spendry */ 49865524Spendry procfs_access(ap) 49967367Smckusick struct vop_access_args /* { 50067367Smckusick struct vnode *a_vp; 50167367Smckusick int a_mode; 50267367Smckusick struct ucred *a_cred; 50367367Smckusick struct proc *a_p; 50467367Smckusick } */ *ap; 50565524Spendry { 50665524Spendry struct vattr *vap; 50765524Spendry struct vattr vattr; 50865524Spendry int error; 50965524Spendry 51065524Spendry /* 51165524Spendry * If you're the super-user, 51265524Spendry * you always get access. 51365524Spendry */ 51467389Spendry if (ap->a_cred->cr_uid == 0) 51565524Spendry return (0); 51667389Spendry 51765524Spendry vap = &vattr; 51865524Spendry if (error = VOP_GETATTR(ap->a_vp, vap, ap->a_cred, ap->a_p)) 51965524Spendry return (error); 52065524Spendry 52165524Spendry /* 52265524Spendry * Access check is based on only one of owner, group, public. 52365524Spendry * If not owner, then check group. If not a member of the 52465524Spendry * group, then check public access. 52565524Spendry */ 52665524Spendry if (ap->a_cred->cr_uid != vap->va_uid) { 52765524Spendry gid_t *gp; 52865524Spendry int i; 52965524Spendry 53067389Spendry ap->a_mode >>= 3; 53165524Spendry gp = ap->a_cred->cr_groups; 53265524Spendry for (i = 0; i < ap->a_cred->cr_ngroups; i++, gp++) 53365524Spendry if (vap->va_gid == *gp) 53465524Spendry goto found; 53565524Spendry ap->a_mode >>= 3; 53665524Spendry found: 53765524Spendry ; 53865524Spendry } 53965524Spendry 54065524Spendry if ((vap->va_mode & ap->a_mode) == ap->a_mode) 54165524Spendry return (0); 54265524Spendry 54365524Spendry return (EACCES); 54465524Spendry } 54565524Spendry 54665524Spendry /* 54765524Spendry * lookup. this is incredibly complicated in the 54865524Spendry * general case, however for most pseudo-filesystems 54965524Spendry * very little needs to be done. 55065524Spendry * 55165524Spendry * unless you want to get a migraine, just make sure your 55265524Spendry * filesystem doesn't do any locking of its own. otherwise 55365524Spendry * read and inwardly digest ufs_lookup(). 55465524Spendry */ 55565524Spendry procfs_lookup(ap) 55667367Smckusick struct vop_lookup_args /* { 55767367Smckusick struct vnode * a_dvp; 55867367Smckusick struct vnode ** a_vpp; 55967367Smckusick struct componentname * a_cnp; 56067367Smckusick } */ *ap; 56165524Spendry { 56265524Spendry struct componentname *cnp = ap->a_cnp; 56365524Spendry struct vnode **vpp = ap->a_vpp; 56465524Spendry struct vnode *dvp = ap->a_dvp; 56565524Spendry char *pname = cnp->cn_nameptr; 566*69442Smckusick struct proc *curp = cnp->cn_proc; 56765524Spendry int error = 0; 56869351Smckusick struct proc_target *pt; 56969351Smckusick struct vnode *fvp; 57065524Spendry pid_t pid; 57165524Spendry struct pfsnode *pfs; 57269351Smckusick struct proc *p; 57365524Spendry int i; 57465524Spendry 57569351Smckusick *vpp = NULL; 57669351Smckusick 57769351Smckusick if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) 57869351Smckusick return (EROFS); 57969351Smckusick 58065524Spendry if (cnp->cn_namelen == 1 && *pname == '.') { 58165524Spendry *vpp = dvp; 58265524Spendry VREF(dvp); 583*69442Smckusick /* vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, curp); */ 58465524Spendry return (0); 58565524Spendry } 58665524Spendry 58765524Spendry pfs = VTOPFS(dvp); 58865524Spendry switch (pfs->pfs_type) { 58965524Spendry case Proot: 59065524Spendry if (cnp->cn_flags & ISDOTDOT) 59165524Spendry return (EIO); 59265524Spendry 59365524Spendry if (CNEQ(cnp, "curproc", 7)) 59467389Spendry return (procfs_allocvp(dvp->v_mount, vpp, 0, Pcurproc)); 59567389Spendry 59667389Spendry pid = atopid(pname, cnp->cn_namelen); 59765524Spendry if (pid == NO_PID) 59869351Smckusick break; 59965524Spendry 60069351Smckusick p = PFIND(pid); 60169351Smckusick if (p == 0) 60269351Smckusick break; 60365524Spendry 60467389Spendry return (procfs_allocvp(dvp->v_mount, vpp, pid, Pproc)); 60565524Spendry 60665524Spendry case Pproc: 60769351Smckusick if (cnp->cn_flags & ISDOTDOT) 60869351Smckusick return (procfs_root(dvp->v_mount, vpp)); 60965524Spendry 61069351Smckusick p = PFIND(pfs->pfs_pid); 61169351Smckusick if (p == 0) 61269351Smckusick break; 61365524Spendry 61469351Smckusick for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) { 61569351Smckusick if (cnp->cn_namelen == pt->pt_namlen && 61669351Smckusick bcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 && 61769351Smckusick (pt->pt_valid == NULL || (*pt->pt_valid)(p))) 61865524Spendry goto found; 61965524Spendry } 62069351Smckusick break; 62165524Spendry 62265524Spendry found: 62369351Smckusick if (pt->pt_pfstype == Pfile) { 62469351Smckusick fvp = procfs_findtextvp(p); 62569351Smckusick /* We already checked that it exists. */ 62669351Smckusick VREF(fvp); 627*69442Smckusick vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, curp); 62869351Smckusick *vpp = fvp; 62967389Spendry return (0); 63065524Spendry } 63165524Spendry 63267389Spendry return (procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, 63369351Smckusick pt->pt_pfstype)); 63467389Spendry 63565524Spendry default: 63665524Spendry return (ENOTDIR); 63765524Spendry } 63869351Smckusick 63969351Smckusick return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS); 64065524Spendry } 64165524Spendry 64267389Spendry int 64367389Spendry procfs_validfile(p) 64467389Spendry struct proc *p; 64567389Spendry { 64667389Spendry 64767389Spendry return (procfs_findtextvp(p) != NULLVP); 64867389Spendry } 64967389Spendry 65065524Spendry /* 65165524Spendry * readdir returns directory entries from pfsnode (vp). 65265524Spendry * 65365524Spendry * the strategy here with procfs is to generate a single 65465524Spendry * directory entry at a time (struct pfsdent) and then 65565524Spendry * copy that out to userland using uiomove. a more efficent 65665524Spendry * though more complex implementation, would try to minimize 65765524Spendry * the number of calls to uiomove(). for procfs, this is 65865524Spendry * hardly worth the added code complexity. 65965524Spendry * 66065524Spendry * this should just be done through read() 66165524Spendry */ 66265524Spendry procfs_readdir(ap) 66367367Smckusick struct vop_readdir_args /* { 66467367Smckusick struct vnode *a_vp; 66567367Smckusick struct uio *a_uio; 66667367Smckusick struct ucred *a_cred; 66767367Smckusick int *a_eofflag; 66867367Smckusick u_long *a_cookies; 66967367Smckusick int a_ncookies; 67067367Smckusick } */ *ap; 67165524Spendry { 67265524Spendry struct uio *uio = ap->a_uio; 67365524Spendry struct pfsdent d; 67465524Spendry struct pfsdent *dp = &d; 67565524Spendry struct pfsnode *pfs; 67665524Spendry int error; 67765524Spendry int count; 67865524Spendry int i; 67965524Spendry 68067367Smckusick /* 68167367Smckusick * We don't allow exporting procfs mounts, and currently local 68267367Smckusick * requests do not need cookies. 68367367Smckusick */ 68467367Smckusick if (ap->a_ncookies) 68567367Smckusick panic("procfs_readdir: not hungry"); 68667367Smckusick 68765524Spendry pfs = VTOPFS(ap->a_vp); 68865524Spendry 68965524Spendry if (uio->uio_resid < UIO_MX) 69065524Spendry return (EINVAL); 69165524Spendry if (uio->uio_offset & (UIO_MX-1)) 69265524Spendry return (EINVAL); 69365524Spendry if (uio->uio_offset < 0) 69465524Spendry return (EINVAL); 69565524Spendry 69665524Spendry error = 0; 69765524Spendry count = 0; 69865524Spendry i = uio->uio_offset / UIO_MX; 69965524Spendry 70065524Spendry switch (pfs->pfs_type) { 70165524Spendry /* 70265524Spendry * this is for the process-specific sub-directories. 70365524Spendry * all that is needed to is copy out all the entries 70465524Spendry * from the procent[] table (top of this file). 70565524Spendry */ 70665524Spendry case Pproc: { 70769351Smckusick struct proc *p; 70869351Smckusick struct proc_target *pt; 70965524Spendry 71069351Smckusick p = PFIND(pfs->pfs_pid); 71169351Smckusick if (p == NULL) 71269351Smckusick break; 71367389Spendry 71469351Smckusick for (pt = &proc_targets[i]; 71569351Smckusick uio->uio_resid >= UIO_MX && i < nproc_targets; pt++, i++) { 71669351Smckusick if (pt->pt_valid && (*pt->pt_valid)(p) == 0) 71767389Spendry continue; 71865524Spendry 71965524Spendry dp->d_reclen = UIO_MX; 72069351Smckusick dp->d_fileno = PROCFS_FILENO(pfs->pfs_pid, pt->pt_pfstype); 72169351Smckusick dp->d_namlen = pt->pt_namlen; 72269351Smckusick bcopy(pt->pt_name, dp->d_name, pt->pt_namlen + 1); 72369351Smckusick dp->d_type = pt->pt_type; 72467389Spendry 72567389Spendry if (error = uiomove((caddr_t)dp, UIO_MX, uio)) 72665524Spendry break; 72765524Spendry } 72865524Spendry 72965524Spendry break; 73065524Spendry } 73165524Spendry 73265524Spendry /* 73365524Spendry * this is for the root of the procfs filesystem 73465524Spendry * what is needed is a special entry for "curproc" 73565524Spendry * followed by an entry for each process on allproc 73665524Spendry #ifdef PROCFS_ZOMBIE 73765524Spendry * and zombproc. 73865524Spendry #endif 73965524Spendry */ 74065524Spendry 74165524Spendry case Proot: { 74265524Spendry #ifdef PROCFS_ZOMBIE 74365524Spendry int doingzomb = 0; 74465524Spendry #endif 74567389Spendry int pcnt = 0; 74667721Smckusick volatile struct proc *p = allproc.lh_first; 74765524Spendry 74867389Spendry again: 74967389Spendry for (; p && uio->uio_resid >= UIO_MX; i++, pcnt++) { 75065524Spendry bzero((char *) dp, UIO_MX); 75165524Spendry dp->d_reclen = UIO_MX; 75265524Spendry 75365524Spendry switch (i) { 75467389Spendry case 0: /* `.' */ 75567389Spendry case 1: /* `..' */ 75667389Spendry dp->d_fileno = PROCFS_FILENO(0, Proot); 75767389Spendry dp->d_namlen = i + 1; 75867389Spendry bcopy("..", dp->d_name, dp->d_namlen); 75967389Spendry dp->d_name[i + 1] = '\0'; 76067389Spendry dp->d_type = DT_DIR; 76165524Spendry break; 76265524Spendry 76367389Spendry case 2: 76467389Spendry dp->d_fileno = PROCFS_FILENO(0, Pcurproc); 76567389Spendry dp->d_namlen = 7; 76667389Spendry bcopy("curproc", dp->d_name, 8); 76767389Spendry dp->d_type = DT_LNK; 76867389Spendry break; 76967389Spendry 77065524Spendry default: 77167389Spendry while (pcnt < i) { 77267389Spendry pcnt++; 77367721Smckusick p = p->p_list.le_next; 77467389Spendry if (!p) 77567389Spendry goto done; 77665524Spendry } 77767389Spendry dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc); 77867389Spendry dp->d_namlen = sprintf(dp->d_name, "%ld", 77967389Spendry (long)p->p_pid); 78067389Spendry dp->d_type = DT_REG; 78167721Smckusick p = p->p_list.le_next; 78265524Spendry break; 78365524Spendry } 78467389Spendry 78567389Spendry if (error = uiomove((caddr_t)dp, UIO_MX, uio)) 78665524Spendry break; 78765524Spendry } 78867389Spendry done: 78965524Spendry 79067389Spendry #ifdef PROCFS_ZOMBIE 79167389Spendry if (p == 0 && doingzomb == 0) { 79267389Spendry doingzomb = 1; 79367721Smckusick p = zombproc.lh_first; 79467389Spendry goto again; 79567389Spendry } 79667389Spendry #endif 79767389Spendry 79865524Spendry break; 79965524Spendry 80065524Spendry } 80165524Spendry 80265524Spendry default: 80365524Spendry error = ENOTDIR; 80465524Spendry break; 80565524Spendry } 80665524Spendry 80765524Spendry uio->uio_offset = i * UIO_MX; 80865524Spendry 80965524Spendry return (error); 81065524Spendry } 81165524Spendry 81265524Spendry /* 81367389Spendry * readlink reads the link of `curproc' 81467389Spendry */ 81567389Spendry procfs_readlink(ap) 81667389Spendry struct vop_readlink_args *ap; 81767389Spendry { 81867389Spendry struct uio *uio = ap->a_uio; 81967389Spendry char buf[16]; /* should be enough */ 82067389Spendry int len; 82167389Spendry 82267389Spendry if (VTOPFS(ap->a_vp)->pfs_fileno != PROCFS_FILENO(0, Pcurproc)) 82367389Spendry return (EINVAL); 82467389Spendry 82567389Spendry len = sprintf(buf, "%ld", (long)curproc->p_pid); 82667389Spendry 82767389Spendry return (uiomove((caddr_t)buf, len, ap->a_uio)); 82867389Spendry } 82967389Spendry 83067389Spendry /* 83165524Spendry * convert decimal ascii to pid_t 83265524Spendry */ 83365524Spendry static pid_t 83465524Spendry atopid(b, len) 83565524Spendry const char *b; 83665524Spendry u_int len; 83765524Spendry { 83865524Spendry pid_t p = 0; 83965524Spendry 84065524Spendry while (len--) { 84165524Spendry char c = *b++; 84265524Spendry if (c < '0' || c > '9') 84365524Spendry return (NO_PID); 84465524Spendry p = 10 * p + (c - '0'); 84565524Spendry if (p > PID_MAX) 84665524Spendry return (NO_PID); 84765524Spendry } 84865524Spendry 84965524Spendry return (p); 85065524Spendry } 85165524Spendry 85265524Spendry /* 85365524Spendry * procfs vnode operations. 85465524Spendry */ 85565524Spendry int (**procfs_vnodeop_p)(); 85665524Spendry struct vnodeopv_entry_desc procfs_vnodeop_entries[] = { 85765524Spendry { &vop_default_desc, vn_default_error }, 85865524Spendry { &vop_lookup_desc, procfs_lookup }, /* lookup */ 85965524Spendry { &vop_create_desc, procfs_create }, /* create */ 86065524Spendry { &vop_mknod_desc, procfs_mknod }, /* mknod */ 86165524Spendry { &vop_open_desc, procfs_open }, /* open */ 86265524Spendry { &vop_close_desc, procfs_close }, /* close */ 86365524Spendry { &vop_access_desc, procfs_access }, /* access */ 86465524Spendry { &vop_getattr_desc, procfs_getattr }, /* getattr */ 86565524Spendry { &vop_setattr_desc, procfs_setattr }, /* setattr */ 86665524Spendry { &vop_read_desc, procfs_read }, /* read */ 86765524Spendry { &vop_write_desc, procfs_write }, /* write */ 86865524Spendry { &vop_ioctl_desc, procfs_ioctl }, /* ioctl */ 86965524Spendry { &vop_select_desc, procfs_select }, /* select */ 87065524Spendry { &vop_mmap_desc, procfs_mmap }, /* mmap */ 87168732Smckusick { &vop_revoke_desc, procfs_revoke }, /* revoke */ 87265524Spendry { &vop_fsync_desc, procfs_fsync }, /* fsync */ 87365524Spendry { &vop_seek_desc, procfs_seek }, /* seek */ 87465524Spendry { &vop_remove_desc, procfs_remove }, /* remove */ 87565524Spendry { &vop_link_desc, procfs_link }, /* link */ 87665524Spendry { &vop_rename_desc, procfs_rename }, /* rename */ 87765524Spendry { &vop_mkdir_desc, procfs_mkdir }, /* mkdir */ 87865524Spendry { &vop_rmdir_desc, procfs_rmdir }, /* rmdir */ 87965524Spendry { &vop_symlink_desc, procfs_symlink }, /* symlink */ 88065524Spendry { &vop_readdir_desc, procfs_readdir }, /* readdir */ 88165524Spendry { &vop_readlink_desc, procfs_readlink }, /* readlink */ 88265524Spendry { &vop_abortop_desc, procfs_abortop }, /* abortop */ 88365524Spendry { &vop_inactive_desc, procfs_inactive }, /* inactive */ 88465524Spendry { &vop_reclaim_desc, procfs_reclaim }, /* reclaim */ 88565524Spendry { &vop_lock_desc, procfs_lock }, /* lock */ 88665524Spendry { &vop_unlock_desc, procfs_unlock }, /* unlock */ 88765524Spendry { &vop_bmap_desc, procfs_bmap }, /* bmap */ 88865524Spendry { &vop_strategy_desc, procfs_strategy }, /* strategy */ 88965524Spendry { &vop_print_desc, procfs_print }, /* print */ 89065524Spendry { &vop_islocked_desc, procfs_islocked }, /* islocked */ 89165524Spendry { &vop_pathconf_desc, procfs_pathconf }, /* pathconf */ 89265524Spendry { &vop_advlock_desc, procfs_advlock }, /* advlock */ 89365524Spendry { &vop_blkatoff_desc, procfs_blkatoff }, /* blkatoff */ 89465524Spendry { &vop_valloc_desc, procfs_valloc }, /* valloc */ 89565524Spendry { &vop_vfree_desc, procfs_vfree }, /* vfree */ 89665524Spendry { &vop_truncate_desc, procfs_truncate }, /* truncate */ 89765524Spendry { &vop_update_desc, procfs_update }, /* update */ 89865524Spendry { (struct vnodeop_desc*)NULL, (int(*)())NULL } 89965524Spendry }; 90065524Spendry struct vnodeopv_desc procfs_vnodeop_opv_desc = 90165524Spendry { &procfs_vnodeop_p, procfs_vnodeop_entries }; 902