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*68174Scgd * @(#)procfs_vnops.c 8.10 (Berkeley) 01/09/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; 18165524Spendry return (0); 18265524Spendry } 18365524Spendry 18465524Spendry /* 18565524Spendry * _inactive is called when the pfsnode 18665524Spendry * is vrele'd and the reference count goes 18765524Spendry * to zero. (vp) will be on the vnode free 18865524Spendry * list, so to get it back vget() must be 18965524Spendry * used. 19065524Spendry * 19165524Spendry * for procfs, check if the process is still 19265524Spendry * alive and if it isn't then just throw away 19365524Spendry * the vnode by calling vgone(). this may 19465524Spendry * be overkill and a waste of time since the 19565524Spendry * chances are that the process will still be 19665524Spendry * there and PFIND is not free. 19765524Spendry * 19865524Spendry * (vp) is not locked on entry or exit. 19965524Spendry */ 20065524Spendry procfs_inactive(ap) 20167367Smckusick struct vop_inactive_args /* { 20267367Smckusick struct vnode *a_vp; 20367367Smckusick } */ *ap; 20465524Spendry { 20565524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 20665524Spendry 20765524Spendry if (PFIND(pfs->pfs_pid) == 0) 20865524Spendry vgone(ap->a_vp); 20965524Spendry 21065524Spendry return (0); 21165524Spendry } 21265524Spendry 21365524Spendry /* 21465524Spendry * _reclaim is called when getnewvnode() 21565524Spendry * wants to make use of an entry on the vnode 21665524Spendry * free list. at this time the filesystem needs 21765524Spendry * to free any private data and remove the node 21865524Spendry * from any private lists. 21965524Spendry */ 22065524Spendry procfs_reclaim(ap) 22167367Smckusick struct vop_reclaim_args /* { 22267367Smckusick struct vnode *a_vp; 22367367Smckusick } */ *ap; 22465524Spendry { 22565524Spendry 22667389Spendry return (procfs_freevp(ap->a_vp)); 22765524Spendry } 22865524Spendry 22965524Spendry /* 23065743Spendry * Return POSIX pathconf information applicable to special devices. 23165743Spendry */ 23265743Spendry procfs_pathconf(ap) 23365743Spendry struct vop_pathconf_args /* { 23465743Spendry struct vnode *a_vp; 23565743Spendry int a_name; 23665743Spendry int *a_retval; 23765743Spendry } */ *ap; 23865743Spendry { 23965743Spendry 24065743Spendry switch (ap->a_name) { 24165743Spendry case _PC_LINK_MAX: 24265743Spendry *ap->a_retval = LINK_MAX; 24365743Spendry return (0); 24465743Spendry case _PC_MAX_CANON: 24565743Spendry *ap->a_retval = MAX_CANON; 24665743Spendry return (0); 24765743Spendry case _PC_MAX_INPUT: 24865743Spendry *ap->a_retval = MAX_INPUT; 24965743Spendry return (0); 25065743Spendry case _PC_PIPE_BUF: 25165743Spendry *ap->a_retval = PIPE_BUF; 25265743Spendry return (0); 25365743Spendry case _PC_CHOWN_RESTRICTED: 25465743Spendry *ap->a_retval = 1; 25565743Spendry return (0); 25665743Spendry case _PC_VDISABLE: 25765743Spendry *ap->a_retval = _POSIX_VDISABLE; 25865743Spendry return (0); 25965743Spendry default: 26065743Spendry return (EINVAL); 26165743Spendry } 26265743Spendry /* NOTREACHED */ 26365743Spendry } 26465743Spendry 26565743Spendry /* 26665524Spendry * _print is used for debugging. 26765524Spendry * just print a readable description 26865524Spendry * of (vp). 26965524Spendry */ 27065524Spendry procfs_print(ap) 27167367Smckusick struct vop_print_args /* { 27267367Smckusick struct vnode *a_vp; 27367367Smckusick } */ *ap; 27465524Spendry { 27565524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 27665524Spendry 27767389Spendry printf("tag VT_PROCFS, type %s, pid %d, mode %x, flags %x\n", 27867389Spendry pfs->pfs_type, pfs->pfs_pid, pfs->pfs_mode, pfs->pfs_flags); 27965524Spendry } 28065524Spendry 28165524Spendry /* 28265524Spendry * _abortop is called when operations such as 28365524Spendry * rename and create fail. this entry is responsible 28465524Spendry * for undoing any side-effects caused by the lookup. 28565524Spendry * this will always include freeing the pathname buffer. 28665524Spendry */ 28765524Spendry procfs_abortop(ap) 28867367Smckusick struct vop_abortop_args /* { 28967367Smckusick struct vnode *a_dvp; 29067367Smckusick struct componentname *a_cnp; 29167367Smckusick } */ *ap; 29265524Spendry { 29365524Spendry 29465524Spendry if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) 29565524Spendry FREE(ap->a_cnp->cn_pnbuf, M_NAMEI); 29665524Spendry return (0); 29765524Spendry } 29865524Spendry 29965524Spendry /* 30065524Spendry * generic entry point for unsupported operations 30165524Spendry */ 30265524Spendry procfs_badop() 30365524Spendry { 30465524Spendry 30565524Spendry return (EIO); 30665524Spendry } 30765524Spendry 30865524Spendry /* 30965524Spendry * Invent attributes for pfsnode (vp) and store 31065524Spendry * them in (vap). 31165524Spendry * Directories lengths are returned as zero since 31265524Spendry * any real length would require the genuine size 31365524Spendry * to be computed, and nothing cares anyway. 31465524Spendry * 31565524Spendry * this is relatively minimal for procfs. 31665524Spendry */ 31765524Spendry procfs_getattr(ap) 31867367Smckusick struct vop_getattr_args /* { 31967367Smckusick struct vnode *a_vp; 32067367Smckusick struct vattr *a_vap; 32167367Smckusick struct ucred *a_cred; 32267367Smckusick struct proc *a_p; 32367367Smckusick } */ *ap; 32465524Spendry { 32565524Spendry struct pfsnode *pfs = VTOPFS(ap->a_vp); 32665536Spendry struct vattr *vap = ap->a_vap; 32765524Spendry struct proc *procp; 328*68174Scgd struct timeval tv; 32965524Spendry int error; 33065524Spendry 33165524Spendry /* first check the process still exists */ 33266025Spendry switch (pfs->pfs_type) { 33366025Spendry case Proot: 33467389Spendry case Pcurproc: 33566025Spendry procp = 0; 33666025Spendry break; 33765524Spendry 33866025Spendry default: 33966025Spendry procp = PFIND(pfs->pfs_pid); 34066025Spendry if (procp == 0) 34166025Spendry return (ENOENT); 34266025Spendry } 34366025Spendry 34465524Spendry error = 0; 34565524Spendry 34665524Spendry /* start by zeroing out the attributes */ 34765536Spendry VATTR_NULL(vap); 34865524Spendry 34965524Spendry /* next do all the common fields */ 35065536Spendry vap->va_type = ap->a_vp->v_type; 35165536Spendry vap->va_mode = pfs->pfs_mode; 35265536Spendry vap->va_fileid = pfs->pfs_fileno; 35365536Spendry vap->va_flags = 0; 35465536Spendry vap->va_blocksize = PAGE_SIZE; 35565536Spendry vap->va_bytes = vap->va_size = 0; 35665524Spendry 35765524Spendry /* 35867389Spendry * Make all times be current TOD. 35967389Spendry * It would be possible to get the process start 36067389Spendry * time from the p_stat structure, but there's 36167389Spendry * no "file creation" time stamp anyway, and the 36267389Spendry * p_stat structure is not addressible if u. gets 36367389Spendry * swapped out for that process. 36467389Spendry */ 365*68174Scgd microtime(&tv); 366*68174Scgd TIMEVAL_TO_TIMESPEC(&tv, &vap->va_ctime); 36767389Spendry vap->va_atime = vap->va_mtime = vap->va_ctime; 36867389Spendry 36967389Spendry /* 37066025Spendry * If the process has exercised some setuid or setgid 37166025Spendry * privilege, then rip away read/write permission so 37266025Spendry * that only root can gain access. 37366025Spendry */ 37466025Spendry switch (pfs->pfs_type) { 37567389Spendry case Pmem: 37666025Spendry case Pregs: 37766025Spendry case Pfpregs: 37866025Spendry if (procp->p_flag & P_SUGID) 37966025Spendry vap->va_mode &= ~((VREAD|VWRITE)| 38066025Spendry ((VREAD|VWRITE)>>3)| 38166025Spendry ((VREAD|VWRITE)>>6)); 38267389Spendry case Pctl: 38367389Spendry case Pstatus: 38467389Spendry case Pnote: 38567389Spendry case Pnotepg: 38667389Spendry vap->va_nlink = 1; 38767389Spendry vap->va_uid = procp->p_ucred->cr_uid; 38867389Spendry vap->va_gid = procp->p_ucred->cr_gid; 38966025Spendry break; 39066025Spendry } 39166025Spendry 39266025Spendry /* 39365524Spendry * now do the object specific fields 39465524Spendry * 39565524Spendry * The size could be set from struct reg, but it's hardly 39665524Spendry * worth the trouble, and it puts some (potentially) machine 39765524Spendry * dependent data into this machine-independent code. If it 39865524Spendry * becomes important then this function should break out into 39965524Spendry * a per-file stat function in the corresponding .c file. 40065524Spendry */ 40165524Spendry 40265524Spendry switch (pfs->pfs_type) { 40365524Spendry case Proot: 40467389Spendry /* 40567389Spendry * Set nlink to 1 to tell fts(3) we don't actually know. 40667389Spendry */ 40767389Spendry vap->va_nlink = 1; 40865536Spendry vap->va_uid = 0; 40965536Spendry vap->va_gid = 0; 41067389Spendry vap->va_size = vap->va_bytes = DEV_BSIZE; 41165524Spendry break; 41265524Spendry 41367389Spendry case Pcurproc: { 41467389Spendry char buf[16]; /* should be enough */ 41567389Spendry vap->va_nlink = 1; 41667389Spendry vap->va_uid = 0; 41767389Spendry vap->va_gid = 0; 41867389Spendry vap->va_size = vap->va_bytes = 41967389Spendry sprintf(buf, "%ld", (long)curproc->p_pid); 42067389Spendry break; 42167389Spendry } 42267389Spendry 42365524Spendry case Pproc: 42465536Spendry vap->va_nlink = 2; 42565536Spendry vap->va_uid = procp->p_ucred->cr_uid; 42665536Spendry vap->va_gid = procp->p_ucred->cr_gid; 42767389Spendry vap->va_size = vap->va_bytes = DEV_BSIZE; 42865524Spendry break; 42965524Spendry 43065524Spendry case Pfile: 43165524Spendry error = EOPNOTSUPP; 43265524Spendry break; 43365524Spendry 43465524Spendry case Pmem: 43565536Spendry vap->va_bytes = vap->va_size = 43665524Spendry ctob(procp->p_vmspace->vm_tsize + 43765524Spendry procp->p_vmspace->vm_dsize + 43865524Spendry procp->p_vmspace->vm_ssize); 43965524Spendry break; 44065524Spendry 44165524Spendry case Pregs: 44267389Spendry vap->va_bytes = vap->va_size = sizeof(struct reg); 44367389Spendry break; 44467389Spendry 44565924Spendry case Pfpregs: 44667389Spendry vap->va_bytes = vap->va_size = sizeof(struct fpreg); 44767389Spendry break; 44867389Spendry 44965524Spendry case Pctl: 45065524Spendry case Pstatus: 45165524Spendry case Pnote: 45265524Spendry case Pnotepg: 45365524Spendry break; 45465524Spendry 45565524Spendry default: 45665524Spendry panic("procfs_getattr"); 45765524Spendry } 45865524Spendry 45965524Spendry return (error); 46065524Spendry } 46165524Spendry 46265524Spendry procfs_setattr(ap) 46367367Smckusick struct vop_setattr_args /* { 46467367Smckusick struct vnode *a_vp; 46567367Smckusick struct vattr *a_vap; 46667367Smckusick struct ucred *a_cred; 46767367Smckusick struct proc *a_p; 46867367Smckusick } */ *ap; 46965524Spendry { 47065524Spendry /* 47165524Spendry * just fake out attribute setting 47265524Spendry * it's not good to generate an error 47365524Spendry * return, otherwise things like creat() 47465524Spendry * will fail when they try to set the 47565524Spendry * file length to 0. worse, this means 47665524Spendry * that echo $note > /proc/$pid/note will fail. 47765524Spendry */ 47865524Spendry 47965524Spendry return (0); 48065524Spendry } 48165524Spendry 48265524Spendry /* 48365524Spendry * implement access checking. 48465524Spendry * 48565524Spendry * something very similar to this code is duplicated 48665524Spendry * throughout the 4bsd kernel and should be moved 48765524Spendry * into kern/vfs_subr.c sometime. 48865524Spendry * 48965524Spendry * actually, the check for super-user is slightly 49065524Spendry * broken since it will allow read access to write-only 49165524Spendry * objects. this doesn't cause any particular trouble 49265524Spendry * but does mean that the i/o entry points need to check 49365524Spendry * that the operation really does make sense. 49465524Spendry */ 49565524Spendry procfs_access(ap) 49667367Smckusick struct vop_access_args /* { 49767367Smckusick struct vnode *a_vp; 49867367Smckusick int a_mode; 49967367Smckusick struct ucred *a_cred; 50067367Smckusick struct proc *a_p; 50167367Smckusick } */ *ap; 50265524Spendry { 50365524Spendry struct vattr *vap; 50465524Spendry struct vattr vattr; 50565524Spendry int error; 50665524Spendry 50765524Spendry /* 50865524Spendry * If you're the super-user, 50965524Spendry * you always get access. 51065524Spendry */ 51167389Spendry if (ap->a_cred->cr_uid == 0) 51265524Spendry return (0); 51367389Spendry 51465524Spendry vap = &vattr; 51565524Spendry if (error = VOP_GETATTR(ap->a_vp, vap, ap->a_cred, ap->a_p)) 51665524Spendry return (error); 51765524Spendry 51865524Spendry /* 51965524Spendry * Access check is based on only one of owner, group, public. 52065524Spendry * If not owner, then check group. If not a member of the 52165524Spendry * group, then check public access. 52265524Spendry */ 52365524Spendry if (ap->a_cred->cr_uid != vap->va_uid) { 52465524Spendry gid_t *gp; 52565524Spendry int i; 52665524Spendry 52767389Spendry ap->a_mode >>= 3; 52865524Spendry gp = ap->a_cred->cr_groups; 52965524Spendry for (i = 0; i < ap->a_cred->cr_ngroups; i++, gp++) 53065524Spendry if (vap->va_gid == *gp) 53165524Spendry goto found; 53265524Spendry ap->a_mode >>= 3; 53365524Spendry found: 53465524Spendry ; 53565524Spendry } 53665524Spendry 53765524Spendry if ((vap->va_mode & ap->a_mode) == ap->a_mode) 53865524Spendry return (0); 53965524Spendry 54065524Spendry return (EACCES); 54165524Spendry } 54265524Spendry 54365524Spendry /* 54465524Spendry * lookup. this is incredibly complicated in the 54565524Spendry * general case, however for most pseudo-filesystems 54665524Spendry * very little needs to be done. 54765524Spendry * 54865524Spendry * unless you want to get a migraine, just make sure your 54965524Spendry * filesystem doesn't do any locking of its own. otherwise 55065524Spendry * read and inwardly digest ufs_lookup(). 55165524Spendry */ 55265524Spendry procfs_lookup(ap) 55367367Smckusick struct vop_lookup_args /* { 55467367Smckusick struct vnode * a_dvp; 55567367Smckusick struct vnode ** a_vpp; 55667367Smckusick struct componentname * a_cnp; 55767367Smckusick } */ *ap; 55865524Spendry { 55965524Spendry struct componentname *cnp = ap->a_cnp; 56065524Spendry struct vnode **vpp = ap->a_vpp; 56165524Spendry struct vnode *dvp = ap->a_dvp; 56265524Spendry char *pname = cnp->cn_nameptr; 56365524Spendry int error = 0; 56465524Spendry pid_t pid; 56565524Spendry struct vnode *nvp; 56665524Spendry struct pfsnode *pfs; 56765524Spendry struct proc *procp; 56865524Spendry pfstype pfs_type; 56965524Spendry int i; 57065524Spendry 57165524Spendry if (cnp->cn_namelen == 1 && *pname == '.') { 57265524Spendry *vpp = dvp; 57365524Spendry VREF(dvp); 57465524Spendry /*VOP_LOCK(dvp);*/ 57565524Spendry return (0); 57665524Spendry } 57765524Spendry 57865524Spendry *vpp = NULL; 57965524Spendry 58065524Spendry pfs = VTOPFS(dvp); 58165524Spendry switch (pfs->pfs_type) { 58265524Spendry case Proot: 58365524Spendry if (cnp->cn_flags & ISDOTDOT) 58465524Spendry return (EIO); 58565524Spendry 58665524Spendry if (CNEQ(cnp, "curproc", 7)) 58767389Spendry return (procfs_allocvp(dvp->v_mount, vpp, 0, Pcurproc)); 58867389Spendry 58967389Spendry pid = atopid(pname, cnp->cn_namelen); 59065524Spendry if (pid == NO_PID) 59165524Spendry return (ENOENT); 59265524Spendry 59365524Spendry procp = PFIND(pid); 59465524Spendry if (procp == 0) 59565524Spendry return (ENOENT); 59665524Spendry 59767389Spendry return (procfs_allocvp(dvp->v_mount, vpp, pid, Pproc)); 59865524Spendry 59965524Spendry case Pproc: 60065524Spendry if (cnp->cn_flags & ISDOTDOT) { 60165524Spendry error = procfs_root(dvp->v_mount, vpp); 60265524Spendry return (error); 60365524Spendry } 60465524Spendry 60565524Spendry procp = PFIND(pfs->pfs_pid); 60665524Spendry if (procp == 0) 60765524Spendry return (ENOENT); 60865524Spendry 60965524Spendry for (i = 0; i < Nprocent; i++) { 61065524Spendry struct pfsnames *dp = &procent[i]; 61165524Spendry 61265524Spendry if (cnp->cn_namelen == dp->d_namlen && 61367389Spendry bcmp(pname, dp->d_name, dp->d_namlen) == 0 && 61467389Spendry (dp->d_valid == NULL || (*dp->d_valid)(procp))) { 61565524Spendry pfs_type = dp->d_pfstype; 61665524Spendry goto found; 61765524Spendry } 61865524Spendry } 61965524Spendry return (ENOENT); 62065524Spendry 62165524Spendry found: 62265524Spendry if (pfs_type == Pfile) { 62365524Spendry nvp = procfs_findtextvp(procp); 62467389Spendry if (nvp == NULLVP) 62567389Spendry return (ENXIO); 62667389Spendry VREF(nvp); 62767389Spendry VOP_LOCK(nvp); 62867389Spendry *vpp = nvp; 62967389Spendry return (0); 63065524Spendry } 63165524Spendry 63267389Spendry return (procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, 63367389Spendry pfs_type)); 63467389Spendry 63565524Spendry default: 63665524Spendry return (ENOTDIR); 63765524Spendry } 63865524Spendry } 63965524Spendry 64067389Spendry int 64167389Spendry procfs_validfile(p) 64267389Spendry struct proc *p; 64367389Spendry { 64467389Spendry 64567389Spendry return (procfs_findtextvp(p) != NULLVP); 64667389Spendry } 64767389Spendry 64865524Spendry /* 64965524Spendry * readdir returns directory entries from pfsnode (vp). 65065524Spendry * 65165524Spendry * the strategy here with procfs is to generate a single 65265524Spendry * directory entry at a time (struct pfsdent) and then 65365524Spendry * copy that out to userland using uiomove. a more efficent 65465524Spendry * though more complex implementation, would try to minimize 65565524Spendry * the number of calls to uiomove(). for procfs, this is 65665524Spendry * hardly worth the added code complexity. 65765524Spendry * 65865524Spendry * this should just be done through read() 65965524Spendry */ 66065524Spendry procfs_readdir(ap) 66167367Smckusick struct vop_readdir_args /* { 66267367Smckusick struct vnode *a_vp; 66367367Smckusick struct uio *a_uio; 66467367Smckusick struct ucred *a_cred; 66567367Smckusick int *a_eofflag; 66667367Smckusick u_long *a_cookies; 66767367Smckusick int a_ncookies; 66867367Smckusick } */ *ap; 66965524Spendry { 67065524Spendry struct uio *uio = ap->a_uio; 67165524Spendry struct pfsdent d; 67265524Spendry struct pfsdent *dp = &d; 67365524Spendry struct pfsnode *pfs; 67465524Spendry int error; 67565524Spendry int count; 67665524Spendry int i; 67765524Spendry 67867367Smckusick /* 67967367Smckusick * We don't allow exporting procfs mounts, and currently local 68067367Smckusick * requests do not need cookies. 68167367Smckusick */ 68267367Smckusick if (ap->a_ncookies) 68367367Smckusick panic("procfs_readdir: not hungry"); 68467367Smckusick 68565524Spendry pfs = VTOPFS(ap->a_vp); 68665524Spendry 68765524Spendry if (uio->uio_resid < UIO_MX) 68865524Spendry return (EINVAL); 68965524Spendry if (uio->uio_offset & (UIO_MX-1)) 69065524Spendry return (EINVAL); 69165524Spendry if (uio->uio_offset < 0) 69265524Spendry return (EINVAL); 69365524Spendry 69465524Spendry error = 0; 69565524Spendry count = 0; 69665524Spendry i = uio->uio_offset / UIO_MX; 69765524Spendry 69865524Spendry switch (pfs->pfs_type) { 69965524Spendry /* 70065524Spendry * this is for the process-specific sub-directories. 70165524Spendry * all that is needed to is copy out all the entries 70265524Spendry * from the procent[] table (top of this file). 70365524Spendry */ 70465524Spendry case Pproc: { 70567389Spendry pid_t pid = pfs->pfs_pid; 70667389Spendry struct pfsnames *dt; 70765524Spendry 70867389Spendry for (dt = &procent[i]; i < Nprocent && uio->uio_resid >= UIO_MX; 70967389Spendry dt++, i++) { 71067389Spendry struct proc *p = PFIND(pid); 71167389Spendry 71267389Spendry if (p == NULL) 71365524Spendry break; 71465524Spendry 71567389Spendry if (dt->d_valid && (*dt->d_valid)(p) == 0) 71667389Spendry continue; 71765524Spendry 71865524Spendry dp->d_reclen = UIO_MX; 71967389Spendry dp->d_fileno = PROCFS_FILENO(pid, dt->d_pfstype); 72065524Spendry dp->d_namlen = dt->d_namlen; 72167389Spendry bcopy(dt->d_name, dp->d_name, dt->d_namlen + 1); 72267389Spendry dp->d_type = dt->d_type; 72367389Spendry 72467389Spendry if (error = uiomove((caddr_t)dp, UIO_MX, uio)) 72565524Spendry break; 72665524Spendry } 72765524Spendry 72865524Spendry break; 72965524Spendry 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 */ 87165524Spendry { &vop_fsync_desc, procfs_fsync }, /* fsync */ 87265524Spendry { &vop_seek_desc, procfs_seek }, /* seek */ 87365524Spendry { &vop_remove_desc, procfs_remove }, /* remove */ 87465524Spendry { &vop_link_desc, procfs_link }, /* link */ 87565524Spendry { &vop_rename_desc, procfs_rename }, /* rename */ 87665524Spendry { &vop_mkdir_desc, procfs_mkdir }, /* mkdir */ 87765524Spendry { &vop_rmdir_desc, procfs_rmdir }, /* rmdir */ 87865524Spendry { &vop_symlink_desc, procfs_symlink }, /* symlink */ 87965524Spendry { &vop_readdir_desc, procfs_readdir }, /* readdir */ 88065524Spendry { &vop_readlink_desc, procfs_readlink }, /* readlink */ 88165524Spendry { &vop_abortop_desc, procfs_abortop }, /* abortop */ 88265524Spendry { &vop_inactive_desc, procfs_inactive }, /* inactive */ 88365524Spendry { &vop_reclaim_desc, procfs_reclaim }, /* reclaim */ 88465524Spendry { &vop_lock_desc, procfs_lock }, /* lock */ 88565524Spendry { &vop_unlock_desc, procfs_unlock }, /* unlock */ 88665524Spendry { &vop_bmap_desc, procfs_bmap }, /* bmap */ 88765524Spendry { &vop_strategy_desc, procfs_strategy }, /* strategy */ 88865524Spendry { &vop_print_desc, procfs_print }, /* print */ 88965524Spendry { &vop_islocked_desc, procfs_islocked }, /* islocked */ 89065524Spendry { &vop_pathconf_desc, procfs_pathconf }, /* pathconf */ 89165524Spendry { &vop_advlock_desc, procfs_advlock }, /* advlock */ 89265524Spendry { &vop_blkatoff_desc, procfs_blkatoff }, /* blkatoff */ 89365524Spendry { &vop_valloc_desc, procfs_valloc }, /* valloc */ 89465524Spendry { &vop_vfree_desc, procfs_vfree }, /* vfree */ 89565524Spendry { &vop_truncate_desc, procfs_truncate }, /* truncate */ 89665524Spendry { &vop_update_desc, procfs_update }, /* update */ 89765524Spendry { (struct vnodeop_desc*)NULL, (int(*)())NULL } 89865524Spendry }; 89965524Spendry struct vnodeopv_desc procfs_vnodeop_opv_desc = 90065524Spendry { &procfs_vnodeop_p, procfs_vnodeop_entries }; 901