165524Spendry /* 2*68232Spendry * Copyright (c) 1993, 1995 Jan-Simon Pendry 3*68232Spendry * 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*68232Spendry * @(#)procfs_vnops.c 8.12 (Berkeley) 02/06/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 */ 4665524Spendry static struct pfsnames { 4767389Spendry u_char d_type; 4867389Spendry u_char d_namlen; 4965524Spendry char d_name[PROCFS_NAMELEN]; 5065524Spendry pfstype d_pfstype; 5167389Spendry int (*d_valid) __P((struct proc *p)); 5265524Spendry } procent[] = { 5365524Spendry #define N(s) sizeof(s)-1, s 5465524Spendry /* namlen, nam, type */ 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 }; 6765524Spendry #define Nprocent (sizeof(procent)/sizeof(procent[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; 174*68232Spendry 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 19665524Spendry * 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) 21165524Spendry 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; 56665524Spendry int error = 0; 56765524Spendry pid_t pid; 56865524Spendry struct vnode *nvp; 56965524Spendry struct pfsnode *pfs; 57065524Spendry struct proc *procp; 57165524Spendry pfstype pfs_type; 57265524Spendry int i; 57365524Spendry 57465524Spendry if (cnp->cn_namelen == 1 && *pname == '.') { 57565524Spendry *vpp = dvp; 57665524Spendry VREF(dvp); 57765524Spendry /*VOP_LOCK(dvp);*/ 57865524Spendry return (0); 57965524Spendry } 58065524Spendry 58165524Spendry *vpp = NULL; 58265524Spendry 58365524Spendry pfs = VTOPFS(dvp); 58465524Spendry switch (pfs->pfs_type) { 58565524Spendry case Proot: 58665524Spendry if (cnp->cn_flags & ISDOTDOT) 58765524Spendry return (EIO); 58865524Spendry 58965524Spendry if (CNEQ(cnp, "curproc", 7)) 59067389Spendry return (procfs_allocvp(dvp->v_mount, vpp, 0, Pcurproc)); 59167389Spendry 59267389Spendry pid = atopid(pname, cnp->cn_namelen); 59365524Spendry if (pid == NO_PID) 59465524Spendry return (ENOENT); 59565524Spendry 59665524Spendry procp = PFIND(pid); 59765524Spendry if (procp == 0) 59865524Spendry return (ENOENT); 59965524Spendry 60067389Spendry return (procfs_allocvp(dvp->v_mount, vpp, pid, Pproc)); 60165524Spendry 60265524Spendry case Pproc: 60365524Spendry if (cnp->cn_flags & ISDOTDOT) { 60465524Spendry error = procfs_root(dvp->v_mount, vpp); 60565524Spendry return (error); 60665524Spendry } 60765524Spendry 60865524Spendry procp = PFIND(pfs->pfs_pid); 60965524Spendry if (procp == 0) 61065524Spendry return (ENOENT); 61165524Spendry 61265524Spendry for (i = 0; i < Nprocent; i++) { 61365524Spendry struct pfsnames *dp = &procent[i]; 61465524Spendry 61565524Spendry if (cnp->cn_namelen == dp->d_namlen && 61667389Spendry bcmp(pname, dp->d_name, dp->d_namlen) == 0 && 61767389Spendry (dp->d_valid == NULL || (*dp->d_valid)(procp))) { 61865524Spendry pfs_type = dp->d_pfstype; 61965524Spendry goto found; 62065524Spendry } 62165524Spendry } 62265524Spendry return (ENOENT); 62365524Spendry 62465524Spendry found: 62565524Spendry if (pfs_type == Pfile) { 62665524Spendry nvp = procfs_findtextvp(procp); 62767389Spendry if (nvp == NULLVP) 62867389Spendry return (ENXIO); 62967389Spendry VREF(nvp); 63067389Spendry VOP_LOCK(nvp); 63167389Spendry *vpp = nvp; 63267389Spendry return (0); 63365524Spendry } 63465524Spendry 63567389Spendry return (procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, 63667389Spendry pfs_type)); 63767389Spendry 63865524Spendry default: 63965524Spendry return (ENOTDIR); 64065524Spendry } 64165524Spendry } 64265524Spendry 64367389Spendry int 64467389Spendry procfs_validfile(p) 64567389Spendry struct proc *p; 64667389Spendry { 64767389Spendry 64867389Spendry return (procfs_findtextvp(p) != NULLVP); 64967389Spendry } 65067389Spendry 65165524Spendry /* 65265524Spendry * readdir returns directory entries from pfsnode (vp). 65365524Spendry * 65465524Spendry * the strategy here with procfs is to generate a single 65565524Spendry * directory entry at a time (struct pfsdent) and then 65665524Spendry * copy that out to userland using uiomove. a more efficent 65765524Spendry * though more complex implementation, would try to minimize 65865524Spendry * the number of calls to uiomove(). for procfs, this is 65965524Spendry * hardly worth the added code complexity. 66065524Spendry * 66165524Spendry * this should just be done through read() 66265524Spendry */ 66365524Spendry procfs_readdir(ap) 66467367Smckusick struct vop_readdir_args /* { 66567367Smckusick struct vnode *a_vp; 66667367Smckusick struct uio *a_uio; 66767367Smckusick struct ucred *a_cred; 66867367Smckusick int *a_eofflag; 66967367Smckusick u_long *a_cookies; 67067367Smckusick int a_ncookies; 67167367Smckusick } */ *ap; 67265524Spendry { 67365524Spendry struct uio *uio = ap->a_uio; 67465524Spendry struct pfsdent d; 67565524Spendry struct pfsdent *dp = &d; 67665524Spendry struct pfsnode *pfs; 67765524Spendry int error; 67865524Spendry int count; 67965524Spendry int i; 68065524Spendry 68167367Smckusick /* 68267367Smckusick * We don't allow exporting procfs mounts, and currently local 68367367Smckusick * requests do not need cookies. 68467367Smckusick */ 68567367Smckusick if (ap->a_ncookies) 68667367Smckusick panic("procfs_readdir: not hungry"); 68767367Smckusick 68865524Spendry pfs = VTOPFS(ap->a_vp); 68965524Spendry 69065524Spendry if (uio->uio_resid < UIO_MX) 69165524Spendry return (EINVAL); 69265524Spendry if (uio->uio_offset & (UIO_MX-1)) 69365524Spendry return (EINVAL); 69465524Spendry if (uio->uio_offset < 0) 69565524Spendry return (EINVAL); 69665524Spendry 69765524Spendry error = 0; 69865524Spendry count = 0; 69965524Spendry i = uio->uio_offset / UIO_MX; 70065524Spendry 70165524Spendry switch (pfs->pfs_type) { 70265524Spendry /* 70365524Spendry * this is for the process-specific sub-directories. 70465524Spendry * all that is needed to is copy out all the entries 70565524Spendry * from the procent[] table (top of this file). 70665524Spendry */ 70765524Spendry case Pproc: { 70867389Spendry pid_t pid = pfs->pfs_pid; 70967389Spendry struct pfsnames *dt; 71065524Spendry 71167389Spendry for (dt = &procent[i]; i < Nprocent && uio->uio_resid >= UIO_MX; 71267389Spendry dt++, i++) { 71367389Spendry struct proc *p = PFIND(pid); 71467389Spendry 71567389Spendry if (p == NULL) 71665524Spendry break; 71765524Spendry 71867389Spendry if (dt->d_valid && (*dt->d_valid)(p) == 0) 71967389Spendry continue; 72065524Spendry 72165524Spendry dp->d_reclen = UIO_MX; 72267389Spendry dp->d_fileno = PROCFS_FILENO(pid, dt->d_pfstype); 72365524Spendry dp->d_namlen = dt->d_namlen; 72467389Spendry bcopy(dt->d_name, dp->d_name, dt->d_namlen + 1); 72567389Spendry dp->d_type = dt->d_type; 72667389Spendry 72767389Spendry if (error = uiomove((caddr_t)dp, UIO_MX, uio)) 72865524Spendry break; 72965524Spendry } 73065524Spendry 73165524Spendry break; 73265524Spendry 73365524Spendry } 73465524Spendry 73565524Spendry /* 73665524Spendry * this is for the root of the procfs filesystem 73765524Spendry * what is needed is a special entry for "curproc" 73865524Spendry * followed by an entry for each process on allproc 73965524Spendry #ifdef PROCFS_ZOMBIE 74065524Spendry * and zombproc. 74165524Spendry #endif 74265524Spendry */ 74365524Spendry 74465524Spendry case Proot: { 74565524Spendry #ifdef PROCFS_ZOMBIE 74665524Spendry int doingzomb = 0; 74765524Spendry #endif 74867389Spendry int pcnt = 0; 74967721Smckusick volatile struct proc *p = allproc.lh_first; 75065524Spendry 75167389Spendry again: 75267389Spendry for (; p && uio->uio_resid >= UIO_MX; i++, pcnt++) { 75365524Spendry bzero((char *) dp, UIO_MX); 75465524Spendry dp->d_reclen = UIO_MX; 75565524Spendry 75665524Spendry switch (i) { 75767389Spendry case 0: /* `.' */ 75867389Spendry case 1: /* `..' */ 75967389Spendry dp->d_fileno = PROCFS_FILENO(0, Proot); 76067389Spendry dp->d_namlen = i + 1; 76167389Spendry bcopy("..", dp->d_name, dp->d_namlen); 76267389Spendry dp->d_name[i + 1] = '\0'; 76367389Spendry dp->d_type = DT_DIR; 76465524Spendry break; 76565524Spendry 76667389Spendry case 2: 76767389Spendry dp->d_fileno = PROCFS_FILENO(0, Pcurproc); 76867389Spendry dp->d_namlen = 7; 76967389Spendry bcopy("curproc", dp->d_name, 8); 77067389Spendry dp->d_type = DT_LNK; 77167389Spendry break; 77267389Spendry 77365524Spendry default: 77467389Spendry while (pcnt < i) { 77567389Spendry pcnt++; 77667721Smckusick p = p->p_list.le_next; 77767389Spendry if (!p) 77867389Spendry goto done; 77965524Spendry } 78067389Spendry dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc); 78167389Spendry dp->d_namlen = sprintf(dp->d_name, "%ld", 78267389Spendry (long)p->p_pid); 78367389Spendry dp->d_type = DT_REG; 78467721Smckusick p = p->p_list.le_next; 78565524Spendry break; 78665524Spendry } 78767389Spendry 78867389Spendry if (error = uiomove((caddr_t)dp, UIO_MX, uio)) 78965524Spendry break; 79065524Spendry } 79167389Spendry done: 79265524Spendry 79367389Spendry #ifdef PROCFS_ZOMBIE 79467389Spendry if (p == 0 && doingzomb == 0) { 79567389Spendry doingzomb = 1; 79667721Smckusick p = zombproc.lh_first; 79767389Spendry goto again; 79867389Spendry } 79967389Spendry #endif 80067389Spendry 80165524Spendry break; 80265524Spendry 80365524Spendry } 80465524Spendry 80565524Spendry default: 80665524Spendry error = ENOTDIR; 80765524Spendry break; 80865524Spendry } 80965524Spendry 81065524Spendry uio->uio_offset = i * UIO_MX; 81165524Spendry 81265524Spendry return (error); 81365524Spendry } 81465524Spendry 81565524Spendry /* 81667389Spendry * readlink reads the link of `curproc' 81767389Spendry */ 81867389Spendry procfs_readlink(ap) 81967389Spendry struct vop_readlink_args *ap; 82067389Spendry { 82167389Spendry struct uio *uio = ap->a_uio; 82267389Spendry char buf[16]; /* should be enough */ 82367389Spendry int len; 82467389Spendry 82567389Spendry if (VTOPFS(ap->a_vp)->pfs_fileno != PROCFS_FILENO(0, Pcurproc)) 82667389Spendry return (EINVAL); 82767389Spendry 82867389Spendry len = sprintf(buf, "%ld", (long)curproc->p_pid); 82967389Spendry 83067389Spendry return (uiomove((caddr_t)buf, len, ap->a_uio)); 83167389Spendry } 83267389Spendry 83367389Spendry /* 83465524Spendry * convert decimal ascii to pid_t 83565524Spendry */ 83665524Spendry static pid_t 83765524Spendry atopid(b, len) 83865524Spendry const char *b; 83965524Spendry u_int len; 84065524Spendry { 84165524Spendry pid_t p = 0; 84265524Spendry 84365524Spendry while (len--) { 84465524Spendry char c = *b++; 84565524Spendry if (c < '0' || c > '9') 84665524Spendry return (NO_PID); 84765524Spendry p = 10 * p + (c - '0'); 84865524Spendry if (p > PID_MAX) 84965524Spendry return (NO_PID); 85065524Spendry } 85165524Spendry 85265524Spendry return (p); 85365524Spendry } 85465524Spendry 85565524Spendry /* 85665524Spendry * procfs vnode operations. 85765524Spendry */ 85865524Spendry int (**procfs_vnodeop_p)(); 85965524Spendry struct vnodeopv_entry_desc procfs_vnodeop_entries[] = { 86065524Spendry { &vop_default_desc, vn_default_error }, 86165524Spendry { &vop_lookup_desc, procfs_lookup }, /* lookup */ 86265524Spendry { &vop_create_desc, procfs_create }, /* create */ 86365524Spendry { &vop_mknod_desc, procfs_mknod }, /* mknod */ 86465524Spendry { &vop_open_desc, procfs_open }, /* open */ 86565524Spendry { &vop_close_desc, procfs_close }, /* close */ 86665524Spendry { &vop_access_desc, procfs_access }, /* access */ 86765524Spendry { &vop_getattr_desc, procfs_getattr }, /* getattr */ 86865524Spendry { &vop_setattr_desc, procfs_setattr }, /* setattr */ 86965524Spendry { &vop_read_desc, procfs_read }, /* read */ 87065524Spendry { &vop_write_desc, procfs_write }, /* write */ 87165524Spendry { &vop_ioctl_desc, procfs_ioctl }, /* ioctl */ 87265524Spendry { &vop_select_desc, procfs_select }, /* select */ 87365524Spendry { &vop_mmap_desc, procfs_mmap }, /* mmap */ 87465524Spendry { &vop_fsync_desc, procfs_fsync }, /* fsync */ 87565524Spendry { &vop_seek_desc, procfs_seek }, /* seek */ 87665524Spendry { &vop_remove_desc, procfs_remove }, /* remove */ 87765524Spendry { &vop_link_desc, procfs_link }, /* link */ 87865524Spendry { &vop_rename_desc, procfs_rename }, /* rename */ 87965524Spendry { &vop_mkdir_desc, procfs_mkdir }, /* mkdir */ 88065524Spendry { &vop_rmdir_desc, procfs_rmdir }, /* rmdir */ 88165524Spendry { &vop_symlink_desc, procfs_symlink }, /* symlink */ 88265524Spendry { &vop_readdir_desc, procfs_readdir }, /* readdir */ 88365524Spendry { &vop_readlink_desc, procfs_readlink }, /* readlink */ 88465524Spendry { &vop_abortop_desc, procfs_abortop }, /* abortop */ 88565524Spendry { &vop_inactive_desc, procfs_inactive }, /* inactive */ 88665524Spendry { &vop_reclaim_desc, procfs_reclaim }, /* reclaim */ 88765524Spendry { &vop_lock_desc, procfs_lock }, /* lock */ 88865524Spendry { &vop_unlock_desc, procfs_unlock }, /* unlock */ 88965524Spendry { &vop_bmap_desc, procfs_bmap }, /* bmap */ 89065524Spendry { &vop_strategy_desc, procfs_strategy }, /* strategy */ 89165524Spendry { &vop_print_desc, procfs_print }, /* print */ 89265524Spendry { &vop_islocked_desc, procfs_islocked }, /* islocked */ 89365524Spendry { &vop_pathconf_desc, procfs_pathconf }, /* pathconf */ 89465524Spendry { &vop_advlock_desc, procfs_advlock }, /* advlock */ 89565524Spendry { &vop_blkatoff_desc, procfs_blkatoff }, /* blkatoff */ 89665524Spendry { &vop_valloc_desc, procfs_valloc }, /* valloc */ 89765524Spendry { &vop_vfree_desc, procfs_vfree }, /* vfree */ 89865524Spendry { &vop_truncate_desc, procfs_truncate }, /* truncate */ 89965524Spendry { &vop_update_desc, procfs_update }, /* update */ 90065524Spendry { (struct vnodeop_desc*)NULL, (int(*)())NULL } 90165524Spendry }; 90265524Spendry struct vnodeopv_desc procfs_vnodeop_opv_desc = 90365524Spendry { &procfs_vnodeop_p, procfs_vnodeop_entries }; 904