diff options
author | green <green@FreeBSD.org> | 2000-04-22 03:44:41 +0000 |
---|---|---|
committer | green <green@FreeBSD.org> | 2000-04-22 03:44:41 +0000 |
commit | d6606f6ffa25f25dd1b21027e947eda396dae2e8 (patch) | |
tree | 1180daeccbf00c233b5f29459132ff6d9dc97ccc /sys/miscfs | |
parent | ceecd18663bf96e4035f579bb44400dfa4b3f99f (diff) | |
download | FreeBSD-src-d6606f6ffa25f25dd1b21027e947eda396dae2e8.zip FreeBSD-src-d6606f6ffa25f25dd1b21027e947eda396dae2e8.tar.gz |
Welcome back our old friend from procfs, "file"!
Diffstat (limited to 'sys/miscfs')
-rw-r--r-- | sys/miscfs/procfs/procfs.h | 1 | ||||
-rw-r--r-- | sys/miscfs/procfs/procfs_subr.c | 104 | ||||
-rw-r--r-- | sys/miscfs/procfs/procfs_vnops.c | 69 |
3 files changed, 155 insertions, 19 deletions
diff --git a/sys/miscfs/procfs/procfs.h b/sys/miscfs/procfs/procfs.h index f000026..ebeea31 100644 --- a/sys/miscfs/procfs/procfs.h +++ b/sys/miscfs/procfs/procfs.h @@ -140,6 +140,7 @@ int procfs_domap __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct int procfs_dotype __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); int procfs_docmdline __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); int procfs_dorlimit __P((struct proc *, struct proc *, struct pfsnode *pfsp, struct uio *uio)); +int procfs_fullpath __P((struct proc *p, char **retbuf, char **retfreebuf)); /* Return 1 if process has special kernel digging privileges */ int procfs_kmemaccess __P((struct proc *)); diff --git a/sys/miscfs/procfs/procfs_subr.c b/sys/miscfs/procfs/procfs_subr.c index 01e8ae9..a7bbfd7 100644 --- a/sys/miscfs/procfs/procfs_subr.c +++ b/sys/miscfs/procfs/procfs_subr.c @@ -41,9 +41,13 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/sysctl.h> #include <sys/proc.h> +#include <sys/mount.h> #include <sys/vnode.h> #include <sys/malloc.h> + #include <miscfs/procfs/procfs.h> static struct pfsnode *pfshead; @@ -159,6 +163,10 @@ loop: break; case Pfile: + pfs->pfs_mode = (VREAD|VEXEC); + vp->v_type = VLNK; + break; + case Pmem: pfs->pfs_mode = (VREAD|VWRITE) | (VREAD) >> 3;; @@ -400,3 +408,99 @@ procfs_exit(struct proc *p) pfs = pfs->pfs_next; } } + +/* + * Thus begins the fullpath magic. + */ + +SYSCTL_DECL(_vfs_cache); + +#define STATNODE(name) \ + static u_int name; \ + SYSCTL_INT(_vfs_cache, OID_AUTO, name, CTLFLAG_RD, &name, 0, "") + +static int disablefullpath; +SYSCTL_INT(_debug, OID_AUTO, disablefullpath, CTLFLAG_RW, + &disablefullpath, 0, ""); + +STATNODE(numfullpathcalls); +STATNODE(numfullpathfail1); +STATNODE(numfullpathfail2); +STATNODE(numfullpathfail3); +STATNODE(numfullpathfail4); +STATNODE(numfullpathfound); + +int +procfs_fullpath(struct proc *p, char **retbuf, char **retfreebuf) { + char *bp, *buf; + int i, slash_prefixed; + struct filedesc *fdp; + struct namecache *ncp; + struct vnode *vp, *textvp; + + numfullpathcalls++; + if (disablefullpath) + return (ENODEV); + textvp = p->p_textvp; + if (textvp == NULL) + return (EINVAL); + buf = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); + bp = buf + MAXPATHLEN - 1; + *bp = '\0'; + fdp = p->p_fd; + slash_prefixed = 0; + for (vp = textvp; vp != fdp->fd_rdir && vp != rootvnode;) { + if (vp->v_flag & VROOT) { + if (vp->v_mount == NULL) { /* forced unmount */ + free(buf, M_TEMP); + return (EBADF); + } + vp = vp->v_mount->mnt_vnodecovered; + continue; + } + if (vp != textvp && vp->v_dd->v_id != vp->v_ddid) { + numfullpathfail1++; + free(buf, M_TEMP); + return (ENOTDIR); + } + ncp = TAILQ_FIRST(&vp->v_cache_dst); + if (!ncp) { + numfullpathfail2++; + free(buf, M_TEMP); + return (ENOENT); + } + if (vp != textvp && ncp->nc_dvp != vp->v_dd) { + numfullpathfail3++; + free(buf, M_TEMP); + return (EBADF); + } + for (i = ncp->nc_nlen - 1; i >= 0; i--) { + if (bp == buf) { + numfullpathfail4++; + free(buf, M_TEMP); + return (ENOMEM); + } + *--bp = ncp->nc_name[i]; + } + if (bp == buf) { + numfullpathfail4++; + free(buf, M_TEMP); + return (ENOMEM); + } + *--bp = '/'; + slash_prefixed = 1; + vp = ncp->nc_dvp; + } + if (!slash_prefixed) { + if (bp == buf) { + numfullpathfail4++; + free(buf, M_TEMP); + return (ENOMEM); + } + *--bp = '/'; + } + numfullpathfound++; + *retbuf = bp; + *retfreebuf = buf; + return (0); +} diff --git a/sys/miscfs/procfs/procfs_vnops.c b/sys/miscfs/procfs/procfs_vnops.c index d7de7ce..a38fe81 100644 --- a/sys/miscfs/procfs/procfs_vnops.c +++ b/sys/miscfs/procfs/procfs_vnops.c @@ -52,9 +52,11 @@ #include <sys/proc.h> #include <sys/signalvar.h> #include <sys/vnode.h> +#include <sys/uio.h> #include <sys/mount.h> #include <sys/namei.h> #include <sys/dirent.h> +#include <sys/malloc.h> #include <machine/reg.h> #include <vm/vm_zone.h> #include <miscfs/procfs/procfs.h> @@ -103,6 +105,7 @@ static struct proc_target { { DT_REG, N("etype"), Ptype, procfs_validtype }, { DT_REG, N("cmdline"), Pcmdline, NULL }, { DT_REG, N("rlimit"), Prlimit, NULL }, + { DT_LNK, N("file"), Pfile, NULL }, #undef N }; static const int nproc_targets = sizeof(proc_targets) / sizeof(proc_targets[0]); @@ -529,9 +532,19 @@ procfs_getattr(ap) vap->va_size = vap->va_bytes = DEV_BSIZE; break; - case Pfile: - error = EOPNOTSUPP; + case Pfile: { + char *fullpath, *freepath; + error = procfs_fullpath(procp, &fullpath, &freepath); + if (error == 0) { + vap->va_size = strlen(fullpath); + free(freepath, M_TEMP); + } else { + vap->va_size = sizeof("unknown") - 1; + error = 0; + } + vap->va_bytes = vap->va_size; break; + } case Pmem: /* @@ -686,7 +699,6 @@ procfs_lookup(ap) char *pname = cnp->cn_nameptr; struct proc *curp = cnp->cn_proc; struct proc_target *pt; - struct vnode *fvp; pid_t pid; struct pfsnode *pfs; struct proc *p; @@ -738,17 +750,7 @@ procfs_lookup(ap) goto found; } break; - found: - if (pt->pt_pfstype == Pfile) { - fvp = procfs_findtextvp(p); - /* We already checked that it exists. */ - VREF(fvp); - vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, curp); - *vpp = fvp; - return (0); - } - return (procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, pt->pt_pfstype)); @@ -932,21 +934,50 @@ procfs_readdir(ap) } /* - * readlink reads the link of `curproc' + * readlink reads the link of `curproc' or `file' */ static int procfs_readlink(ap) struct vop_readlink_args *ap; { char buf[16]; /* should be enough */ - int len; + struct proc *procp; + struct vnode *vp = ap->a_vp; + struct pfsnode *pfs = VTOPFS(vp); + char *fullpath, *freepath; + int error, len; - if (VTOPFS(ap->a_vp)->pfs_fileno != PROCFS_FILENO(0, Pcurproc)) - return (EINVAL); + switch (pfs->pfs_type) { + case Pcurproc: + if (pfs->pfs_fileno != PROCFS_FILENO(0, Pcurproc)) + return (EINVAL); - len = snprintf(buf, sizeof(buf), "%ld", (long)curproc->p_pid); + len = snprintf(buf, sizeof(buf), "%ld", (long)curproc->p_pid); - return (uiomove((caddr_t)buf, len, ap->a_uio)); + return (uiomove(buf, len, ap->a_uio)); + /* + * There _should_ be no way for an entire process to disappear + * from under us... + */ + case Pfile: + procp = PFIND(pfs->pfs_pid); + if (procp == NULL || procp->p_cred == NULL || + procp->p_ucred == NULL) { + printf("procfs_readlink: pid %d disappeared\n", + pfs->pfs_pid); + return (uiomove("unknown", sizeof("unknown") - 1, + ap->a_uio)); + } + error = procfs_fullpath(procp, &fullpath, &freepath); + if (error != 0) + return (uiomove("unknown", sizeof("unknown") - 1, + ap->a_uio)); + error = uiomove(fullpath, strlen(fullpath), ap->a_uio); + free(freepath, M_TEMP); + return (error); + default: + return (EINVAL); + } } /* |