Print this page
12046 Provide /proc/<PID>/fdinfo/
*** 21,30 ****
--- 21,31 ----
/*
* Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, Joyent, Inc.
* Copyright (c) 2017 by Delphix. All rights reserved.
+ * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
*** 152,172 ****
"cwd" },
{ PR_ROOTDIR, 20 * sizeof (prdirent_t), sizeof (prdirent_t),
"root" },
{ PR_FDDIR, 21 * sizeof (prdirent_t), sizeof (prdirent_t),
"fd" },
! { PR_OBJECTDIR, 22 * sizeof (prdirent_t), sizeof (prdirent_t),
"object" },
! { PR_LWPDIR, 23 * sizeof (prdirent_t), sizeof (prdirent_t),
"lwp" },
! { PR_PRIV, 24 * sizeof (prdirent_t), sizeof (prdirent_t),
"priv" },
! { PR_PATHDIR, 25 * sizeof (prdirent_t), sizeof (prdirent_t),
"path" },
! { PR_CTDIR, 26 * sizeof (prdirent_t), sizeof (prdirent_t),
"contracts" },
! { PR_SECFLAGS, 27 * sizeof (prdirent_t), sizeof (prdirent_t),
"secflags" },
#if defined(__x86)
{ PR_LDT, 28 * sizeof (prdirent_t), sizeof (prdirent_t),
"ldt" },
#endif
--- 153,175 ----
"cwd" },
{ PR_ROOTDIR, 20 * sizeof (prdirent_t), sizeof (prdirent_t),
"root" },
{ PR_FDDIR, 21 * sizeof (prdirent_t), sizeof (prdirent_t),
"fd" },
! { PR_FDINFODIR, 22 * sizeof (prdirent_t), sizeof (prdirent_t),
! "fdinfo" },
! { PR_OBJECTDIR, 23 * sizeof (prdirent_t), sizeof (prdirent_t),
"object" },
! { PR_LWPDIR, 24 * sizeof (prdirent_t), sizeof (prdirent_t),
"lwp" },
! { PR_PRIV, 25 * sizeof (prdirent_t), sizeof (prdirent_t),
"priv" },
! { PR_PATHDIR, 26 * sizeof (prdirent_t), sizeof (prdirent_t),
"path" },
! { PR_CTDIR, 27 * sizeof (prdirent_t), sizeof (prdirent_t),
"contracts" },
! { PR_SECFLAGS, 28 * sizeof (prdirent_t), sizeof (prdirent_t),
"secflags" },
#if defined(__x86)
{ PR_LDT, 28 * sizeof (prdirent_t), sizeof (prdirent_t),
"ldt" },
#endif
*** 594,604 ****
pr_read_xregs(), pr_read_priv(),
pr_read_spymaster(), pr_read_secflags(),
#if defined(__sparc)
pr_read_gwindows(), pr_read_asrs(),
#endif
! pr_read_piddir(), pr_read_pidfile(), pr_read_opagedata();
static int (*pr_read_function[PR_NFILES])() = {
pr_read_inval, /* /proc */
pr_read_inval, /* /proc/self */
pr_read_piddir, /* /proc/<pid> (old /proc read()) */
--- 597,608 ----
pr_read_xregs(), pr_read_priv(),
pr_read_spymaster(), pr_read_secflags(),
#if defined(__sparc)
pr_read_gwindows(), pr_read_asrs(),
#endif
! pr_read_piddir(), pr_read_pidfile(), pr_read_opagedata(),
! pr_read_fdinfo();
static int (*pr_read_function[PR_NFILES])() = {
pr_read_inval, /* /proc */
pr_read_inval, /* /proc/self */
pr_read_piddir, /* /proc/<pid> (old /proc read()) */
*** 623,632 ****
--- 627,638 ----
pr_read_watch, /* /proc/<pid>/watch */
pr_read_inval, /* /proc/<pid>/cwd */
pr_read_inval, /* /proc/<pid>/root */
pr_read_inval, /* /proc/<pid>/fd */
pr_read_inval, /* /proc/<pid>/fd/nn */
+ pr_read_inval, /* /proc/<pid>/fdinfo */
+ pr_read_fdinfo, /* /proc/<pid>/fdinfo/nn */
pr_read_inval, /* /proc/<pid>/object */
pr_read_inval, /* /proc/<pid>/object/xxx */
pr_read_inval, /* /proc/<pid>/lwp */
pr_read_inval, /* /proc/<pid>/lwp/<lwpid> */
pr_read_inval, /* /proc/<pid>/lwp/<lwpid>/lwpctl */
*** 811,820 ****
--- 817,910 ----
}
return (error);
}
static int
+ pr_read_fdinfo(prnode_t *pnp, uio_t *uiop)
+ {
+ prfdinfov2_t *fdinfo;
+ list_t data;
+ proc_t *p;
+ vnode_t *vp;
+ uint_t fd;
+ file_t *fp;
+ cred_t *cred;
+ short ufp_flag;
+ int error = 0;
+
+ ASSERT(pnp->pr_type == PR_FDINFO);
+
+ /*
+ * This is a guess at the size of the structure that needs to
+ * be returned. It's a balance between not allocating too much more
+ * space than is required and not requiring too many subsequent
+ * reallocations. Allocate it before acquiring the process lock.
+ */
+ pr_iol_initlist(&data, sizeof (prfdinfov2_t) + MAXPATHLEN + 2, 1);
+
+ if ((error = prlock(pnp, ZNO)) != 0) {
+ pr_iol_freelist(&data);
+ return (error);
+ }
+
+ p = pnp->pr_common->prc_proc;
+
+ if ((p->p_flag & SSYS) || p->p_as == &kas) {
+ prunlock(pnp);
+ pr_iol_freelist(&data);
+ return (0);
+ }
+
+ fd = pnp->pr_index;
+
+ /* Fetch and lock the file_t for this descriptor */
+ fp = pr_getf(p, fd, &ufp_flag);
+
+ if (fp == NULL) {
+ error = ENOENT;
+ prunlock(pnp);
+ goto out;
+ }
+
+ vp = fp->f_vnode;
+ VN_HOLD(vp);
+
+ /*
+ * For fdinfo, we don't want to include the placeholder pr_misc at the
+ * end of the struct. We'll termninate the data with an empty pr_misc
+ * header before returning.
+ */
+
+ fdinfo = pr_iol_newbuf(&data, offsetof(prfdinfov2_t, pr_misc));
+ fdinfo->pr_fd = fd;
+ fdinfo->pr_fdflags = ufp_flag;
+ fdinfo->pr_fileflags = fp->f_flag2 << 16 | fp->f_flag;
+ if ((fdinfo->pr_fileflags & (FSEARCH | FEXEC)) == 0)
+ fdinfo->pr_fileflags += FOPEN;
+ fdinfo->pr_offset = fp->f_offset;
+ cred = fp->f_cred;
+ crhold(cred);
+ pr_releasef(p, fd);
+
+ prunlock(pnp);
+
+ error = prgetfdinfo(p, vp, fdinfo, cred, &data);
+
+ crfree(cred);
+
+ VN_RELE(vp);
+
+ out:
+ if (error == 0)
+ error = pr_iol_uiomove_and_free(&data, uiop, error);
+ else
+ pr_iol_freelist(&data);
+
+ return (error);
+ }
+
+ static int
pr_read_lpsinfo(prnode_t *pnp, uio_t *uiop)
{
proc_t *p;
kthread_t *t;
lwpdir_t *ldp;
*** 1833,1842 ****
--- 1923,1934 ----
pr_read_watch_32, /* /proc/<pid>/watch */
pr_read_inval, /* /proc/<pid>/cwd */
pr_read_inval, /* /proc/<pid>/root */
pr_read_inval, /* /proc/<pid>/fd */
pr_read_inval, /* /proc/<pid>/fd/nn */
+ pr_read_inval, /* /proc/<pid>/fdinfo */
+ pr_read_fdinfo, /* /proc/<pid>/fdinfo/nn */
pr_read_inval, /* /proc/<pid>/object */
pr_read_inval, /* /proc/<pid>/object/xxx */
pr_read_inval, /* /proc/<pid>/lwp */
pr_read_inval, /* /proc/<pid>/lwp/<lwpid> */
pr_read_inval, /* /proc/<pid>/lwp/<lwpid>/lwpctl */
*** 3078,3090 ****
--- 3170,3203 ----
case PR_CT:
vap->va_type = VLNK;
vap->va_size = 0;
break;
case PR_FDDIR:
+ case PR_FDINFODIR:
vap->va_nlink = 2;
vap->va_size = (P_FINFO(p)->fi_nfiles + 2) * PRSDSIZE;
break;
+ case PR_FDINFO: {
+ file_t *fp;
+ vnode_t *vp;
+ int fd = pnp->pr_index;
+
+ fp = pr_getf(p, fd, NULL);
+ if (fp == NULL) {
+ prunlock(pnp);
+ return (ENOENT);
+ }
+ vp = fp->f_vnode;
+ VN_HOLD(vp);
+ pr_releasef(p, fd);
+ prunlock(pnp);
+ vap->va_size = prgetfdinfosize(p, vp, cr);
+ VN_RELE(vp);
+ /* prunlock() has already been called. */
+ vap->va_nblocks = (fsblkcnt64_t)btod(vap->va_size);
+ return (0);
+ }
case PR_LWPDIR:
/*
* va_nlink: count each lwp as a directory link.
* va_size: size of p_lwpdir + 2
*/
*** 3405,3416 ****
/*
* Array of lookup functions, indexed by /proc file type.
*/
static vnode_t *pr_lookup_notdir(), *pr_lookup_procdir(), *pr_lookup_piddir(),
*pr_lookup_objectdir(), *pr_lookup_lwpdir(), *pr_lookup_lwpiddir(),
! *pr_lookup_fddir(), *pr_lookup_pathdir(), *pr_lookup_tmpldir(),
! *pr_lookup_ctdir();
static vnode_t *(*pr_lookup_function[PR_NFILES])() = {
pr_lookup_procdir, /* /proc */
pr_lookup_notdir, /* /proc/self */
pr_lookup_piddir, /* /proc/<pid> */
--- 3518,3529 ----
/*
* Array of lookup functions, indexed by /proc file type.
*/
static vnode_t *pr_lookup_notdir(), *pr_lookup_procdir(), *pr_lookup_piddir(),
*pr_lookup_objectdir(), *pr_lookup_lwpdir(), *pr_lookup_lwpiddir(),
! *pr_lookup_fddir(), *pr_lookup_fdinfodir(), *pr_lookup_pathdir(),
! *pr_lookup_tmpldir(), *pr_lookup_ctdir();
static vnode_t *(*pr_lookup_function[PR_NFILES])() = {
pr_lookup_procdir, /* /proc */
pr_lookup_notdir, /* /proc/self */
pr_lookup_piddir, /* /proc/<pid> */
*** 3435,3444 ****
--- 3548,3559 ----
pr_lookup_notdir, /* /proc/<pid>/watch */
pr_lookup_notdir, /* /proc/<pid>/cwd */
pr_lookup_notdir, /* /proc/<pid>/root */
pr_lookup_fddir, /* /proc/<pid>/fd */
pr_lookup_notdir, /* /proc/<pid>/fd/nn */
+ pr_lookup_fdinfodir, /* /proc/<pid>/fdinfo */
+ pr_lookup_notdir, /* /proc/<pid>/fdinfo/nn */
pr_lookup_objectdir, /* /proc/<pid>/object */
pr_lookup_notdir, /* /proc/<pid>/object/xxx */
pr_lookup_lwpdir, /* /proc/<pid>/lwp */
pr_lookup_lwpiddir, /* /proc/<pid>/lwp/<lwpid> */
pr_lookup_notdir, /* /proc/<pid>/lwp/<lwpid>/lwpctl */
*** 3522,3532 ****
direntflags, realpnp));
default:
break;
}
! if ((type == PR_OBJECTDIR || type == PR_FDDIR || type == PR_PATHDIR) &&
(error = praccess(dp, VEXEC, 0, cr, ct)) != 0)
return (error);
/* XXX - Do we need to pass ct, direntflags, or realpnp? */
*vpp = (pr_lookup_function[type](dp, comp));
--- 3637,3648 ----
direntflags, realpnp));
default:
break;
}
! if ((type == PR_OBJECTDIR || type == PR_FDDIR ||
! type == PR_FDINFODIR || type == PR_PATHDIR) &&
(error = praccess(dp, VEXEC, 0, cr, ct)) != 0)
return (error);
/* XXX - Do we need to pass ct, direntflags, or realpnp? */
*vpp = (pr_lookup_function[type](dp, comp));
*** 4136,4158 ****
vnode_t *vp = NULL;
proc_t *p;
file_t *fp;
uint_t fd;
int c;
- uf_entry_t *ufp;
- uf_info_t *fip;
ASSERT(dpnp->pr_type == PR_FDDIR);
fd = 0;
while ((c = *comp++) != '\0') {
int ofd;
if (c < '0' || c > '9')
return (NULL);
ofd = fd;
! fd = 10*fd + c - '0';
! if (fd/10 != ofd) /* integer overflow */
return (NULL);
}
pnp = prgetnode(dp, PR_FD);
--- 4252,4272 ----
vnode_t *vp = NULL;
proc_t *p;
file_t *fp;
uint_t fd;
int c;
ASSERT(dpnp->pr_type == PR_FDDIR);
fd = 0;
while ((c = *comp++) != '\0') {
int ofd;
if (c < '0' || c > '9')
return (NULL);
ofd = fd;
! fd = 10 * fd + c - '0';
! if (fd / 10 != ofd) /* integer overflow */
return (NULL);
}
pnp = prgetnode(dp, PR_FD);
*** 4165,4197 ****
prunlock(dpnp);
prfreenode(pnp);
return (NULL);
}
! fip = P_FINFO(p);
! mutex_exit(&p->p_lock);
! mutex_enter(&fip->fi_lock);
! if (fd < fip->fi_nfiles) {
! UF_ENTER(ufp, fip, fd);
! if ((fp = ufp->uf_file) != NULL) {
pnp->pr_mode = 07111;
if (fp->f_flag & FREAD)
pnp->pr_mode |= 0444;
if (fp->f_flag & FWRITE)
pnp->pr_mode |= 0222;
vp = fp->f_vnode;
VN_HOLD(vp);
}
! UF_EXIT(ufp);
! }
! mutex_exit(&fip->fi_lock);
! mutex_enter(&p->p_lock);
prunlock(dpnp);
! if (vp == NULL)
prfreenode(pnp);
! else {
/*
* Fill in the prnode so future references will
* be able to find the underlying object's vnode.
* Don't link this prnode into the list of all
* prnodes for the process; this is a one-use node.
--- 4279,4306 ----
prunlock(dpnp);
prfreenode(pnp);
return (NULL);
}
! if ((fp = pr_getf(p, fd, NULL)) != NULL) {
pnp->pr_mode = 07111;
if (fp->f_flag & FREAD)
pnp->pr_mode |= 0444;
if (fp->f_flag & FWRITE)
pnp->pr_mode |= 0222;
vp = fp->f_vnode;
VN_HOLD(vp);
+ pr_releasef(p, fd);
}
!
prunlock(dpnp);
! if (vp == NULL) {
prfreenode(pnp);
! return (NULL);
! }
!
/*
* Fill in the prnode so future references will
* be able to find the underlying object's vnode.
* Don't link this prnode into the list of all
* prnodes for the process; this is a one-use node.
*** 4202,4213 ****
--- 4311,4368 ----
vp = PTOV(pnp);
if (pnp->pr_realvp->v_type == VDIR) {
vp->v_type = VDIR;
vp->v_flag |= VTRAVERSE;
}
+
+ return (vp);
+ }
+
+ static vnode_t *
+ pr_lookup_fdinfodir(vnode_t *dp, char *comp)
+ {
+ prnode_t *dpnp = VTOP(dp);
+ prnode_t *pnp;
+ vnode_t *vp = NULL;
+ proc_t *p;
+ uint_t fd;
+ int c;
+
+ ASSERT(dpnp->pr_type == PR_FDINFODIR);
+
+ fd = 0;
+ while ((c = *comp++) != '\0') {
+ int ofd;
+ if (c < '0' || c > '9')
+ return (NULL);
+ ofd = fd;
+ fd = 10 * fd + c - '0';
+ if (fd / 10 != ofd) /* integer overflow */
+ return (NULL);
}
+ pnp = prgetnode(dp, PR_FDINFO);
+
+ if (prlock(dpnp, ZNO) != 0) {
+ prfreenode(pnp);
+ return (NULL);
+ }
+ p = dpnp->pr_common->prc_proc;
+ if ((p->p_flag & SSYS) || p->p_as == &kas) {
+ prunlock(dpnp);
+ prfreenode(pnp);
+ return (NULL);
+ }
+
+ pnp->pr_common = dpnp->pr_common;
+ pnp->pr_pcommon = dpnp->pr_pcommon;
+ pnp->pr_parent = dp;
+ pnp->pr_index = fd;
+ VN_HOLD(dp);
+ prunlock(dpnp);
+ vp = PTOV(pnp);
+
return (vp);
}
static vnode_t *
pr_lookup_pathdir(vnode_t *dp, char *comp)
*** 4665,4674 ****
--- 4820,4830 ----
break;
case PR_CURDIR:
case PR_ROOTDIR:
case PR_FDDIR:
+ case PR_FDINFODIR:
case PR_OBJECTDIR:
case PR_PATHDIR:
case PR_CTDIR:
case PR_TMPLDIR:
vp->v_type = VDIR;
*** 4797,4808 ****
/*
* Array of readdir functions, indexed by /proc file type.
*/
static int pr_readdir_notdir(), pr_readdir_procdir(), pr_readdir_piddir(),
pr_readdir_objectdir(), pr_readdir_lwpdir(), pr_readdir_lwpiddir(),
! pr_readdir_fddir(), pr_readdir_pathdir(), pr_readdir_tmpldir(),
! pr_readdir_ctdir();
static int (*pr_readdir_function[PR_NFILES])() = {
pr_readdir_procdir, /* /proc */
pr_readdir_notdir, /* /proc/self */
pr_readdir_piddir, /* /proc/<pid> */
--- 4953,4964 ----
/*
* Array of readdir functions, indexed by /proc file type.
*/
static int pr_readdir_notdir(), pr_readdir_procdir(), pr_readdir_piddir(),
pr_readdir_objectdir(), pr_readdir_lwpdir(), pr_readdir_lwpiddir(),
! pr_readdir_fddir(), pr_readdir_fdinfodir(), pr_readdir_pathdir(),
! pr_readdir_tmpldir(), pr_readdir_ctdir();
static int (*pr_readdir_function[PR_NFILES])() = {
pr_readdir_procdir, /* /proc */
pr_readdir_notdir, /* /proc/self */
pr_readdir_piddir, /* /proc/<pid> */
*** 4827,4836 ****
--- 4983,4994 ----
pr_readdir_notdir, /* /proc/<pid>/watch */
pr_readdir_notdir, /* /proc/<pid>/cwd */
pr_readdir_notdir, /* /proc/<pid>/root */
pr_readdir_fddir, /* /proc/<pid>/fd */
pr_readdir_notdir, /* /proc/<pid>/fd/nn */
+ pr_readdir_fdinfodir, /* /proc/<pid>/fdinfo */
+ pr_readdir_notdir, /* /proc/<pid>/fdinfo/nn */
pr_readdir_objectdir, /* /proc/<pid>/object */
pr_readdir_notdir, /* /proc/<pid>/object/xxx */
pr_readdir_lwpdir, /* /proc/<pid>/lwp */
pr_readdir_lwpiddir, /* /proc/<pid>/lwp/<lwpid> */
pr_readdir_notdir, /* /proc/<pid>/lwp/<lwpid>/lwpctl */
*** 5359,5391 ****
if (eofp)
*eofp = (uiop->uio_offset >= sizeof (lwpiddir));
return (0);
}
! /* ARGSUSED */
static int
! pr_readdir_fddir(prnode_t *pnp, uio_t *uiop, int *eofp)
{
gfs_readdir_state_t gstate;
int error, eof = 0;
offset_t n;
proc_t *p;
int pslot;
int fddirsize;
uf_info_t *fip;
- ASSERT(pnp->pr_type == PR_FDDIR);
-
if ((error = prlock(pnp, ZNO)) != 0)
return (error);
p = pnp->pr_common->prc_proc;
pslot = p->p_slot;
fip = P_FINFO(p);
mutex_exit(&p->p_lock);
if ((error = gfs_readdir_init(&gstate, PLNSIZ, PRSDSIZE, uiop,
! pmkino(0, pslot, PR_PIDDIR), pmkino(0, pslot, PR_FDDIR), 0)) != 0) {
mutex_enter(&p->p_lock);
prunlock(pnp);
return (error);
}
--- 5517,5550 ----
if (eofp)
*eofp = (uiop->uio_offset >= sizeof (lwpiddir));
return (0);
}
! /*
! * Helper function for reading a directory which lists open file desciptors
! */
static int
! pr_readdir_fdlist(prnode_t *pnp, uio_t *uiop, int *eofp,
! prnodetype_t dirtype, prnodetype_t entrytype)
{
gfs_readdir_state_t gstate;
int error, eof = 0;
offset_t n;
proc_t *p;
int pslot;
int fddirsize;
uf_info_t *fip;
if ((error = prlock(pnp, ZNO)) != 0)
return (error);
p = pnp->pr_common->prc_proc;
pslot = p->p_slot;
fip = P_FINFO(p);
mutex_exit(&p->p_lock);
if ((error = gfs_readdir_init(&gstate, PLNSIZ, PRSDSIZE, uiop,
! pmkino(0, pslot, PR_PIDDIR), pmkino(0, pslot, dirtype), 0)) != 0) {
mutex_enter(&p->p_lock);
prunlock(pnp);
return (error);
}
*** 5412,5422 ****
eof = 1;
break;
}
error = gfs_readdir_emitn(&gstate, uiop, n,
! pmkino(n, pslot, PR_FD), n);
if (error)
break;
}
mutex_exit(&fip->fi_lock);
--- 5571,5581 ----
eof = 1;
break;
}
error = gfs_readdir_emitn(&gstate, uiop, n,
! pmkino(n, pslot, entrytype), n);
if (error)
break;
}
mutex_exit(&fip->fi_lock);
*** 5424,5433 ****
--- 5583,5610 ----
prunlock(pnp);
return (gfs_readdir_fini(&gstate, error, eofp, eof));
}
+ static int
+ pr_readdir_fddir(prnode_t *pnp, uio_t *uiop, int *eofp)
+ {
+
+ ASSERT(pnp->pr_type == PR_FDDIR);
+
+ return (pr_readdir_fdlist(pnp, uiop, eofp, pnp->pr_type, PR_FD));
+ }
+
+ static int
+ pr_readdir_fdinfodir(prnode_t *pnp, uio_t *uiop, int *eofp)
+ {
+
+ ASSERT(pnp->pr_type == PR_FDINFODIR);
+
+ return (pr_readdir_fdlist(pnp, uiop, eofp, pnp->pr_type, PR_FDINFO));
+ }
+
/* ARGSUSED */
static int
pr_readdir_pathdir(prnode_t *pnp, uio_t *uiop, int *eofp)
{
longlong_t bp[DIRENT64_RECLEN(64) / sizeof (longlong_t)];
*** 5733,5742 ****
--- 5910,5920 ----
prnode_t *opnp = NULL;
switch (type) {
case PR_OBJECT:
case PR_FD:
+ case PR_FDDIR:
case PR_SELF:
case PR_PATH:
/* These are not linked into the usual lists */
ASSERT(vp->v_count == 1);
if ((dp = pnp->pr_parent) != NULL)