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*67389Spendry * @(#)procfs_vnops.c 8.8 (Berkeley) 06/15/94 1265524Spendry * 1365524Spendry * From: 1465524Spendry * $Id: procfs_vnops.c,v 3.2 1993/12/15 09:40:17 jsp Exp $ 1565524Spendry */ 1665524Spendry 1765524Spendry /* 1865524Spendry * procfs vnode interface 1965524Spendry */ 2065524Spendry 2165524Spendry #include <sys/param.h> 2265524Spendry #include <sys/systm.h> 2365524Spendry #include <sys/time.h> 2465524Spendry #include <sys/kernel.h> 2565524Spendry #include <sys/file.h> 2665524Spendry #include <sys/proc.h> 2765524Spendry #include <sys/vnode.h> 2865524Spendry #include <sys/namei.h> 2965524Spendry #include <sys/malloc.h> 3065524Spendry #include <sys/dirent.h> 3165524Spendry #include <sys/resourcevar.h> 32*67389Spendry #include <vm/vm.h> /* for PAGE_SIZE */ 33*67389Spendry #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 { 47*67389Spendry u_char d_type; 48*67389Spendry u_char d_namlen; 4965524Spendry char d_name[PROCFS_NAMELEN]; 5065524Spendry pfstype d_pfstype; 51*67389Spendry int (*d_valid) __P((struct proc *p)); 5265524Spendry } procent[] = { 5365524Spendry #define N(s) sizeof(s)-1, s 5465524Spendry /* namlen, nam, type */ 55*67389Spendry { DT_DIR, N("."), Pproc, NULL }, 56*67389Spendry { DT_DIR, N(".."), Proot, NULL }, 57*67389Spendry { DT_REG, N("file"), Pfile, procfs_validfile }, 58*67389Spendry { DT_REG, N("mem"), Pmem, NULL }, 59*67389Spendry { DT_REG, N("regs"), Pregs, procfs_validregs }, 60*67389Spendry { DT_REG, N("fpregs"), Pfpregs, procfs_validfpregs }, 61*67389Spendry { DT_REG, N("ctl"), Pctl, NULL }, 62*67389Spendry { DT_REG, N("status"), Pstatus, NULL }, 63*67389Spendry { DT_REG, N("note"), Pnote, NULL }, 64*67389Spendry { 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) || 98*67389Spendry (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 226*67389Spendry 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 277*67389Spendry printf("tag VT_PROCFS, type %s, pid %d, mode %x, flags %x\n", 278*67389Spendry 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; 32865524Spendry int error; 32965524Spendry 33065524Spendry /* first check the process still exists */ 33166025Spendry switch (pfs->pfs_type) { 33266025Spendry case Proot: 333*67389Spendry case Pcurproc: 33466025Spendry procp = 0; 33566025Spendry break; 33665524Spendry 33766025Spendry default: 33866025Spendry procp = PFIND(pfs->pfs_pid); 33966025Spendry if (procp == 0) 34066025Spendry return (ENOENT); 34166025Spendry } 34266025Spendry 34365524Spendry error = 0; 34465524Spendry 34565524Spendry /* start by zeroing out the attributes */ 34665536Spendry VATTR_NULL(vap); 34765524Spendry 34865524Spendry /* next do all the common fields */ 34965536Spendry vap->va_type = ap->a_vp->v_type; 35065536Spendry vap->va_mode = pfs->pfs_mode; 35165536Spendry vap->va_fileid = pfs->pfs_fileno; 35265536Spendry vap->va_flags = 0; 35365536Spendry vap->va_blocksize = PAGE_SIZE; 35465536Spendry vap->va_bytes = vap->va_size = 0; 35565524Spendry 35665524Spendry /* 357*67389Spendry * Make all times be current TOD. 358*67389Spendry * It would be possible to get the process start 359*67389Spendry * time from the p_stat structure, but there's 360*67389Spendry * no "file creation" time stamp anyway, and the 361*67389Spendry * p_stat structure is not addressible if u. gets 362*67389Spendry * swapped out for that process. 363*67389Spendry * 364*67389Spendry * XXX 365*67389Spendry * Note that microtime() returns a timeval, not a timespec. 366*67389Spendry */ 367*67389Spendry microtime(&vap->va_ctime); 368*67389Spendry vap->va_atime = vap->va_mtime = vap->va_ctime; 369*67389Spendry 370*67389Spendry /* 37166025Spendry * If the process has exercised some setuid or setgid 37266025Spendry * privilege, then rip away read/write permission so 37366025Spendry * that only root can gain access. 37466025Spendry */ 37566025Spendry switch (pfs->pfs_type) { 376*67389Spendry case Pmem: 37766025Spendry case Pregs: 37866025Spendry case Pfpregs: 37966025Spendry if (procp->p_flag & P_SUGID) 38066025Spendry vap->va_mode &= ~((VREAD|VWRITE)| 38166025Spendry ((VREAD|VWRITE)>>3)| 38266025Spendry ((VREAD|VWRITE)>>6)); 383*67389Spendry case Pctl: 384*67389Spendry case Pstatus: 385*67389Spendry case Pnote: 386*67389Spendry case Pnotepg: 387*67389Spendry vap->va_nlink = 1; 388*67389Spendry vap->va_uid = procp->p_ucred->cr_uid; 389*67389Spendry vap->va_gid = procp->p_ucred->cr_gid; 39066025Spendry break; 39166025Spendry } 39266025Spendry 39366025Spendry /* 39465524Spendry * now do the object specific fields 39565524Spendry * 39665524Spendry * The size could be set from struct reg, but it's hardly 39765524Spendry * worth the trouble, and it puts some (potentially) machine 39865524Spendry * dependent data into this machine-independent code. If it 39965524Spendry * becomes important then this function should break out into 40065524Spendry * a per-file stat function in the corresponding .c file. 40165524Spendry */ 40265524Spendry 40365524Spendry switch (pfs->pfs_type) { 40465524Spendry case Proot: 405*67389Spendry /* 406*67389Spendry * Set nlink to 1 to tell fts(3) we don't actually know. 407*67389Spendry */ 408*67389Spendry vap->va_nlink = 1; 40965536Spendry vap->va_uid = 0; 41065536Spendry vap->va_gid = 0; 411*67389Spendry vap->va_size = vap->va_bytes = DEV_BSIZE; 41265524Spendry break; 41365524Spendry 414*67389Spendry case Pcurproc: { 415*67389Spendry char buf[16]; /* should be enough */ 416*67389Spendry vap->va_nlink = 1; 417*67389Spendry vap->va_uid = 0; 418*67389Spendry vap->va_gid = 0; 419*67389Spendry vap->va_size = vap->va_bytes = 420*67389Spendry sprintf(buf, "%ld", (long)curproc->p_pid); 421*67389Spendry break; 422*67389Spendry } 423*67389Spendry 42465524Spendry case Pproc: 42565536Spendry vap->va_nlink = 2; 42665536Spendry vap->va_uid = procp->p_ucred->cr_uid; 42765536Spendry vap->va_gid = procp->p_ucred->cr_gid; 428*67389Spendry vap->va_size = vap->va_bytes = DEV_BSIZE; 42965524Spendry break; 43065524Spendry 43165524Spendry case Pfile: 43265524Spendry error = EOPNOTSUPP; 43365524Spendry break; 43465524Spendry 43565524Spendry case Pmem: 43665536Spendry vap->va_bytes = vap->va_size = 43765524Spendry ctob(procp->p_vmspace->vm_tsize + 43865524Spendry procp->p_vmspace->vm_dsize + 43965524Spendry procp->p_vmspace->vm_ssize); 44065524Spendry break; 44165524Spendry 44265524Spendry case Pregs: 443*67389Spendry vap->va_bytes = vap->va_size = sizeof(struct reg); 444*67389Spendry break; 445*67389Spendry 44665924Spendry case Pfpregs: 447*67389Spendry vap->va_bytes = vap->va_size = sizeof(struct fpreg); 448*67389Spendry break; 449*67389Spendry 45065524Spendry case Pctl: 45165524Spendry case Pstatus: 45265524Spendry case Pnote: 45365524Spendry case Pnotepg: 45465524Spendry break; 45565524Spendry 45665524Spendry default: 45765524Spendry panic("procfs_getattr"); 45865524Spendry } 45965524Spendry 46065524Spendry return (error); 46165524Spendry } 46265524Spendry 46365524Spendry procfs_setattr(ap) 46467367Smckusick struct vop_setattr_args /* { 46567367Smckusick struct vnode *a_vp; 46667367Smckusick struct vattr *a_vap; 46767367Smckusick struct ucred *a_cred; 46867367Smckusick struct proc *a_p; 46967367Smckusick } */ *ap; 47065524Spendry { 47165524Spendry /* 47265524Spendry * just fake out attribute setting 47365524Spendry * it's not good to generate an error 47465524Spendry * return, otherwise things like creat() 47565524Spendry * will fail when they try to set the 47665524Spendry * file length to 0. worse, this means 47765524Spendry * that echo $note > /proc/$pid/note will fail. 47865524Spendry */ 47965524Spendry 48065524Spendry return (0); 48165524Spendry } 48265524Spendry 48365524Spendry /* 48465524Spendry * implement access checking. 48565524Spendry * 48665524Spendry * something very similar to this code is duplicated 48765524Spendry * throughout the 4bsd kernel and should be moved 48865524Spendry * into kern/vfs_subr.c sometime. 48965524Spendry * 49065524Spendry * actually, the check for super-user is slightly 49165524Spendry * broken since it will allow read access to write-only 49265524Spendry * objects. this doesn't cause any particular trouble 49365524Spendry * but does mean that the i/o entry points need to check 49465524Spendry * that the operation really does make sense. 49565524Spendry */ 49665524Spendry procfs_access(ap) 49767367Smckusick struct vop_access_args /* { 49867367Smckusick struct vnode *a_vp; 49967367Smckusick int a_mode; 50067367Smckusick struct ucred *a_cred; 50167367Smckusick struct proc *a_p; 50267367Smckusick } */ *ap; 50365524Spendry { 50465524Spendry struct vattr *vap; 50565524Spendry struct vattr vattr; 50665524Spendry int error; 50765524Spendry 50865524Spendry /* 50965524Spendry * If you're the super-user, 51065524Spendry * you always get access. 51165524Spendry */ 512*67389Spendry if (ap->a_cred->cr_uid == 0) 51365524Spendry return (0); 514*67389Spendry 51565524Spendry vap = &vattr; 51665524Spendry if (error = VOP_GETATTR(ap->a_vp, vap, ap->a_cred, ap->a_p)) 51765524Spendry return (error); 51865524Spendry 51965524Spendry /* 52065524Spendry * Access check is based on only one of owner, group, public. 52165524Spendry * If not owner, then check group. If not a member of the 52265524Spendry * group, then check public access. 52365524Spendry */ 52465524Spendry if (ap->a_cred->cr_uid != vap->va_uid) { 52565524Spendry gid_t *gp; 52665524Spendry int i; 52765524Spendry 528*67389Spendry ap->a_mode >>= 3; 52965524Spendry gp = ap->a_cred->cr_groups; 53065524Spendry for (i = 0; i < ap->a_cred->cr_ngroups; i++, gp++) 53165524Spendry if (vap->va_gid == *gp) 53265524Spendry goto found; 53365524Spendry ap->a_mode >>= 3; 53465524Spendry found: 53565524Spendry ; 53665524Spendry } 53765524Spendry 53865524Spendry if ((vap->va_mode & ap->a_mode) == ap->a_mode) 53965524Spendry return (0); 54065524Spendry 54165524Spendry return (EACCES); 54265524Spendry } 54365524Spendry 54465524Spendry /* 54565524Spendry * lookup. this is incredibly complicated in the 54665524Spendry * general case, however for most pseudo-filesystems 54765524Spendry * very little needs to be done. 54865524Spendry * 54965524Spendry * unless you want to get a migraine, just make sure your 55065524Spendry * filesystem doesn't do any locking of its own. otherwise 55165524Spendry * read and inwardly digest ufs_lookup(). 55265524Spendry */ 55365524Spendry procfs_lookup(ap) 55467367Smckusick struct vop_lookup_args /* { 55567367Smckusick struct vnode * a_dvp; 55667367Smckusick struct vnode ** a_vpp; 55767367Smckusick struct componentname * a_cnp; 55867367Smckusick } */ *ap; 55965524Spendry { 56065524Spendry struct componentname *cnp = ap->a_cnp; 56165524Spendry struct vnode **vpp = ap->a_vpp; 56265524Spendry struct vnode *dvp = ap->a_dvp; 56365524Spendry char *pname = cnp->cn_nameptr; 56465524Spendry int error = 0; 56565524Spendry pid_t pid; 56665524Spendry struct vnode *nvp; 56765524Spendry struct pfsnode *pfs; 56865524Spendry struct proc *procp; 56965524Spendry pfstype pfs_type; 57065524Spendry int i; 57165524Spendry 57265524Spendry if (cnp->cn_namelen == 1 && *pname == '.') { 57365524Spendry *vpp = dvp; 57465524Spendry VREF(dvp); 57565524Spendry /*VOP_LOCK(dvp);*/ 57665524Spendry return (0); 57765524Spendry } 57865524Spendry 57965524Spendry *vpp = NULL; 58065524Spendry 58165524Spendry pfs = VTOPFS(dvp); 58265524Spendry switch (pfs->pfs_type) { 58365524Spendry case Proot: 58465524Spendry if (cnp->cn_flags & ISDOTDOT) 58565524Spendry return (EIO); 58665524Spendry 58765524Spendry if (CNEQ(cnp, "curproc", 7)) 588*67389Spendry return (procfs_allocvp(dvp->v_mount, vpp, 0, Pcurproc)); 589*67389Spendry 590*67389Spendry pid = atopid(pname, cnp->cn_namelen); 59165524Spendry if (pid == NO_PID) 59265524Spendry return (ENOENT); 59365524Spendry 59465524Spendry procp = PFIND(pid); 59565524Spendry if (procp == 0) 59665524Spendry return (ENOENT); 59765524Spendry 598*67389Spendry return (procfs_allocvp(dvp->v_mount, vpp, pid, Pproc)); 59965524Spendry 60065524Spendry case Pproc: 60165524Spendry if (cnp->cn_flags & ISDOTDOT) { 60265524Spendry error = procfs_root(dvp->v_mount, vpp); 60365524Spendry return (error); 60465524Spendry } 60565524Spendry 60665524Spendry procp = PFIND(pfs->pfs_pid); 60765524Spendry if (procp == 0) 60865524Spendry return (ENOENT); 60965524Spendry 61065524Spendry for (i = 0; i < Nprocent; i++) { 61165524Spendry struct pfsnames *dp = &procent[i]; 61265524Spendry 61365524Spendry if (cnp->cn_namelen == dp->d_namlen && 614*67389Spendry bcmp(pname, dp->d_name, dp->d_namlen) == 0 && 615*67389Spendry (dp->d_valid == NULL || (*dp->d_valid)(procp))) { 61665524Spendry pfs_type = dp->d_pfstype; 61765524Spendry goto found; 61865524Spendry } 61965524Spendry } 62065524Spendry return (ENOENT); 62165524Spendry 62265524Spendry found: 62365524Spendry if (pfs_type == Pfile) { 62465524Spendry nvp = procfs_findtextvp(procp); 625*67389Spendry if (nvp == NULLVP) 626*67389Spendry return (ENXIO); 627*67389Spendry VREF(nvp); 628*67389Spendry VOP_LOCK(nvp); 629*67389Spendry *vpp = nvp; 630*67389Spendry return (0); 63165524Spendry } 63265524Spendry 633*67389Spendry return (procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, 634*67389Spendry pfs_type)); 635*67389Spendry 63665524Spendry default: 63765524Spendry return (ENOTDIR); 63865524Spendry } 63965524Spendry } 64065524Spendry 641*67389Spendry int 642*67389Spendry procfs_validfile(p) 643*67389Spendry struct proc *p; 644*67389Spendry { 645*67389Spendry 646*67389Spendry return (procfs_findtextvp(p) != NULLVP); 647*67389Spendry } 648*67389Spendry 64965524Spendry /* 65065524Spendry * readdir returns directory entries from pfsnode (vp). 65165524Spendry * 65265524Spendry * the strategy here with procfs is to generate a single 65365524Spendry * directory entry at a time (struct pfsdent) and then 65465524Spendry * copy that out to userland using uiomove. a more efficent 65565524Spendry * though more complex implementation, would try to minimize 65665524Spendry * the number of calls to uiomove(). for procfs, this is 65765524Spendry * hardly worth the added code complexity. 65865524Spendry * 65965524Spendry * this should just be done through read() 66065524Spendry */ 66165524Spendry procfs_readdir(ap) 66267367Smckusick struct vop_readdir_args /* { 66367367Smckusick struct vnode *a_vp; 66467367Smckusick struct uio *a_uio; 66567367Smckusick struct ucred *a_cred; 66667367Smckusick int *a_eofflag; 66767367Smckusick u_long *a_cookies; 66867367Smckusick int a_ncookies; 66967367Smckusick } */ *ap; 67065524Spendry { 67165524Spendry struct uio *uio = ap->a_uio; 67265524Spendry struct pfsdent d; 67365524Spendry struct pfsdent *dp = &d; 67465524Spendry struct pfsnode *pfs; 67565524Spendry int error; 67665524Spendry int count; 67765524Spendry int i; 67865524Spendry 67967367Smckusick /* 68067367Smckusick * We don't allow exporting procfs mounts, and currently local 68167367Smckusick * requests do not need cookies. 68267367Smckusick */ 68367367Smckusick if (ap->a_ncookies) 68467367Smckusick panic("procfs_readdir: not hungry"); 68567367Smckusick 68665524Spendry pfs = VTOPFS(ap->a_vp); 68765524Spendry 68865524Spendry if (uio->uio_resid < UIO_MX) 68965524Spendry return (EINVAL); 69065524Spendry if (uio->uio_offset & (UIO_MX-1)) 69165524Spendry return (EINVAL); 69265524Spendry if (uio->uio_offset < 0) 69365524Spendry return (EINVAL); 69465524Spendry 69565524Spendry error = 0; 69665524Spendry count = 0; 69765524Spendry i = uio->uio_offset / UIO_MX; 69865524Spendry 69965524Spendry switch (pfs->pfs_type) { 70065524Spendry /* 70165524Spendry * this is for the process-specific sub-directories. 70265524Spendry * all that is needed to is copy out all the entries 70365524Spendry * from the procent[] table (top of this file). 70465524Spendry */ 70565524Spendry case Pproc: { 706*67389Spendry pid_t pid = pfs->pfs_pid; 707*67389Spendry struct pfsnames *dt; 70865524Spendry 709*67389Spendry for (dt = &procent[i]; i < Nprocent && uio->uio_resid >= UIO_MX; 710*67389Spendry dt++, i++) { 711*67389Spendry struct proc *p = PFIND(pid); 712*67389Spendry 713*67389Spendry if (p == NULL) 71465524Spendry break; 71565524Spendry 716*67389Spendry if (dt->d_valid && (*dt->d_valid)(p) == 0) 717*67389Spendry continue; 71865524Spendry 71965524Spendry dp->d_reclen = UIO_MX; 720*67389Spendry dp->d_fileno = PROCFS_FILENO(pid, dt->d_pfstype); 72165524Spendry dp->d_namlen = dt->d_namlen; 722*67389Spendry bcopy(dt->d_name, dp->d_name, dt->d_namlen + 1); 723*67389Spendry dp->d_type = dt->d_type; 724*67389Spendry 725*67389Spendry if (error = uiomove((caddr_t)dp, UIO_MX, uio)) 72665524Spendry break; 72765524Spendry } 72865524Spendry 72965524Spendry break; 73065524Spendry 73165524Spendry } 73265524Spendry 73365524Spendry /* 73465524Spendry * this is for the root of the procfs filesystem 73565524Spendry * what is needed is a special entry for "curproc" 73665524Spendry * followed by an entry for each process on allproc 73765524Spendry #ifdef PROCFS_ZOMBIE 73865524Spendry * and zombproc. 73965524Spendry #endif 74065524Spendry */ 74165524Spendry 74265524Spendry case Proot: { 74365524Spendry #ifdef PROCFS_ZOMBIE 74465524Spendry int doingzomb = 0; 74565524Spendry #endif 746*67389Spendry int pcnt = 0; 747*67389Spendry volatile struct proc *p = allproc; 74865524Spendry 749*67389Spendry again: 750*67389Spendry for (; p && uio->uio_resid >= UIO_MX; i++, pcnt++) { 75165524Spendry bzero((char *) dp, UIO_MX); 75265524Spendry dp->d_reclen = UIO_MX; 75365524Spendry 75465524Spendry switch (i) { 755*67389Spendry case 0: /* `.' */ 756*67389Spendry case 1: /* `..' */ 757*67389Spendry dp->d_fileno = PROCFS_FILENO(0, Proot); 758*67389Spendry dp->d_namlen = i + 1; 759*67389Spendry bcopy("..", dp->d_name, dp->d_namlen); 760*67389Spendry dp->d_name[i + 1] = '\0'; 761*67389Spendry dp->d_type = DT_DIR; 76265524Spendry break; 76365524Spendry 764*67389Spendry case 2: 765*67389Spendry dp->d_fileno = PROCFS_FILENO(0, Pcurproc); 766*67389Spendry dp->d_namlen = 7; 767*67389Spendry bcopy("curproc", dp->d_name, 8); 768*67389Spendry dp->d_type = DT_LNK; 769*67389Spendry break; 770*67389Spendry 77165524Spendry default: 772*67389Spendry while (pcnt < i) { 773*67389Spendry pcnt++; 774*67389Spendry p = p->p_next; 775*67389Spendry if (!p) 776*67389Spendry goto done; 77765524Spendry } 778*67389Spendry dp->d_fileno = PROCFS_FILENO(p->p_pid, Pproc); 779*67389Spendry dp->d_namlen = sprintf(dp->d_name, "%ld", 780*67389Spendry (long)p->p_pid); 781*67389Spendry dp->d_type = DT_REG; 78265524Spendry p = p->p_next; 78365524Spendry break; 78465524Spendry } 785*67389Spendry 786*67389Spendry if (error = uiomove((caddr_t)dp, UIO_MX, uio)) 78765524Spendry break; 78865524Spendry } 789*67389Spendry done: 79065524Spendry 791*67389Spendry #ifdef PROCFS_ZOMBIE 792*67389Spendry if (p == 0 && doingzomb == 0) { 793*67389Spendry doingzomb = 1; 794*67389Spendry p = zombproc; 795*67389Spendry goto again; 796*67389Spendry } 797*67389Spendry #endif 798*67389Spendry 79965524Spendry break; 80065524Spendry 80165524Spendry } 80265524Spendry 80365524Spendry default: 80465524Spendry error = ENOTDIR; 80565524Spendry break; 80665524Spendry } 80765524Spendry 80865524Spendry uio->uio_offset = i * UIO_MX; 80965524Spendry 81065524Spendry return (error); 81165524Spendry } 81265524Spendry 81365524Spendry /* 814*67389Spendry * readlink reads the link of `curproc' 815*67389Spendry */ 816*67389Spendry procfs_readlink(ap) 817*67389Spendry struct vop_readlink_args *ap; 818*67389Spendry { 819*67389Spendry struct uio *uio = ap->a_uio; 820*67389Spendry char buf[16]; /* should be enough */ 821*67389Spendry int len; 822*67389Spendry 823*67389Spendry if (VTOPFS(ap->a_vp)->pfs_fileno != PROCFS_FILENO(0, Pcurproc)) 824*67389Spendry return (EINVAL); 825*67389Spendry 826*67389Spendry len = sprintf(buf, "%ld", (long)curproc->p_pid); 827*67389Spendry 828*67389Spendry return (uiomove((caddr_t)buf, len, ap->a_uio)); 829*67389Spendry } 830*67389Spendry 831*67389Spendry /* 83265524Spendry * convert decimal ascii to pid_t 83365524Spendry */ 83465524Spendry static pid_t 83565524Spendry atopid(b, len) 83665524Spendry const char *b; 83765524Spendry u_int len; 83865524Spendry { 83965524Spendry pid_t p = 0; 84065524Spendry 84165524Spendry while (len--) { 84265524Spendry char c = *b++; 84365524Spendry if (c < '0' || c > '9') 84465524Spendry return (NO_PID); 84565524Spendry p = 10 * p + (c - '0'); 84665524Spendry if (p > PID_MAX) 84765524Spendry return (NO_PID); 84865524Spendry } 84965524Spendry 85065524Spendry return (p); 85165524Spendry } 85265524Spendry 85365524Spendry /* 85465524Spendry * procfs vnode operations. 85565524Spendry */ 85665524Spendry int (**procfs_vnodeop_p)(); 85765524Spendry struct vnodeopv_entry_desc procfs_vnodeop_entries[] = { 85865524Spendry { &vop_default_desc, vn_default_error }, 85965524Spendry { &vop_lookup_desc, procfs_lookup }, /* lookup */ 86065524Spendry { &vop_create_desc, procfs_create }, /* create */ 86165524Spendry { &vop_mknod_desc, procfs_mknod }, /* mknod */ 86265524Spendry { &vop_open_desc, procfs_open }, /* open */ 86365524Spendry { &vop_close_desc, procfs_close }, /* close */ 86465524Spendry { &vop_access_desc, procfs_access }, /* access */ 86565524Spendry { &vop_getattr_desc, procfs_getattr }, /* getattr */ 86665524Spendry { &vop_setattr_desc, procfs_setattr }, /* setattr */ 86765524Spendry { &vop_read_desc, procfs_read }, /* read */ 86865524Spendry { &vop_write_desc, procfs_write }, /* write */ 86965524Spendry { &vop_ioctl_desc, procfs_ioctl }, /* ioctl */ 87065524Spendry { &vop_select_desc, procfs_select }, /* select */ 87165524Spendry { &vop_mmap_desc, procfs_mmap }, /* mmap */ 87265524Spendry { &vop_fsync_desc, procfs_fsync }, /* fsync */ 87365524Spendry { &vop_seek_desc, procfs_seek }, /* seek */ 87465524Spendry { &vop_remove_desc, procfs_remove }, /* remove */ 87565524Spendry { &vop_link_desc, procfs_link }, /* link */ 87665524Spendry { &vop_rename_desc, procfs_rename }, /* rename */ 87765524Spendry { &vop_mkdir_desc, procfs_mkdir }, /* mkdir */ 87865524Spendry { &vop_rmdir_desc, procfs_rmdir }, /* rmdir */ 87965524Spendry { &vop_symlink_desc, procfs_symlink }, /* symlink */ 88065524Spendry { &vop_readdir_desc, procfs_readdir }, /* readdir */ 88165524Spendry { &vop_readlink_desc, procfs_readlink }, /* readlink */ 88265524Spendry { &vop_abortop_desc, procfs_abortop }, /* abortop */ 88365524Spendry { &vop_inactive_desc, procfs_inactive }, /* inactive */ 88465524Spendry { &vop_reclaim_desc, procfs_reclaim }, /* reclaim */ 88565524Spendry { &vop_lock_desc, procfs_lock }, /* lock */ 88665524Spendry { &vop_unlock_desc, procfs_unlock }, /* unlock */ 88765524Spendry { &vop_bmap_desc, procfs_bmap }, /* bmap */ 88865524Spendry { &vop_strategy_desc, procfs_strategy }, /* strategy */ 88965524Spendry { &vop_print_desc, procfs_print }, /* print */ 89065524Spendry { &vop_islocked_desc, procfs_islocked }, /* islocked */ 89165524Spendry { &vop_pathconf_desc, procfs_pathconf }, /* pathconf */ 89265524Spendry { &vop_advlock_desc, procfs_advlock }, /* advlock */ 89365524Spendry { &vop_blkatoff_desc, procfs_blkatoff }, /* blkatoff */ 89465524Spendry { &vop_valloc_desc, procfs_valloc }, /* valloc */ 89565524Spendry { &vop_vfree_desc, procfs_vfree }, /* vfree */ 89665524Spendry { &vop_truncate_desc, procfs_truncate }, /* truncate */ 89765524Spendry { &vop_update_desc, procfs_update }, /* update */ 89865524Spendry { (struct vnodeop_desc*)NULL, (int(*)())NULL } 89965524Spendry }; 90065524Spendry struct vnodeopv_desc procfs_vnodeop_opv_desc = 90165524Spendry { &procfs_vnodeop_p, procfs_vnodeop_entries }; 902