Welcome back our old friend from procfs, "file"!
This commit is contained in:
parent
8a2852b12f
commit
081d7b00c7
@ -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 *));
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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 *));
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user