aboutsummaryrefslogtreecommitdiff
path: root/sys/fs
diff options
context:
space:
mode:
authorBrian Feldman <green@FreeBSD.org>2000-04-22 03:44:41 +0000
committerBrian Feldman <green@FreeBSD.org>2000-04-22 03:44:41 +0000
commit081d7b00c7859484f10516ed10c541adc3c796c1 (patch)
tree0734ff83a980b60ae4108a3dae47bbaac504e454 /sys/fs
parent8a2852b12fc59a3852063209a0a1c99d3234f0d4 (diff)
downloadsrc-081d7b00c7859484f10516ed10c541adc3c796c1.tar.gz
src-081d7b00c7859484f10516ed10c541adc3c796c1.zip
Welcome back our old friend from procfs, "file"!
Notes
Notes: svn path=/head/; revision=59481
Diffstat (limited to 'sys/fs')
-rw-r--r--sys/fs/procfs/procfs.h1
-rw-r--r--sys/fs/procfs/procfs_subr.c104
-rw-r--r--sys/fs/procfs/procfs_vnops.c69
3 files changed, 155 insertions, 19 deletions
diff --git a/sys/fs/procfs/procfs.h b/sys/fs/procfs/procfs.h
index f0000267b5d7..ebeea31534c0 100644
--- a/sys/fs/procfs/procfs.h
+++ b/sys/fs/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/fs/procfs/procfs_subr.c b/sys/fs/procfs/procfs_subr.c
index 01e8ae9e014a..a7bbfd716075 100644
--- a/sys/fs/procfs/procfs_subr.c
+++ b/sys/fs/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/fs/procfs/procfs_vnops.c b/sys/fs/procfs/procfs_vnops.c
index d7de7ce230f8..a38fe8191b83 100644
--- a/sys/fs/procfs/procfs_vnops.c
+++ b/sys/fs/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);
+ }
}
/*