Welcome back our old friend from procfs, "file"!

This commit is contained in:
Brian Feldman 2000-04-22 03:44:41 +00:00
parent 8a2852b12f
commit 081d7b00c7
6 changed files with 312 additions and 40 deletions

View File

@ -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 *));

View File

@ -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);
}

View File

@ -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))
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);
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);
len = snprintf(buf, sizeof(buf), "%ld", (long)curproc->p_pid);
return (uiomove((caddr_t)buf, len, ap->a_uio));
}
}
/*

View File

@ -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 *));

View File

@ -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);
}

View File

@ -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))
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);
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);
len = snprintf(buf, sizeof(buf), "%ld", (long)curproc->p_pid);
return (uiomove((caddr_t)buf, len, ap->a_uio));
}
}
/*