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*68230Spendry * @(#)procfs_vnops.c 8.11 (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; 17467367Smckusick } */ *ap; 17565524Spendry { 17665524Spendry 17765524Spendry if (ap->a_vpp != NULL) 17865524Spendry *ap->a_vpp = ap->a_vp; 17965524Spendry if (ap->a_bnp != NULL) 18065524Spendry *ap->a_bnp = ap->a_bn; 181*68230Spendry if (ap->a_runp != NULL) 182*68230Spendry *ap->a_runp = 0; 18365524Spendry return (0); 18465524Spendry } 18565524Spendry 18665524Spendry /* 18765524Spendry * _inactive is called when the pfsnode 18865524Spendry * is vrele'd and the reference count goes 18965524Spendry * to zero. (vp) will be on the vnode free 19065524Spendry * list, so to get it back vget() must be 19165524Spendry * used. 19265524Spendry * 19365524Spendry * for procfs, check if the process is still 19465524Spendry * alive and if it isn't then just throw away 19565524Spendry * the vnode by calling vgone(). this may 19665524Spendry * be overkill and a waste of time since the 19765524Spendry * chances are that the process will still be 19865524Spendry * there and PFIND is not free. 19965524Spendry * 20065524Spendry * (vp) is not locked on entry or exit. 20165524Spendry */ 20265524Spendry procfs_inactive(ap) 20367367Smckusick struct vop_inactive_args /* { 20467367Smckusick struct vnode *a_vp; 20567367Smckusick } */ *ap; 20665524Spendry { 20765524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 20865524Spendry 20965524Spendry if (PFIND(pfs->pfs_pid) == 0) 21065524Spendry vgone(ap->a_vp); 21165524Spendry 21265524Spendry return (0); 21365524Spendry } 21465524Spendry 21565524Spendry /* 21665524Spendry * _reclaim is called when getnewvnode() 21765524Spendry * wants to make use of an entry on the vnode 21865524Spendry * free list. at this time the filesystem needs 21965524Spendry * to free any private data and remove the node 22065524Spendry * from any private lists. 22165524Spendry */ 22265524Spendry procfs_reclaim(ap) 22367367Smckusick struct vop_reclaim_args /* { 22467367Smckusick struct vnode *a_vp; 22567367Smckusick } */ *ap; 22665524Spendry { 22765524Spendry 22867389Spendry return (procfs_freevp(ap->a_vp)); 22965524Spendry } 23065524Spendry 23165524Spendry /* 23265743Spendry * Return POSIX pathconf information applicable to special devices. 23365743Spendry */ 23465743Spendry procfs_pathconf(ap) 23565743Spendry struct vop_pathconf_args /* { 23665743Spendry struct vnode *a_vp; 23765743Spendry int a_name; 23865743Spendry int *a_retval; 23965743Spendry } */ *ap; 24065743Spendry { 24165743Spendry 24265743Spendry switch (ap->a_name) { 24365743Spendry case _PC_LINK_MAX: 24465743Spendry *ap->a_retval = LINK_MAX; 24565743Spendry return (0); 24665743Spendry case _PC_MAX_CANON: 24765743Spendry *ap->a_retval = MAX_CANON; 24865743Spendry return (0); 24965743Spendry case _PC_MAX_INPUT: 25065743Spendry *ap->a_retval = MAX_INPUT; 25165743Spendry return (0); 25265743Spendry case _PC_PIPE_BUF: 25365743Spendry *ap->a_retval = PIPE_BUF; 25465743Spendry return (0); 25565743Spendry case _PC_CHOWN_RESTRICTED: 25665743Spendry *ap->a_retval = 1; 25765743Spendry return (0); 25865743Spendry case _PC_VDISABLE: 25965743Spendry *ap->a_retval = _POSIX_VDISABLE; 26065743Spendry return (0); 26165743Spendry default: 26265743Spendry return (EINVAL); 26365743Spendry } 26465743Spendry /* NOTREACHED */ 26565743Spendry } 26665743Spendry 26765743Spendry /* 26865524Spendry * _print is used for debugging. 26965524Spendry * just print a readable description 27065524Spendry * of (vp). 27165524Spendry */ 27265524Spendry procfs_print(ap) 27367367Smckusick struct vop_print_args /* { 27467367Smckusick struct vnode *a_vp; 27567367Smckusick } */ *ap; 27665524Spendry { 27765524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 27865524Spendry 27967389Spendry printf("tag VT_PROCFS, type %s, pid %d, mode %x, flags %x\n", 28067389Spendry pfs->pfs_type, pfs->pfs_pid, pfs->pfs_mode, pfs->pfs_flags); 28165524Spendry } 28265524Spendry 28365524Spendry /* 28465524Spendry * _abortop is called when operations such as 28565524Spendry * rename and create fail. this entry is responsible 28665524Spendry * for undoing any side-effects caused by the lookup. 28765524Spendry * this will always include freeing the pathname buffer. 28865524Spendry */ 28965524Spendry procfs_abortop(ap) 29067367Smckusick struct vop_abortop_args /* { 29167367Smckusick struct vnode *a_dvp; 29267367Smckusick struct componentname *a_cnp; 29367367Smckusick } */ *ap; 29465524Spendry { 29565524Spendry 29665524Spendry if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) 29765524Spendry FREE(ap->a_cnp->cn_pnbuf, M_NAMEI); 29865524Spendry return (0); 29965524Spendry } 30065524Spendry 30165524Spendry /* 30265524Spendry * generic entry point for unsupported operations 30365524Spendry */ 30465524Spendry procfs_badop() 30565524Spendry { 30665524Spendry 30765524Spendry return (EIO); 30865524Spendry } 30965524Spendry 31065524Spendry /* 31165524Spendry * Invent attributes for pfsnode (vp) and store 31265524Spendry * them in (vap). 31365524Spendry * Directories lengths are returned as zero since 31465524Spendry * any real length would require the genuine size 31565524Spendry * to be computed, and nothing cares anyway. 31665524Spendry * 31765524Spendry * this is relatively minimal for procfs. 31865524Spendry */ 31965524Spendry procfs_getattr(ap) 32067367Smckusick struct vop_getattr_args /* { 32167367Smckusick struct vnode *a_vp; 32267367Smckusick struct vattr *a_vap; 32367367Smckusick struct ucred *a_cred; 32467367Smckusick struct proc *a_p; 32567367Smckusick } */ *ap; 32665524Spendry { 32765524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 32865536Spendry struct vattr *vap = ap->a_vap; 32965524Spendry struct proc *procp; 33068174Scgd struct timeval tv; 33165524Spendry int error; 33265524Spendry 33365524Spendry /* first check the process still exists */ 33466025Spendry switch (pfs->pfs_type) { 33566025Spendry case Proot: 33667389Spendry case Pcurproc: 33766025Spendry procp = 0; 33866025Spendry break; 33965524Spendry 34066025Spendry default: 34166025Spendry procp = PFIND(pfs->pfs_pid); 34266025Spendry if (procp == 0) 34366025Spendry return (ENOENT); 34466025Spendry } 34566025Spendry 34665524Spendry error = 0; 34765524Spendry 34865524Spendry /* start by zeroing out the attributes */ 34965536Spendry VATTR_NULL(vap); 35065524Spendry 35165524Spendry /* next do all the common fields */ 35265536Spendry vap->va_type = ap->a_vp->v_type; 35365536Spendry vap->va_mode = pfs->pfs_mode; 35465536Spendry vap->va_fileid = pfs->pfs_fileno; 35565536Spendry vap->va_flags = 0; 35665536Spendry vap->va_blocksize = PAGE_SIZE; 35765536Spendry vap->va_bytes = vap->va_size = 0; 35865524Spendry 35965524Spendry /* 36067389Spendry * Make all times be current TOD. 36167389Spendry * It would be possible to get the process start 36267389Spendry * time from the p_stat structure, but there's 36367389Spendry * no "file creation" time stamp anyway, and the 36467389Spendry * p_stat structure is not addressible if u. gets 36567389Spendry * swapped out for that process. 36667389Spendry */ 36768174Scgd microtime(&tv); 36868174Scgd TIMEVAL_TO_TIMESPEC(&tv, &vap->va_ctime); 36967389Spendry vap->va_atime = vap->va_mtime = vap->va_ctime; 37067389Spendry 37167389Spendry /* 37266025Spendry * If the process has exercised some setuid or setgid 37366025Spendry * privilege, then rip away read/write permission so 37466025Spendry * that only root can gain access. 37566025Spendry */ 37666025Spendry switch (pfs->pfs_type) { 37767389Spendry case Pmem: 37866025Spendry case Pregs: 37966025Spendry case Pfpregs: 38066025Spendry if (procp->p_flag & P_SUGID) 38166025Spendry vap->va_mode &= ~((VREAD|VWRITE)| 38266025Spendry ((VREAD|VWRITE)>>3)| 38366025Spendry ((VREAD|VWRITE)>>6)); 38467389Spendry case Pctl: 38567389Spendry case Pstatus: 38667389Spendry case Pnote: 38767389Spendry case Pnotepg: 38867389Spendry vap->va_nlink = 1; 38967389Spendry vap->va_uid = procp->p_ucred->cr_uid; 39067389Spendry vap->va_gid = procp->p_ucred->cr_gid; 39166025Spendry break; 39266025Spendry } 39366025Spendry 39466025Spendry /* 39565524Spendry * now do the object specific fields 39665524Spendry * 39765524Spendry * The size could be set from struct reg, but it's hardly 39865524Spendry * worth the trouble, and it puts some (potentially) machine 39965524Spendry * dependent data into this machine-independent code. If it 40065524Spendry * becomes important then this function should break out into 40165524Spendry * a per-file stat function in the corresponding .c file. 40265524Spendry */ 40365524Spendry 40465524Spendry switch (pfs->pfs_type) { 40565524Spendry case Proot: 40667389Spendry /* 40767389Spendry * Set nlink to 1 to tell fts(3) we don't actually know. 40867389Spendry */ 40967389Spendry vap->va_nlink = 1; 41065536Spendry vap->va_uid = 0; 41165536Spendry vap->va_gid = 0; 41267389Spendry vap->va_size = vap->va_bytes = DEV_BSIZE; 41365524Spendry break; 41465524Spendry 41567389Spendry case Pcurproc: { 41667389Spendry char buf[16]; /* should be enough */ 41767389Spendry vap->va_nlink = 1; 41867389Spendry vap->va_uid = 0; 41967389Spendry vap->va_gid = 0; 42067389Spendry vap->va_size = vap->va_bytes = 42167389Spendry sprintf(buf, "%ld", (long)curproc->p_pid); 42267389Spendry break; 42367389Spendry } 42467389Spendry 42565524Spendry case Pproc: 42665536Spendry vap->va_nlink = 2; 42765536Spendry vap->va_uid = procp->p_ucred->cr_uid; 42865536Spendry vap->va_gid = procp->p_ucred->cr_gid; 42967389Spendry vap->va_size = vap->va_bytes = DEV_BSIZE; 43065524Spendry break; 43165524Spendry 43265524Spendry case Pfile: 43365524Spendry error = EOPNOTSUPP; 43465524Spendry break; 43565524Spendry 43665524Spendry case Pmem: 43765536Spendry vap->va_bytes = vap->va_size = 43865524Spendry ctob(procp->p_vmspace->vm_tsize + 43965524Spendry procp->p_vmspace->vm_dsize + 44065524Spendry procp->p_vmspace->vm_ssize); 44165524Spendry break; 44265524Spendry 44365524Spendry case Pregs: 44467389Spendry vap->va_bytes = vap->va_size = sizeof(struct reg); 44567389Spendry break; 44667389Spendry 44765924Spendry case Pfpregs: 44867389Spendry vap->va_bytes = vap->va_size = sizeof(struct fpreg); 44967389Spendry break; 45067389Spendry 45165524Spendry case Pctl: 45265524Spendry case Pstatus: 45365524Spendry case Pnote: 45465524Spendry case Pnotepg: 45565524Spendry break; 45665524Spendry 45765524Spendry default: 45865524Spendry panic("procfs_getattr"); 45965524Spendry } 46065524Spendry 46165524Spendry return (error); 46265524Spendry } 46365524Spendry 46465524Spendry procfs_setattr(ap) 46567367Smckusick struct vop_setattr_args /* { 46667367Smckusick struct vnode *a_vp; 46767367Smckusick struct vattr *a_vap; 46867367Smckusick struct ucred *a_cred; 46967367Smckusick struct proc *a_p; 47067367Smckusick } */ *ap; 47165524Spendry { 47265524Spendry /* 47365524Spendry * just fake out attribute setting 47465524Spendry * it's not good to generate an error 47565524Spendry * return, otherwise things like creat() 47665524Spendry * will fail when they try to set the 47765524Spendry * file length to 0. worse, this means 47865524Spendry * that echo $note > /proc/$pid/note will fail. 47965524Spendry */ 48065524Spendry 48165524Spendry return (0); 48265524Spendry } 48365524Spendry 48465524Spendry /* 48565524Spendry * implement access checking. 48665524Spendry * 48765524Spendry * something very similar to this code is duplicated 48865524Spendry * throughout the 4bsd kernel and should be moved 48965524Spendry * into kern/vfs_subr.c sometime. 49065524Spendry * 49165524Spendry * actually, the check for super-user is slightly 49265524Spendry * broken since it will allow read access to write-only 49365524Spendry * objects. this doesn't cause any particular trouble 49465524Spendry * but does mean that the i/o entry points need to check 49565524Spendry * that the operation really does make sense. 49665524Spendry */ 49765524Spendry procfs_access(ap) 49867367Smckusick struct vop_access_args /* { 49967367Smckusick struct vnode *a_vp; 50067367Smckusick int a_mode; 50167367Smckusick struct ucred *a_cred; 50267367Smckusick struct proc *a_p; 50367367Smckusick } */ *ap; 50465524Spendry { 50565524Spendry struct vattr *vap; 50665524Spendry struct vattr vattr; 50765524Spendry int error; 50865524Spendry 50965524Spendry /* 51065524Spendry * If you're the super-user, 51165524Spendry * you always get access. 51265524Spendry */ 51367389Spendry if (ap->a_cred->cr_uid == 0) 51465524Spendry return (0); 51567389Spendry 51665524Spendry vap = &vattr; 51765524Spendry if (error = VOP_GETATTR(ap->a_vp, vap, ap->a_cred, ap->a_p)) 51865524Spendry return (error); 51965524Spendry 52065524Spendry /* 52165524Spendry * Access check is based on only one of owner, group, public. 52265524Spendry * If not owner, then check group. If not a member of the 52365524Spendry * group, then check public access. 52465524Spendry */ 52565524Spendry if (ap->a_cred->cr_uid != vap->va_uid) { 52665524Spendry gid_t *gp; 52765524Spendry int i; 52865524Spendry 52967389Spendry ap->a_mode >>= 3; 53065524Spendry gp = ap->a_cred->cr_groups; 53165524Spendry for (i = 0; i < ap->a_cred->cr_ngroups; i++, gp++) 53265524Spendry if (vap->va_gid == *gp) 53365524Spendry goto found; 53465524Spendry ap->a_mode >>= 3; 53565524Spendry found: 53665524Spendry ; 53765524Spendry } 53865524Spendry 53965524Spendry if ((vap->va_mode & ap->a_mode) == ap->a_mode) 54065524Spendry return (0); 54165524Spendry 54265524Spendry return (EACCES); 54365524Spendry } 54465524Spendry 54565524Spendry /* 54665524Spendry * lookup. this is incredibly complicated in the 54765524Spendry * general case, however for most pseudo-filesystems 54865524Spendry * very little needs to be done. 54965524Spendry * 55065524Spendry * unless you want to get a migraine, just make sure your 55165524Spendry * filesystem doesn't do any locking of its own. otherwise 55265524Spendry * read and inwardly digest ufs_lookup(). 55365524Spendry */ 55465524Spendry procfs_lookup(ap) 55567367Smckusick struct vop_lookup_args /* { 55667367Smckusick struct vnode * a_dvp; 55767367Smckusick struct vnode ** a_vpp; 55867367Smckusick struct componentname * a_cnp; 55967367Smckusick } */ *ap; 56065524Spendry { 56165524Spendry struct componentname *cnp = ap->a_cnp; 56265524Spendry struct vnode **vpp = ap->a_vpp; 56365524Spendry struct vnode *dvp = ap->a_dvp; 56465524Spendry char *pname = cnp->cn_nameptr; 56565524Spendry int error = 0; 56665524Spendry pid_t pid; 56765524Spendry struct vnode *nvp; 56865524Spendry struct pfsnode *pfs; 56965524Spendry struct proc *procp; 57065524Spendry pfstype pfs_type; 57165524Spendry int i; 57265524Spendry 57365524Spendry if (cnp->cn_namelen == 1 && *pname == '.') { 57465524Spendry *vpp = dvp; 57565524Spendry VREF(dvp); 57665524Spendry /*VOP_LOCK(dvp);*/ 57765524Spendry return (0); 57865524Spendry } 57965524Spendry 58065524Spendry *vpp = NULL; 58165524Spendry 58265524Spendry pfs = VTOPFS(dvp); 58365524Spendry switch (pfs->pfs_type) { 58465524Spendry case Proot: 58565524Spendry if (cnp->cn_flags & ISDOTDOT) 58665524Spendry return (EIO); 58765524Spendry 58865524Spendry if (CNEQ(cnp, "curproc", 7)) 58967389Spendry return (procfs_allocvp(dvp->v_mount, vpp, 0, Pcurproc)); 59067389Spendry 59167389Spendry pid = atopid(pname, cnp->cn_namelen); 59265524Spendry if (pid == NO_PID) 59365524Spendry return (ENOENT); 59465524Spendry 59565524Spendry procp = PFIND(pid); 59665524Spendry if (procp == 0) 59765524Spendry return (ENOENT); 59865524Spendry 59967389Spendry return (procfs_allocvp(dvp->v_mount, vpp, pid, Pproc)); 60065524Spendry 60165524Spendry case Pproc: 60265524Spendry if (cnp->cn_flags & ISDOTDOT) { 60365524Spendry error = procfs_root(dvp->v_mount, vpp); 60465524Spendry return (error); 60565524Spendry } 60665524Spendry 60765524Spendry procp = PFIND(pfs->pfs_pid); 60865524Spendry if (procp == 0) 60965524Spendry return (ENOENT); 61065524Spendry 61165524Spendry for (i = 0; i < Nprocent; i++) { 61265524Spendry struct pfsnames *dp = &procent[i]; 61365524Spendry 61465524Spendry if (cnp->cn_namelen == dp->d_namlen && 61567389Spendry bcmp(pname, dp->d_name, dp->d_namlen) == 0 && 61667389Spendry (dp->d_valid == NULL || (*dp->d_valid)(procp))) { 61765524Spendry pfs_type = dp->d_pfstype; 61865524Spendry goto found; 61965524Spendry } 62065524Spendry } 62165524Spendry return (ENOENT); 62265524Spendry 62365524Spendry found: 62465524Spendry if (pfs_type == Pfile) { 62565524Spendry nvp = procfs_findtextvp(procp); 62667389Spendry if (nvp == NULLVP) 62767389Spendry return (ENXIO); 62867389Spendry VREF(nvp); 62967389Spendry VOP_LOCK(nvp); 63067389Spendry *vpp = nvp; 63167389Spendry return (0); 63265524Spendry } 63365524Spendry 63467389Spendry return (procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, 63567389Spendry pfs_type)); 63667389Spendry 63765524Spendry default: 63865524Spendry return (ENOTDIR); 63965524Spendry } 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: { 70767389Spendry pid_t pid = pfs->pfs_pid; 70867389Spendry struct pfsnames *dt; 70965524Spendry 71067389Spendry for (dt = &procent[i]; i < Nprocent && uio->uio_resid >= UIO_MX; 71167389Spendry dt++, i++) { 71267389Spendry struct proc *p = PFIND(pid); 71367389Spendry 71467389Spendry if (p == NULL) 71565524Spendry break; 71665524Spendry 71767389Spendry if (dt->d_valid && (*dt->d_valid)(p) == 0) 71867389Spendry continue; 71965524Spendry 72065524Spendry dp->d_reclen = UIO_MX; 72167389Spendry dp->d_fileno = PROCFS_FILENO(pid, dt->d_pfstype); 72265524Spendry dp->d_namlen = dt->d_namlen; 72367389Spendry bcopy(dt->d_name, dp->d_name, dt->d_namlen + 1); 72467389Spendry dp->d_type = dt->d_type; 72567389Spendry 72667389Spendry if (error = uiomove((caddr_t)dp, UIO_MX, uio)) 72765524Spendry break; 72865524Spendry } 72965524Spendry 73065524Spendry break; 73165524Spendry 73265524Spendry } 73365524Spendry 73465524Spendry /* 73565524Spendry * this is for the root of the procfs filesystem 73665524Spendry * what is needed is a special entry for "curproc" 73765524Spendry * followed by an entry for each process on allproc 73865524Spendry #ifdef PROCFS_ZOMBIE 73965524Spendry * and zombproc. 74065524Spendry #endif 74165524Spendry */ 74265524Spendry 74365524Spendry case Proot: { 74465524Spendry #ifdef PROCFS_ZOMBIE 74565524Spendry int doingzomb = 0; 74665524Spendry #endif 74767389Spendry int pcnt = 0; 74867721Smckusick volatile struct proc *p = allproc.lh_first; 74965524Spendry 75067389Spendry again: 75167389Spendry for (; p && uio->uio_resid >= UIO_MX; i++, pcnt++) { 75265524Spendry bzero((char *) dp, UIO_MX); 75365524Spendry dp->d_reclen = UIO_MX; 75465524Spendry 75565524Spendry switch (i) { 75667389Spendry case 0: /* `.' */ 75767389Spendry case 1: /* `..' */ 75867389Spendry dp->d_fileno = PROCFS_FILENO(0, Proot); 75967389Spendry dp->d_namlen = i + 1; 76067389Spendry bcopy("..", dp->d_name, dp->d_namlen); 76167389Spendry dp->d_name[i + 1] = '\0'; 76267389Spendry dp->d_type = DT_DIR; 76365524Spendry break; 76465524Spendry 76567389Spendry case 2: 76667389Spendry dp->d_fileno = PROCFS_FILENO(0, Pcurproc); 76767389Spendry dp->d_namlen = 7; 76867389Spendry bcopy("curproc", dp->d_name, 8); 76967389Spendry dp->d_type = DT_LNK; 77067389Spendry break; 77167389Spendry 77265524Spendry default: 77367389Spendry while (pcnt < i) { 77467389Spendry pcnt++; 77567721Smckusick p = p->p_list.le_next; 77667389Spendry if (!p) 77767389Spendry goto done; 77865524Spendry } 77967389Spendry dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc); 78067389Spendry dp->d_namlen = sprintf(dp->d_name, "%ld", 78167389Spendry (long)p->p_pid); 78267389Spendry dp->d_type = DT_REG; 78367721Smckusick p = p->p_list.le_next; 78465524Spendry break; 78565524Spendry } 78667389Spendry 78767389Spendry if (error = uiomove((caddr_t)dp, UIO_MX, uio)) 78865524Spendry break; 78965524Spendry } 79067389Spendry done: 79165524Spendry 79267389Spendry #ifdef PROCFS_ZOMBIE 79367389Spendry if (p == 0 && doingzomb == 0) { 79467389Spendry doingzomb = 1; 79567721Smckusick p = zombproc.lh_first; 79667389Spendry goto again; 79767389Spendry } 79867389Spendry #endif 79967389Spendry 80065524Spendry break; 80165524Spendry 80265524Spendry } 80365524Spendry 80465524Spendry default: 80565524Spendry error = ENOTDIR; 80665524Spendry break; 80765524Spendry } 80865524Spendry 80965524Spendry uio->uio_offset = i * UIO_MX; 81065524Spendry 81165524Spendry return (error); 81265524Spendry } 81365524Spendry 81465524Spendry /* 81567389Spendry * readlink reads the link of `curproc' 81667389Spendry */ 81767389Spendry procfs_readlink(ap) 81867389Spendry struct vop_readlink_args *ap; 81967389Spendry { 82067389Spendry struct uio *uio = ap->a_uio; 82167389Spendry char buf[16]; /* should be enough */ 82267389Spendry int len; 82367389Spendry 82467389Spendry if (VTOPFS(ap->a_vp)->pfs_fileno != PROCFS_FILENO(0, Pcurproc)) 82567389Spendry return (EINVAL); 82667389Spendry 82767389Spendry len = sprintf(buf, "%ld", (long)curproc->p_pid); 82867389Spendry 82967389Spendry return (uiomove((caddr_t)buf, len, ap->a_uio)); 83067389Spendry } 83167389Spendry 83267389Spendry /* 83365524Spendry * convert decimal ascii to pid_t 83465524Spendry */ 83565524Spendry static pid_t 83665524Spendry atopid(b, len) 83765524Spendry const char *b; 83865524Spendry u_int len; 83965524Spendry { 84065524Spendry pid_t p = 0; 84165524Spendry 84265524Spendry while (len--) { 84365524Spendry char c = *b++; 84465524Spendry if (c < '0' || c > '9') 84565524Spendry return (NO_PID); 84665524Spendry p = 10 * p + (c - '0'); 84765524Spendry if (p > PID_MAX) 84865524Spendry return (NO_PID); 84965524Spendry } 85065524Spendry 85165524Spendry return (p); 85265524Spendry } 85365524Spendry 85465524Spendry /* 85565524Spendry * procfs vnode operations. 85665524Spendry */ 85765524Spendry int (**procfs_vnodeop_p)(); 85865524Spendry struct vnodeopv_entry_desc procfs_vnodeop_entries[] = { 85965524Spendry { &vop_default_desc, vn_default_error }, 86065524Spendry { &vop_lookup_desc, procfs_lookup }, /* lookup */ 86165524Spendry { &vop_create_desc, procfs_create }, /* create */ 86265524Spendry { &vop_mknod_desc, procfs_mknod }, /* mknod */ 86365524Spendry { &vop_open_desc, procfs_open }, /* open */ 86465524Spendry { &vop_close_desc, procfs_close }, /* close */ 86565524Spendry { &vop_access_desc, procfs_access }, /* access */ 86665524Spendry { &vop_getattr_desc, procfs_getattr }, /* getattr */ 86765524Spendry { &vop_setattr_desc, procfs_setattr }, /* setattr */ 86865524Spendry { &vop_read_desc, procfs_read }, /* read */ 86965524Spendry { &vop_write_desc, procfs_write }, /* write */ 87065524Spendry { &vop_ioctl_desc, procfs_ioctl }, /* ioctl */ 87165524Spendry { &vop_select_desc, procfs_select }, /* select */ 87265524Spendry { &vop_mmap_desc, procfs_mmap }, /* mmap */ 87365524Spendry { &vop_fsync_desc, procfs_fsync }, /* fsync */ 87465524Spendry { &vop_seek_desc, procfs_seek }, /* seek */ 87565524Spendry { &vop_remove_desc, procfs_remove }, /* remove */ 87665524Spendry { &vop_link_desc, procfs_link }, /* link */ 87765524Spendry { &vop_rename_desc, procfs_rename }, /* rename */ 87865524Spendry { &vop_mkdir_desc, procfs_mkdir }, /* mkdir */ 87965524Spendry { &vop_rmdir_desc, procfs_rmdir }, /* rmdir */ 88065524Spendry { &vop_symlink_desc, procfs_symlink }, /* symlink */ 88165524Spendry { &vop_readdir_desc, procfs_readdir }, /* readdir */ 88265524Spendry { &vop_readlink_desc, procfs_readlink }, /* readlink */ 88365524Spendry { &vop_abortop_desc, procfs_abortop }, /* abortop */ 88465524Spendry { &vop_inactive_desc, procfs_inactive }, /* inactive */ 88565524Spendry { &vop_reclaim_desc, procfs_reclaim }, /* reclaim */ 88665524Spendry { &vop_lock_desc, procfs_lock }, /* lock */ 88765524Spendry { &vop_unlock_desc, procfs_unlock }, /* unlock */ 88865524Spendry { &vop_bmap_desc, procfs_bmap }, /* bmap */ 88965524Spendry { &vop_strategy_desc, procfs_strategy }, /* strategy */ 89065524Spendry { &vop_print_desc, procfs_print }, /* print */ 89165524Spendry { &vop_islocked_desc, procfs_islocked }, /* islocked */ 89265524Spendry { &vop_pathconf_desc, procfs_pathconf }, /* pathconf */ 89365524Spendry { &vop_advlock_desc, procfs_advlock }, /* advlock */ 89465524Spendry { &vop_blkatoff_desc, procfs_blkatoff }, /* blkatoff */ 89565524Spendry { &vop_valloc_desc, procfs_valloc }, /* valloc */ 89665524Spendry { &vop_vfree_desc, procfs_vfree }, /* vfree */ 89765524Spendry { &vop_truncate_desc, procfs_truncate }, /* truncate */ 89865524Spendry { &vop_update_desc, procfs_update }, /* update */ 89965524Spendry { (struct vnodeop_desc*)NULL, (int(*)())NULL } 90065524Spendry }; 90165524Spendry struct vnodeopv_desc procfs_vnodeop_opv_desc = 90265524Spendry { &procfs_vnodeop_p, procfs_vnodeop_entries }; 903