Print this page
    
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/ps/ps.c
          +++ new/usr/src/cmd/ps/ps.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 2013 Gary Mills
  24   24   *
  25   25   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  26   26   * Use is subject to license terms.
  27   27   */
  28   28  
  29   29  /*
  30   30   * Copyright 2015 Joyent, Inc.
  31   31   */
  32   32  
  33   33  /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
  34   34  /*        All Rights Reserved   */
  35   35  
  36   36  /*
  37   37   * ps -- print things about processes.
  38   38   */
  39   39  #include <stdio.h>
  40   40  #include <ctype.h>
  41   41  #include <string.h>
  42   42  #include <errno.h>
  43   43  #include <fcntl.h>
  44   44  #include <pwd.h>
  45   45  #include <grp.h>
  46   46  #include <sys/types.h>
  47   47  #include <sys/stat.h>
  48   48  #include <sys/mkdev.h>
  49   49  #include <unistd.h>
  50   50  #include <stdlib.h>
  51   51  #include <limits.h>
  52   52  #include <dirent.h>
  53   53  #include <sys/signal.h>
  54   54  #include <sys/fault.h>
  55   55  #include <sys/syscall.h>
  56   56  #include <sys/time.h>
  57   57  #include <procfs.h>
  58   58  #include <locale.h>
  59   59  #include <wctype.h>
  60   60  #include <wchar.h>
  61   61  #include <libw.h>
  62   62  #include <stdarg.h>
  63   63  #include <sys/proc.h>
  64   64  #include <sys/pset.h>
  65   65  #include <project.h>
  66   66  #include <zone.h>
  67   67  
  68   68  #define min(a, b)       ((a) > (b) ? (b) : (a))
  69   69  #define max(a, b)       ((a) < (b) ? (b) : (a))
  70   70  
  71   71  #define NTTYS   20      /* initial size of table for -t option  */
  72   72  #define SIZ     30      /* initial size of tables for -p, -s, -g, -h and -z */
  73   73  
  74   74  /*
  75   75   * Size of buffer holding args for t, p, s, g, u, U, G, z options.
  76   76   * Set to ZONENAME_MAX, the minimum value needed to allow any
  77   77   * zone to be specified.
  78   78   */
  79   79  #define ARGSIZ ZONENAME_MAX
  80   80  
  81   81  /* Max chars in a user/group name or printed u/g id */
  82   82  #define MAXUGNAME (LOGNAME_MAX+2)
  83   83  
  84   84  /* Structure for storing user or group info */
  85   85  struct ugdata {
  86   86          id_t    id;                     /* numeric user-id or group-id */
  87   87          char    name[MAXUGNAME+1];      /* user/group name, null terminated */
  88   88  };
  89   89  
  90   90  struct ughead {
  91   91          size_t  size;           /* number of ugdata structs allocated */
  92   92          size_t  nent;           /* number of active entries */
  93   93          struct ugdata *ent;     /* pointer to array of actual entries */
  94   94  };
  95   95  
  96   96  enum fname {    /* enumeration of field names */
  97   97          F_USER,         /* effective user of the process */
  98   98          F_RUSER,        /* real user of the process */
  99   99          F_GROUP,        /* effective group of the process */
 100  100          F_RGROUP,       /* real group of the process */
 101  101          F_UID,          /* numeric effective uid of the process */
 102  102          F_RUID,         /* numeric real uid of the process */
 103  103          F_GID,          /* numeric effective gid of the process */
 104  104          F_RGID,         /* numeric real gid of the process */
 105  105          F_PID,          /* process id */
 106  106          F_PPID,         /* parent process id */
 107  107          F_PGID,         /* process group id */
 108  108          F_SID,          /* session id */
 109  109          F_PSR,          /* bound processor */
 110  110          F_LWP,          /* lwp-id */
 111  111          F_NLWP,         /* number of lwps */
 112  112          F_OPRI,         /* old priority (obsolete) */
 113  113          F_PRI,          /* new priority */
 114  114          F_F,            /* process flags */
 115  115          F_S,            /* letter indicating the state */
 116  116          F_C,            /* processor utilization (obsolete) */
 117  117          F_PCPU,         /* percent of recently used cpu time */
 118  118          F_PMEM,         /* percent of physical memory used (rss) */
 119  119          F_OSZ,          /* virtual size of the process in pages */
 120  120          F_VSZ,          /* virtual size of the process in kilobytes */
 121  121          F_RSS,          /* resident set size of the process in kilobytes */
 122  122          F_NICE,         /* "nice" value of the process */
 123  123          F_CLASS,        /* scheduler class */
 124  124          F_STIME,        /* start time of the process, hh:mm:ss or Month Day */
 125  125          F_ETIME,        /* elapsed time of the process, [[dd-]hh:]mm:ss */
 126  126          F_TIME,         /* cpu time of the process, [[dd-]hh:]mm:ss */
 127  127          F_TTY,          /* name of the controlling terminal */
 128  128          F_ADDR,         /* address of the process (obsolete) */
 129  129          F_WCHAN,        /* wait channel (sleep condition variable) */
 130  130          F_FNAME,        /* file name of command */
 131  131          F_COMM,         /* name of command (argv[0] value) */
 132  132          F_ARGS,         /* name of command plus all its arguments */
 133  133          F_TASKID,       /* task id */
 134  134          F_PROJID,       /* project id */
 135  135          F_PROJECT,      /* project name of the process */
 136  136          F_PSET,         /* bound processor set */
 137  137          F_ZONE,         /* zone name */
 138  138          F_ZONEID,       /* zone id */
 139  139          F_CTID,         /* process contract id */
 140  140          F_LGRP,         /* process home lgroup */
 141  141          F_DMODEL        /* process data model */
 142  142  };
 143  143  
 144  144  struct field {
 145  145          struct field    *next;          /* linked list */
 146  146          int             fname;          /* field index */
 147  147          const char      *header;        /* header to use */
 148  148          int             width;          /* width of field */
 149  149  };
 150  150  
 151  151  static  struct field *fields = NULL;    /* fields selected via -o */
 152  152  static  struct field *last_field = NULL;
 153  153  static  int do_header = 0;
 154  154  static  struct timeval now;
 155  155  
 156  156  /* array of defined fields, in fname order */
 157  157  struct def_field {
 158  158          const char *fname;
 159  159          const char *header;
 160  160          int width;
 161  161          int minwidth;
 162  162  };
 163  163  
 164  164  static struct def_field fname[] = {
 165  165          /* fname        header          width   minwidth */
 166  166          { "user",       "USER",         8,      8       },
 167  167          { "ruser",      "RUSER",        8,      8       },
 168  168          { "group",      "GROUP",        8,      8       },
 169  169          { "rgroup",     "RGROUP",       8,      8       },
 170  170          { "uid",        "UID",          5,      5       },
 171  171          { "ruid",       "RUID",         5,      5       },
 172  172          { "gid",        "GID",          5,      5       },
 173  173          { "rgid",       "RGID",         5,      5       },
 174  174          { "pid",        "PID",          5,      5       },
 175  175          { "ppid",       "PPID",         5,      5       },
 176  176          { "pgid",       "PGID",         5,      5       },
 177  177          { "sid",        "SID",          5,      5       },
 178  178          { "psr",        "PSR",          3,      2       },
 179  179          { "lwp",        "LWP",          6,      2       },
 180  180          { "nlwp",       "NLWP",         4,      2       },
 181  181          { "opri",       "PRI",          3,      2       },
 182  182          { "pri",        "PRI",          3,      2       },
 183  183          { "f",          "F",            2,      2       },
 184  184          { "s",          "S",            1,      1       },
 185  185          { "c",          "C",            2,      2       },
 186  186          { "pcpu",       "%CPU",         4,      4       },
 187  187          { "pmem",       "%MEM",         4,      4       },
 188  188          { "osz",        "SZ",           4,      4       },
 189  189          { "vsz",        "VSZ",          4,      4       },
 190  190          { "rss",        "RSS",          4,      4       },
 191  191          { "nice",       "NI",           2,      2       },
 192  192          { "class",      "CLS",          4,      2       },
 193  193          { "stime",      "STIME",        8,      8       },
 194  194          { "etime",      "ELAPSED",      11,     7       },
 195  195          { "time",       "TIME",         11,     5       },
 196  196          { "tty",        "TT",           7,      7       },
 197  197  #ifdef _LP64
 198  198          { "addr",       "ADDR",         16,     8       },
 199  199          { "wchan",      "WCHAN",        16,     8       },
 200  200  #else
 201  201          { "addr",       "ADDR",         8,      8       },
 202  202          { "wchan",      "WCHAN",        8,      8       },
 203  203  #endif
 204  204          { "fname",      "COMMAND",      8,      8       },
 205  205          { "comm",       "COMMAND",      80,     8       },
 206  206          { "args",       "COMMAND",      80,     80      },
 207  207          { "taskid",     "TASKID",       5,      5       },
 208  208          { "projid",     "PROJID",       5,      5       },
 209  209          { "project",    "PROJECT",      8,      8       },
 210  210          { "pset",       "PSET",         3,      3       },
 211  211          { "zone",       "ZONE",         8,      8       },
 212  212          { "zoneid",     "ZONEID",       5,      5       },
 213  213          { "ctid",       "CTID",         5,      5       },
 214  214          { "lgrp",       "LGRP",         4,      2       },
 215  215          { "dmodel",     "DMODEL",       6,      6       },
 216  216  };
 217  217  
 218  218  #define NFIELDS (sizeof (fname) / sizeof (fname[0]))
 219  219  
 220  220  static  int     retcode = 1;
 221  221  static  int     lflg;
 222  222  static  int     Aflg;
 223  223  static  int     uflg;
 224  224  static  int     Uflg;
 225  225  static  int     Gflg;
 226  226  static  int     aflg;
 227  227  static  int     dflg;
 228  228  static  int     Lflg;
 229  229  static  int     Pflg;
 230  230  static  int     Wflg;
 231  231  static  int     yflg;
 232  232  static  int     pflg;
 233  233  static  int     fflg;
 234  234  static  int     cflg;
 235  235  static  int     jflg;
 236  236  static  int     gflg;
 237  237  static  int     sflg;
 238  238  static  int     tflg;
 239  239  static  int     zflg;
 240  240  static  int     Zflg;
 241  241  static  int     hflg;
 242  242  static  int     Hflg;
 243  243  static  uid_t   tuid = (uid_t)-1;
 244  244  static  int     errflg;
 245  245  
 246  246  static  int     ndev;           /* number of devices */
 247  247  static  int     maxdev;         /* number of devl structures allocated */
 248  248  
 249  249  #define DNINCR  100
 250  250  #define DNSIZE  14
 251  251  static struct devl {            /* device list   */
 252  252          char    dname[DNSIZE];  /* device name   */
 253  253          dev_t   ddev;           /* device number */
 254  254  } *devl;
 255  255  
 256  256  static  struct tty {
 257  257          char *tname;
 258  258          dev_t tdev;
 259  259  } *tty = NULL;                  /* for t option */
 260  260  static  size_t  ttysz = 0;
 261  261  static  int     ntty = 0;
 262  262  
 263  263  static  pid_t   *pid = NULL;    /* for p option */
 264  264  static  size_t  pidsz = 0;
 265  265  static  size_t  npid = 0;
 266  266  
 267  267  static  int     *lgrps = NULL;  /* list of lgroup IDs for for h option */
 268  268  static  size_t  lgrps_size = 0; /* size of the lgrps list */
 269  269  static  size_t  nlgrps = 0;     /* number elements in the list */
 270  270  
 271  271  /* Maximum possible lgroup ID value */
 272  272  #define MAX_LGRP_ID 256
 273  273  
 274  274  static  pid_t   *grpid = NULL;  /* for g option */
 275  275  static  size_t  grpidsz = 0;
 276  276  static  int     ngrpid = 0;
 277  277  
 278  278  static  pid_t   *sessid = NULL; /* for s option */
 279  279  static  size_t  sessidsz = 0;
 280  280  static  int     nsessid = 0;
 281  281  
 282  282  static  zoneid_t *zoneid = NULL; /* for z option */
 283  283  static  size_t  zoneidsz = 0;
 284  284  static  int     nzoneid = 0;
 285  285  
 286  286  static  int     kbytes_per_page;
 287  287  static  int     pidwidth;
 288  288  
 289  289  static  char    procdir[MAXPATHLEN];    /* standard /proc directory */
 290  290  
 291  291  static struct ughead    euid_tbl;       /* table to store selected euid's */
 292  292  static struct ughead    ruid_tbl;       /* table to store selected real uid's */
 293  293  static struct ughead    egid_tbl;       /* table to store selected egid's */
 294  294  static struct ughead    rgid_tbl;       /* table to store selected real gid's */
 295  295  static prheader_t *lpsinfobuf;          /* buffer to contain lpsinfo */
 296  296  static size_t   lpbufsize;
 297  297  
 298  298  /*
 299  299   * This constant defines the sentinal number of process IDs below which we
 300  300   * only examine individual entries in /proc rather than scanning through
 301  301   * /proc. This optimization is a huge win in the common case.
 302  302   */
 303  303  #define PTHRESHOLD      40
 304  304  
 305  305  #define UCB_OPTS        "-aceglnrtuvwxSU"
 306  306  
 307  307  static  void    usage(void);
 308  308  static  char    *getarg(char **);
 309  309  static  char    *parse_format(char *);
 310  310  static  char    *gettty(psinfo_t *);
 311  311  static  int     prfind(int, psinfo_t *, char **);
 312  312  static  void    prcom(psinfo_t *, char *);
 313  313  static  void    prtpct(ushort_t, int);
 314  314  static  void    print_time(time_t, int);
 315  315  static  void    print_field(psinfo_t *, struct field *, const char *);
 316  316  static  void    print_zombie_field(psinfo_t *, struct field *, const char *);
 317  317  static  void    pr_fields(psinfo_t *, const char *,
 318  318                  void (*print_fld)(psinfo_t *, struct field *, const char *));
 319  319  static  int     search(pid_t *, int, pid_t);
 320  320  static  void    add_ugentry(struct ughead *, char *);
 321  321  static  int     uconv(struct ughead *);
 322  322  static  int     gconv(struct ughead *);
 323  323  static  int     ugfind(id_t, struct ughead *);
 324  324  static  void    prtime(timestruc_t, int, int);
 325  325  static  void    przom(psinfo_t *);
 326  326  static  int     namencnt(char *, int, int);
 327  327  static  char    *err_string(int);
 328  328  static  int     print_proc(char *pname);
 329  329  static  time_t  delta_secs(const timestruc_t *);
 330  330  static  int     str2id(const char *, pid_t *, long, long);
 331  331  static  int     str2uid(const char *,  uid_t *, unsigned long, unsigned long);
 332  332  static  void    *Realloc(void *, size_t);
 333  333  static  int     pidcmp(const void *p1, const void *p2);
 334  334  
 335  335  extern  int     ucbmain(int, char **);
 336  336  static  int     stdmain(int, char **);
 337  337  
 338  338  int
 339  339  main(int argc, char **argv)
 340  340  {
 341  341          const char *me;
 342  342          const char *zroot = zone_get_nroot();
 343  343  
 344  344          /*
 345  345           * If this is a branded zone, the native procfs may mounted in a
 346  346           * non-standard location.  Apply such a path prefix if it exists.
 347  347           */
 348  348          (void) snprintf(procdir, sizeof (procdir), "%s/proc", zroot != NULL ?
 349  349              zroot : "");
 350  350  
 351  351          /*
 352  352           * The original two ps'es are linked in a single binary;
 353  353           * their main()s are renamed to stdmain for /usr/bin/ps and
 354  354           * ucbmain for /usr/ucb/ps.
 355  355           * We try to figure out which instance of ps the user wants to run.
 356  356           * Traditionally, the UCB variant doesn't require the flag argument
 357  357           * start with a "-".  If the first argument doesn't start with a
 358  358           * "-", we call "ucbmain".
 359  359           * If there's a first argument and it starts with a "-", we check
 360  360           * whether any of the options isn't acceptable to "ucbmain"; in that
 361  361           * case we run "stdmain".
 362  362           * If we can't tell from the options which main to call, we check
 363  363           * the binary we are running.  We default to "stdmain" but
 364  364           * any mention in the executable name of "ucb" causes us to call
 365  365           * ucbmain.
 366  366           */
 367  367          if (argv[1] != NULL) {
 368  368                  if (argv[1][0] != '-')
 369  369                          return (ucbmain(argc, argv));
 370  370                  else if (argv[1][strspn(argv[1], UCB_OPTS)] != '\0')
 371  371                          return (stdmain(argc, argv));
 372  372          }
 373  373  
 374  374          me = getexecname();
 375  375  
 376  376          if (me != NULL && strstr(me, "ucb") != NULL)
 377  377                  return (ucbmain(argc, argv));
 378  378          else
 379  379                  return (stdmain(argc, argv));
 380  380  }
 381  381  
 382  382  static int
 383  383  stdmain(int argc, char **argv)
 384  384  {
 385  385          char    *p;
 386  386          char    *p1;
 387  387          char    *parg;
 388  388          int     c;
 389  389          int     i;
 390  390          int     pgerrflg = 0;   /* err flg: non-numeric arg w/p & g options */
 391  391          size_t  size, len;
 392  392          DIR     *dirp;
 393  393          struct dirent *dentp;
 394  394          pid_t   maxpid;
 395  395          pid_t   id;
 396  396          int     ret;
 397  397          char    loc_stime_str[32];
 398  398  
 399  399          (void) setlocale(LC_ALL, "");
 400  400  #if !defined(TEXT_DOMAIN)       /* Should be defined by cc -D */
 401  401  #define TEXT_DOMAIN     "SYS_TEST"      /* Use this only if it weren't */
 402  402  #endif
 403  403          (void) textdomain(TEXT_DOMAIN);
 404  404  
 405  405          (void) memset(&euid_tbl, 0, sizeof (euid_tbl));
 406  406          (void) memset(&ruid_tbl, 0, sizeof (ruid_tbl));
 407  407          (void) memset(&egid_tbl, 0, sizeof (egid_tbl));
 408  408          (void) memset(&rgid_tbl, 0, sizeof (rgid_tbl));
 409  409  
 410  410          kbytes_per_page = sysconf(_SC_PAGESIZE) / 1024;
 411  411  
 412  412          (void) gettimeofday(&now, NULL);
 413  413  
 414  414          /*
 415  415           * calculate width of pid fields based on configured MAXPID
 416  416           * (must be at least 5 to retain output format compatibility)
 417  417           */
 418  418          id = maxpid = (pid_t)sysconf(_SC_MAXPID);
 419  419          pidwidth = 1;
 420  420          while ((id /= 10) > 0)
 421  421                  ++pidwidth;
 422  422          pidwidth = pidwidth < 5 ? 5 : pidwidth;
 423  423  
 424  424          fname[F_PID].width = fname[F_PPID].width = pidwidth;
 425  425          fname[F_PGID].width = fname[F_SID].width = pidwidth;
 426  426  
 427  427          /*
 428  428           * TRANSLATION_NOTE
 429  429           * Specify the printf format with width and precision for
 430  430           * the STIME field.
 431  431           */
 432  432          len = snprintf(loc_stime_str, sizeof (loc_stime_str),
 433  433              dcgettext(NULL, "%8.8s", LC_TIME), "STIME");
 434  434          if (len >= sizeof (loc_stime_str))
 435  435                  len = sizeof (loc_stime_str) - 1;
 436  436  
 437  437          fname[F_STIME].width = fname[F_STIME].minwidth = len;
 438  438  
 439  439          while ((c = getopt(argc, argv, "jlfceAadLPWyZHh:t:p:g:u:U:G:n:s:o:z:"))
 440  440              != EOF)
 441  441                  switch (c) {
 442  442                  case 'H':               /* Show home lgroups */
 443  443                          Hflg++;
 444  444                          break;
 445  445                  case 'h':
 446  446                          /*
 447  447                           * Show processes/threads with given home lgroups
 448  448                           */
 449  449                          hflg++;
 450  450                          p1 = optarg;
 451  451                          do {
 452  452                                  int id;
 453  453  
 454  454                                  /*
 455  455                                   * Get all IDs in the list, verify for
 456  456                                   * correctness and place in lgrps array.
 457  457                                   */
 458  458                                  parg = getarg(&p1);
 459  459                                  /* Convert string to integer */
 460  460                                  ret = str2id(parg, (pid_t *)&id, 0,
 461  461                                      MAX_LGRP_ID);
 462  462                                  /* Complain if ID didn't parse correctly */
 463  463                                  if (ret != 0) {
 464  464                                          pgerrflg++;
 465  465                                          (void) fprintf(stderr,
 466  466                                              gettext("ps: %s "), parg);
 467  467                                          if (ret == EINVAL)
 468  468                                                  (void) fprintf(stderr,
 469  469                                                      gettext("is an invalid "
 470  470                                                      "non-numeric argument"));
 471  471                                          else
 472  472                                                  (void) fprintf(stderr,
 473  473                                                      gettext("exceeds valid "
 474  474                                                      "range"));
 475  475                                          (void) fprintf(stderr,
 476  476                                              gettext(" for -h option\n"));
 477  477                                          continue;
 478  478                                  }
 479  479  
 480  480                                  /* Extend lgrps array if needed */
 481  481                                  if (nlgrps == lgrps_size) {
 482  482                                          /* Double the size of the lgrps array */
 483  483                                          if (lgrps_size == 0)
 484  484                                                  lgrps_size = SIZ;
 485  485                                          lgrps_size *= 2;
 486  486                                          lgrps = Realloc(lgrps,
 487  487                                              lgrps_size * sizeof (int));
 488  488                                  }
 489  489                                  /* place the id in the lgrps table */
 490  490                                  lgrps[nlgrps++] = id;
 491  491                          } while (*p1);
 492  492                          break;
 493  493                  case 'l':               /* long listing */
 494  494                          lflg++;
 495  495                          break;
 496  496                  case 'f':               /* full listing */
 497  497                          fflg++;
 498  498                          break;
 499  499                  case 'j':
 500  500                          jflg++;
 501  501                          break;
 502  502                  case 'c':
 503  503                          /*
 504  504                           * Format output to reflect scheduler changes:
 505  505                           * high numbers for high priorities and don't
 506  506                           * print nice or p_cpu values.  'c' option only
 507  507                           * effective when used with 'l' or 'f' options.
 508  508                           */
 509  509                          cflg++;
 510  510                          break;
 511  511                  case 'A':               /* list every process */
 512  512                  case 'e':               /* (obsolete) list every process */
 513  513                          Aflg++;
 514  514                          tflg = Gflg = Uflg = uflg = pflg = gflg = sflg = 0;
 515  515                          zflg = hflg = 0;
 516  516                          break;
 517  517                  case 'a':
 518  518                          /*
 519  519                           * Same as 'e' except no session group leaders
 520  520                           * and no non-terminal processes.
 521  521                           */
 522  522                          aflg++;
 523  523                          break;
 524  524                  case 'd':       /* same as e except no session leaders */
 525  525                          dflg++;
 526  526                          break;
 527  527                  case 'L':       /* show lwps */
 528  528                          Lflg++;
 529  529                          break;
 530  530                  case 'P':       /* show bound processor */
 531  531                          Pflg++;
 532  532                          break;
 533  533                  case 'W':       /* truncate long names */
 534  534                          Wflg++;
 535  535                          break;
 536  536                  case 'y':       /* omit F & ADDR, report RSS & SZ in Kby */
 537  537                          yflg++;
 538  538                          break;
 539  539                  case 'n':       /* no longer needed; retain as no-op */
 540  540                          (void) fprintf(stderr,
 541  541                              gettext("ps: warning: -n option ignored\n"));
 542  542                          break;
 543  543                  case 't':               /* terminals */
 544  544  #define TSZ     30
 545  545                          tflg++;
 546  546                          p1 = optarg;
 547  547                          do {
 548  548                                  char nambuf[TSZ+6];     /* for "/dev/" + '\0' */
 549  549                                  struct stat64 s;
 550  550                                  parg = getarg(&p1);
 551  551                                  p = Realloc(NULL, TSZ+1);       /* for '\0' */
 552  552                                  /* zero the buffer before using it */
 553  553                                  p[0] = '\0';
 554  554                                  size = TSZ;
 555  555                                  if (isdigit(*parg)) {
 556  556                                          (void) strcpy(p, "tty");
 557  557                                          size -= 3;
 558  558                                  }
 559  559                                  (void) strncat(p, parg, size);
 560  560                                  if (ntty == ttysz) {
 561  561                                          if ((ttysz *= 2) == 0)
 562  562                                                  ttysz = NTTYS;
 563  563                                          tty = Realloc(tty,
 564  564                                              (ttysz + 1) * sizeof (struct tty));
 565  565                                  }
 566  566                                  tty[ntty].tdev = PRNODEV;
 567  567                                  (void) strcpy(nambuf, "/dev/");
 568  568                                  (void) strcat(nambuf, p);
 569  569                                  if (stat64(nambuf, &s) == 0)
 570  570                                          tty[ntty].tdev = s.st_rdev;
 571  571                                  tty[ntty++].tname = p;
 572  572                          } while (*p1);
 573  573                          break;
 574  574                  case 'p':               /* proc ids */
 575  575                          pflg++;
 576  576                          p1 = optarg;
 577  577                          do {
 578  578                                  pid_t id;
 579  579  
 580  580                                  parg = getarg(&p1);
 581  581                                  if ((ret = str2id(parg, &id, 0, maxpid)) != 0) {
 582  582                                          pgerrflg++;
 583  583                                          (void) fprintf(stderr,
 584  584                                              gettext("ps: %s "), parg);
 585  585                                          if (ret == EINVAL)
 586  586                                                  (void) fprintf(stderr,
 587  587                                                      gettext("is an invalid "
 588  588                                                      "non-numeric argument"));
 589  589                                          else
 590  590                                                  (void) fprintf(stderr,
 591  591                                                      gettext("exceeds valid "
 592  592                                                      "range"));
 593  593                                          (void) fprintf(stderr,
 594  594                                              gettext(" for -p option\n"));
 595  595                                          continue;
 596  596                                  }
 597  597  
 598  598                                  if (npid == pidsz) {
 599  599                                          if ((pidsz *= 2) == 0)
 600  600                                                  pidsz = SIZ;
 601  601                                          pid = Realloc(pid,
 602  602                                              pidsz * sizeof (pid_t));
 603  603                                  }
 604  604                                  pid[npid++] = id;
 605  605                          } while (*p1);
 606  606                          break;
 607  607                  case 's':               /* session */
 608  608                          sflg++;
 609  609                          p1 = optarg;
 610  610                          do {
 611  611                                  pid_t id;
 612  612  
 613  613                                  parg = getarg(&p1);
 614  614                                  if ((ret = str2id(parg, &id, 0, maxpid)) != 0) {
 615  615                                          pgerrflg++;
 616  616                                          (void) fprintf(stderr,
 617  617                                              gettext("ps: %s "), parg);
 618  618                                          if (ret == EINVAL)
 619  619                                                  (void) fprintf(stderr,
 620  620                                                      gettext("is an invalid "
 621  621                                                      "non-numeric argument"));
 622  622                                          else
 623  623                                                  (void) fprintf(stderr,
 624  624                                                      gettext("exceeds valid "
 625  625                                                      "range"));
 626  626                                          (void) fprintf(stderr,
 627  627                                              gettext(" for -s option\n"));
 628  628                                          continue;
 629  629                                  }
 630  630  
 631  631                                  if (nsessid == sessidsz) {
 632  632                                          if ((sessidsz *= 2) == 0)
 633  633                                                  sessidsz = SIZ;
 634  634                                          sessid = Realloc(sessid,
 635  635                                              sessidsz * sizeof (pid_t));
 636  636                                  }
 637  637                                  sessid[nsessid++] = id;
 638  638                          } while (*p1);
 639  639                          break;
 640  640                  case 'g':               /* proc group */
 641  641                          gflg++;
 642  642                          p1 = optarg;
 643  643                          do {
 644  644                                  pid_t id;
 645  645  
 646  646                                  parg = getarg(&p1);
 647  647                                  if ((ret = str2id(parg, &id, 0, maxpid)) != 0) {
 648  648                                          pgerrflg++;
 649  649                                          (void) fprintf(stderr,
 650  650                                              gettext("ps: %s "), parg);
 651  651                                          if (ret == EINVAL)
 652  652                                                  (void) fprintf(stderr,
 653  653                                                      gettext("is an invalid "
 654  654                                                      "non-numeric argument"));
 655  655                                          else
 656  656                                                  (void) fprintf(stderr,
 657  657                                                      gettext("exceeds valid "
 658  658                                                      "range"));
 659  659                                          (void) fprintf(stderr,
 660  660                                              gettext(" for -g option\n"));
 661  661                                          continue;
 662  662                                  }
 663  663  
 664  664                                  if (ngrpid == grpidsz) {
 665  665                                          if ((grpidsz *= 2) == 0)
 666  666                                                  grpidsz = SIZ;
 667  667                                          grpid = Realloc(grpid,
 668  668                                              grpidsz * sizeof (pid_t));
 669  669                                  }
 670  670                                  grpid[ngrpid++] = id;
 671  671                          } while (*p1);
 672  672                          break;
 673  673                  case 'u':               /* effective user name or number */
 674  674                          uflg++;
 675  675                          p1 = optarg;
 676  676                          do {
 677  677                                  parg = getarg(&p1);
 678  678                                  add_ugentry(&euid_tbl, parg);
 679  679                          } while (*p1);
 680  680                          break;
 681  681                  case 'U':               /* real user name or number */
 682  682                          Uflg++;
 683  683                          p1 = optarg;
 684  684                          do {
 685  685                                  parg = getarg(&p1);
 686  686                                  add_ugentry(&ruid_tbl, parg);
 687  687                          } while (*p1);
 688  688                          break;
 689  689                  case 'G':               /* real group name or number */
 690  690                          Gflg++;
 691  691                          p1 = optarg;
 692  692                          do {
 693  693                                  parg = getarg(&p1);
 694  694                                  add_ugentry(&rgid_tbl, parg);
 695  695                          } while (*p1);
 696  696                          break;
 697  697                  case 'o':               /* output format */
 698  698                          p = optarg;
 699  699                          while ((p = parse_format(p)) != NULL)
 700  700                                  ;
 701  701                          break;
 702  702                  case 'z':               /* zone name or number */
 703  703                          zflg++;
 704  704                          p1 = optarg;
 705  705                          do {
 706  706                                  zoneid_t id;
 707  707  
 708  708                                  parg = getarg(&p1);
 709  709                                  if (zone_get_id(parg, &id) != 0) {
 710  710                                          pgerrflg++;
 711  711                                          (void) fprintf(stderr,
 712  712                                              gettext("ps: unknown zone %s\n"),
 713  713                                              parg);
 714  714                                          continue;
 715  715                                  }
 716  716  
 717  717                                  if (nzoneid == zoneidsz) {
 718  718                                          if ((zoneidsz *= 2) == 0)
 719  719                                                  zoneidsz = SIZ;
 720  720                                          zoneid = Realloc(zoneid,
 721  721                                              zoneidsz * sizeof (zoneid_t));
 722  722                                  }
 723  723                                  zoneid[nzoneid++] = id;
 724  724                          } while (*p1);
 725  725                          break;
 726  726                  case 'Z':               /* show zone name */
 727  727                          Zflg++;
 728  728                          break;
 729  729                  default:                        /* error on ? */
 730  730                          errflg++;
 731  731                          break;
 732  732                  }
 733  733  
 734  734          if (errflg || optind < argc || pgerrflg)
 735  735                  usage();
 736  736  
 737  737          if (tflg)
 738  738                  tty[ntty].tname = NULL;
 739  739          /*
 740  740           * If an appropriate option has not been specified, use the
 741  741           * current terminal and effective uid as the default.
 742  742           */
 743  743          if (!(aflg|Aflg|dflg|Gflg|hflg|Uflg|uflg|tflg|pflg|gflg|sflg|zflg)) {
 744  744                  psinfo_t info;
 745  745                  int procfd;
 746  746                  char *name;
 747  747                  char pname[100];
 748  748  
 749  749                  /* get our own controlling tty name using /proc */
 750  750                  (void) snprintf(pname, sizeof (pname),
 751  751                      "%s/self/psinfo", procdir);
 752  752                  if ((procfd = open(pname, O_RDONLY)) < 0 ||
 753  753                      read(procfd, (char *)&info, sizeof (info)) < 0 ||
 754  754                      info.pr_ttydev == PRNODEV) {
 755  755                          (void) fprintf(stderr,
 756  756                              gettext("ps: no controlling terminal\n"));
 757  757                          exit(1);
 758  758                  }
 759  759                  (void) close(procfd);
 760  760  
 761  761                  i = 0;
 762  762                  name = gettty(&info);
 763  763                  if (*name == '?') {
 764  764                          (void) fprintf(stderr,
 765  765                              gettext("ps: can't find controlling terminal\n"));
 766  766                          exit(1);
 767  767                  }
 768  768                  if (ntty == ttysz) {
 769  769                          if ((ttysz *= 2) == 0)
 770  770                                  ttysz = NTTYS;
 771  771                          tty = Realloc(tty, (ttysz + 1) * sizeof (struct tty));
 772  772                  }
 773  773                  tty[ntty].tdev = info.pr_ttydev;
 774  774                  tty[ntty++].tname = name;
 775  775                  tty[ntty].tname = NULL;
 776  776                  tflg++;
 777  777                  tuid = getuid();
 778  778          }
 779  779          if (Aflg) {
 780  780                  Gflg = Uflg = uflg = pflg = sflg = gflg = aflg = dflg = 0;
 781  781                  zflg = hflg = 0;
 782  782          }
 783  783          if (Aflg | aflg | dflg)
 784  784                  tflg = 0;
 785  785  
 786  786          i = 0;          /* prepare to exit on name lookup errors */
 787  787          i += uconv(&euid_tbl);
 788  788          i += uconv(&ruid_tbl);
 789  789          i += gconv(&egid_tbl);
 790  790          i += gconv(&rgid_tbl);
 791  791          if (i)
 792  792                  exit(1);
 793  793  
 794  794          /* allocate a buffer for lwpsinfo structures */
 795  795          lpbufsize = 4096;
 796  796          if (Lflg && (lpsinfobuf = malloc(lpbufsize)) == NULL) {
 797  797                  (void) fprintf(stderr,
 798  798                      gettext("ps: no memory\n"));
 799  799                  exit(1);
 800  800          }
 801  801  
 802  802          if (fields) {   /* print user-specified header */
 803  803                  if (do_header) {
 804  804                          struct field *f;
 805  805  
 806  806                          for (f = fields; f != NULL; f = f->next) {
 807  807                                  if (f != fields)
 808  808                                          (void) printf(" ");
 809  809                                  switch (f->fname) {
 810  810                                  case F_TTY:
 811  811                                          (void) printf("%-*s",
 812  812                                              f->width, f->header);
 813  813                                          break;
 814  814                                  case F_FNAME:
 815  815                                  case F_COMM:
 816  816                                  case F_ARGS:
 817  817                                          /*
 818  818                                           * Print these headers full width
 819  819                                           * unless they appear at the end.
 820  820                                           */
 821  821                                          if (f->next != NULL) {
 822  822                                                  (void) printf("%-*s",
 823  823                                                      f->width, f->header);
 824  824                                          } else {
 825  825                                                  (void) printf("%s",
 826  826                                                      f->header);
 827  827                                          }
 828  828                                          break;
 829  829                                  default:
 830  830                                          (void) printf("%*s",
 831  831                                              f->width, f->header);
 832  832                                          break;
 833  833                                  }
 834  834                          }
 835  835                          (void) printf("\n");
 836  836                  }
 837  837          } else {        /* print standard header */
 838  838                  /*
 839  839                   * All fields before 'PID' are printed with a trailing space
 840  840                   * as a separator and that is how we print the headers too.
 841  841                   */
 842  842                  if (lflg) {
 843  843                          if (yflg)
 844  844                                  (void) printf("S ");
 845  845                          else
 846  846                                  (void) printf(" F S ");
 847  847                  }
 848  848                  if (Zflg)
 849  849                          (void) printf("    ZONE ");
 850  850                  if (fflg) {
 851  851                          (void) printf("     UID ");
 852  852                  } else if (lflg)
 853  853                          (void) printf("   UID ");
 854  854  
 855  855                  (void) printf("%*s", pidwidth,  "PID");
 856  856                  if (lflg || fflg)
 857  857                          (void) printf(" %*s", pidwidth, "PPID");
 858  858                  if (jflg)
 859  859                          (void) printf(" %*s %*s", pidwidth, "PGID",
 860  860                              pidwidth, "SID");
 861  861                  if (Lflg)
 862  862                          (void) printf("   LWP");
 863  863                  if (Pflg)
 864  864                          (void) printf(" PSR");
 865  865                  if (Lflg && fflg)
 866  866                          (void) printf("  NLWP");
 867  867                  if (cflg)
 868  868                          (void) printf("  CLS PRI");
 869  869                  else if (lflg || fflg) {
 870  870                          (void) printf("   C");
 871  871                          if (lflg)
 872  872                                  (void) printf(" PRI NI");
 873  873                  }
 874  874                  if (lflg) {
 875  875                          if (yflg)
 876  876                                  (void) printf("   RSS     SZ    WCHAN");
 877  877                          else
 878  878                                  (void) printf("     ADDR     SZ    WCHAN");
 879  879                  }
 880  880                  if (fflg)
 881  881                          (void) printf(" %s", loc_stime_str);
 882  882                  if (Hflg)
 883  883                          (void) printf(" LGRP");
 884  884                  if (Lflg)
 885  885                          (void) printf(" TTY        LTIME CMD\n");
 886  886                  else
 887  887                          (void) printf(" TTY         TIME CMD\n");
 888  888          }
 889  889  
 890  890  
 891  891          if (pflg && !(aflg|Aflg|dflg|Gflg|Uflg|uflg|hflg|tflg|gflg|sflg|zflg) &&
 892  892              npid <= PTHRESHOLD) {
 893  893                  /*
 894  894                   * If we are looking at specific processes go straight
 895  895                   * to their /proc entries and don't scan /proc.
 896  896                   */
 897  897                  int i;
 898  898  
 899  899                  (void) qsort(pid, npid, sizeof (pid_t), pidcmp);
 900  900                  for (i = 0; i < npid; i++) {
 901  901                          char pname[12];
 902  902  
 903  903                          if (i >= 1 && pid[i] == pid[i - 1])
 904  904                                  continue;
 905  905                          (void) sprintf(pname, "%d", (int)pid[i]);
 906  906                          if (print_proc(pname) == 0)
 907  907                                  retcode = 0;
 908  908                  }
 909  909          } else {
 910  910                  /*
 911  911                   * Determine which processes to print info about by searching
 912  912                   * the /proc directory and looking at each process.
 913  913                   */
 914  914                  if ((dirp = opendir(procdir)) == NULL) {
 915  915                          (void) fprintf(stderr,
 916  916                              gettext("ps: cannot open PROC directory %s\n"),
 917  917                              procdir);
 918  918                          exit(1);
 919  919                  }
 920  920  
 921  921                  /* for each active process --- */
 922  922                  while ((dentp = readdir(dirp)) != NULL) {
 923  923                          if (dentp->d_name[0] == '.')    /* skip . and .. */
 924  924                                  continue;
 925  925                          if (print_proc(dentp->d_name) == 0)
 926  926                                  retcode = 0;
 927  927                  }
 928  928  
 929  929                  (void) closedir(dirp);
 930  930          }
 931  931          return (retcode);
 932  932  }
 933  933  
 934  934  
 935  935  int
 936  936  print_proc(char *pid_name)
 937  937  {
 938  938          char    pname[PATH_MAX];
 939  939          int     pdlen;
 940  940          int     found;
 941  941          int     procfd; /* filedescriptor for /proc/nnnnn/psinfo */
 942  942          char    *tp;    /* ptr to ttyname,  if any */
 943  943          psinfo_t info;  /* process information from /proc */
 944  944          lwpsinfo_t *lwpsinfo;   /* array of lwpsinfo structs */
 945  945  
 946  946          pdlen = snprintf(pname, sizeof (pname), "%s/%s/", procdir, pid_name);
 947  947          if (pdlen >= sizeof (pname) - 10)
 948  948                  return (1);
 949  949  retry:
 950  950          (void) strcpy(&pname[pdlen], "psinfo");
 951  951          if ((procfd = open(pname, O_RDONLY)) == -1) {
 952  952                  /* Process may have exited meanwhile. */
 953  953                  return (1);
 954  954          }
 955  955          /*
 956  956           * Get the info structure for the process and close quickly.
 957  957           */
 958  958          if (read(procfd, (char *)&info, sizeof (info)) < 0) {
 959  959                  int     saverr = errno;
 960  960  
 961  961                  (void) close(procfd);
 962  962                  if (saverr == EAGAIN)
 963  963                          goto retry;
 964  964                  if (saverr != ENOENT)
 965  965                          (void) fprintf(stderr,
 966  966                              gettext("ps: read() on %s: %s\n"),
 967  967                              pname, err_string(saverr));
 968  968                  return (1);
 969  969          }
 970  970          (void) close(procfd);
 971  971  
 972  972          found = 0;
 973  973          if (info.pr_lwp.pr_state == 0)  /* can't happen? */
 974  974                  return (1);
 975  975  
 976  976          /*
 977  977           * Omit session group leaders for 'a' and 'd' options.
 978  978           */
 979  979          if ((info.pr_pid == info.pr_sid) && (dflg || aflg))
 980  980                  return (1);
 981  981          if (Aflg || dflg)
 982  982                  found++;
 983  983          else if (pflg && search(pid, npid, info.pr_pid))
 984  984                  found++;        /* ppid in p option arg list */
 985  985          else if (uflg && ugfind((id_t)info.pr_euid, &euid_tbl))
 986  986                  found++;        /* puid in u option arg list */
 987  987          else if (Uflg && ugfind((id_t)info.pr_uid, &ruid_tbl))
 988  988                  found++;        /* puid in U option arg list */
 989  989  #ifdef NOT_YET
 990  990          else if (gflg && ugfind((id_t)info.pr_egid, &egid_tbl))
 991  991                  found++;        /* pgid in g option arg list */
 992  992  #endif  /* NOT_YET */
 993  993          else if (Gflg && ugfind((id_t)info.pr_gid, &rgid_tbl))
 994  994                  found++;        /* pgid in G option arg list */
 995  995          else if (gflg && search(grpid, ngrpid, info.pr_pgid))
 996  996                  found++;        /* grpid in g option arg list */
 997  997          else if (sflg && search(sessid, nsessid, info.pr_sid))
 998  998                  found++;        /* sessid in s option arg list */
 999  999          else if (zflg && search(zoneid, nzoneid, info.pr_zoneid))
1000 1000                  found++;        /* zoneid in z option arg list */
1001 1001          else if (hflg && search((pid_t *)lgrps, nlgrps, info.pr_lwp.pr_lgrp))
1002 1002                  found++;        /* home lgroup in h option arg list */
1003 1003          if (!found && !tflg && !aflg)
1004 1004                  return (1);
1005 1005          if (!prfind(found, &info, &tp))
1006 1006                  return (1);
1007 1007          if (Lflg && (info.pr_nlwp + info.pr_nzomb) > 1) {
1008 1008                  ssize_t prsz;
1009 1009  
1010 1010                  (void) strcpy(&pname[pdlen], "lpsinfo");
1011 1011                  if ((procfd = open(pname, O_RDONLY)) == -1)
1012 1012                          return (1);
1013 1013                  /*
1014 1014                   * Get the info structures for the lwps.
1015 1015                   */
1016 1016                  prsz = read(procfd, lpsinfobuf, lpbufsize);
1017 1017                  if (prsz == -1) {
1018 1018                          int     saverr = errno;
1019 1019  
1020 1020                          (void) close(procfd);
1021 1021                          if (saverr == EAGAIN)
1022 1022                                  goto retry;
1023 1023                          if (saverr != ENOENT)
1024 1024                                  (void) fprintf(stderr,
1025 1025                                      gettext("ps: read() on %s: %s\n"),
1026 1026                                      pname, err_string(saverr));
1027 1027                          return (1);
1028 1028                  }
1029 1029                  (void) close(procfd);
1030 1030                  if (prsz == lpbufsize) {
1031 1031                          /*
1032 1032                           * buffer overflow. Realloc new buffer.
1033 1033                           * Error handling is done in Realloc().
1034 1034                           */
1035 1035                          lpbufsize *= 2;
1036 1036                          lpsinfobuf = Realloc(lpsinfobuf, lpbufsize);
1037 1037                          goto retry;
1038 1038                  }
1039 1039                  if (lpsinfobuf->pr_nent != (info.pr_nlwp + info.pr_nzomb))
1040 1040                          goto retry;
1041 1041                  lwpsinfo = (lwpsinfo_t *)(lpsinfobuf + 1);
1042 1042          }
1043 1043          if (!Lflg || (info.pr_nlwp + info.pr_nzomb) <= 1) {
1044 1044                  prcom(&info, tp);
1045 1045          } else {
1046 1046                  int nlwp = 0;
1047 1047  
1048 1048                  do {
1049 1049                          info.pr_lwp = *lwpsinfo;
1050 1050                          prcom(&info, tp);
1051 1051                          /* LINTED improper alignment */
1052 1052                          lwpsinfo = (lwpsinfo_t *)((char *)lwpsinfo +
1053 1053                              lpsinfobuf->pr_entsize);
1054 1054                  } while (++nlwp < lpsinfobuf->pr_nent);
1055 1055          }
1056 1056          return (0);
1057 1057  }
1058 1058  
1059 1059  static int
1060 1060  field_cmp(const void *l, const void *r)
1061 1061  {
1062 1062          struct def_field *lhs = *((struct def_field **)l);
1063 1063          struct def_field *rhs = *((struct def_field **)r);
1064 1064  
1065 1065          return (strcmp(lhs->fname, rhs->fname));
1066 1066  }
1067 1067  
1068 1068  static void
1069 1069  usage(void)             /* print usage message and quit */
1070 1070  {
1071 1071          struct def_field *df, *sorted[NFIELDS];
1072 1072          int pos = 80, i = 0;
1073 1073  
1074 1074          static char usage1[] =
1075 1075              "ps [ -aAdefHlcjLPWyZ ] [ -o format ] [ -t termlist ]";
1076 1076          static char usage2[] =
1077 1077              "\t[ -u userlist ] [ -U userlist ] [ -G grouplist ]";
1078 1078          static char usage3[] =
1079 1079              "\t[ -p proclist ] [ -g pgrplist ] [ -s sidlist ]";
1080 1080          static char usage4[] =
1081 1081              "\t[ -z zonelist ] [-h lgrplist]";
1082 1082          static char usage5[] =
1083 1083              "  'format' is one or more of:";
1084 1084  
1085 1085          (void) fprintf(stderr,
1086 1086              gettext("usage: %s\n%s\n%s\n%s\n%s"),
1087 1087              gettext(usage1), gettext(usage2), gettext(usage3),
1088 1088              gettext(usage4), gettext(usage5));
1089 1089  
1090 1090          /*
1091 1091           * Now print out the possible output formats such that they neatly fit
1092 1092           * into eighty columns.  Note that the fact that we are determining
1093 1093           * this output programmatically means that a gettext() is impossible --
1094 1094           * but it would be a mistake to localize the output formats anyway as
1095 1095           * they are tokens for input, not output themselves.
1096 1096           */
1097 1097          for (df = &fname[0]; df < &fname[NFIELDS]; df++)
1098 1098                  sorted[i++] = df;
1099 1099  
1100 1100          (void) qsort(sorted, NFIELDS, sizeof (void *), field_cmp);
1101 1101  
1102 1102          for (i = 0; i < NFIELDS; i++) {
1103 1103                  if (pos + strlen((df = sorted[i])->fname) + 1 >= 80) {
1104 1104                          (void) fprintf(stderr, "\n\t");
1105 1105                          pos = 8;
1106 1106                  }
1107 1107  
1108 1108                  (void) fprintf(stderr, "%s%s", pos > 8 ? " " : "", df->fname);
1109 1109                  pos += strlen(df->fname) + 1;
1110 1110          }
1111 1111  
1112 1112          (void) fprintf(stderr, "\n");
1113 1113  
1114 1114          exit(1);
1115 1115  }
1116 1116  
1117 1117  /*
1118 1118   * getarg() finds the next argument in list and copies arg into argbuf.
1119 1119   * p1 first pts to arg passed back from getopt routine.  p1 is then
1120 1120   * bumped to next character that is not a comma or blank -- p1 NULL
1121 1121   * indicates end of list.
1122 1122   */
1123 1123  static char *
1124 1124  getarg(char **pp1)
1125 1125  {
1126 1126          static char argbuf[ARGSIZ];
1127 1127          char *p1 = *pp1;
1128 1128          char *parga = argbuf;
1129 1129          int c;
1130 1130  
1131 1131          while ((c = *p1) != '\0' && (c == ',' || isspace(c)))
1132 1132                  p1++;
1133 1133  
1134 1134          while ((c = *p1) != '\0' && c != ',' && !isspace(c)) {
1135 1135                  if (parga < argbuf + ARGSIZ - 1)
1136 1136                          *parga++ = c;
1137 1137                  p1++;
1138 1138          }
1139 1139          *parga = '\0';
1140 1140  
1141 1141          while ((c = *p1) != '\0' && (c == ',' || isspace(c)))
1142 1142                  p1++;
1143 1143  
1144 1144          *pp1 = p1;
1145 1145  
1146 1146          return (argbuf);
1147 1147  }
1148 1148  
1149 1149  /*
1150 1150   * parse_format() takes the argument to the -o option,
1151 1151   * sets up the next output field structure, and returns
1152 1152   * a pointer to any further output field specifier(s).
1153 1153   * As a side-effect, it increments errflg if encounters a format error.
1154 1154   */
1155 1155  static char *
1156 1156  parse_format(char *arg)
1157 1157  {
1158 1158          int c;
1159 1159          char *name;
1160 1160          char *header = NULL;
1161 1161          int width = 0;
1162 1162          struct def_field *df;
1163 1163          struct field *f;
1164 1164  
1165 1165          while ((c = *arg) != '\0' && (c == ',' || isspace(c)))
1166 1166                  arg++;
1167 1167          if (c == '\0')
1168 1168                  return (NULL);
1169 1169          name = arg;
1170 1170          arg = strpbrk(arg, " \t\r\v\f\n,=");
1171 1171          if (arg != NULL) {
1172 1172                  c = *arg;
1173 1173                  *arg++ = '\0';
1174 1174                  if (c == '=') {
1175 1175                          char *s;
1176 1176  
1177 1177                          header = arg;
1178 1178                          arg = NULL;
1179 1179                          width = strlen(header);
1180 1180                          s = header + width;
1181 1181                          while (s > header && isspace(*--s))
1182 1182                                  *s = '\0';
1183 1183                          while (isspace(*header))
1184 1184                                  header++;
1185 1185                  }
1186 1186          }
1187 1187          for (df = &fname[0]; df < &fname[NFIELDS]; df++)
1188 1188                  if (strcmp(name, df->fname) == 0) {
1189 1189                          if (strcmp(name, "lwp") == 0)
1190 1190                                  Lflg++;
1191 1191                          break;
1192 1192                  }
1193 1193          if (df >= &fname[NFIELDS]) {
1194 1194                  (void) fprintf(stderr,
1195 1195                      gettext("ps: unknown output format: -o %s\n"),
1196 1196                      name);
1197 1197                  errflg++;
1198 1198                  return (arg);
1199 1199          }
1200 1200          if ((f = malloc(sizeof (*f))) == NULL) {
1201 1201                  (void) fprintf(stderr,
1202 1202                      gettext("ps: malloc() for output format failed, %s\n"),
1203 1203                      err_string(errno));
1204 1204                  exit(1);
1205 1205          }
1206 1206          f->next = NULL;
1207 1207          f->fname = df - &fname[0];
1208 1208          f->header = header? header : df->header;
1209 1209          if (width == 0)
1210 1210                  width = df->width;
1211 1211          if (*f->header != '\0')
1212 1212                  do_header = 1;
1213 1213          f->width = max(width, df->minwidth);
1214 1214  
1215 1215          if (fields == NULL)
1216 1216                  fields = last_field = f;
1217 1217          else {
1218 1218                  last_field->next = f;
1219 1219                  last_field = f;
1220 1220          }
1221 1221  
1222 1222          return (arg);
1223 1223  }
1224 1224  
1225 1225  static char *
1226 1226  devlookup(dev_t ddev)
1227 1227  {
1228 1228          struct devl *dp;
1229 1229          int i;
1230 1230  
1231 1231          for (dp = devl, i = 0; i < ndev; dp++, i++) {
1232 1232                  if (dp->ddev == ddev)
1233 1233                          return (dp->dname);
1234 1234          }
1235 1235          return (NULL);
1236 1236  }
1237 1237  
1238 1238  static char *
1239 1239  devadd(char *name, dev_t ddev)
1240 1240  {
1241 1241          struct devl *dp;
1242 1242          int leng, start, i;
1243 1243  
1244 1244          if (ndev == maxdev) {
1245 1245                  maxdev += DNINCR;
1246 1246                  devl = Realloc(devl, maxdev * sizeof (struct devl));
1247 1247          }
1248 1248          dp = &devl[ndev++];
1249 1249  
1250 1250          dp->ddev = ddev;
1251 1251          if (name == NULL) {
1252 1252                  (void) strcpy(dp->dname, "??");
1253 1253                  return (dp->dname);
1254 1254          }
1255 1255  
1256 1256          leng = strlen(name);
1257 1257          /* Strip off /dev/ */
1258 1258          if (leng < DNSIZE + 4)
1259 1259                  (void) strcpy(dp->dname, &name[5]);
1260 1260          else {
1261 1261                  start = leng - DNSIZE - 1;
1262 1262  
1263 1263                  for (i = start; i < leng && name[i] != '/'; i++)
1264 1264                                  ;
1265 1265                  if (i == leng)
1266 1266                          (void) strncpy(dp->dname, &name[start], DNSIZE);
1267 1267                  else
1268 1268                          (void) strncpy(dp->dname, &name[i+1], DNSIZE);
1269 1269          }
1270 1270          return (dp->dname);
1271 1271  }
1272 1272  
1273 1273  /*
1274 1274   * gettty returns the user's tty number or ? if none.
1275 1275   */
1276 1276  static char *
1277 1277  gettty(psinfo_t *psinfo)
1278 1278  {
1279 1279          extern char *_ttyname_dev(dev_t, char *, size_t);
1280 1280          static zoneid_t zid = -1;
1281 1281          char devname[TTYNAME_MAX];
1282 1282          char *retval;
1283 1283  
1284 1284          if (zid == -1)
1285 1285                  zid = getzoneid();
1286 1286  
1287 1287          if (psinfo->pr_ttydev == PRNODEV || psinfo->pr_zoneid != zid)
1288 1288                  return ("?");
1289 1289  
1290 1290          if ((retval = devlookup(psinfo->pr_ttydev)) != NULL)
1291 1291                  return (retval);
1292 1292  
1293 1293          retval = _ttyname_dev(psinfo->pr_ttydev, devname, sizeof (devname));
1294 1294  
1295 1295          return (devadd(retval, psinfo->pr_ttydev));
1296 1296  }
1297 1297  
1298 1298  /*
1299 1299   * Find the process's tty and return 1 if process is to be printed.
1300 1300   */
1301 1301  static int
1302 1302  prfind(int found, psinfo_t *psinfo, char **tpp)
1303 1303  {
1304 1304          char    *tp;
1305 1305          struct tty *ttyp;
1306 1306  
1307 1307          if (psinfo->pr_nlwp == 0) {
1308 1308                  /* process is a zombie */
1309 1309                  *tpp = "?";
1310 1310                  if (tflg && !found)
1311 1311                          return (0);
1312 1312                  return (1);
1313 1313          }
1314 1314  
1315 1315          /*
1316 1316           * Get current terminal.  If none ("?") and 'a' is set, don't print
1317 1317           * info.  If 't' is set, check if term is in list of desired terminals
1318 1318           * and print it if it is.
1319 1319           */
1320 1320          tp = gettty(psinfo);
1321 1321          if (aflg && *tp == '?') {
1322 1322                  *tpp = tp;
1323 1323                  return (0);
1324 1324          }
1325 1325          if (tflg && !found) {
1326 1326                  int match = 0;
1327 1327                  char *other = NULL;
1328 1328                  for (ttyp = tty; ttyp->tname != NULL; ttyp++) {
1329 1329                          /*
1330 1330                           * Look for a name match
1331 1331                           */
1332 1332                          if (strcmp(tp, ttyp->tname) == 0) {
1333 1333                                  match = 1;
1334 1334                                  break;
1335 1335                          }
1336 1336                          /*
1337 1337                           * Look for same device under different names.
1338 1338                           */
1339 1339                          if ((other == NULL) &&
1340 1340                              (ttyp->tdev != PRNODEV) &&
1341 1341                              (psinfo->pr_ttydev == ttyp->tdev))
1342 1342                                  other = ttyp->tname;
1343 1343                  }
1344 1344                  if (!match && (other != NULL)) {
1345 1345                          /*
1346 1346                           * found under a different name
1347 1347                           */
1348 1348                          match = 1;
1349 1349                          tp = other;
1350 1350                  }
1351 1351                  if (!match || (tuid != (uid_t)-1 && tuid != psinfo->pr_euid)) {
1352 1352                          /*
1353 1353                           * not found OR not matching euid
1354 1354                           */
1355 1355                          *tpp = tp;
1356 1356                          return (0);
1357 1357                  }
1358 1358          }
1359 1359          *tpp = tp;
1360 1360          return (1);
1361 1361  }
1362 1362  
1363 1363  /*
1364 1364   * Print info about the process.
1365 1365   */
1366 1366  static void
1367 1367  prcom(psinfo_t *psinfo, char *ttyp)
1368 1368  {
1369 1369          char    *cp;
1370 1370          long    tm;
1371 1371          int     bytesleft;
1372 1372          int     wcnt, length;
1373 1373          wchar_t wchar;
1374 1374          struct passwd *pwd;
1375 1375          int     zombie_lwp;
1376 1376          char    zonename[ZONENAME_MAX];
1377 1377  
1378 1378          /*
1379 1379           * If process is zombie, call zombie print routine and return.
1380 1380           */
1381 1381          if (psinfo->pr_nlwp == 0) {
1382 1382                  if (fields != NULL)
1383 1383                          pr_fields(psinfo, ttyp, print_zombie_field);
1384 1384                  else
1385 1385                          przom(psinfo);
1386 1386                  return;
1387 1387          }
1388 1388  
1389 1389          zombie_lwp = (Lflg && psinfo->pr_lwp.pr_sname == 'Z');
1390 1390  
1391 1391          /*
1392 1392           * If user specified '-o format', print requested fields and return.
1393 1393           */
1394 1394          if (fields != NULL) {
1395 1395                  pr_fields(psinfo, ttyp, print_field);
1396 1396                  return;
1397 1397          }
1398 1398  
1399 1399          /*
1400 1400           * All fields before 'PID' are printed with a trailing space as a
1401 1401           * separator, rather than keeping track of which column is first.  All
1402 1402           * other fields are printed with a leading space.
1403 1403           */
1404 1404          if (lflg) {
1405 1405                  if (!yflg)
1406 1406                          (void) printf("%2x ", psinfo->pr_flag & 0377); /* F */
1407 1407                  (void) printf("%c ", psinfo->pr_lwp.pr_sname);  /* S */
1408 1408          }
1409 1409  
1410 1410          if (Zflg) {                                             /* ZONE */
1411 1411                  if (getzonenamebyid(psinfo->pr_zoneid, zonename,
1412 1412                      sizeof (zonename)) < 0) {
1413 1413                          if (snprintf(NULL, 0, "%d",
1414 1414                              ((int)psinfo->pr_zoneid)) > 7)
1415 1415                                  (void) printf(" %6.6d%c ",
1416 1416                                      ((int)psinfo->pr_zoneid), '*');
1417 1417                          else
1418 1418                                  (void) printf(" %7.7d ",
1419 1419                                      ((int)psinfo->pr_zoneid));
1420 1420                  } else {
1421 1421                          size_t nw;
1422 1422  
1423 1423                          nw = mbstowcs(NULL, zonename, 0);
1424 1424                          if (nw == (size_t)-1)
1425 1425                                  (void) printf("%8.8s ", "ERROR");
1426 1426                          else if (nw > 8)
1427 1427                                  (void) wprintf(L"%7.7s%c ", zonename, '*');
1428 1428                          else
1429 1429                                  (void) wprintf(L"%8.8s ", zonename);
1430 1430                  }
1431 1431          }
1432 1432  
1433 1433          if (fflg) {                                             /* UID */
1434 1434                  if ((pwd = getpwuid(psinfo->pr_euid)) != NULL) {
1435 1435                          size_t nw;
1436 1436  
1437 1437                          nw = mbstowcs(NULL, pwd->pw_name, 0);
1438 1438                          if (nw == (size_t)-1)
1439 1439                                  (void) printf("%8.8s ", "ERROR");
1440 1440                          else if (nw > 8)
1441 1441                                  (void) wprintf(L"%7.7s%c ", pwd->pw_name, '*');
1442 1442                          else
1443 1443                                  (void) wprintf(L"%8.8s ", pwd->pw_name);
1444 1444                  } else {
1445 1445                          if (snprintf(NULL, 0, "%u",
1446 1446                              (psinfo->pr_euid)) > 7)
1447 1447                                  (void) printf(" %6.6u%c ", psinfo->pr_euid,
1448 1448                                      '*');
1449 1449                          else
1450 1450                                  (void) printf(" %7.7u ", psinfo->pr_euid);
1451 1451                  }
1452 1452          } else if (lflg) {
1453 1453                  if (snprintf(NULL, 0, "%u", (psinfo->pr_euid)) > 6)
1454 1454                          (void) printf("%5.5u%c ", psinfo->pr_euid, '*');
1455 1455                  else
1456 1456                          (void) printf("%6u ", psinfo->pr_euid);
1457 1457          }
1458 1458          (void) printf("%*d", pidwidth, (int)psinfo->pr_pid); /* PID */
1459 1459          if (lflg || fflg)
1460 1460                  (void) printf(" %*d", pidwidth,
1461 1461                      (int)psinfo->pr_ppid); /* PPID */
1462 1462          if (jflg) {
1463 1463                  (void) printf(" %*d", pidwidth,
1464 1464                      (int)psinfo->pr_pgid);      /* PGID */
1465 1465                  (void) printf(" %*d", pidwidth,
1466 1466                      (int)psinfo->pr_sid);       /* SID  */
1467 1467          }
1468 1468          if (Lflg)
1469 1469                  (void) printf(" %5d", (int)psinfo->pr_lwp.pr_lwpid); /* LWP */
1470 1470          if (Pflg) {
1471 1471                  if (psinfo->pr_lwp.pr_bindpro == PBIND_NONE)    /* PSR */
1472 1472                          (void) printf("   -");
1473 1473                  else
1474 1474                          (void) printf(" %3d", psinfo->pr_lwp.pr_bindpro);
1475 1475          }
1476 1476          if (Lflg && fflg)                                       /* NLWP */
1477 1477                  (void) printf(" %5d", psinfo->pr_nlwp + psinfo->pr_nzomb);
1478 1478          if (cflg) {
1479 1479                  if (zombie_lwp)                                 /* CLS */
1480 1480                          (void) printf("     ");
1481 1481                  else
1482 1482                          (void) printf(" %4s", psinfo->pr_lwp.pr_clname);
1483 1483                  (void) printf(" %3d", psinfo->pr_lwp.pr_pri);   /* PRI */
1484 1484          } else if (lflg || fflg) {
1485 1485                  (void) printf(" %3d", psinfo->pr_lwp.pr_cpu & 0377); /* C   */
1486 1486                  if (lflg) {                                         /* PRI NI */
1487 1487                          /*
1488 1488                           * Print priorities the old way (lower numbers
1489 1489                           * mean higher priority) and print nice value
1490 1490                           * for time sharing procs.
1491 1491                           */
1492 1492                          (void) printf(" %3d", psinfo->pr_lwp.pr_oldpri);
1493 1493                          if (psinfo->pr_lwp.pr_oldpri != 0)
1494 1494                                  (void) printf(" %2d", psinfo->pr_lwp.pr_nice);
1495 1495                          else
1496 1496                                  (void) printf(" %2.2s",
1497 1497                                      psinfo->pr_lwp.pr_clname);
1498 1498                  }
1499 1499          }
1500 1500          if (lflg) {
1501 1501                  if (yflg) {
1502 1502                          if (psinfo->pr_flag & SSYS)             /* RSS */
1503 1503                                  (void) printf("     0");
1504 1504                          else if (psinfo->pr_rssize)
1505 1505                                  (void) printf(" %5lu",
1506 1506                                      (ulong_t)psinfo->pr_rssize);
1507 1507                          else
1508 1508                                  (void) printf("     ?");
1509 1509                          if (psinfo->pr_flag & SSYS)             /* SZ */
1510 1510                                  (void) printf("      0");
1511 1511                          else if (psinfo->pr_size)
1512 1512                                  (void) printf(" %6lu",
1513 1513                                      (ulong_t)psinfo->pr_size);
1514 1514                          else
1515 1515                                  (void) printf("      ?");
1516 1516                  } else {
1517 1517  #ifndef _LP64
1518 1518                          if (psinfo->pr_addr)                    /* ADDR */
1519 1519                                  (void) printf(" %8lx",
1520 1520                                      (ulong_t)psinfo->pr_addr);
1521 1521                          else
1522 1522  #endif
1523 1523                                  (void) printf("        ?");
1524 1524                          if (psinfo->pr_flag & SSYS)             /* SZ */
1525 1525                                  (void) printf("      0");
1526 1526                          else if (psinfo->pr_size)
1527 1527                                  (void) printf(" %6lu",
1528 1528                                      (ulong_t)psinfo->pr_size / kbytes_per_page);
1529 1529                          else
1530 1530                                  (void) printf("      ?");
1531 1531                  }
1532 1532                  if (psinfo->pr_lwp.pr_sname != 'S')             /* WCHAN */
1533 1533                          (void) printf("         ");
1534 1534  #ifndef _LP64
1535 1535                  else if (psinfo->pr_lwp.pr_wchan)
1536 1536                          (void) printf(" %8lx",
1537 1537                              (ulong_t)psinfo->pr_lwp.pr_wchan);
1538 1538  #endif
1539 1539                  else
1540 1540                          (void) printf("        ?");
1541 1541          }
1542 1542          if (fflg) {                                             /* STIME */
1543 1543                  int width = fname[F_STIME].width;
1544 1544                  if (Lflg)
1545 1545                          prtime(psinfo->pr_lwp.pr_start, width + 1, 1);
1546 1546                  else
1547 1547                          prtime(psinfo->pr_start, width + 1, 1);
1548 1548          }
1549 1549  
1550 1550          if (Hflg) {
1551 1551                  /* Display home lgroup */
1552 1552                  (void) printf(" %4d", (int)psinfo->pr_lwp.pr_lgrp);
1553 1553          }
1554 1554  
1555 1555          (void) printf(" %-8.14s", ttyp);                        /* TTY */
1556 1556          if (Lflg) {
1557 1557                  tm = psinfo->pr_lwp.pr_time.tv_sec;
1558 1558                  if (psinfo->pr_lwp.pr_time.tv_nsec > 500000000)
1559 1559                          tm++;
1560 1560          } else {
1561 1561                  tm = psinfo->pr_time.tv_sec;
1562 1562                  if (psinfo->pr_time.tv_nsec > 500000000)
1563 1563                          tm++;
1564 1564          }
1565 1565          (void) printf(" %4ld:%.2ld", tm / 60, tm % 60);         /* [L]TIME */
1566 1566  
1567 1567          if (zombie_lwp) {
1568 1568                  (void) printf(" <defunct>\n");
1569 1569                  return;
1570 1570          }
1571 1571  
1572 1572          if (!fflg) {                                            /* CMD */
1573 1573                  wcnt = namencnt(psinfo->pr_fname, 16, 8);
1574 1574                  (void) printf(" %.*s\n", wcnt, psinfo->pr_fname);
1575 1575                  return;
1576 1576          }
1577 1577  
1578 1578  
1579 1579          /*
1580 1580           * PRARGSZ == length of cmd arg string.
1581 1581           */
1582 1582          psinfo->pr_psargs[PRARGSZ-1] = '\0';
1583 1583          bytesleft = PRARGSZ;
1584 1584          for (cp = psinfo->pr_psargs; *cp != '\0'; cp += length) {
1585 1585                  length = mbtowc(&wchar, cp, MB_LEN_MAX);
1586 1586                  if (length == 0)
1587 1587                          break;
1588 1588                  if (length < 0 || !iswprint(wchar)) {
1589 1589                          if (length < 0)
1590 1590                                  length = 1;
1591 1591                          if (bytesleft <= length) {
1592 1592                                  *cp = '\0';
1593 1593                                  break;
1594 1594                          }
1595 1595                          /* omit the unprintable character */
1596 1596                          (void) memmove(cp, cp+length, bytesleft-length);
1597 1597                          length = 0;
1598 1598                  }
1599 1599                  bytesleft -= length;
1600 1600          }
1601 1601          wcnt = namencnt(psinfo->pr_psargs, PRARGSZ, lflg ? 35 : PRARGSZ);
1602 1602          (void) printf(" %.*s\n", wcnt, psinfo->pr_psargs);
1603 1603  }
1604 1604  
1605 1605  /*
1606 1606   * Print percent from 16-bit binary fraction [0 .. 1]
1607 1607   * Round up .01 to .1 to indicate some small percentage (the 0x7000 below).
1608 1608   */
1609 1609  static void
1610 1610  prtpct(ushort_t pct, int width)
1611 1611  {
1612 1612          uint_t value = pct;     /* need 32 bits to compute with */
1613 1613  
1614 1614          value = ((value * 1000) + 0x7000) >> 15;        /* [0 .. 1000] */
1615 1615          if (value >= 1000)
1616 1616                  value = 999;
1617 1617          if ((width -= 2) < 2)
1618 1618                  width = 2;
1619 1619          (void) printf("%*u.%u", width, value / 10, value % 10);
1620 1620  }
1621 1621  
1622 1622  static void
1623 1623  print_time(time_t tim, int width)
1624 1624  {
1625 1625          char buf[30];
1626 1626          time_t seconds;
1627 1627          time_t minutes;
1628 1628          time_t hours;
1629 1629          time_t days;
1630 1630  
1631 1631          if (tim < 0) {
1632 1632                  (void) printf("%*s", width, "-");
1633 1633                  return;
1634 1634          }
1635 1635  
1636 1636          seconds = tim % 60;
1637 1637          tim /= 60;
1638 1638          minutes = tim % 60;
1639 1639          tim /= 60;
1640 1640          hours = tim % 24;
1641 1641          days = tim / 24;
1642 1642  
1643 1643          if (days > 0) {
1644 1644                  (void) snprintf(buf, sizeof (buf), "%ld-%2.2ld:%2.2ld:%2.2ld",
1645 1645                      days, hours, minutes, seconds);
1646 1646          } else if (hours > 0) {
1647 1647                  (void) snprintf(buf, sizeof (buf), "%2.2ld:%2.2ld:%2.2ld",
1648 1648                      hours, minutes, seconds);
1649 1649          } else {
1650 1650                  (void) snprintf(buf, sizeof (buf), "%2.2ld:%2.2ld",
1651 1651                      minutes, seconds);
1652 1652          }
1653 1653  
1654 1654          (void) printf("%*s", width, buf);
1655 1655  }
1656 1656  
1657 1657  static void
1658 1658  print_field(psinfo_t *psinfo, struct field *f, const char *ttyp)
1659 1659  {
1660 1660          int width = f->width;
1661 1661          struct passwd *pwd;
1662 1662          struct group *grp;
1663 1663          time_t cputime;
1664 1664          int bytesleft;
1665 1665          int wcnt;
1666 1666          wchar_t wchar;
1667 1667          char *cp;
1668 1668          int length;
1669 1669          ulong_t mask;
1670 1670          char c = '\0', *csave = NULL;
1671 1671          int zombie_lwp;
1672 1672  
1673 1673          zombie_lwp = (Lflg && psinfo->pr_lwp.pr_sname == 'Z');
1674 1674  
1675 1675          switch (f->fname) {
1676 1676          case F_RUSER:
1677 1677                  if ((pwd = getpwuid(psinfo->pr_uid)) != NULL) {
1678 1678                          size_t nw;
1679 1679  
1680 1680                          nw = mbstowcs(NULL, pwd->pw_name, 0);
1681 1681                          if (nw == (size_t)-1)
1682 1682                                  (void) printf("%*s ", width, "ERROR");
1683 1683                          else if (Wflg && nw > width)
1684 1684                                  (void) wprintf(L"%.*s%c", width - 1,
1685 1685                                      pwd->pw_name, '*');
1686 1686                          else
1687 1687                                  (void) wprintf(L"%*s", width, pwd->pw_name);
1688 1688                  } else {
1689 1689                          if (Wflg && snprintf(NULL, 0, "%u",
1690 1690                              (psinfo->pr_uid)) > width)
1691 1691  
1692 1692                                  (void) printf("%*u%c", width - 1,
1693 1693                                      psinfo->pr_uid, '*');
1694 1694                          else
1695 1695                                  (void) printf("%*u", width, psinfo->pr_uid);
1696 1696                  }
1697 1697                  break;
1698 1698          case F_USER:
1699 1699                  if ((pwd = getpwuid(psinfo->pr_euid)) != NULL) {
1700 1700                          size_t nw;
1701 1701  
1702 1702                          nw = mbstowcs(NULL, pwd->pw_name, 0);
1703 1703                          if (nw == (size_t)-1)
1704 1704                                  (void) printf("%*s ", width, "ERROR");
1705 1705                          else if (Wflg && nw > width)
1706 1706                                  (void) wprintf(L"%.*s%c", width - 1,
1707 1707                                      pwd->pw_name, '*');
1708 1708                          else
1709 1709                                  (void) wprintf(L"%*s", width, pwd->pw_name);
1710 1710                  } else {
1711 1711                          if (Wflg && snprintf(NULL, 0, "%u",
1712 1712                              (psinfo->pr_euid)) > width)
1713 1713  
1714 1714                                  (void) printf("%*u%c", width - 1,
1715 1715                                      psinfo->pr_euid, '*');
1716 1716                          else
1717 1717                                  (void) printf("%*u", width, psinfo->pr_euid);
1718 1718                  }
1719 1719                  break;
1720 1720          case F_RGROUP:
1721 1721                  if ((grp = getgrgid(psinfo->pr_gid)) != NULL)
1722 1722                          (void) printf("%*s", width, grp->gr_name);
1723 1723                  else
1724 1724                          (void) printf("%*u", width, psinfo->pr_gid);
1725 1725                  break;
1726 1726          case F_GROUP:
1727 1727                  if ((grp = getgrgid(psinfo->pr_egid)) != NULL)
1728 1728                          (void) printf("%*s", width, grp->gr_name);
1729 1729                  else
1730 1730                          (void) printf("%*u", width, psinfo->pr_egid);
1731 1731                  break;
1732 1732          case F_RUID:
1733 1733                  (void) printf("%*u", width, psinfo->pr_uid);
1734 1734                  break;
1735 1735          case F_UID:
1736 1736                  (void) printf("%*u", width, psinfo->pr_euid);
1737 1737                  break;
1738 1738          case F_RGID:
1739 1739                  (void) printf("%*u", width, psinfo->pr_gid);
1740 1740                  break;
1741 1741          case F_GID:
1742 1742                  (void) printf("%*u", width, psinfo->pr_egid);
1743 1743                  break;
1744 1744          case F_PID:
1745 1745                  (void) printf("%*d", width, (int)psinfo->pr_pid);
1746 1746                  break;
1747 1747          case F_PPID:
1748 1748                  (void) printf("%*d", width, (int)psinfo->pr_ppid);
1749 1749                  break;
1750 1750          case F_PGID:
1751 1751                  (void) printf("%*d", width, (int)psinfo->pr_pgid);
1752 1752                  break;
1753 1753          case F_SID:
1754 1754                  (void) printf("%*d", width, (int)psinfo->pr_sid);
1755 1755                  break;
1756 1756          case F_PSR:
1757 1757                  if (zombie_lwp || psinfo->pr_lwp.pr_bindpro == PBIND_NONE)
1758 1758                          (void) printf("%*s", width, "-");
1759 1759                  else
1760 1760                          (void) printf("%*d", width, psinfo->pr_lwp.pr_bindpro);
1761 1761                  break;
1762 1762          case F_LWP:
1763 1763                  (void) printf("%*d", width, (int)psinfo->pr_lwp.pr_lwpid);
1764 1764                  break;
1765 1765          case F_NLWP:
1766 1766                  (void) printf("%*d", width, psinfo->pr_nlwp + psinfo->pr_nzomb);
1767 1767                  break;
1768 1768          case F_OPRI:
1769 1769                  if (zombie_lwp)
1770 1770                          (void) printf("%*s", width, "-");
1771 1771                  else
1772 1772                          (void) printf("%*d", width, psinfo->pr_lwp.pr_oldpri);
1773 1773                  break;
1774 1774          case F_PRI:
1775 1775                  if (zombie_lwp)
1776 1776                          (void) printf("%*s", width, "-");
1777 1777                  else
1778 1778                          (void) printf("%*d", width, psinfo->pr_lwp.pr_pri);
1779 1779                  break;
1780 1780          case F_F:
1781 1781                  mask = 0xffffffffUL;
1782 1782                  if (width < 8)
1783 1783                          mask >>= (8 - width) * 4;
1784 1784                  (void) printf("%*lx", width, psinfo->pr_flag & mask);
1785 1785                  break;
1786 1786          case F_S:
1787 1787                  (void) printf("%*c", width, psinfo->pr_lwp.pr_sname);
1788 1788                  break;
1789 1789          case F_C:
1790 1790                  if (zombie_lwp)
1791 1791                          (void) printf("%*s", width, "-");
1792 1792                  else
1793 1793                          (void) printf("%*d", width, psinfo->pr_lwp.pr_cpu);
1794 1794                  break;
1795 1795          case F_PCPU:
1796 1796                  if (zombie_lwp)
1797 1797                          (void) printf("%*s", width, "-");
1798 1798                  else if (Lflg)
1799 1799                          prtpct(psinfo->pr_lwp.pr_pctcpu, width);
1800 1800                  else
1801 1801                          prtpct(psinfo->pr_pctcpu, width);
1802 1802                  break;
1803 1803          case F_PMEM:
1804 1804                  prtpct(psinfo->pr_pctmem, width);
1805 1805                  break;
1806 1806          case F_OSZ:
1807 1807                  (void) printf("%*lu", width,
1808 1808                      (ulong_t)psinfo->pr_size / kbytes_per_page);
1809 1809                  break;
1810 1810          case F_VSZ:
1811 1811                  (void) printf("%*lu", width, (ulong_t)psinfo->pr_size);
1812 1812                  break;
1813 1813          case F_RSS:
1814 1814                  (void) printf("%*lu", width, (ulong_t)psinfo->pr_rssize);
1815 1815                  break;
1816 1816          case F_NICE:
1817 1817                  /* if pr_oldpri is zero, then this class has no nice */
1818 1818                  if (zombie_lwp)
1819 1819                          (void) printf("%*s", width, "-");
1820 1820                  else if (psinfo->pr_lwp.pr_oldpri != 0)
1821 1821                          (void) printf("%*d", width, psinfo->pr_lwp.pr_nice);
1822 1822                  else
1823 1823                          (void) printf("%*.*s", width, width,
1824 1824                              psinfo->pr_lwp.pr_clname);
1825 1825                  break;
1826 1826          case F_CLASS:
1827 1827                  if (zombie_lwp)
1828 1828                          (void) printf("%*s", width, "-");
1829 1829                  else
1830 1830                          (void) printf("%*.*s", width, width,
1831 1831                              psinfo->pr_lwp.pr_clname);
1832 1832                  break;
1833 1833          case F_STIME:
1834 1834                  if (Lflg)
1835 1835                          prtime(psinfo->pr_lwp.pr_start, width, 0);
1836 1836                  else
1837 1837                          prtime(psinfo->pr_start, width, 0);
1838 1838                  break;
1839 1839          case F_ETIME:
1840 1840                  if (Lflg)
1841 1841                          print_time(delta_secs(&psinfo->pr_lwp.pr_start),
1842 1842                              width);
1843 1843                  else
1844 1844                          print_time(delta_secs(&psinfo->pr_start), width);
1845 1845                  break;
1846 1846          case F_TIME:
1847 1847                  if (Lflg) {
1848 1848                          cputime = psinfo->pr_lwp.pr_time.tv_sec;
1849 1849                          if (psinfo->pr_lwp.pr_time.tv_nsec > 500000000)
1850 1850                                  cputime++;
1851 1851                  } else {
1852 1852                          cputime = psinfo->pr_time.tv_sec;
1853 1853                          if (psinfo->pr_time.tv_nsec > 500000000)
1854 1854                                  cputime++;
1855 1855                  }
1856 1856                  print_time(cputime, width);
1857 1857                  break;
1858 1858          case F_TTY:
1859 1859                  (void) printf("%-*s", width, ttyp);
1860 1860                  break;
1861 1861          case F_ADDR:
1862 1862                  if (zombie_lwp)
1863 1863                          (void) printf("%*s", width, "-");
1864 1864                  else if (Lflg)
1865 1865                          (void) printf("%*lx", width,
1866 1866                              (long)psinfo->pr_lwp.pr_addr);
1867 1867                  else
1868 1868                          (void) printf("%*lx", width, (long)psinfo->pr_addr);
1869 1869                  break;
1870 1870          case F_WCHAN:
1871 1871                  if (!zombie_lwp && psinfo->pr_lwp.pr_wchan)
1872 1872                          (void) printf("%*lx", width,
1873 1873                              (long)psinfo->pr_lwp.pr_wchan);
1874 1874                  else
1875 1875                          (void) printf("%*.*s", width, width, "-");
1876 1876                  break;
1877 1877          case F_FNAME:
1878 1878                  /*
1879 1879                   * Print full width unless this is the last output format.
1880 1880                   */
1881 1881                  if (zombie_lwp) {
1882 1882                          if (f->next != NULL)
1883 1883                                  (void) printf("%-*s", width, "<defunct>");
1884 1884                          else
1885 1885                                  (void) printf("%s", "<defunct>");
1886 1886                          break;
1887 1887                  }
1888 1888                  wcnt = namencnt(psinfo->pr_fname, 16, width);
1889 1889                  if (f->next != NULL)
1890 1890                          (void) printf("%-*.*s", width, wcnt, psinfo->pr_fname);
1891 1891                  else
1892 1892                          (void) printf("%-.*s", wcnt, psinfo->pr_fname);
1893 1893                  break;
1894 1894          case F_COMM:
1895 1895                  if (zombie_lwp) {
1896 1896                          if (f->next != NULL)
1897 1897                                  (void) printf("%-*s", width, "<defunct>");
1898 1898                          else
1899 1899                                  (void) printf("%s", "<defunct>");
1900 1900                          break;
1901 1901                  }
1902 1902                  csave = strpbrk(psinfo->pr_psargs, " \t\r\v\f\n");
1903 1903                  if (csave) {
1904 1904                          c = *csave;
1905 1905                          *csave = '\0';
1906 1906                  }
1907 1907                  /* FALLTHROUGH */
1908 1908          case F_ARGS:
1909 1909                  /*
1910 1910                   * PRARGSZ == length of cmd arg string.
1911 1911                   */
1912 1912                  if (zombie_lwp) {
1913 1913                          (void) printf("%-*s", width, "<defunct>");
1914 1914                          break;
1915 1915                  }
1916 1916                  psinfo->pr_psargs[PRARGSZ-1] = '\0';
1917 1917                  bytesleft = PRARGSZ;
1918 1918                  for (cp = psinfo->pr_psargs; *cp != '\0'; cp += length) {
1919 1919                          length = mbtowc(&wchar, cp, MB_LEN_MAX);
1920 1920                          if (length == 0)
1921 1921                                  break;
1922 1922                          if (length < 0 || !iswprint(wchar)) {
1923 1923                                  if (length < 0)
1924 1924                                          length = 1;
1925 1925                                  if (bytesleft <= length) {
1926 1926                                          *cp = '\0';
1927 1927                                          break;
1928 1928                                  }
1929 1929                                  /* omit the unprintable character */
1930 1930                                  (void) memmove(cp, cp+length, bytesleft-length);
1931 1931                                  length = 0;
1932 1932                          }
1933 1933                          bytesleft -= length;
1934 1934                  }
1935 1935                  wcnt = namencnt(psinfo->pr_psargs, PRARGSZ, width);
1936 1936                  /*
1937 1937                   * Print full width unless this is the last format.
1938 1938                   */
1939 1939                  if (f->next != NULL)
1940 1940                          (void) printf("%-*.*s", width, wcnt,
1941 1941                              psinfo->pr_psargs);
1942 1942                  else
1943 1943                          (void) printf("%-.*s", wcnt,
1944 1944                              psinfo->pr_psargs);
1945 1945                  if (f->fname == F_COMM && csave)
1946 1946                          *csave = c;
1947 1947                  break;
1948 1948          case F_TASKID:
1949 1949                  (void) printf("%*d", width, (int)psinfo->pr_taskid);
1950 1950                  break;
1951 1951          case F_PROJID:
1952 1952                  (void) printf("%*d", width, (int)psinfo->pr_projid);
1953 1953                  break;
1954 1954          case F_PROJECT:
1955 1955                  {
1956 1956                          struct project cproj;
1957 1957                          char proj_buf[PROJECT_BUFSZ];
1958 1958  
1959 1959                          if ((getprojbyid(psinfo->pr_projid, &cproj,
1960 1960                              (void *)&proj_buf, PROJECT_BUFSZ)) == NULL) {
1961 1961                                  if (Wflg && snprintf(NULL, 0, "%d",
1962 1962                                      ((int)psinfo->pr_projid)) > width)
1963 1963                                          (void) printf("%.*d%c", width - 1,
1964 1964                                              ((int)psinfo->pr_projid), '*');
1965 1965                                  else
1966 1966                                          (void) printf("%*d", width,
1967 1967                                              (int)psinfo->pr_projid);
1968 1968                          } else {
1969 1969                                  size_t nw;
1970 1970  
1971 1971                                  if (cproj.pj_name != NULL)
1972 1972                                          nw = mbstowcs(NULL, cproj.pj_name, 0);
1973 1973                                  if (cproj.pj_name == NULL)
1974 1974                                          (void) printf("%*s ", width, "---");
1975 1975                                  else if (nw == (size_t)-1)
1976 1976                                          (void) printf("%*s ", width, "ERROR");
1977 1977                                  else if (Wflg && nw > width)
1978 1978                                          (void) wprintf(L"%.*s%c", width - 1,
1979 1979                                              cproj.pj_name, '*');
1980 1980                                  else
1981 1981                                          (void) wprintf(L"%*s", width,
1982 1982                                              cproj.pj_name);
1983 1983                          }
1984 1984                  }
1985 1985                  break;
1986 1986          case F_PSET:
1987 1987                  if (zombie_lwp || psinfo->pr_lwp.pr_bindpset == PS_NONE)
1988 1988                          (void) printf("%*s", width, "-");
1989 1989                  else
1990 1990                          (void) printf("%*d", width, psinfo->pr_lwp.pr_bindpset);
1991 1991                  break;
1992 1992          case F_ZONEID:
1993 1993                  (void) printf("%*d", width, (int)psinfo->pr_zoneid);
1994 1994                  break;
1995 1995          case F_ZONE:
1996 1996                  {
1997 1997                          char zonename[ZONENAME_MAX];
1998 1998  
1999 1999                          if (getzonenamebyid(psinfo->pr_zoneid, zonename,
2000 2000                              sizeof (zonename)) < 0) {
2001 2001                                  if (Wflg && snprintf(NULL, 0, "%d",
2002 2002                                      ((int)psinfo->pr_zoneid)) > width)
2003 2003                                          (void) printf("%.*d%c", width - 1,
2004 2004                                              ((int)psinfo->pr_zoneid), '*');
2005 2005                                  else
2006 2006                                          (void) printf("%*d", width,
2007 2007                                              (int)psinfo->pr_zoneid);
2008 2008                          } else {
2009 2009                                  size_t nw;
2010 2010  
2011 2011                                  nw = mbstowcs(NULL, zonename, 0);
2012 2012                                  if (nw == (size_t)-1)
2013 2013                                          (void) printf("%*s ", width, "ERROR");
2014 2014                                  else if (Wflg && nw > width)
2015 2015                                          (void) wprintf(L"%.*s%c", width - 1,
2016 2016                                              zonename, '*');
2017 2017                                  else
2018 2018                                          (void) wprintf(L"%*s", width, zonename);
2019 2019                          }
2020 2020                  }
2021 2021                  break;
2022 2022          case F_CTID:
2023 2023                  if (psinfo->pr_contract == -1)
2024 2024                          (void) printf("%*s", width, "-");
2025 2025                  else
2026 2026                          (void) printf("%*ld", width, (long)psinfo->pr_contract);
2027 2027                  break;
2028 2028          case F_LGRP:
2029 2029                  /* Display home lgroup */
2030 2030                  (void) printf("%*d", width, (int)psinfo->pr_lwp.pr_lgrp);
2031 2031                  break;
2032 2032  
2033 2033          case F_DMODEL:
2034 2034                  (void) printf("%*s", width,
2035 2035                      psinfo->pr_dmodel == PR_MODEL_LP64 ? "_LP64" : "_ILP32");
2036 2036                  break;
2037 2037          }
2038 2038  }
2039 2039  
2040 2040  static void
2041 2041  print_zombie_field(psinfo_t *psinfo, struct field *f, const char *ttyp)
2042 2042  {
2043 2043          int wcnt;
2044 2044          int width = f->width;
2045 2045  
2046 2046          switch (f->fname) {
2047 2047          case F_FNAME:
2048 2048          case F_COMM:
2049 2049          case F_ARGS:
2050 2050                  /*
2051 2051                   * Print full width unless this is the last output format.
2052 2052                   */
2053 2053                  wcnt = min(width, sizeof ("<defunct>"));
2054 2054                  if (f->next != NULL)
2055 2055                          (void) printf("%-*.*s", width, wcnt, "<defunct>");
2056 2056                  else
2057 2057                          (void) printf("%-.*s", wcnt, "<defunct>");
2058 2058                  break;
2059 2059  
2060 2060          case F_PSR:
2061 2061          case F_PCPU:
2062 2062          case F_PMEM:
2063 2063          case F_NICE:
2064 2064          case F_CLASS:
2065 2065          case F_STIME:
2066 2066          case F_ETIME:
2067 2067          case F_WCHAN:
2068 2068          case F_PSET:
2069 2069                  (void) printf("%*s", width, "-");
2070 2070                  break;
2071 2071  
2072 2072          case F_OPRI:
2073 2073          case F_PRI:
2074 2074          case F_OSZ:
2075 2075          case F_VSZ:
2076 2076          case F_RSS:
2077 2077                  (void) printf("%*d", width, 0);
2078 2078                  break;
2079 2079  
2080 2080          default:
2081 2081                  print_field(psinfo, f, ttyp);
2082 2082                  break;
2083 2083          }
2084 2084  }
2085 2085  
2086 2086  static void
2087 2087  pr_fields(psinfo_t *psinfo, const char *ttyp,
2088 2088      void (*print_fld)(psinfo_t *, struct field *, const char *))
2089 2089  {
2090 2090          struct field *f;
2091 2091  
2092 2092          for (f = fields; f != NULL; f = f->next) {
2093 2093                  print_fld(psinfo, f, ttyp);
2094 2094                  if (f->next != NULL)
2095 2095                          (void) printf(" ");
2096 2096          }
2097 2097          (void) printf("\n");
2098 2098  }
2099 2099  
2100 2100  /*
2101 2101   * Returns 1 if arg is found in array arr, of length num; 0 otherwise.
2102 2102   */
2103 2103  static int
2104 2104  search(pid_t *arr, int number, pid_t arg)
2105 2105  {
2106 2106          int i;
2107 2107  
2108 2108          for (i = 0; i < number; i++)
2109 2109                  if (arg == arr[i])
2110 2110                          return (1);
2111 2111          return (0);
2112 2112  }
2113 2113  
2114 2114  /*
2115 2115   * Add an entry (user, group) to the specified table.
2116 2116   */
2117 2117  static void
2118 2118  add_ugentry(struct ughead *tbl, char *name)
2119 2119  {
2120 2120          struct ugdata *entp;
2121 2121  
2122 2122          if (tbl->size == tbl->nent) {   /* reallocate the table entries */
2123 2123                  if ((tbl->size *= 2) == 0)
2124 2124                          tbl->size = 32;         /* first time */
2125 2125                  tbl->ent = Realloc(tbl->ent, tbl->size*sizeof (struct ugdata));
2126 2126          }
2127 2127          entp = &tbl->ent[tbl->nent++];
2128 2128          entp->id = 0;
2129 2129          (void) strncpy(entp->name, name, MAXUGNAME);
2130 2130          entp->name[MAXUGNAME] = '\0';
2131 2131  }
2132 2132  
2133 2133  static int
2134 2134  uconv(struct ughead *uhead)
2135 2135  {
2136 2136          struct ugdata *utbl = uhead->ent;
2137 2137          int n = uhead->nent;
2138 2138          struct passwd *pwd;
2139 2139          int i;
2140 2140          int fnd = 0;
2141 2141          uid_t uid;
2142 2142  
2143 2143          /*
2144 2144           * Ask the name service for names.
2145 2145           */
2146 2146          for (i = 0; i < n; i++) {
2147 2147                  /*
2148 2148                   * If name is numeric, ask for numeric id
2149 2149                   */
2150 2150                  if (str2uid(utbl[i].name, &uid, 0, MAXEPHUID) == 0)
2151 2151                          pwd = getpwuid(uid);
2152 2152                  else
2153 2153                          pwd = getpwnam(utbl[i].name);
2154 2154  
2155 2155                  /*
2156 2156                   * If found, enter found index into tbl array.
2157 2157                   */
2158 2158                  if (pwd == NULL) {
2159 2159                          (void) fprintf(stderr,
2160 2160                              gettext("ps: unknown user %s\n"), utbl[i].name);
2161 2161                          continue;
2162 2162                  }
2163 2163  
2164 2164                  utbl[fnd].id = pwd->pw_uid;
2165 2165                  (void) strncpy(utbl[fnd].name, pwd->pw_name, MAXUGNAME);
2166 2166                  fnd++;
2167 2167          }
2168 2168  
2169 2169          uhead->nent = fnd;      /* in case it changed */
2170 2170          return (n - fnd);
2171 2171  }
2172 2172  
2173 2173  static int
2174 2174  gconv(struct ughead *ghead)
2175 2175  {
2176 2176          struct ugdata *gtbl = ghead->ent;
2177 2177          int n = ghead->nent;
2178 2178          struct group *grp;
2179 2179          gid_t gid;
2180 2180          int i;
2181 2181          int fnd = 0;
2182 2182  
2183 2183          /*
2184 2184           * Ask the name service for names.
2185 2185           */
2186 2186          for (i = 0; i < n; i++) {
2187 2187                  /*
2188 2188                   * If name is numeric, ask for numeric id
2189 2189                   */
2190 2190                  if (str2uid(gtbl[i].name, (uid_t *)&gid, 0, MAXEPHUID) == 0)
2191 2191                          grp = getgrgid(gid);
2192 2192                  else
2193 2193                          grp = getgrnam(gtbl[i].name);
2194 2194                  /*
2195 2195                   * If found, enter found index into tbl array.
2196 2196                   */
2197 2197                  if (grp == NULL) {
2198 2198                          (void) fprintf(stderr,
2199 2199                              gettext("ps: unknown group %s\n"), gtbl[i].name);
2200 2200                          continue;
2201 2201                  }
2202 2202  
2203 2203                  gtbl[fnd].id = grp->gr_gid;
2204 2204                  (void) strncpy(gtbl[fnd].name, grp->gr_name, MAXUGNAME);
2205 2205                  fnd++;
2206 2206          }
2207 2207  
2208 2208          ghead->nent = fnd;      /* in case it changed */
2209 2209          return (n - fnd);
2210 2210  }
2211 2211  
2212 2212  /*
2213 2213   * Return 1 if puid is in table, otherwise 0.
2214 2214   */
2215 2215  static int
2216 2216  ugfind(id_t id, struct ughead *ughead)
2217 2217  {
2218 2218          struct ugdata *utbl = ughead->ent;
2219 2219          int n = ughead->nent;
2220 2220          int i;
2221 2221  
2222 2222          for (i = 0; i < n; i++)
2223 2223                  if (utbl[i].id == id)
2224 2224                          return (1);
2225 2225          return (0);
2226 2226  }
2227 2227  
2228 2228  /*
2229 2229   * Print starting time of process unless process started more than 24 hours
2230 2230   * ago, in which case the date is printed.  The date is printed in the form
2231 2231   * "MMM dd" if old format, else the blank is replaced with an '_' so
2232 2232   * it appears as a single word (for parseability).
2233 2233   */
2234 2234  static void
2235 2235  prtime(timestruc_t st, int width, int old)
2236 2236  {
2237 2237          char sttim[26];
2238 2238          time_t starttime;
2239 2239  
2240 2240          starttime = st.tv_sec;
2241 2241          if (st.tv_nsec > 500000000)
2242 2242                  starttime++;
2243 2243          if ((now.tv_sec - starttime) >= 24*60*60) {
2244 2244                  (void) strftime(sttim, sizeof (sttim), old?
2245 2245                  /*
2246 2246                   * TRANSLATION_NOTE
2247 2247                   * This time format is used by STIME field when -f option
2248 2248                   * is specified.  Used for processes that begun more than
2249 2249                   * 24 hours.
2250 2250                   */
2251 2251                      dcgettext(NULL, "%b %d", LC_TIME) :
2252 2252                  /*
2253 2253                   * TRANSLATION_NOTE
2254 2254                   * This time format is used by STIME field when -o option
2255 2255                   * is specified.  Used for processes that begun more than
2256 2256                   * 24 hours.
2257 2257                   */
2258 2258                      dcgettext(NULL, "%b_%d", LC_TIME), localtime(&starttime));
2259 2259          } else {
2260 2260                  /*
2261 2261                   * TRANSLATION_NOTE
2262 2262                   * This time format is used by STIME field when -f or -o option
2263 2263                   * is specified.  Used for processes that begun less than
2264 2264                   * 24 hours.
2265 2265                   */
2266 2266                  (void) strftime(sttim, sizeof (sttim),
2267 2267                      dcgettext(NULL, "%H:%M:%S", LC_TIME),
2268 2268                      localtime(&starttime));
2269 2269          }
2270 2270          (void) printf("%*.*s", width, width, sttim);
2271 2271  }
2272 2272  
2273 2273  static void
2274 2274  przom(psinfo_t *psinfo)
2275 2275  {
2276 2276          long    tm;
2277 2277          struct passwd *pwd;
2278 2278          char zonename[ZONENAME_MAX];
2279 2279  
2280 2280          /*
2281 2281           * All fields before 'PID' are printed with a trailing space as a
2282 2282           * spearator, rather than keeping track of which column is first.  All
2283 2283           * other fields are printed with a leading space.
2284 2284           */
2285 2285          if (lflg) {     /* F S */
2286 2286                  if (!yflg)
2287 2287                          (void) printf("%2x ", psinfo->pr_flag & 0377); /* F */
2288 2288                  (void) printf("%c ", psinfo->pr_lwp.pr_sname);  /* S */
2289 2289          }
2290 2290          if (Zflg) {
2291 2291                  if (getzonenamebyid(psinfo->pr_zoneid, zonename,
2292 2292                      sizeof (zonename)) < 0) {
2293 2293                          if (snprintf(NULL, 0, "%d",
2294 2294                              ((int)psinfo->pr_zoneid)) > 7)
2295 2295                                  (void) printf(" %6.6d%c ",
2296 2296                                      ((int)psinfo->pr_zoneid), '*');
2297 2297                          else
2298 2298                                  (void) printf(" %7.7d ",
2299 2299                                      ((int)psinfo->pr_zoneid));
2300 2300                  } else {
2301 2301                          size_t nw;
2302 2302  
2303 2303                          nw = mbstowcs(NULL, zonename, 0);
2304 2304                          if (nw == (size_t)-1)
2305 2305                                  (void) printf("%8.8s ", "ERROR");
2306 2306                          else if (nw > 8)
2307 2307                                  (void) wprintf(L"%7.7s%c ", zonename, '*');
2308 2308                          else
2309 2309                                  (void) wprintf(L"%8.8s ", zonename);
2310 2310                  }
2311 2311          }
2312 2312          if (Hflg) {
2313 2313                  /* Display home lgroup */
2314 2314                  (void) printf(" %6d", (int)psinfo->pr_lwp.pr_lgrp); /* LGRP */
2315 2315          }
2316 2316          if (fflg) {
2317 2317                  if ((pwd = getpwuid(psinfo->pr_euid)) != NULL) {
2318 2318                          size_t nw;
2319 2319  
2320 2320                          nw = mbstowcs(NULL, pwd->pw_name, 0);
2321 2321                          if (nw == (size_t)-1)
2322 2322                                  (void) printf("%8.8s ", "ERROR");
2323 2323                          else if (nw > 8)
2324 2324                                  (void) wprintf(L"%7.7s%c ", pwd->pw_name, '*');
2325 2325                          else
2326 2326                                  (void) wprintf(L"%8.8s ", pwd->pw_name);
2327 2327                  } else {
2328 2328                          if (snprintf(NULL, 0, "%u",
2329 2329                              (psinfo->pr_euid)) > 7)
2330 2330                                  (void) printf(" %6.6u%c ", psinfo->pr_euid,
2331 2331                                      '*');
2332 2332                          else
2333 2333                                  (void) printf(" %7.7u ", psinfo->pr_euid);
2334 2334                  }
2335 2335          } else if (lflg) {
2336 2336                  if (snprintf(NULL, 0, "%u", (psinfo->pr_euid)) > 6)
2337 2337                          (void) printf("%5.5u%c ", psinfo->pr_euid, '*');
2338 2338                  else
2339 2339                          (void) printf("%6u ", psinfo->pr_euid);
2340 2340          }
2341 2341  
2342 2342          (void) printf("%*d", pidwidth, (int)psinfo->pr_pid);    /* PID */
2343 2343          if (lflg || fflg)
2344 2344                  (void) printf(" %*d", pidwidth,
2345 2345                      (int)psinfo->pr_ppid);                      /* PPID */
2346 2346  
2347 2347          if (jflg) {
2348 2348                  (void) printf(" %*d", pidwidth,
2349 2349                      (int)psinfo->pr_pgid);                      /* PGID */
2350 2350                  (void) printf(" %*d", pidwidth,
2351 2351                      (int)psinfo->pr_sid);                       /* SID  */
2352 2352          }
2353 2353  
2354 2354          if (Lflg)
2355 2355                  (void) printf(" %5d", 0);                       /* LWP */
2356 2356          if (Pflg)
2357 2357                  (void) printf("   -");                          /* PSR */
2358 2358          if (Lflg && fflg)
2359 2359                  (void) printf(" %5d", 0);                       /* NLWP */
2360 2360  
2361 2361          if (cflg) {
2362 2362                  (void) printf(" %4s", "-");     /* zombies have no class */
2363 2363                  (void) printf(" %3d", psinfo->pr_lwp.pr_pri);   /* PRI  */
2364 2364          } else if (lflg || fflg) {
2365 2365                  (void) printf(" %3d", psinfo->pr_lwp.pr_cpu & 0377); /* C   */
2366 2366                  if (lflg)
2367 2367                          (void) printf(" %3d %2s",
2368 2368                              psinfo->pr_lwp.pr_oldpri, "-");     /* PRI NI */
2369 2369          }
2370 2370          if (lflg) {
2371 2371                  if (yflg)                               /* RSS SZ WCHAN */
2372 2372                          (void) printf(" %5d %6d %8s", 0, 0, "-");
2373 2373                  else                                    /* ADDR SZ WCHAN */
2374 2374                          (void) printf(" %8s %6d %8s", "-", 0, "-");
2375 2375          }
2376 2376          if (fflg) {
2377 2377                  int width = fname[F_STIME].width;
2378 2378                  (void) printf(" %*.*s", width, width, "-");     /* STIME */
2379 2379          }
2380 2380          (void) printf(" %-8.14s", "?");                         /* TTY */
2381 2381  
2382 2382          tm = psinfo->pr_time.tv_sec;
2383 2383          if (psinfo->pr_time.tv_nsec > 500000000)
2384 2384                  tm++;
2385 2385          (void) printf(" %4ld:%.2ld", tm / 60, tm % 60); /* TIME */
2386 2386          (void) printf(" <defunct>\n");
2387 2387  }
2388 2388  
2389 2389  /*
2390 2390   * Function to compute the number of printable bytes in a multibyte
2391 2391   * command string ("internationalization").
2392 2392   */
2393 2393  static int
2394 2394  namencnt(char *cmd, int csisize, int scrsize)
2395 2395  {
2396 2396          int csiwcnt = 0, scrwcnt = 0;
2397 2397          int ncsisz, nscrsz;
2398 2398          wchar_t  wchar;
2399 2399          int      len;
2400 2400  
2401 2401          while (*cmd != '\0') {
2402 2402                  if ((len = csisize - csiwcnt) > (int)MB_CUR_MAX)
2403 2403                          len = MB_CUR_MAX;
2404 2404                  if ((ncsisz = mbtowc(&wchar, cmd, len)) < 0)
2405 2405                          return (8); /* default to use for illegal chars */
2406 2406                  if ((nscrsz = wcwidth(wchar)) <= 0)
2407 2407                          return (8);
2408 2408                  if (csiwcnt + ncsisz > csisize || scrwcnt + nscrsz > scrsize)
2409 2409                          break;
2410 2410                  csiwcnt += ncsisz;
2411 2411                  scrwcnt += nscrsz;
2412 2412                  cmd += ncsisz;
2413 2413          }
2414 2414          return (csiwcnt);
2415 2415  }
2416 2416  
2417 2417  static char *
2418 2418  err_string(int err)
2419 2419  {
2420 2420          static char buf[32];
2421 2421          char *str = strerror(err);
2422 2422  
2423 2423          if (str == NULL)
2424 2424                  (void) snprintf(str = buf, sizeof (buf), "Errno #%d", err);
2425 2425  
2426 2426          return (str);
2427 2427  }
2428 2428  
2429 2429  /* If allocation fails, die */
2430 2430  static void *
2431 2431  Realloc(void *ptr, size_t size)
2432 2432  {
2433 2433          ptr = realloc(ptr, size);
2434 2434          if (ptr == NULL) {
2435 2435                  (void) fprintf(stderr, gettext("ps: no memory\n"));
2436 2436                  exit(1);
2437 2437          }
2438 2438          return (ptr);
2439 2439  }
2440 2440  
2441 2441  static time_t
2442 2442  delta_secs(const timestruc_t *start)
2443 2443  {
2444 2444          time_t seconds = now.tv_sec - start->tv_sec;
2445 2445          long nanosecs = now.tv_usec * 1000 - start->tv_nsec;
2446 2446  
2447 2447          if (nanosecs >= (NANOSEC / 2))
2448 2448                  seconds++;
2449 2449          else if (nanosecs < -(NANOSEC / 2))
2450 2450                  seconds--;
2451 2451  
2452 2452          return (seconds);
2453 2453  }
2454 2454  
2455 2455  /*
2456 2456   * Returns the following:
2457 2457   *
2458 2458   *      0       No error
2459 2459   *      EINVAL  Invalid number
2460 2460   *      ERANGE  Value exceeds (min, max) range
2461 2461   */
2462 2462  static int
2463 2463  str2id(const char *p, pid_t *val, long min, long max)
2464 2464  {
2465 2465          char *q;
2466 2466          long number;
2467 2467          int error;
2468 2468  
2469 2469          errno = 0;
2470 2470          number = strtol(p, &q, 10);
2471 2471  
2472 2472          if (errno != 0 || q == p || *q != '\0') {
2473 2473                  if ((error = errno) == 0) {
2474 2474                          /*
2475 2475                           * strtol() can fail without setting errno, or it can
2476 2476                           * set it to EINVAL or ERANGE.  In the case errno is
2477 2477                           * still zero, return EINVAL.
2478 2478                           */
2479 2479                          error = EINVAL;
2480 2480                  }
2481 2481          } else if (number < min || number > max) {
2482 2482                  error = ERANGE;
2483 2483          } else {
2484 2484                  error = 0;
2485 2485          }
2486 2486  
2487 2487          *val = number;
2488 2488  
2489 2489          return (error);
2490 2490  }
2491 2491  
2492 2492  /*
2493 2493   * Returns the following:
2494 2494   *
2495 2495   *      0       No error
2496 2496   *      EINVAL  Invalid number
2497 2497   *      ERANGE  Value exceeds (min, max) range
2498 2498   */
2499 2499  static int
2500 2500  str2uid(const char *p, uid_t *val, unsigned long min, unsigned long max)
2501 2501  {
2502 2502          char *q;
2503 2503          unsigned long number;
2504 2504          int error;
2505 2505  
2506 2506          errno = 0;
2507 2507          number = strtoul(p, &q, 10);
2508 2508  
2509 2509          if (errno != 0 || q == p || *q != '\0') {
2510 2510                  if ((error = errno) == 0) {
2511 2511                          /*
2512 2512                           * strtoul() can fail without setting errno, or it can
2513 2513                           * set it to EINVAL or ERANGE.  In the case errno is
2514 2514                           * still zero, return EINVAL.
2515 2515                           */
2516 2516                          error = EINVAL;
2517 2517                  }
2518 2518          } else if (number < min || number > max) {
2519 2519                  error = ERANGE;
2520 2520          } else {
2521 2521                  error = 0;
2522 2522          }
2523 2523  
2524 2524          *val = number;
2525 2525  
2526 2526          return (error);
2527 2527  }
2528 2528  
2529 2529  static int
2530 2530  pidcmp(const void *p1, const void *p2)
2531 2531  {
2532 2532          pid_t i = *((pid_t *)p1);
2533 2533          pid_t j = *((pid_t *)p2);
2534 2534  
2535 2535          return (i - j);
2536 2536  }
  
    | 
      ↓ open down ↓ | 
    2536 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX