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)