Print this page
OS-3463 expose process argv through procfs
OS-3207 in lx zone, 'ps auxww' does not show full cmdline for processes
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
OS-3383 lx brand: node.js test test-setproctitle.js fails
OS-15 add procfs equivalent to prctl(PR_SET_NAME)

*** 19,29 **** * CDDL HEADER END */ /* * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright (c) 2014, Joyent, Inc. All rights reserved. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ --- 19,29 ---- * CDDL HEADER END */ /* * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright 2015, Joyent, Inc. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */
*** 94,103 **** --- 94,108 ---- }; #define PRSDSIZE (sizeof (struct prdirect)) /* + * Maximum length of the /proc/$$/argv file: + */ + int prmaxargvlen = 4096; + + /* * Directory characteristics. */ typedef struct prdirent { ino64_t d_ino; /* "inode number" of entry */ off64_t d_off; /* offset of disk directory entry */
*** 164,173 **** --- 169,180 ---- "contracts" }, #if defined(__x86) { PR_LDT, 27 * sizeof (prdirent_t), sizeof (prdirent_t), "ldt" }, #endif + { PR_ARGV, 28 * sizeof (prdirent_t), sizeof (prdirent_t), + "argv" }, }; #define NPIDDIRFILES (sizeof (piddir) / sizeof (piddir[0]) - 2) /*
*** 580,589 **** --- 587,597 ---- pr_read_map(), pr_read_rmap(), pr_read_xmap(), pr_read_cred(), pr_read_sigact(), pr_read_auxv(), #if defined(__x86) pr_read_ldt(), #endif + pr_read_argv(), pr_read_usage(), pr_read_lusage(), pr_read_pagedata(), pr_read_watch(), pr_read_lwpstatus(), pr_read_lwpsinfo(), pr_read_lwpusage(), pr_read_xregs(), pr_read_priv(), pr_read_spymaster(), #if defined(__sparc)
*** 608,617 **** --- 616,626 ---- pr_read_sigact, /* /proc/<pid>/sigact */ pr_read_auxv, /* /proc/<pid>/auxv */ #if defined(__x86) pr_read_ldt, /* /proc/<pid>/ldt */ #endif + pr_read_argv, /* /proc/<pid>/argv */ pr_read_usage, /* /proc/<pid>/usage */ pr_read_lusage, /* /proc/<pid>/lusage */ pr_read_pagedata, /* /proc/<pid>/pagedata */ pr_read_watch, /* /proc/<pid>/watch */ pr_read_inval, /* /proc/<pid>/cwd */
*** 670,679 **** --- 679,723 ---- return (error); } static int + pr_read_argv(prnode_t *pnp, uio_t *uiop) + { + char *args; + int error; + size_t asz = prmaxargvlen, sz; + + /* + * Allocate a scratch buffer for collection of the process arguments. + */ + args = kmem_alloc(asz, KM_SLEEP); + + ASSERT(pnp->pr_type == PR_ARGV); + + if ((error = prlock(pnp, ZNO)) != 0) { + kmem_free(args, asz); + return (error); + } + + if ((error = prreadargv(pnp->pr_common->prc_proc, args, asz, + &sz)) != 0) { + prunlock(pnp); + kmem_free(args, asz); + return (error); + } + + prunlock(pnp); + + error = pr_uioread(args, sz, uiop); + + kmem_free(args, asz); + + return (error); + } + + static int pr_read_as(prnode_t *pnp, uio_t *uiop) { int error; ASSERT(pnp->pr_type == PR_AS);
*** 1765,1774 **** --- 1809,1819 ---- pr_read_sigact_32, /* /proc/<pid>/sigact */ pr_read_auxv_32, /* /proc/<pid>/auxv */ #if defined(__x86) pr_read_ldt, /* /proc/<pid>/ldt */ #endif + pr_read_argv, /* /proc/<pid>/argv */ pr_read_usage_32, /* /proc/<pid>/usage */ pr_read_lusage_32, /* /proc/<pid>/lusage */ pr_read_pagedata_32, /* /proc/<pid>/pagedata */ pr_read_watch_32, /* /proc/<pid>/watch */ pr_read_inval, /* /proc/<pid>/cwd */
*** 2684,2693 **** --- 2729,2835 ---- #else return (pr_read_function[pnp->pr_type](pnp, uiop)); #endif } + /* + * We make pr_write_psinfo_fname() somewhat simpler by asserting at compile + * time that PRFNSZ has the same definition as MAXCOMLEN. + */ + #if PRFNSZ != MAXCOMLEN + #error PRFNSZ/MAXCOMLEN mismatch + #endif + + static int + pr_write_psinfo_fname(prnode_t *pnp, uio_t *uiop) + { + char fname[PRFNSZ]; + int offset = offsetof(psinfo_t, pr_fname), error; + + #ifdef _SYSCALL32_IMPL + if (curproc->p_model != DATAMODEL_LP64) + offset = offsetof(psinfo32_t, pr_fname); + #endif + + /* + * If this isn't a write to pr_fname (or if the size doesn't match + * PRFNSZ) return. + */ + if (uiop->uio_offset != offset || uiop->uio_resid != PRFNSZ) + return (0); + + if ((error = uiomove(fname, PRFNSZ, UIO_WRITE, uiop)) != 0) + return (error); + + fname[PRFNSZ - 1] = '\0'; + + if ((error = prlock(pnp, ZNO)) != 0) + return (error); + + bcopy(fname, pnp->pr_common->prc_proc->p_user.u_comm, PRFNSZ); + + prunlock(pnp); + + return (0); + } + + /* + * We make pr_write_psinfo_psargs() somewhat simpler by asserting at compile + * time that PRARGSZ has the same definition as PSARGSZ. + */ + #if PRARGSZ != PSARGSZ + #error PRARGSZ/PSARGSZ mismatch + #endif + + static int + pr_write_psinfo_psargs(prnode_t *pnp, uio_t *uiop) + { + char psargs[PRARGSZ]; + int offset = offsetof(psinfo_t, pr_psargs), error; + + #ifdef _SYSCALL32_IMPL + if (curproc->p_model != DATAMODEL_LP64) + offset = offsetof(psinfo32_t, pr_psargs); + #endif + + /* + * If this isn't a write to pr_psargs (or if the size doesn't match + * PRARGSZ) return. + */ + if (uiop->uio_offset != offset || uiop->uio_resid != PRARGSZ) + return (0); + + if ((error = uiomove(psargs, PRARGSZ, UIO_WRITE, uiop)) != 0) + return (error); + + psargs[PRARGSZ - 1] = '\0'; + + if ((error = prlock(pnp, ZNO)) != 0) + return (error); + + bcopy(psargs, pnp->pr_common->prc_proc->p_user.u_psargs, PRARGSZ); + + prunlock(pnp); + + return (0); + } + + int + pr_write_psinfo(prnode_t *pnp, uio_t *uiop) + { + int error; + + if ((error = pr_write_psinfo_fname(pnp, uiop)) != 0) + return (error); + + if ((error = pr_write_psinfo_psargs(pnp, uiop)) != 0) + return (error); + + return (0); + } + + /* ARGSUSED */ static int prwrite(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, caller_context_t *ct) { prnode_t *pnp = VTOP(vp);
*** 2762,2771 **** --- 2904,2916 ---- */ if (error == EINTR) uiop->uio_resid = resid; return (error); + case PR_PSINFO: + return (pr_write_psinfo(pnp, uiop)); + default: return ((vp->v_type == VDIR)? EISDIR : EBADF); } /* NOTREACHED */ }
*** 3045,3054 **** --- 3190,3206 ---- PR_OBJSIZE(struct sigaction32, struct sigaction); break; case PR_AUXV: vap->va_size = __KERN_NAUXV_IMPL * PR_OBJSIZE(auxv32_t, auxv_t); break; + case PR_ARGV: + if ((p->p_flag & SSYS) || p->p_as == &kas) { + vap->va_size = PSARGSZ; + } else { + vap->va_size = prmaxargvlen; + } + break; #if defined(__x86) case PR_LDT: mutex_exit(&p->p_lock); mutex_enter(&p->p_ldtlock); vap->va_size = prnldt(p) * sizeof (struct ssd);
*** 3220,3229 **** --- 3372,3382 ---- case PR_LWPDIR: case PR_LWPIDDIR: case PR_USAGE: case PR_LUSAGE: case PR_LWPUSAGE: + case PR_ARGV: p = pr_p_lock(pnp); mutex_exit(&pr_pidlock); if (p == NULL) return (ENOENT); prunlock(pnp);
*** 3305,3314 **** --- 3458,3468 ---- pr_lookup_notdir, /* /proc/<pid>/sigact */ pr_lookup_notdir, /* /proc/<pid>/auxv */ #if defined(__x86) pr_lookup_notdir, /* /proc/<pid>/ldt */ #endif + pr_lookup_notdir, /* /proc/<pid>/argv */ pr_lookup_notdir, /* /proc/<pid>/usage */ pr_lookup_notdir, /* /proc/<pid>/lusage */ pr_lookup_notdir, /* /proc/<pid>/pagedata */ pr_lookup_notdir, /* /proc/<pid>/watch */ pr_lookup_notdir, /* /proc/<pid>/cwd */
*** 4544,4558 **** --- 4698,4716 ---- case PR_LWPIDFILE: pnp->pr_mode = 0600; /* read-write by owner only */ break; case PR_PSINFO: + pnp->pr_mode = 0644; /* readable by all + owner can write */ + break; + case PR_LPSINFO: case PR_LWPSINFO: case PR_USAGE: case PR_LUSAGE: case PR_LWPUSAGE: + case PR_ARGV: pnp->pr_mode = 0444; /* read-only by all */ break; default: pnp->pr_mode = 0400; /* read-only by owner only */
*** 4654,4663 **** --- 4812,4822 ---- pr_readdir_notdir, /* /proc/<pid>/sigact */ pr_readdir_notdir, /* /proc/<pid>/auxv */ #if defined(__x86) pr_readdir_notdir, /* /proc/<pid>/ldt */ #endif + pr_readdir_notdir, /* /proc/<pid>/argv */ pr_readdir_notdir, /* /proc/<pid>/usage */ pr_readdir_notdir, /* /proc/<pid>/lusage */ pr_readdir_notdir, /* /proc/<pid>/pagedata */ pr_readdir_notdir, /* /proc/<pid>/watch */ pr_readdir_notdir, /* /proc/<pid>/cwd */
*** 4803,4812 **** --- 4962,4972 ---- switch (dirp->d_ino) { case PR_PIDDIR: case PR_PROCDIR: case PR_PSINFO: case PR_USAGE: + case PR_ARGV: break; default: continue; } }