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