/* * lookup. this is incredibly complicated in the * general case, however for most pseudo-filesystems * very little needs to be done. * * unless you want to get a migraine, just make sure your * filesystem doesn't do any locking of its own. otherwise * read and inwardly digest ufs_lookup(). */ int procfs_lookup(void *v) { struct vop_lookup_args *ap = v; struct componentname *cnp = ap->a_cnp; struct vnode **vpp = ap->a_vpp; struct vnode *dvp = ap->a_dvp; char *pname = cnp->cn_nameptr; struct proc *curp = curproc; const struct proc_target *pt; struct vnode *fvp; pid_t pid; struct pfsnode *pfs; struct proc *p = NULL; int i, error, wantpunlock, iscurproc = 0, isself = 0; *vpp = NULL; cnp->cn_flags &= ~PDIRUNLOCK; if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) return (EROFS); if (cnp->cn_namelen == 1 && *pname == '.') { *vpp = dvp; VREF(dvp); return (0); } wantpunlock = (~cnp->cn_flags & (LOCKPARENT | ISLASTCN)); pfs = VTOPFS(dvp); switch (pfs->pfs_type) { case Proot: if (cnp->cn_flags & ISDOTDOT) return (EIO); iscurproc = CNEQ(cnp, "curproc", 7); isself = CNEQ(cnp, "self", 4); if (iscurproc || isself) { error = procfs_allocvp(dvp->v_mount, vpp, 0, iscurproc ? Pcurproc : Pself); if ((error == 0) && (wantpunlock)) { VOP_UNLOCK(dvp, 0, curp); cnp->cn_flags |= PDIRUNLOCK; } return (error); } for (i = 0; i < nproc_root_targets; i++) { pt = &proc_root_targets[i]; if (cnp->cn_namelen == pt->pt_namlen && memcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 && (pt->pt_valid == NULL || (*pt->pt_valid)(p, dvp->v_mount))) break; } if (i != nproc_root_targets) { error = procfs_allocvp(dvp->v_mount, vpp, 0, pt->pt_pfstype); if ((error == 0) && (wantpunlock)) { VOP_UNLOCK(dvp, 0, curp); cnp->cn_flags |= PDIRUNLOCK; } return (error); } pid = atopid(pname, cnp->cn_namelen); if (pid == NO_PID) break; p = pfind(pid); if (p == 0) break; error = procfs_allocvp(dvp->v_mount, vpp, pid, Pproc); if ((error == 0) && wantpunlock) { VOP_UNLOCK(dvp, 0, curp); cnp->cn_flags |= PDIRUNLOCK; } return (error); case Pproc: /* * do the .. dance. We unlock the directory, and then * get the root dir. That will automatically return .. * locked. Then if the caller wanted dvp locked, we * re-lock. */ if (cnp->cn_flags & ISDOTDOT) { VOP_UNLOCK(dvp, 0, p); cnp->cn_flags |= PDIRUNLOCK; error = procfs_root(dvp->v_mount, vpp); if ((error == 0) && (wantpunlock == 0) && ((error = vn_lock(dvp, LK_EXCLUSIVE, curp)) == 0)) cnp->cn_flags &= ~PDIRUNLOCK; return (error); } p = pfind(pfs->pfs_pid); if (p == 0) break; for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) { if (cnp->cn_namelen == pt->pt_namlen && bcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 && (pt->pt_valid == NULL || (*pt->pt_valid)(p, dvp->v_mount))) goto found; } break; found: if (pt->pt_pfstype == Pfile) { fvp = p->p_textvp; /* We already checked that it exists. */ VREF(fvp); vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, curp); if (wantpunlock) { VOP_UNLOCK(dvp, 0, curp); cnp->cn_flags |= PDIRUNLOCK; } *vpp = fvp; return (0); } error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, pt->pt_pfstype); if ((error == 0) && (wantpunlock)) { VOP_UNLOCK(dvp, 0, curp); cnp->cn_flags |= PDIRUNLOCK; } return (error); default: return (ENOTDIR); } return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS); }
/* * lookup. this is incredibly complicated in the general case, however * for most pseudo-filesystems very little needs to be done. * * procfs_lookup(struct vnode *a_dvp, struct vnode **a_vpp, * struct componentname *a_cnp) */ static int procfs_lookup(struct vop_old_lookup_args *ap) { struct componentname *cnp = ap->a_cnp; struct vnode **vpp = ap->a_vpp; struct vnode *dvp = ap->a_dvp; char *pname = cnp->cn_nameptr; /* struct proc *curp = cnp->cn_proc; */ struct proc_target *pt; pid_t pid; struct pfsnode *pfs; struct proc *p; struct lwp *lp; int i; int error; *vpp = NULL; if (cnp->cn_nameiop == NAMEI_DELETE || cnp->cn_nameiop == NAMEI_RENAME) return (EROFS); p = NULL; error = 0; if (cnp->cn_namelen == 1 && *pname == '.') { *vpp = dvp; vref(*vpp); goto out; } pfs = VTOPFS(dvp); switch (pfs->pfs_type) { case Proot: if (cnp->cn_flags & CNP_ISDOTDOT) return (EIO); if (CNEQ(cnp, "curproc", 7)) { error = procfs_allocvp(dvp->v_mount, vpp, 0, Pcurproc); goto out; } pid = atopid(pname, cnp->cn_namelen); if (pid == NO_PID) break; p = pfs_pfind(pid); if (p == NULL) break; if (!PRISON_CHECK(ap->a_cnp->cn_cred, p->p_ucred)) break; if (ps_showallprocs == 0 && ap->a_cnp->cn_cred->cr_uid != 0 && ap->a_cnp->cn_cred->cr_uid != p->p_ucred->cr_uid) break; error = procfs_allocvp(dvp->v_mount, vpp, pid, Pproc); goto out; case Pproc: if (cnp->cn_flags & CNP_ISDOTDOT) { error = procfs_root(dvp->v_mount, vpp); goto out; } p = pfs_pfind(pfs->pfs_pid); if (p == NULL) break; /* XXX lwp */ lp = FIRST_LWP_IN_PROC(p); if (!PRISON_CHECK(ap->a_cnp->cn_cred, p->p_ucred)) break; if (ps_showallprocs == 0 && ap->a_cnp->cn_cred->cr_uid != 0 && ap->a_cnp->cn_cred->cr_uid != p->p_ucred->cr_uid) break; for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) { if (cnp->cn_namelen == pt->pt_namlen && bcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 && (pt->pt_valid == NULL || (*pt->pt_valid)(lp))) goto found; } break; found: error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, pt->pt_pfstype); goto out; default: error = ENOTDIR; goto out; } if (cnp->cn_nameiop == NAMEI_LOOKUP) error = ENOENT; else error = EROFS; /* * If no error occured *vpp will hold a referenced locked vnode. * dvp was passed to us locked and *vpp must be returned locked. * If *vpp != dvp then we should unlock dvp if (1) this is not the * last component or (2) CNP_LOCKPARENT is not set. */ out: if (error == 0 && *vpp != dvp) { if ((cnp->cn_flags & CNP_LOCKPARENT) == 0) { cnp->cn_flags |= CNP_PDIRUNLOCK; vn_unlock(dvp); } } if (p) PRELE(p); return (error); }