Print this page
    
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/prstat/prstat.c
          +++ new/usr/src/cmd/prstat/prstat.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   *
  
    | 
      ↓ open down ↓ | 
    18 lines elided | 
    
      ↑ open up ↑ | 
  
  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   * Portions Copyright 2009 Chad Mynhier
  29      - * Copyright 2012 Joyent, Inc.  All rights reserved.
  30   29   */
  31   30  
  32   31  #include <sys/types.h>
  33   32  #include <sys/resource.h>
  34   33  #include <sys/loadavg.h>
  35   34  #include <sys/time.h>
  36   35  #include <sys/pset.h>
  37   36  #include <sys/vm_usage.h>
  38   37  #include <zone.h>
  39   38  #include <libzonecfg.h>
  40   39  
  41   40  #include <stdio.h>
  42   41  #include <stdlib.h>
  43   42  #include <unistd.h>
  44   43  #include <dirent.h>
  45   44  #include <string.h>
  46   45  #include <errno.h>
  47   46  #include <poll.h>
  48   47  #include <ctype.h>
  49   48  #include <fcntl.h>
  50   49  #include <limits.h>
  51   50  #include <signal.h>
  52   51  #include <time.h>
  53   52  #include <project.h>
  54   53  
  55   54  #include <langinfo.h>
  56   55  #include <libintl.h>
  57   56  #include <locale.h>
  58   57  
  59   58  #include "prstat.h"
  60   59  #include "prutil.h"
  61   60  #include "prtable.h"
  62   61  #include "prsort.h"
  63   62  #include "prfile.h"
  64   63  
  65   64  /*
  66   65   * x86 <sys/regs.h> ERR conflicts with <curses.h> ERR.  For the purposes
  67   66   * of this file, we care about the curses.h ERR so include that last.
  68   67   */
  69   68  
  70   69  #if     defined(ERR)
  71   70  #undef  ERR
  72   71  #endif
  73   72  
  74   73  #ifndef TEXT_DOMAIN                     /* should be defined by cc -D */
  75   74  #define TEXT_DOMAIN     "SYS_TEST"      /* use this only if it wasn't */
  76   75  #endif
  77   76  
  78   77  #include <curses.h>
  79   78  #include <term.h>
  80   79  
  81   80  #define LOGIN_WIDTH     8
  82   81  #define ZONE_WIDTH      28
  83   82  #define PROJECT_WIDTH   28
  84   83  
  85   84  #define PSINFO_HEADER_PROC \
  86   85  "   PID USERNAME  SIZE   RSS STATE  PRI NICE      TIME  CPU PROCESS/NLWP       "
  87   86  #define PSINFO_HEADER_PROC_LGRP \
  88   87  "   PID USERNAME  SIZE   RSS STATE  PRI NICE      TIME  CPU LGRP PROCESS/NLWP  "
  89   88  #define PSINFO_HEADER_LWP \
  90   89  "   PID USERNAME  SIZE   RSS STATE  PRI NICE      TIME  CPU PROCESS/LWPID      "
  91   90  #define PSINFO_HEADER_LWP_LGRP \
  92   91  "   PID USERNAME  SIZE   RSS STATE  PRI NICE      TIME  CPU LGRP PROCESS/LWPID "
  93   92  #define USAGE_HEADER_PROC \
  94   93  "   PID USERNAME USR SYS TRP TFL DFL LCK SLP LAT VCX ICX SCL SIG PROCESS/NLWP  "
  95   94  #define USAGE_HEADER_LWP \
  96   95  "   PID USERNAME USR SYS TRP TFL DFL LCK SLP LAT VCX ICX SCL SIG PROCESS/LWPID "
  97   96  #define USER_HEADER_PROC \
  98   97  " NPROC USERNAME  SWAP   RSS MEMORY      TIME  CPU                             "
  99   98  #define USER_HEADER_LWP \
 100   99  "  NLWP USERNAME  SWAP   RSS MEMORY      TIME  CPU                             "
 101  100  #define TASK_HEADER_PROC \
 102  101  "TASKID    NPROC  SWAP   RSS MEMORY      TIME  CPU PROJECT                     "
 103  102  #define TASK_HEADER_LWP \
 104  103  "TASKID     NLWP  SWAP   RSS MEMORY      TIME  CPU PROJECT                     "
 105  104  #define PROJECT_HEADER_PROC \
 106  105  "PROJID    NPROC  SWAP   RSS MEMORY      TIME  CPU PROJECT                     "
 107  106  #define PROJECT_HEADER_LWP \
 108  107  "PROJID     NLWP  SWAP   RSS MEMORY      TIME  CPU PROJECT                     "
 109  108  #define ZONE_HEADER_PROC \
 110  109  "ZONEID    NPROC  SWAP   RSS MEMORY      TIME  CPU ZONE                        "
 111  110  #define ZONE_HEADER_LWP \
 112  111  "ZONEID     NLWP  SWAP   RSS MEMORY      TIME  CPU ZONE                        "
 113  112  #define PSINFO_LINE \
 114  113  "%6d %-8s %5s %5s %-6s %3s  %3s %9s %3.3s%% %-.16s/%d"
 115  114  #define PSINFO_LINE_LGRP \
 116  115  "%6d %-8s %5s %5s %-6s %3s  %3s %9s %3.3s%% %4d %-.16s/%d"
 117  116  #define USAGE_LINE \
 118  117  "%6d %-8s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s %3.3s "\
 119  118  "%3.3s %3.3s %-.12s/%d"
 120  119  #define USER_LINE \
 121  120  "%6d %-8s %5.5s %5.5s   %3.3s%% %9s %3.3s%%"
 122  121  #define TASK_LINE \
 123  122  "%6d %8d %5s %5s   %3.3s%% %9s %3.3s%% %28s"
 124  123  #define PROJECT_LINE \
 125  124  "%6d %8d %5s %5s   %3.3s%% %9s %3.3s%% %28s"
 126  125  #define ZONE_LINE \
 127  126  "%6d %8d %5s %5s   %3.3s%% %9s %3.3s%% %28s"
 128  127  
 129  128  #define TOTAL_LINE \
 130  129  "Total: %d processes, %d lwps, load averages: %3.2f, %3.2f, %3.2f"
 131  130  
 132  131  /* global variables */
 133  132  
 134  133  static char     *t_ulon;                        /* termcap: start underline */
 135  134  static char     *t_uloff;                       /* termcap: end underline */
 136  135  static char     *t_up;                          /* termcap: cursor 1 line up */
 137  136  static char     *t_eol;                         /* termcap: clear end of line */
 138  137  static char     *t_smcup;                       /* termcap: cursor mvcap on */
 139  138  static char     *t_rmcup;                       /* termcap: cursor mvcap off */
 140  139  static char     *t_home;                        /* termcap: move cursor home */
 141  140  static char     *movecur = NULL;                /* termcap: move up string */
 142  141  static char     *empty_string = "\0";           /* termcap: empty string */
 143  142  static uint_t   print_movecur = FALSE;          /* print movecur or not */
 144  143  static int      is_curses_on = FALSE;           /* current curses state */
 145  144  
 146  145  static table_t  pid_tbl = {0, 0, NULL};         /* selected processes */
 147  146  static table_t  cpu_tbl = {0, 0, NULL};         /* selected processors */
 148  147  static table_t  set_tbl = {0, 0, NULL};         /* selected processor sets */
 149  148  static table_t  prj_tbl = {0, 0, NULL};         /* selected projects */
 150  149  static table_t  tsk_tbl = {0, 0, NULL};         /* selected tasks */
 151  150  static table_t  lgr_tbl = {0, 0, NULL};         /* selected lgroups */
 152  151  static zonetbl_t zone_tbl = {0, 0, NULL};       /* selected zones */
 153  152  static uidtbl_t euid_tbl = {0, 0, NULL};        /* selected effective users */
 154  153  static uidtbl_t ruid_tbl = {0, 0, NULL};        /* selected real users */
 155  154  
 156  155  static uint_t   total_procs;                    /* total number of procs */
 157  156  static uint_t   total_lwps;                     /* total number of lwps */
 158  157  static float    total_cpu;                      /* total cpu usage */
 159  158  static float    total_mem;                      /* total memory usage */
 160  159  
 161  160  static list_t   lwps;                           /* list of lwps/processes */
 162  161  static list_t   users;                          /* list of users */
 163  162  static list_t   tasks;                          /* list of tasks */
 164  163  static list_t   projects;                       /* list of projects */
 165  164  static list_t   zones;                          /* list of zones */
 166  165  static list_t   lgroups;                        /* list of lgroups */
 167  166  
 168  167  static volatile uint_t sigwinch = 0;
 169  168  static volatile uint_t sigtstp = 0;
 170  169  static volatile uint_t sigterm = 0;
 171  170  
 172  171  static long pagesize;
 173  172  
 174  173  /* default settings */
 175  174  
 176  175  static optdesc_t opts = {
 177  176          5,                      /* interval between updates, seconds */
 178  177          15,                     /* number of lines in top part */
 179  178          5,                      /* number of lines in bottom part */
 180  179          -1,                     /* number of iterations; infinitely */
 181  180          OPT_PSINFO | OPT_FULLSCREEN | OPT_USEHOME | OPT_TERMCAP,
 182  181          -1                      /* sort in decreasing order */
 183  182  };
 184  183  
 185  184  
 186  185  static int
 187  186  proc_snprintf(char *_RESTRICT_KYWD s, size_t n,
 188  187      const char *_RESTRICT_KYWD fmt, ...)
 189  188  {
 190  189          static boolean_t ptools_zroot_valid = B_FALSE;
 191  190          static const char *ptools_zroot = NULL;
 192  191          va_list args;
 193  192          int ret, nret = 0;
 194  193  
 195  194          if (ptools_zroot_valid == B_FALSE) {
 196  195                  ptools_zroot_valid = B_TRUE;
 197  196                  ptools_zroot = zone_get_nroot();
 198  197          }
 199  198  
 200  199          if (ptools_zroot != NULL) {
 201  200                  nret = snprintf(s, n, "%s", ptools_zroot);
 202  201                  if (nret > n)
 203  202                          return (nret);
 204  203          }
 205  204          va_start(args, fmt);
 206  205          ret = vsnprintf(s + nret, n - nret, fmt, args);
 207  206          va_end(args);
 208  207  
 209  208          return (ret + nret);
 210  209  }
 211  210  
 212  211  /*
 213  212   * Print timestamp as decimal reprentation of time_t value (-d u was specified)
 214  213   * or the standard date format (-d d was specified).
 215  214   */
 216  215  static void
 217  216  print_timestamp(void)
 218  217  {
 219  218          time_t t = time(NULL);
 220  219          static char *fmt = NULL;
 221  220  
 222  221          /* We only need to retrieve this once per invocation */
 223  222          if (fmt == NULL)
 224  223                  fmt = nl_langinfo(_DATE_FMT);
 225  224  
 226  225          if (opts.o_outpmode & OPT_UDATE) {
 227  226                  (void) printf("%ld", t);
 228  227          } else if (opts.o_outpmode & OPT_DDATE) {
 229  228                  char dstr[64];
 230  229                  int len;
 231  230  
 232  231                  len = strftime(dstr, sizeof (dstr), fmt, localtime(&t));
 233  232                  if (len > 0)
 234  233                          (void) printf("%s", dstr);
 235  234          }
 236  235          (void) putp(t_eol);
 237  236          (void) putchar('\n');
 238  237  }
 239  238  
 240  239  static void
 241  240  psetloadavg(long psetid, void *ptr)
 242  241  {
 243  242          double psetloadavg[3];
 244  243          double *loadavg = ptr;
 245  244  
 246  245          if (pset_getloadavg((psetid_t)psetid, psetloadavg, 3) != -1) {
 247  246                  *loadavg++ += psetloadavg[0];
 248  247                  *loadavg++ += psetloadavg[1];
 249  248                  *loadavg += psetloadavg[2];
 250  249          }
 251  250  }
 252  251  
 253  252  /*
 254  253   * Queries the memory virtual and rss size for each member of a list.
 255  254   * This will override the values computed by /proc aggregation.
 256  255   */
  
    | 
      ↓ open down ↓ | 
    217 lines elided | 
    
      ↑ open up ↑ | 
  
 257  256  static void
 258  257  list_getsize(list_t *list)
 259  258  {
 260  259          id_info_t *id;
 261  260          vmusage_t *results, *next;
 262  261          vmusage_t *match;
 263  262          size_t nres = 0;
 264  263          size_t i;
 265  264          uint_t flags = 0;
 266  265          int ret;
 267      -        size_t physmem;
      266 +        size_t physmem = sysconf(_SC_PHYS_PAGES) * pagesize;
 268  267  
 269      -        if (!(opts.o_outpmode & OPT_VMUSAGE))
 270      -                return;
 271      -
 272      -        physmem = sysconf(_SC_PHYS_PAGES) * pagesize;
 273      -
 274  268          /*
 275  269           * Determine what swap/rss results to calculate.  getvmusage() will
 276  270           * prune results returned to non-global zones automatically, so
 277  271           * there is no need to pass different flags when calling from a
 278  272           * non-global zone.
 279  273           *
 280  274           * Currently list_getsize() is only called with a single flag.  This
 281  275           * is because -Z, -J, -T, and -a are mutually exclusive.  Regardless
 282  276           * of this, we handle multiple flags.
 283  277           */
 284  278          if (opts.o_outpmode & OPT_USERS) {
 285  279                  /*
 286  280                   * Gather rss for all users in all zones.  Treat the same
 287  281                   * uid in different zones as the same user.
 288  282                   */
 289  283                  flags |= VMUSAGE_COL_RUSERS;
 290  284  
 291  285          } else if (opts.o_outpmode & OPT_TASKS) {
 292  286                  /* Gather rss for all tasks in all zones */
 293  287                  flags |= VMUSAGE_ALL_TASKS;
 294  288  
 295  289          } else if (opts.o_outpmode & OPT_PROJECTS) {
 296  290                  /*
 297  291                   * Gather rss for all projects in all zones.  Treat the same
 298  292                   * projid in diffrent zones as the same project.
 299  293                   */
 300  294                  flags |= VMUSAGE_COL_PROJECTS;
 301  295  
 302  296          } else if (opts.o_outpmode & OPT_ZONES) {
 303  297                  /* Gather rss for all zones */
 304  298                  flags |= VMUSAGE_ALL_ZONES;
 305  299  
 306  300          } else {
 307  301                  Die(gettext(
 308  302                      "Cannot determine rss flags for output options %x\n"),
 309  303                      opts.o_outpmode);
 310  304          }
 311  305  
 312  306          /*
 313  307           * getvmusage() returns an array of result structures.  One for
 314  308           * each zone, project, task, or user on the system, depending on
 315  309           * flags.
 316  310           *
 317  311           * If getvmusage() fails, prstat will use the size already gathered
 318  312           * from psinfo
 319  313           */
 320  314          if (getvmusage(flags, opts.o_interval, NULL, &nres) != 0)
 321  315                  return;
 322  316  
 323  317          results = (vmusage_t *)Malloc(sizeof (vmusage_t) * nres);
 324  318          for (;;) {
 325  319                  ret = getvmusage(flags, opts.o_interval, results, &nres);
 326  320                  if (ret == 0)
 327  321                          break;
 328  322                  if (errno == EOVERFLOW) {
 329  323                          results = (vmusage_t *)Realloc(results,
 330  324                              sizeof (vmusage_t) * nres);
 331  325                          continue;
 332  326                  }
 333  327                  /*
 334  328                   * Failure for some other reason.  Prstat will use the size
 335  329                   * already gathered from psinfo.
 336  330                   */
 337  331                  free(results);
 338  332                  return;
 339  333          }
 340  334          for (id = list->l_head; id != NULL; id = id->id_next) {
 341  335  
 342  336                  match = NULL;
 343  337                  next = results;
 344  338                  for (i = 0; i < nres; i++, next++) {
 345  339                          switch (flags) {
 346  340                          case VMUSAGE_COL_RUSERS:
 347  341                                  if (next->vmu_id == id->id_uid)
 348  342                                          match = next;
 349  343                                  break;
 350  344                          case VMUSAGE_ALL_TASKS:
 351  345                                  if (next->vmu_id == id->id_taskid)
 352  346                                          match = next;
 353  347                                  break;
 354  348                          case VMUSAGE_COL_PROJECTS:
 355  349                                  if (next->vmu_id == id->id_projid)
 356  350                                          match = next;
 357  351                                  break;
 358  352                          case VMUSAGE_ALL_ZONES:
 359  353                                  if (next->vmu_id == id->id_zoneid)
 360  354                                          match = next;
 361  355                                  break;
 362  356                          default:
 363  357                                  Die(gettext(
 364  358                                      "Unknown vmusage flags %d\n"), flags);
 365  359                          }
 366  360                  }
 367  361                  if (match != NULL) {
 368  362                          id->id_size = match->vmu_swap_all / 1024;
 369  363                          id->id_rssize = match->vmu_rss_all / 1024;
 370  364                          id->id_pctmem = (100.0 * (float)match->vmu_rss_all) /
 371  365                              (float)physmem;
 372  366                          /* Output using data from getvmusage() */
 373  367                          id->id_sizematch = B_TRUE;
 374  368                  }
 375  369                  /*
 376  370                   * If no match is found, prstat will use the size already
 377  371                   * gathered from psinfo.
 378  372                   */
 379  373          }
 380  374          free(results);
 381  375  }
 382  376  
 383  377  /*
 384  378   * A routine to display the contents of the list on the screen
 385  379   */
 386  380  static void
 387  381  list_print(list_t *list)
 388  382  {
 389  383          lwp_info_t *lwp;
 390  384          id_info_t *id;
 391  385          char usr[4], sys[4], trp[4], tfl[4];
 392  386          char dfl[4], lck[4], slp[4], lat[4];
 393  387          char vcx[4], icx[4], scl[4], sig[4];
 394  388          char psize[6], prssize[6], pmem[6], pcpu[6], ptime[12];
 395  389          char pstate[7], pnice[4], ppri[4];
 396  390          char pname[LOGNAME_MAX+1];
 397  391          char projname[PROJNAME_MAX+1];
 398  392          char zonename[ZONENAME_MAX+1];
 399  393          float cpu, mem;
 400  394          double loadavg[3] = {0, 0, 0};
 401  395          int i, lwpid;
 402  396  
 403  397          if (list->l_size == 0)
 404  398                  return;
 405  399  
 406  400          if (foreach_element(&set_tbl, &loadavg, psetloadavg) == 0) {
 407  401                  /*
 408  402                   * If processor sets aren't specified, we display system-wide
 409  403                   * load averages.
 410  404                   */
 411  405                  (void) getloadavg(loadavg, 3);
 412  406          }
 413  407  
 414  408          if (((opts.o_outpmode & OPT_UDATE) || (opts.o_outpmode & OPT_DDATE)) &&
 415  409              ((list->l_type == LT_LWPS) || !(opts.o_outpmode & OPT_SPLIT)))
 416  410                  print_timestamp();
 417  411          if (opts.o_outpmode & OPT_TTY)
 418  412                  (void) putchar('\r');
 419  413          (void) putp(t_ulon);
 420  414  
 421  415          switch (list->l_type) {
 422  416          case LT_PROJECTS:
 423  417                  if (opts.o_outpmode & OPT_LWPS)
 424  418                          (void) printf(PROJECT_HEADER_LWP);
 425  419                  else
 426  420                          (void) printf(PROJECT_HEADER_PROC);
 427  421                  break;
 428  422          case LT_TASKS:
 429  423                  if (opts.o_outpmode & OPT_LWPS)
 430  424                          (void) printf(TASK_HEADER_LWP);
 431  425                  else
 432  426                          (void) printf(TASK_HEADER_PROC);
 433  427                  break;
 434  428          case LT_ZONES:
 435  429                  if (opts.o_outpmode & OPT_LWPS)
 436  430                          (void) printf(ZONE_HEADER_LWP);
 437  431                  else
 438  432                          (void) printf(ZONE_HEADER_PROC);
 439  433                  break;
 440  434          case LT_USERS:
 441  435                  if (opts.o_outpmode & OPT_LWPS)
 442  436                          (void) printf(USER_HEADER_LWP);
 443  437                  else
 444  438                          (void) printf(USER_HEADER_PROC);
 445  439                  break;
 446  440          case LT_LWPS:
 447  441                  if (opts.o_outpmode & OPT_LWPS) {
 448  442                          if (opts.o_outpmode & OPT_PSINFO) {
 449  443                                  if (opts.o_outpmode & OPT_LGRP)
 450  444                                          (void) printf(PSINFO_HEADER_LWP_LGRP);
 451  445                                  else
 452  446                                          (void) printf(PSINFO_HEADER_LWP);
 453  447                          }
 454  448                          if (opts.o_outpmode & OPT_MSACCT)
 455  449                                  (void) printf(USAGE_HEADER_LWP);
 456  450                  } else {
 457  451                          if (opts.o_outpmode & OPT_PSINFO) {
 458  452                                  if (opts.o_outpmode & OPT_LGRP)
 459  453                                          (void) printf(PSINFO_HEADER_PROC_LGRP);
 460  454                                  else
 461  455                                          (void) printf(PSINFO_HEADER_PROC);
 462  456                          }
 463  457                          if (opts.o_outpmode & OPT_MSACCT)
 464  458                                  (void) printf(USAGE_HEADER_PROC);
 465  459                  }
 466  460                  break;
 467  461          }
 468  462  
 469  463          (void) putp(t_uloff);
 470  464          (void) putp(t_eol);
 471  465          (void) putchar('\n');
 472  466  
 473  467          for (i = 0; i < list->l_used; i++) {
 474  468                  switch (list->l_type) {
 475  469                  case LT_PROJECTS:
 476  470                  case LT_TASKS:
 477  471                  case LT_USERS:
 478  472                  case LT_ZONES:
 479  473                          id = list->l_ptrs[i];
 480  474                          /*
 481  475                           * CPU usage and memory usage normalization
 482  476                           */
 483  477                          if (total_cpu >= 100)
 484  478                                  cpu = (100 * id->id_pctcpu) / total_cpu;
 485  479                          else
 486  480                                  cpu = id->id_pctcpu;
 487  481                          if (id->id_sizematch == B_FALSE && total_mem >= 100)
 488  482                                  mem = (100 * id->id_pctmem) / total_mem;
 489  483                          else
 490  484                                  mem = id->id_pctmem;
 491  485                          if (list->l_type == LT_USERS) {
 492  486                                  pwd_getname(id->id_uid, pname, sizeof (pname),
 493  487                                      opts.o_outpmode & OPT_NORESOLVE,
 494  488                                      opts.o_outpmode & (OPT_TERMCAP|OPT_TRUNC),
 495  489                                      LOGIN_WIDTH);
 496  490                          } else if (list->l_type == LT_ZONES) {
 497  491                                  getzonename(id->id_zoneid, zonename,
 498  492                                      sizeof (zonename),
 499  493                                      opts.o_outpmode & (OPT_TERMCAP|OPT_TRUNC),
 500  494                                      ZONE_WIDTH);
 501  495                          } else {
 502  496                                  getprojname(id->id_projid, projname,
 503  497                                      sizeof (projname),
 504  498                                      opts.o_outpmode & OPT_NORESOLVE,
 505  499                                      opts.o_outpmode & (OPT_TERMCAP|OPT_TRUNC),
 506  500                                      PROJECT_WIDTH);
 507  501                          }
 508  502                          Format_size(psize, id->id_size, 6);
 509  503                          Format_size(prssize, id->id_rssize, 6);
 510  504                          Format_pct(pmem, mem, 4);
 511  505                          Format_pct(pcpu, cpu, 4);
 512  506                          Format_time(ptime, id->id_time, 10);
 513  507                          if (opts.o_outpmode & OPT_TTY)
 514  508                                  (void) putchar('\r');
 515  509                          if (list->l_type == LT_PROJECTS)
 516  510                                  (void) printf(PROJECT_LINE, (int)id->id_projid,
 517  511                                      id->id_nproc, psize, prssize, pmem, ptime,
 518  512                                      pcpu, projname);
 519  513                          else if (list->l_type == LT_TASKS)
 520  514                                  (void) printf(TASK_LINE, (int)id->id_taskid,
 521  515                                      id->id_nproc, psize, prssize, pmem, ptime,
 522  516                                      pcpu, projname);
 523  517                          else if (list->l_type == LT_ZONES)
 524  518                                  (void) printf(ZONE_LINE, (int)id->id_zoneid,
 525  519                                      id->id_nproc, psize, prssize, pmem, ptime,
 526  520                                      pcpu, zonename);
 527  521                          else
 528  522                                  (void) printf(USER_LINE, id->id_nproc, pname,
 529  523                                      psize, prssize, pmem, ptime, pcpu);
 530  524                          (void) putp(t_eol);
 531  525                          (void) putchar('\n');
 532  526                          break;
 533  527                  case LT_LWPS:
 534  528                          lwp = list->l_ptrs[i];
 535  529                          if (opts.o_outpmode & OPT_LWPS)
 536  530                                  lwpid = lwp->li_info.pr_lwp.pr_lwpid;
 537  531                          else
 538  532                                  lwpid = lwp->li_info.pr_nlwp +
 539  533                                      lwp->li_info.pr_nzomb;
 540  534                          pwd_getname(lwp->li_info.pr_uid, pname, sizeof (pname),
 541  535                              opts.o_outpmode & OPT_NORESOLVE,
 542  536                              opts.o_outpmode & (OPT_TERMCAP|OPT_TRUNC),
 543  537                              LOGIN_WIDTH);
 544  538                          if (opts.o_outpmode & OPT_PSINFO) {
 545  539                                  Format_size(psize, lwp->li_info.pr_size, 6);
 546  540                                  Format_size(prssize, lwp->li_info.pr_rssize, 6);
 547  541                                  Format_state(pstate,
 548  542                                      lwp->li_info.pr_lwp.pr_sname,
 549  543                                      lwp->li_info.pr_lwp.pr_onpro, 7);
 550  544                                  if (strcmp(lwp->li_info.pr_lwp.pr_clname,
 551  545                                      "RT") == 0 ||
 552  546                                      strcmp(lwp->li_info.pr_lwp.pr_clname,
 553  547                                      "SYS") == 0 ||
 554  548                                      lwp->li_info.pr_lwp.pr_sname == 'Z')
 555  549                                          (void) strcpy(pnice, "  -");
 556  550                                  else
 557  551                                          Format_num(pnice,
 558  552                                              lwp->li_info.pr_lwp.pr_nice - NZERO,
 559  553                                              4);
 560  554                                  Format_num(ppri, lwp->li_info.pr_lwp.pr_pri, 4);
 561  555                                  Format_pct(pcpu,
 562  556                                      FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu), 4);
 563  557                                  if (opts.o_outpmode & OPT_LWPS)
 564  558                                          Format_time(ptime,
 565  559                                              lwp->li_info.pr_lwp.pr_time.tv_sec,
 566  560                                              10);
 567  561                                  else
 568  562                                          Format_time(ptime,
 569  563                                              lwp->li_info.pr_time.tv_sec, 10);
 570  564                                  if (opts.o_outpmode & OPT_TTY)
 571  565                                          (void) putchar('\r');
 572  566                                  stripfname(lwp->li_info.pr_fname);
 573  567                                  if (opts.o_outpmode & OPT_LGRP) {
 574  568                                          (void) printf(PSINFO_LINE_LGRP,
 575  569                                              (int)lwp->li_info.pr_pid, pname,
 576  570                                              psize, prssize, pstate,
 577  571                                              ppri, pnice, ptime, pcpu,
 578  572                                              (int)lwp->li_info.pr_lwp.pr_lgrp,
 579  573                                              lwp->li_info.pr_fname, lwpid);
 580  574                                  } else {
 581  575                                          (void) printf(PSINFO_LINE,
 582  576                                              (int)lwp->li_info.pr_pid, pname,
 583  577                                              psize, prssize,
 584  578                                              pstate, ppri, pnice,
 585  579                                              ptime, pcpu,
 586  580                                              lwp->li_info.pr_fname, lwpid);
 587  581                                  }
 588  582                                  (void) putp(t_eol);
 589  583                                  (void) putchar('\n');
 590  584                          }
 591  585                          if (opts.o_outpmode & OPT_MSACCT) {
 592  586                                  Format_pct(usr, lwp->li_usr, 4);
 593  587                                  Format_pct(sys, lwp->li_sys, 4);
 594  588                                  Format_pct(slp, lwp->li_slp, 4);
 595  589                                  Format_num(vcx, lwp->li_vcx, 4);
 596  590                                  Format_num(icx, lwp->li_icx, 4);
 597  591                                  Format_num(scl, lwp->li_scl, 4);
 598  592                                  Format_num(sig, lwp->li_sig, 4);
 599  593                                  Format_pct(trp, lwp->li_trp, 4);
 600  594                                  Format_pct(tfl, lwp->li_tfl, 4);
 601  595                                  Format_pct(dfl, lwp->li_dfl, 4);
 602  596                                  Format_pct(lck, lwp->li_lck, 4);
 603  597                                  Format_pct(lat, lwp->li_lat, 4);
 604  598                                  if (opts.o_outpmode & OPT_TTY)
 605  599                                          (void) putchar('\r');
 606  600                                  stripfname(lwp->li_info.pr_fname);
 607  601                                  (void) printf(USAGE_LINE,
 608  602                                      (int)lwp->li_info.pr_pid, pname,
 609  603                                      usr, sys, trp, tfl, dfl, lck,
 610  604                                      slp, lat, vcx, icx, scl, sig,
 611  605                                      lwp->li_info.pr_fname, lwpid);
 612  606                                  (void) putp(t_eol);
 613  607                                  (void) putchar('\n');
 614  608                          }
 615  609                          break;
 616  610                  }
 617  611          }
 618  612  
 619  613          if (opts.o_outpmode & OPT_TTY)
 620  614                  (void) putchar('\r');
 621  615          if (opts.o_outpmode & OPT_TERMCAP) {
 622  616                  switch (list->l_type) {
 623  617                  case LT_PROJECTS:
 624  618                  case LT_USERS:
 625  619                  case LT_TASKS:
 626  620                  case LT_ZONES:
 627  621                          while (i++ < opts.o_nbottom) {
 628  622                                  (void) putp(t_eol);
 629  623                                  (void) putchar('\n');
 630  624                          }
 631  625                          break;
 632  626                  case LT_LWPS:
 633  627                          while (i++ < opts.o_ntop) {
 634  628                                  (void) putp(t_eol);
 635  629                                  (void) putchar('\n');
 636  630                          }
 637  631                  }
 638  632          }
 639  633  
 640  634          if (opts.o_outpmode & OPT_TTY)
 641  635                  (void) putchar('\r');
 642  636  
 643  637          if ((opts.o_outpmode & OPT_SPLIT) && list->l_type == LT_LWPS)
 644  638                  return;
 645  639  
 646  640          (void) printf(TOTAL_LINE, total_procs, total_lwps,
 647  641              loadavg[LOADAVG_1MIN], loadavg[LOADAVG_5MIN],
 648  642              loadavg[LOADAVG_15MIN]);
 649  643          (void) putp(t_eol);
 650  644          (void) putchar('\n');
 651  645          if (opts.o_outpmode & OPT_TTY)
 652  646                  (void) putchar('\r');
 653  647          (void) putp(t_eol);
 654  648          (void) fflush(stdout);
 655  649  }
 656  650  
 657  651  static lwp_info_t *
 658  652  list_add_lwp(list_t *list, pid_t pid, id_t lwpid)
 659  653  {
 660  654          lwp_info_t *lwp;
 661  655  
 662  656          if (list->l_head == NULL) {
 663  657                  list->l_head = list->l_tail = lwp = Zalloc(sizeof (lwp_info_t));
 664  658          } else {
 665  659                  lwp = Zalloc(sizeof (lwp_info_t));
 666  660                  lwp->li_prev = list->l_tail;
 667  661                  ((lwp_info_t *)list->l_tail)->li_next = lwp;
 668  662                  list->l_tail = lwp;
 669  663          }
 670  664          lwp->li_info.pr_pid = pid;
 671  665          lwp->li_info.pr_lwp.pr_lwpid = lwpid;
 672  666          lwpid_add(lwp, pid, lwpid);
 673  667          list->l_count++;
 674  668          return (lwp);
 675  669  }
 676  670  
 677  671  static void
 678  672  list_remove_lwp(list_t *list, lwp_info_t *lwp)
 679  673  {
 680  674          if (lwp->li_prev)
 681  675                  lwp->li_prev->li_next = lwp->li_next;
 682  676          else
 683  677                  list->l_head = lwp->li_next;    /* removing the head */
 684  678          if (lwp->li_next)
 685  679                  lwp->li_next->li_prev = lwp->li_prev;
 686  680          else
 687  681                  list->l_tail = lwp->li_prev;    /* removing the tail */
 688  682          lwpid_del(lwp->li_info.pr_pid, lwp->li_info.pr_lwp.pr_lwpid);
 689  683          if (lwpid_pidcheck(lwp->li_info.pr_pid) == 0)
 690  684                  fds_rm(lwp->li_info.pr_pid);
 691  685          list->l_count--;
 692  686          free(lwp);
 693  687  }
 694  688  
 695  689  static void
 696  690  list_clear(list_t *list)
 697  691  {
 698  692          if (list->l_type == LT_LWPS) {
 699  693                  lwp_info_t      *lwp = list->l_tail;
 700  694                  lwp_info_t      *lwp_tmp;
 701  695  
 702  696                  fd_closeall();
 703  697                  while (lwp) {
 704  698                          lwp_tmp = lwp;
 705  699                          lwp = lwp->li_prev;
 706  700                          list_remove_lwp(&lwps, lwp_tmp);
 707  701                  }
 708  702          } else {
 709  703                  id_info_t *id = list->l_head;
 710  704                  id_info_t *nextid;
 711  705  
 712  706                  while (id) {
 713  707                          nextid = id->id_next;
 714  708                          free(id);
 715  709                          id = nextid;
 716  710                  }
 717  711                  list->l_count = 0;
 718  712                  list->l_head = list->l_tail = NULL;
 719  713          }
 720  714  }
 721  715  
 722  716  static void
 723  717  list_update(list_t *list, lwp_info_t *lwp)
 724  718  {
 725  719          id_info_t *id;
 726  720  
 727  721          if (list->l_head == NULL) {                     /* first element */
 728  722                  list->l_head = list->l_tail = id = Zalloc(sizeof (id_info_t));
 729  723                  goto update;
 730  724          }
 731  725  
 732  726          for (id = list->l_head; id; id = id->id_next) {
 733  727                  if ((list->l_type == LT_USERS) &&
 734  728                      (id->id_uid != lwp->li_info.pr_uid))
 735  729                          continue;
 736  730                  if ((list->l_type == LT_TASKS) &&
 737  731                      (id->id_taskid != lwp->li_info.pr_taskid))
 738  732                          continue;
 739  733                  if ((list->l_type == LT_PROJECTS) &&
 740  734                      (id->id_projid != lwp->li_info.pr_projid))
 741  735                          continue;
 742  736                  if ((list->l_type == LT_ZONES) &&
 743  737                      (id->id_zoneid != lwp->li_info.pr_zoneid))
 744  738                          continue;
 745  739                  if ((list->l_type == LT_LGRPS) &&
 746  740                      (id->id_lgroup != lwp->li_info.pr_lwp.pr_lgrp))
 747  741                          continue;
 748  742                  id->id_nproc++;
 749  743                  id->id_taskid   = lwp->li_info.pr_taskid;
 750  744                  id->id_projid   = lwp->li_info.pr_projid;
 751  745                  id->id_zoneid   = lwp->li_info.pr_zoneid;
 752  746                  id->id_lgroup   = lwp->li_info.pr_lwp.pr_lgrp;
 753  747  
 754  748                  if (lwp->li_flags & LWP_REPRESENT) {
 755  749                          id->id_size     += lwp->li_info.pr_size;
 756  750                          id->id_rssize   += lwp->li_info.pr_rssize;
 757  751                  }
 758  752                  id->id_pctcpu   += FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu);
 759  753                  if (opts.o_outpmode & OPT_LWPS)
 760  754                          id->id_time += TIME2SEC(lwp->li_info.pr_lwp.pr_time);
 761  755                  else
 762  756                          id->id_time += TIME2SEC(lwp->li_info.pr_time);
 763  757                  id->id_pctmem   += FRC2PCT(lwp->li_info.pr_pctmem);
 764  758                  id->id_key      += lwp->li_key;
 765  759                  total_cpu       += FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu);
 766  760                  total_mem       += FRC2PCT(lwp->li_info.pr_pctmem);
 767  761                  return;
 768  762          }
 769  763  
 770  764          id = list->l_tail;
 771  765          id->id_next = Zalloc(sizeof (id_info_t));
 772  766          id->id_next->id_prev = list->l_tail;
 773  767          id->id_next->id_next = NULL;
 774  768          list->l_tail = id->id_next;
 775  769          id = list->l_tail;
 776  770  update:
 777  771          id->id_uid      = lwp->li_info.pr_uid;
 778  772          id->id_projid   = lwp->li_info.pr_projid;
 779  773          id->id_taskid   = lwp->li_info.pr_taskid;
 780  774          id->id_zoneid   = lwp->li_info.pr_zoneid;
 781  775          id->id_lgroup   = lwp->li_info.pr_lwp.pr_lgrp;
 782  776          id->id_nproc++;
 783  777          id->id_sizematch = B_FALSE;
 784  778          if (lwp->li_flags & LWP_REPRESENT) {
 785  779                  id->id_size     = lwp->li_info.pr_size;
 786  780                  id->id_rssize   = lwp->li_info.pr_rssize;
 787  781          }
 788  782          id->id_pctcpu   = FRC2PCT(lwp->li_info.pr_lwp.pr_pctcpu);
 789  783          if (opts.o_outpmode & OPT_LWPS)
 790  784                  id->id_time = TIME2SEC(lwp->li_info.pr_lwp.pr_time);
 791  785          else
 792  786                  id->id_time = TIME2SEC(lwp->li_info.pr_time);
 793  787          id->id_pctmem   = FRC2PCT(lwp->li_info.pr_pctmem);
 794  788          id->id_key      = lwp->li_key;
 795  789          total_cpu       += id->id_pctcpu;
 796  790          total_mem       += id->id_pctmem;
 797  791          list->l_count++;
 798  792  }
 799  793  
 800  794  static void
 801  795  lwp_update(lwp_info_t *lwp, pid_t pid, id_t lwpid, struct prusage *usage)
 802  796  {
 803  797          float period;
 804  798  
 805  799          if (!lwpid_is_active(pid, lwpid)) {
 806  800                  /*
 807  801                   * If we are reading cpu times for the first time then
 808  802                   * calculate average cpu times based on whole process
 809  803                   * execution time.
 810  804                   */
 811  805                  (void) memcpy(&lwp->li_usage, usage, sizeof (prusage_t));
 812  806                  period = TIME2NSEC(usage->pr_rtime);
 813  807                  period = period/(float)100;
 814  808  
 815  809                  if (period == 0) { /* zombie */
 816  810                          period = 1;
 817  811                          lwp->li_usr = 0;
 818  812                          lwp->li_sys = 0;
 819  813                          lwp->li_slp = 0;
 820  814                  } else {
 821  815                          lwp->li_usr = TIME2NSEC(usage->pr_utime)/period;
 822  816                          lwp->li_sys = TIME2NSEC(usage->pr_stime)/period;
 823  817                          lwp->li_slp = TIME2NSEC(usage->pr_slptime)/period;
 824  818                  }
 825  819                  lwp->li_trp = TIME2NSEC(usage->pr_ttime)/period;
 826  820                  lwp->li_tfl = TIME2NSEC(usage->pr_tftime)/period;
 827  821                  lwp->li_dfl = TIME2NSEC(usage->pr_dftime)/period;
 828  822                  lwp->li_lck = TIME2NSEC(usage->pr_ltime)/period;
 829  823                  lwp->li_lat = TIME2NSEC(usage->pr_wtime)/period;
 830  824                  period = (period / NANOSEC)*(float)100; /* now in seconds */
 831  825                  lwp->li_vcx = (ulong_t)
 832  826                      (opts.o_interval * (usage->pr_vctx/period));
 833  827                  lwp->li_icx = (ulong_t)
 834  828                      (opts.o_interval * (usage->pr_ictx/period));
 835  829                  lwp->li_scl = (ulong_t)
 836  830                      (opts.o_interval * (usage->pr_sysc/period));
 837  831                  lwp->li_sig = (ulong_t)
 838  832                      (opts.o_interval * (usage->pr_sigs/period));
 839  833                  (void) lwpid_set_active(pid, lwpid);
 840  834          } else {
 841  835                  /*
 842  836                   * If this is not a first time we are reading a process's
 843  837                   * CPU times then recalculate CPU times based on fresh data
 844  838                   * obtained from procfs and previous CPU time usage values.
 845  839                   */
 846  840                  period = TIME2NSEC(usage->pr_rtime)-
 847  841                      TIME2NSEC(lwp->li_usage.pr_rtime);
 848  842                  period = period/(float)100;
 849  843  
 850  844                  if (period == 0) { /* zombie */
 851  845                          period = 1;
 852  846                          lwp->li_usr = 0;
 853  847                          lwp->li_sys = 0;
 854  848                          lwp->li_slp = 0;
 855  849                  } else {
 856  850                          lwp->li_usr = (TIME2NSEC(usage->pr_utime)-
 857  851                              TIME2NSEC(lwp->li_usage.pr_utime))/period;
 858  852                          lwp->li_sys = (TIME2NSEC(usage->pr_stime) -
 859  853                              TIME2NSEC(lwp->li_usage.pr_stime))/period;
 860  854                          lwp->li_slp = (TIME2NSEC(usage->pr_slptime) -
 861  855                              TIME2NSEC(lwp->li_usage.pr_slptime))/period;
 862  856                  }
 863  857                  lwp->li_trp = (TIME2NSEC(usage->pr_ttime) -
 864  858                      TIME2NSEC(lwp->li_usage.pr_ttime))/period;
 865  859                  lwp->li_tfl = (TIME2NSEC(usage->pr_tftime) -
 866  860                      TIME2NSEC(lwp->li_usage.pr_tftime))/period;
 867  861                  lwp->li_dfl = (TIME2NSEC(usage->pr_dftime) -
 868  862                      TIME2NSEC(lwp->li_usage.pr_dftime))/period;
 869  863                  lwp->li_lck = (TIME2NSEC(usage->pr_ltime) -
 870  864                      TIME2NSEC(lwp->li_usage.pr_ltime))/period;
 871  865                  lwp->li_lat = (TIME2NSEC(usage->pr_wtime) -
 872  866                      TIME2NSEC(lwp->li_usage.pr_wtime))/period;
 873  867                  lwp->li_vcx = usage->pr_vctx - lwp->li_usage.pr_vctx;
 874  868                  lwp->li_icx = usage->pr_ictx - lwp->li_usage.pr_ictx;
 875  869                  lwp->li_scl = usage->pr_sysc - lwp->li_usage.pr_sysc;
 876  870                  lwp->li_sig = usage->pr_sigs - lwp->li_usage.pr_sigs;
 877  871                  (void) memcpy(&lwp->li_usage, usage, sizeof (prusage_t));
 878  872          }
 879  873  }
 880  874  
 881  875  static int
 882  876  read_procfile(fd_t **fd, char *pidstr, char *file, void *buf, size_t bufsize)
 883  877  {
 884  878          char procfile[PATH_MAX];
 885  879  
 886  880          (void) proc_snprintf(procfile, PATH_MAX,
 887  881              "/proc/%s/%s", pidstr, file);
 888  882          if ((*fd = fd_open(procfile, O_RDONLY, *fd)) == NULL)
 889  883                  return (1);
 890  884          if (pread(fd_getfd(*fd), buf, bufsize, 0) != bufsize) {
 891  885                  fd_close(*fd);
 892  886                  return (1);
 893  887          }
 894  888          return (0);
 895  889  }
 896  890  
 897  891  static void
 898  892  add_proc(psinfo_t *psinfo)
 899  893  {
 900  894          lwp_info_t *lwp;
 901  895          id_t lwpid;
 902  896          pid_t pid = psinfo->pr_pid;
 903  897  
 904  898          lwpid = psinfo->pr_lwp.pr_lwpid;
 905  899          if ((lwp = lwpid_get(pid, lwpid)) == NULL)
 906  900                  lwp = list_add_lwp(&lwps, pid, lwpid);
 907  901          lwp->li_flags |= LWP_ALIVE | LWP_REPRESENT;
 908  902          (void) memcpy(&lwp->li_info, psinfo, sizeof (psinfo_t));
 909  903          lwp->li_info.pr_lwp.pr_pctcpu = lwp->li_info.pr_pctcpu;
 910  904  }
 911  905  
 912  906  static void
 913  907  add_lwp(psinfo_t *psinfo, lwpsinfo_t *lwpsinfo, int flags)
 914  908  {
 915  909          lwp_info_t *lwp;
 916  910          pid_t pid = psinfo->pr_pid;
 917  911          id_t lwpid = lwpsinfo->pr_lwpid;
 918  912  
 919  913          if ((lwp = lwpid_get(pid, lwpid)) == NULL)
 920  914                  lwp = list_add_lwp(&lwps, pid, lwpid);
 921  915          lwp->li_flags &= ~LWP_REPRESENT;
 922  916          lwp->li_flags |= LWP_ALIVE;
 923  917          lwp->li_flags |= flags;
 924  918          (void) memcpy(&lwp->li_info, psinfo,
 925  919              sizeof (psinfo_t) - sizeof (lwpsinfo_t));
 926  920          (void) memcpy(&lwp->li_info.pr_lwp, lwpsinfo, sizeof (lwpsinfo_t));
 927  921  }
 928  922  
 929  923  static void
 930  924  prstat_scandir(DIR *procdir)
 931  925  {
 932  926          char *pidstr;
 933  927          pid_t pid;
 934  928          id_t lwpid;
 935  929          size_t entsz;
 936  930          long nlwps, nent, i;
 937  931          char *buf, *ptr;
 938  932  
 939  933          fds_t *fds;
 940  934          lwp_info_t *lwp;
 941  935          dirent_t *direntp;
 942  936  
 943  937          prheader_t      header;
 944  938          psinfo_t        psinfo;
 945  939          prusage_t       usage;
 946  940          lwpsinfo_t      *lwpsinfo;
 947  941          prusage_t       *lwpusage;
 948  942  
 949  943          total_procs = 0;
 950  944          total_lwps = 0;
 951  945          total_cpu = 0;
 952  946          total_mem = 0;
 953  947  
 954  948          convert_zone(&zone_tbl);
 955  949          for (rewinddir(procdir); (direntp = readdir(procdir)); ) {
 956  950                  pidstr = direntp->d_name;
 957  951                  if (pidstr[0] == '.')   /* skip "." and ".."  */
 958  952                          continue;
 959  953                  pid = atoi(pidstr);
 960  954                  if (pid == 0 || pid == 2 || pid == 3)
 961  955                          continue;       /* skip sched, pageout and fsflush */
 962  956                  if (has_element(&pid_tbl, pid) == 0)
 963  957                          continue;       /* check if we really want this pid */
 964  958                  fds = fds_get(pid);     /* get ptr to file descriptors */
 965  959  
 966  960                  if (read_procfile(&fds->fds_psinfo, pidstr,
 967  961                      "psinfo", &psinfo, sizeof (psinfo_t)) != 0)
 968  962                          continue;
 969  963                  if (!has_uid(&ruid_tbl, psinfo.pr_uid) ||
 970  964                      !has_uid(&euid_tbl, psinfo.pr_euid) ||
 971  965                      !has_element(&prj_tbl, psinfo.pr_projid) ||
 972  966                      !has_element(&tsk_tbl, psinfo.pr_taskid) ||
 973  967                      !has_zone(&zone_tbl, psinfo.pr_zoneid)) {
 974  968                          fd_close(fds->fds_psinfo);
 975  969                          continue;
 976  970                  }
 977  971                  nlwps = psinfo.pr_nlwp + psinfo.pr_nzomb;
 978  972  
 979  973                  if (nlwps > 1 && (opts.o_outpmode & (OPT_LWPS | OPT_PSETS))) {
 980  974                          int rep_lwp = 0;
 981  975  
 982  976                          if (read_procfile(&fds->fds_lpsinfo, pidstr, "lpsinfo",
 983  977                              &header, sizeof (prheader_t)) != 0) {
 984  978                                  fd_close(fds->fds_psinfo);
 985  979                                  continue;
 986  980                          }
 987  981  
 988  982                          nent = header.pr_nent;
 989  983                          entsz = header.pr_entsize * nent;
 990  984                          ptr = buf = Malloc(entsz);
 991  985                          if (pread(fd_getfd(fds->fds_lpsinfo), buf,
 992  986                              entsz, sizeof (struct prheader)) != entsz) {
 993  987                                  fd_close(fds->fds_lpsinfo);
 994  988                                  fd_close(fds->fds_psinfo);
 995  989                                  free(buf);
 996  990                                  continue;
 997  991                          }
 998  992  
 999  993                          nlwps = 0;
1000  994                          for (i = 0; i < nent; i++, ptr += header.pr_entsize) {
1001  995                                  /*LINTED ALIGNMENT*/
1002  996                                  lwpsinfo = (lwpsinfo_t *)ptr;
1003  997                                  if (!has_element(&cpu_tbl,
1004  998                                      lwpsinfo->pr_onpro) ||
1005  999                                      !has_element(&set_tbl,
1006 1000                                      lwpsinfo->pr_bindpset) ||
1007 1001                                      !has_element(&lgr_tbl, lwpsinfo->pr_lgrp))
1008 1002                                          continue;
1009 1003                                  nlwps++;
1010 1004                                  if ((opts.o_outpmode & (OPT_PSETS | OPT_LWPS))
1011 1005                                      == OPT_PSETS) {
1012 1006                                          /*
1013 1007                                           * If one of process's LWPs is bound
1014 1008                                           * to a given processor set, report the
1015 1009                                           * whole process.  We may be doing this
1016 1010                                           * a few times but we'll get an accurate
1017 1011                                           * lwp count in return.
1018 1012                                           */
1019 1013                                          add_proc(&psinfo);
1020 1014                                  } else {
1021 1015                                          if (rep_lwp == 0) {
1022 1016                                                  rep_lwp = 1;
1023 1017                                                  add_lwp(&psinfo, lwpsinfo,
1024 1018                                                      LWP_REPRESENT);
1025 1019                                          } else {
1026 1020                                                  add_lwp(&psinfo, lwpsinfo, 0);
1027 1021                                          }
1028 1022                                  }
1029 1023                          }
1030 1024                          free(buf);
1031 1025                          if (nlwps == 0) {
1032 1026                                  fd_close(fds->fds_lpsinfo);
1033 1027                                  fd_close(fds->fds_psinfo);
1034 1028                                  continue;
1035 1029                          }
1036 1030                  } else {
1037 1031                          if (!has_element(&cpu_tbl, psinfo.pr_lwp.pr_onpro) ||
1038 1032                              !has_element(&set_tbl, psinfo.pr_lwp.pr_bindpset) ||
1039 1033                              !has_element(&lgr_tbl, psinfo.pr_lwp.pr_lgrp)) {
1040 1034                                  fd_close(fds->fds_psinfo);
1041 1035                                  continue;
1042 1036                          }
1043 1037                          add_proc(&psinfo);
1044 1038                  }
1045 1039                  if (!(opts.o_outpmode & OPT_MSACCT)) {
1046 1040                          total_procs++;
1047 1041                          total_lwps += nlwps;
1048 1042                          continue;
1049 1043                  }
1050 1044                  /*
1051 1045                   * Get more information about processes from /proc/pid/usage.
1052 1046                   * If process has more than one lwp, then we may have to
1053 1047                   * also look at the /proc/pid/lusage file.
1054 1048                   */
1055 1049                  if ((opts.o_outpmode & OPT_LWPS) && (nlwps > 1)) {
1056 1050                          if (read_procfile(&fds->fds_lusage, pidstr, "lusage",
1057 1051                              &header, sizeof (prheader_t)) != 0) {
1058 1052                                  fd_close(fds->fds_lpsinfo);
1059 1053                                  fd_close(fds->fds_psinfo);
1060 1054                                  continue;
1061 1055                          }
1062 1056                          nent = header.pr_nent;
1063 1057                          entsz = header.pr_entsize * nent;
1064 1058                          buf = Malloc(entsz);
1065 1059                          if (pread(fd_getfd(fds->fds_lusage), buf,
1066 1060                              entsz, sizeof (struct prheader)) != entsz) {
1067 1061                                  fd_close(fds->fds_lusage);
1068 1062                                  fd_close(fds->fds_lpsinfo);
1069 1063                                  fd_close(fds->fds_psinfo);
1070 1064                                  free(buf);
1071 1065                                  continue;
1072 1066                          }
1073 1067                          for (i = 1, ptr = buf + header.pr_entsize; i < nent;
1074 1068                              i++, ptr += header.pr_entsize) {
1075 1069                                  /*LINTED ALIGNMENT*/
1076 1070                                  lwpusage = (prusage_t *)ptr;
1077 1071                                  lwpid = lwpusage->pr_lwpid;
1078 1072                                  /*
1079 1073                                   * New LWPs created after we read lpsinfo
1080 1074                                   * will be ignored.  Don't want to do
1081 1075                                   * everything all over again.
1082 1076                                   */
1083 1077                                  if ((lwp = lwpid_get(pid, lwpid)) == NULL)
1084 1078                                          continue;
1085 1079                                  lwp_update(lwp, pid, lwpid, lwpusage);
1086 1080                          }
1087 1081                          free(buf);
1088 1082                  } else {
1089 1083                          if (read_procfile(&fds->fds_usage, pidstr, "usage",
1090 1084                              &usage, sizeof (prusage_t)) != 0) {
1091 1085                                  fd_close(fds->fds_lpsinfo);
1092 1086                                  fd_close(fds->fds_psinfo);
1093 1087                                  continue;
1094 1088                          }
1095 1089                          lwpid = psinfo.pr_lwp.pr_lwpid;
1096 1090                          if ((lwp = lwpid_get(pid, lwpid)) == NULL)
1097 1091                                  continue;
1098 1092                          lwp_update(lwp, pid, lwpid, &usage);
1099 1093                  }
1100 1094                  total_procs++;
1101 1095                  total_lwps += nlwps;
1102 1096          }
1103 1097          fd_update();
1104 1098  }
1105 1099  
1106 1100  /*
1107 1101   * This procedure removes all dead lwps from the linked list of all lwps.
1108 1102   * It also creates linked list of ids if necessary.
1109 1103   */
1110 1104  static void
1111 1105  list_refresh(list_t *list)
1112 1106  {
1113 1107          lwp_info_t *lwp, *lwp_next;
1114 1108  
1115 1109          if (!(list->l_type & LT_LWPS))
1116 1110                  return;
1117 1111  
1118 1112          for (lwp = list->l_head; lwp != NULL; ) {
1119 1113                  if (lwp->li_flags & LWP_ALIVE) {
1120 1114                          /*
1121 1115                           * Process all live LWPs.
1122 1116                           * When we're done, mark them as dead.
1123 1117                           * They will be marked "alive" on the next
1124 1118                           * /proc scan if they still exist.
1125 1119                           */
1126 1120                          lwp->li_key = list_getkeyval(list, lwp);
1127 1121                          if (opts.o_outpmode & OPT_USERS)
1128 1122                                  list_update(&users, lwp);
1129 1123                          if (opts.o_outpmode & OPT_TASKS)
1130 1124                                  list_update(&tasks, lwp);
1131 1125                          if (opts.o_outpmode & OPT_PROJECTS)
1132 1126                                  list_update(&projects, lwp);
1133 1127                          if (opts.o_outpmode & OPT_ZONES)
1134 1128                                  list_update(&zones, lwp);
1135 1129                          if (opts.o_outpmode & OPT_LGRP)
1136 1130                                  list_update(&lgroups, lwp);
1137 1131                          lwp->li_flags &= ~LWP_ALIVE;
1138 1132                          lwp = lwp->li_next;
1139 1133  
1140 1134                  } else {
1141 1135                          lwp_next = lwp->li_next;
1142 1136                          list_remove_lwp(&lwps, lwp);
1143 1137                          lwp = lwp_next;
1144 1138                  }
1145 1139          }
1146 1140  }
1147 1141  
1148 1142  static void
1149 1143  curses_on()
1150 1144  {
1151 1145          if ((opts.o_outpmode & OPT_TERMCAP) && (is_curses_on == FALSE)) {
1152 1146                  (void) initscr();
1153 1147                  (void) nonl();
1154 1148                  (void) putp(t_smcup);
1155 1149                  is_curses_on = TRUE;
1156 1150          }
1157 1151  }
1158 1152  
1159 1153  static void
1160 1154  curses_off()
1161 1155  {
1162 1156          if ((is_curses_on == TRUE) && (opts.o_outpmode & OPT_TERMCAP)) {
1163 1157                  (void) putp(t_rmcup);
1164 1158                  (void) endwin();
1165 1159                  is_curses_on = FALSE;
1166 1160          }
1167 1161          (void) fflush(stdout);
1168 1162  }
1169 1163  
1170 1164  static int
1171 1165  nlines()
1172 1166  {
1173 1167          struct winsize ws;
1174 1168          char *envp;
1175 1169          int n;
1176 1170          if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1) {
1177 1171                  if (ws.ws_row > 0)
1178 1172                          return (ws.ws_row);
1179 1173          }
1180 1174          if (envp = getenv("LINES")) {
1181 1175                  if ((n = Atoi(envp)) > 0) {
1182 1176                          opts.o_outpmode &= ~OPT_USEHOME;
1183 1177                          return (n);
1184 1178                  }
1185 1179          }
1186 1180          return (-1);
1187 1181  }
1188 1182  
1189 1183  static void
1190 1184  setmovecur()
1191 1185  {
1192 1186          int i, n;
1193 1187          if ((opts.o_outpmode & OPT_FULLSCREEN) &&
1194 1188              (opts.o_outpmode & OPT_USEHOME)) {
1195 1189                  movecur = t_home;
1196 1190                  return;
1197 1191          }
1198 1192          if (opts.o_outpmode & OPT_SPLIT) {
1199 1193                  if (opts.o_ntop == 0)
1200 1194                          n = opts.o_nbottom + 1;
1201 1195                  else
1202 1196                          n = opts.o_ntop + opts.o_nbottom + 2;
1203 1197          } else {
1204 1198                  if (opts.o_outpmode & OPT_USERS)
1205 1199                          n = opts.o_nbottom + 1;
1206 1200                  else
1207 1201                          n = opts.o_ntop + 1;
1208 1202          }
1209 1203          if (((opts.o_outpmode & OPT_UDATE) || (opts.o_outpmode & OPT_DDATE)))
1210 1204                  n++;
1211 1205  
1212 1206          if (movecur != NULL && movecur != empty_string && movecur != t_home)
1213 1207                  free(movecur);
1214 1208          movecur = Zalloc(strlen(t_up) * (n + 5));
1215 1209          for (i = 0; i <= n; i++)
1216 1210                  (void) strcat(movecur, t_up);
1217 1211  }
1218 1212  
1219 1213  static int
1220 1214  setsize()
1221 1215  {
1222 1216          static int oldn = 0;
1223 1217          int n;
1224 1218  
1225 1219          if (opts.o_outpmode & OPT_FULLSCREEN) {
1226 1220                  n = nlines();
1227 1221                  if (n == oldn)
1228 1222                          return (0);
1229 1223                  oldn = n;
1230 1224                  if (n == -1) {
1231 1225                          opts.o_outpmode &= ~OPT_USEHOME;
1232 1226                          setmovecur();           /* set default window size */
1233 1227                          return (1);
1234 1228                  }
1235 1229                  n = n - 3;      /* minus header, total and cursor lines */
1236 1230                  if ((opts.o_outpmode & OPT_UDATE) ||
1237 1231                      (opts.o_outpmode & OPT_DDATE))
1238 1232                          n--;    /* minus timestamp */
1239 1233                  if (n < 1)
1240 1234                          Die(gettext("window is too small (try -n)\n"));
1241 1235                  if (opts.o_outpmode & OPT_SPLIT) {
1242 1236                          if (n < 8) {
1243 1237                                  Die(gettext("window is too small (try -n)\n"));
1244 1238                          } else {
1245 1239                                  opts.o_ntop = (n / 4) * 3;
1246 1240                                  opts.o_nbottom = n - 1 - opts.o_ntop;
1247 1241                          }
1248 1242                  } else {
1249 1243                          if (opts.o_outpmode & OPT_USERS)
1250 1244                                  opts.o_nbottom = n;
1251 1245                          else
1252 1246                                  opts.o_ntop = n;
1253 1247                  }
1254 1248          }
1255 1249          setmovecur();
1256 1250          return (1);
1257 1251  }
1258 1252  
1259 1253  static void
1260 1254  ldtermcap()
1261 1255  {
1262 1256          int err;
1263 1257          if (setupterm(NULL, STDIN_FILENO, &err) == ERR) {
1264 1258                  switch (err) {
1265 1259                  case 0:
1266 1260                          Warn(gettext("failed to load terminal info, "
1267 1261                              "defaulting to -c option\n"));
1268 1262                          break;
1269 1263                  case -1:
1270 1264                          Warn(gettext("terminfo database not found, "
1271 1265                              "defaulting to -c option\n"));
1272 1266                          break;
1273 1267                  default:
1274 1268                          Warn(gettext("failed to initialize terminal, "
1275 1269                              "defaulting to -c option\n"));
1276 1270                  }
1277 1271                  opts.o_outpmode &= ~OPT_TERMCAP;
1278 1272                  t_up = t_eol = t_smcup = t_rmcup = movecur = empty_string;
1279 1273                  t_ulon = t_uloff = empty_string;
1280 1274                  return;
1281 1275          }
1282 1276          t_ulon  = tigetstr("smul");
1283 1277          t_uloff = tigetstr("rmul");
1284 1278          t_up    = tigetstr("cuu1");
1285 1279          t_eol   = tigetstr("el");
1286 1280          t_smcup = tigetstr("smcup");
1287 1281          t_rmcup = tigetstr("rmcup");
1288 1282          t_home  = tigetstr("home");
1289 1283          if ((t_up == (char *)-1) || (t_eol == (char *)-1) ||
1290 1284              (t_smcup == (char *)-1) || (t_rmcup == (char *)-1)) {
1291 1285                  opts.o_outpmode &= ~OPT_TERMCAP;
1292 1286                  t_up = t_eol = t_smcup = t_rmcup = movecur = empty_string;
1293 1287                  return;
1294 1288          }
1295 1289          if (t_up == NULL || t_eol == NULL) {
1296 1290                  opts.o_outpmode &= ~OPT_TERMCAP;
1297 1291                  t_eol = t_up = movecur = empty_string;
1298 1292                  return;
1299 1293          }
1300 1294          if (t_ulon == (char *)-1 || t_uloff == (char *)-1 ||
1301 1295              t_ulon == NULL || t_uloff == NULL) {
1302 1296                  t_ulon = t_uloff = empty_string;  /* can live without it */
1303 1297          }
1304 1298          if (t_smcup == NULL || t_rmcup == NULL)
1305 1299                  t_smcup = t_rmcup = empty_string;
1306 1300          if (t_home == (char *)-1 || t_home == NULL) {
1307 1301                  opts.o_outpmode &= ~OPT_USEHOME;
1308 1302                  t_home = empty_string;
1309 1303          }
1310 1304  }
1311 1305  
1312 1306  static void
1313 1307  sig_handler(int sig)
1314 1308  {
1315 1309          switch (sig) {
1316 1310          case SIGTSTP:   sigtstp = 1;
1317 1311                          break;
1318 1312          case SIGWINCH:  sigwinch = 1;
1319 1313                          break;
1320 1314          case SIGINT:
1321 1315          case SIGTERM:   sigterm = 1;
1322 1316                          break;
1323 1317          }
1324 1318  }
1325 1319  
1326 1320  static void
1327 1321  set_signals()
1328 1322  {
1329 1323          (void) signal(SIGTSTP, sig_handler);
1330 1324          (void) signal(SIGINT, sig_handler);
1331 1325          (void) signal(SIGTERM, sig_handler);
1332 1326          if (opts.o_outpmode & OPT_FULLSCREEN)
1333 1327                  (void) signal(SIGWINCH, sig_handler);
1334 1328  }
1335 1329  
1336 1330  static void
1337 1331  fill_table(table_t *table, char *arg, char option)
1338 1332  {
1339 1333          char *p = strtok(arg, ", ");
1340 1334  
1341 1335          if (p == NULL)
1342 1336                  Die(gettext("invalid argument for -%c\n"), option);
1343 1337  
1344 1338          add_element(table, (long)Atoi(p));
1345 1339          while (p = strtok(NULL, ", "))
1346 1340                  add_element(table, (long)Atoi(p));
1347 1341  }
1348 1342  
1349 1343  static void
1350 1344  fill_prj_table(char *arg)
1351 1345  {
1352 1346          projid_t projid;
1353 1347          char *p = strtok(arg, ", ");
1354 1348  
1355 1349          if (p == NULL)
1356 1350                  Die(gettext("invalid argument for -j\n"));
1357 1351  
1358 1352          if ((projid = getprojidbyname(p)) == -1)
1359 1353                  projid = Atoi(p);
1360 1354          add_element(&prj_tbl, (long)projid);
1361 1355  
1362 1356          while (p = strtok(NULL, ", ")) {
1363 1357                  if ((projid = getprojidbyname(p)) == -1)
1364 1358                          projid = Atoi(p);
1365 1359                  add_element(&prj_tbl, (long)projid);
1366 1360          }
1367 1361  }
1368 1362  
1369 1363  static void
1370 1364  fill_set_table(char *arg)
1371 1365  {
1372 1366          char *p = strtok(arg, ", ");
1373 1367          psetid_t id;
1374 1368  
1375 1369          if (p == NULL)
1376 1370                  Die(gettext("invalid argument for -C\n"));
1377 1371  
1378 1372          if ((id = Atoi(p)) == 0)
1379 1373                  id = PS_NONE;
1380 1374          add_element(&set_tbl, id);
1381 1375          while (p = strtok(NULL, ", ")) {
1382 1376                  if ((id = Atoi(p)) == 0)
1383 1377                          id = PS_NONE;
1384 1378                  if (!has_element(&set_tbl, id))
1385 1379                          add_element(&set_tbl, id);
1386 1380          }
1387 1381  }
1388 1382  
1389 1383  static void
1390 1384  Exit()
1391 1385  {
1392 1386          curses_off();
1393 1387          list_clear(&lwps);
1394 1388          list_clear(&users);
1395 1389          list_clear(&tasks);
1396 1390          list_clear(&projects);
1397 1391          list_clear(&zones);
1398 1392          fd_exit();
1399 1393  }
1400 1394  
1401 1395  
1402 1396  int
1403 1397  main(int argc, char **argv)
1404 1398  {
1405 1399          DIR *procdir;
1406 1400          char *p;
1407 1401          char *sortk = "cpu";    /* default sort key */
1408 1402          int opt;
1409 1403          int timeout;
1410 1404          struct pollfd pollset;
1411 1405          char key;
1412 1406          char procpath[PATH_MAX];
  
    | 
      ↓ open down ↓ | 
    1129 lines elided | 
    
      ↑ open up ↑ | 
  
1413 1407  
1414 1408          (void) setlocale(LC_ALL, "");
1415 1409          (void) textdomain(TEXT_DOMAIN);
1416 1410          Progname(argv[0]);
1417 1411          lwpid_init();
1418 1412          fd_init(Setrlimit());
1419 1413  
1420 1414          pagesize = sysconf(_SC_PAGESIZE);
1421 1415  
1422 1416          while ((opt = getopt(argc, argv,
1423      -            "vVcd:HmarRLtu:U:n:p:C:P:h:s:S:j:k:TJWz:Z")) != (int)EOF) {
     1417 +            "vcd:HmarRLtu:U:n:p:C:P:h:s:S:j:k:TJWz:Z")) != (int)EOF) {
1424 1418                  switch (opt) {
1425 1419                  case 'r':
1426 1420                          opts.o_outpmode |= OPT_NORESOLVE;
1427 1421                          break;
1428 1422                  case 'R':
1429 1423                          opts.o_outpmode |= OPT_REALTIME;
1430 1424                          break;
1431 1425                  case 'c':
1432 1426                          opts.o_outpmode &= ~OPT_TERMCAP;
1433 1427                          opts.o_outpmode &= ~OPT_FULLSCREEN;
1434 1428                          break;
1435 1429                  case 'd':
1436 1430                          if (optarg) {
1437 1431                                  if (*optarg == 'u')
1438 1432                                          opts.o_outpmode |= OPT_UDATE;
1439 1433                                  else if (*optarg == 'd')
1440 1434                                          opts.o_outpmode |= OPT_DDATE;
1441 1435                                  else
1442 1436                                          Usage();
1443 1437                          } else {
1444 1438                                  Usage();
1445 1439                          }
1446 1440                          break;
1447 1441                  case 'h':
1448 1442                          fill_table(&lgr_tbl, optarg, 'h');
1449 1443                          break;
1450 1444                  case 'H':
1451 1445                          opts.o_outpmode |= OPT_LGRP;
1452 1446                          break;
1453 1447                  case 'm':
1454 1448                  case 'v':
1455 1449                          opts.o_outpmode &= ~OPT_PSINFO;
1456 1450                          opts.o_outpmode |=  OPT_MSACCT;
1457 1451                          break;
1458 1452                  case 't':
1459 1453                          opts.o_outpmode &= ~OPT_PSINFO;
1460 1454                          opts.o_outpmode |= OPT_USERS;
1461 1455                          break;
1462 1456                  case 'a':
1463 1457                          opts.o_outpmode |= OPT_SPLIT | OPT_USERS;
1464 1458                          break;
1465 1459                  case 'T':
1466 1460                          opts.o_outpmode |= OPT_SPLIT | OPT_TASKS;
1467 1461                          break;
1468 1462                  case 'J':
1469 1463                          opts.o_outpmode |= OPT_SPLIT | OPT_PROJECTS;
1470 1464                          break;
1471 1465                  case 'n':
1472 1466                          if ((p = strtok(optarg, ",")) == NULL)
1473 1467                                  Die(gettext("invalid argument for -n\n"));
1474 1468                          opts.o_ntop = Atoi(p);
1475 1469                          if (p = strtok(NULL, ","))
1476 1470                                  opts.o_nbottom = Atoi(p);
1477 1471                          else if (opts.o_ntop == 0)
1478 1472                                  opts.o_nbottom = 5;
1479 1473                          opts.o_outpmode &= ~OPT_FULLSCREEN;
1480 1474                          break;
1481 1475                  case 's':
1482 1476                          opts.o_sortorder = -1;
1483 1477                          sortk = optarg;
1484 1478                          break;
1485 1479                  case 'S':
1486 1480                          opts.o_sortorder = 1;
1487 1481                          sortk = optarg;
1488 1482                          break;
1489 1483                  case 'u':
1490 1484                          if ((p = strtok(optarg, ", ")) == NULL)
1491 1485                                  Die(gettext("invalid argument for -u\n"));
1492 1486                          add_uid(&euid_tbl, p);
  
    | 
      ↓ open down ↓ | 
    59 lines elided | 
    
      ↑ open up ↑ | 
  
1493 1487                          while (p = strtok(NULL, ", "))
1494 1488                                  add_uid(&euid_tbl, p);
1495 1489                          break;
1496 1490                  case 'U':
1497 1491                          if ((p = strtok(optarg, ", ")) == NULL)
1498 1492                                  Die(gettext("invalid argument for -U\n"));
1499 1493                          add_uid(&ruid_tbl, p);
1500 1494                          while (p = strtok(NULL, ", "))
1501 1495                                  add_uid(&ruid_tbl, p);
1502 1496                          break;
1503      -                case 'V':
1504      -                        opts.o_outpmode |= OPT_VMUSAGE;
1505      -                        break;
1506 1497                  case 'p':
1507 1498                          fill_table(&pid_tbl, optarg, 'p');
1508 1499                          break;
1509 1500                  case 'C':
1510 1501                          fill_set_table(optarg);
1511 1502                          opts.o_outpmode |= OPT_PSETS;
1512 1503                          break;
1513 1504                  case 'P':
1514 1505                          fill_table(&cpu_tbl, optarg, 'P');
1515 1506                          break;
1516 1507                  case 'k':
1517 1508                          fill_table(&tsk_tbl, optarg, 'k');
1518 1509                          break;
1519 1510                  case 'j':
1520 1511                          fill_prj_table(optarg);
1521 1512                          break;
1522 1513                  case 'L':
1523 1514                          opts.o_outpmode |= OPT_LWPS;
1524 1515                          break;
1525 1516                  case 'W':
1526 1517                          opts.o_outpmode |= OPT_TRUNC;
1527 1518                          break;
1528 1519                  case 'z':
1529 1520                          if ((p = strtok(optarg, ", ")) == NULL)
1530 1521                                  Die(gettext("invalid argument for -z\n"));
1531 1522                          add_zone(&zone_tbl, p);
1532 1523                          while (p = strtok(NULL, ", "))
1533 1524                                  add_zone(&zone_tbl, p);
1534 1525                          break;
1535 1526                  case 'Z':
1536 1527                          opts.o_outpmode |= OPT_SPLIT | OPT_ZONES;
1537 1528                          break;
1538 1529                  default:
1539 1530                          Usage();
1540 1531                  }
1541 1532          }
1542 1533  
1543 1534          (void) atexit(Exit);
1544 1535          if ((opts.o_outpmode & OPT_USERS) &&
1545 1536              !(opts.o_outpmode & OPT_SPLIT))
1546 1537                  opts.o_nbottom = opts.o_ntop;
1547 1538          if (!(opts.o_outpmode & OPT_SPLIT) && opts.o_ntop == 0)
1548 1539                  Die(gettext("invalid argument for -n\n"));
1549 1540          if (opts.o_nbottom == 0)
1550 1541                  Die(gettext("invalid argument for -n\n"));
1551 1542          if (!(opts.o_outpmode & OPT_SPLIT) && (opts.o_outpmode & OPT_USERS) &&
1552 1543              ((opts.o_outpmode & (OPT_PSINFO | OPT_MSACCT))))
1553 1544                  Die(gettext("-t option cannot be used with -v or -m\n"));
1554 1545  
1555 1546          if ((opts.o_outpmode & OPT_SPLIT) && (opts.o_outpmode & OPT_USERS) &&
1556 1547              !((opts.o_outpmode & (OPT_PSINFO | OPT_MSACCT))))
1557 1548                  Die(gettext("-t option cannot be used with "
1558 1549                      "-a, -J, -T or -Z\n"));
1559 1550  
1560 1551          if ((opts.o_outpmode & OPT_USERS) &&
1561 1552              (opts.o_outpmode & (OPT_TASKS | OPT_PROJECTS | OPT_ZONES)))
1562 1553                  Die(gettext("-a option cannot be used with "
1563 1554                      "-t, -J, -T or -Z\n"));
1564 1555  
1565 1556          if (((opts.o_outpmode & OPT_TASKS) &&
1566 1557              (opts.o_outpmode & (OPT_PROJECTS|OPT_ZONES))) ||
1567 1558              ((opts.o_outpmode & OPT_PROJECTS) &&
1568 1559              (opts.o_outpmode & (OPT_TASKS|OPT_ZONES)))) {
1569 1560                  Die(gettext(
1570 1561                      "-J, -T and -Z options are mutually exclusive\n"));
1571 1562          }
1572 1563  
1573 1564          /*
1574 1565           * There is not enough space to combine microstate information and
1575 1566           * lgroup information and still fit in 80-column output.
1576 1567           */
1577 1568          if ((opts.o_outpmode & OPT_LGRP) && (opts.o_outpmode & OPT_MSACCT)) {
1578 1569                  Die(gettext("-H and -m options are mutually exclusive\n"));
1579 1570          }
1580 1571  
1581 1572          if (argc > optind)
1582 1573                  opts.o_interval = Atoi(argv[optind++]);
1583 1574          if (argc > optind)
1584 1575                  opts.o_count = Atoi(argv[optind++]);
1585 1576          if (opts.o_count == 0)
1586 1577                  Die(gettext("invalid counter value\n"));
1587 1578          if (argc > optind)
1588 1579                  Usage();
1589 1580          if (opts.o_outpmode & OPT_REALTIME)
1590 1581                  Priocntl("RT");
1591 1582          if (isatty(STDOUT_FILENO) == 1 && isatty(STDIN_FILENO))
1592 1583                  opts.o_outpmode |= OPT_TTY;     /* interactive */
1593 1584          if (!(opts.o_outpmode & OPT_TTY)) {
1594 1585                  opts.o_outpmode &= ~OPT_TERMCAP; /* no termcap for pipes */
1595 1586                  opts.o_outpmode &= ~OPT_FULLSCREEN;
1596 1587          }
1597 1588          if (opts.o_outpmode & OPT_TERMCAP)
1598 1589                  ldtermcap();            /* can turn OPT_TERMCAP off */
1599 1590          if (opts.o_outpmode & OPT_TERMCAP)
1600 1591                  (void) setsize();
1601 1592          list_alloc(&lwps, opts.o_ntop);
1602 1593          list_alloc(&users, opts.o_nbottom);
1603 1594          list_alloc(&tasks, opts.o_nbottom);
1604 1595          list_alloc(&projects, opts.o_nbottom);
1605 1596          list_alloc(&zones, opts.o_nbottom);
1606 1597          list_alloc(&lgroups, opts.o_nbottom);
1607 1598          list_setkeyfunc(sortk, &opts, &lwps, LT_LWPS);
1608 1599          list_setkeyfunc(NULL, &opts, &users, LT_USERS);
1609 1600          list_setkeyfunc(NULL, &opts, &tasks, LT_TASKS);
1610 1601          list_setkeyfunc(NULL, &opts, &projects, LT_PROJECTS);
1611 1602          list_setkeyfunc(NULL, &opts, &zones, LT_ZONES);
1612 1603          list_setkeyfunc(NULL, &opts, &lgroups, LT_LGRPS);
1613 1604          if (opts.o_outpmode & OPT_TERMCAP)
1614 1605                  curses_on();
1615 1606          (void) proc_snprintf(procpath, sizeof (procpath), "/proc");
1616 1607          if ((procdir = opendir(procpath)) == NULL)
1617 1608                  Die(gettext("cannot open /proc directory\n"));
1618 1609          if (opts.o_outpmode & OPT_TTY) {
1619 1610                  (void) printf(gettext("Please wait...\r"));
1620 1611                  if (!(opts.o_outpmode & OPT_TERMCAP))
1621 1612                          (void) putchar('\n');
1622 1613                  (void) fflush(stdout);
1623 1614          }
1624 1615          set_signals();
1625 1616          pollset.fd = STDIN_FILENO;
1626 1617          pollset.events = POLLIN;
1627 1618          timeout = opts.o_interval * MILLISEC;
1628 1619  
1629 1620          /*
1630 1621           * main program loop
1631 1622           */
1632 1623          do {
1633 1624                  if (sigterm == 1)
1634 1625                          break;
1635 1626                  if (sigtstp == 1) {
1636 1627                          curses_off();
1637 1628                          (void) signal(SIGTSTP, SIG_DFL);
1638 1629                          (void) kill(0, SIGTSTP);
1639 1630                          /*
1640 1631                           * prstat stops here until it receives SIGCONT signal.
1641 1632                           */
1642 1633                          sigtstp = 0;
1643 1634                          (void) signal(SIGTSTP, sig_handler);
1644 1635                          curses_on();
1645 1636                          print_movecur = FALSE;
1646 1637                          if (opts.o_outpmode & OPT_FULLSCREEN)
1647 1638                                  sigwinch = 1;
1648 1639                  }
1649 1640                  if (sigwinch == 1) {
1650 1641                          if (setsize() == 1) {
1651 1642                                  list_free(&lwps);
1652 1643                                  list_free(&users);
1653 1644                                  list_free(&tasks);
1654 1645                                  list_free(&projects);
1655 1646                                  list_free(&zones);
1656 1647                                  list_alloc(&lwps, opts.o_ntop);
1657 1648                                  list_alloc(&users, opts.o_nbottom);
1658 1649                                  list_alloc(&tasks, opts.o_nbottom);
1659 1650                                  list_alloc(&projects, opts.o_nbottom);
1660 1651                                  list_alloc(&zones, opts.o_nbottom);
1661 1652                          }
1662 1653                          sigwinch = 0;
1663 1654                          (void) signal(SIGWINCH, sig_handler);
1664 1655                  }
1665 1656                  prstat_scandir(procdir);
1666 1657                  list_refresh(&lwps);
1667 1658                  if (print_movecur)
1668 1659                          (void) putp(movecur);
1669 1660                  print_movecur = TRUE;
1670 1661                  if ((opts.o_outpmode & OPT_PSINFO) ||
1671 1662                      (opts.o_outpmode & OPT_MSACCT)) {
1672 1663                          list_sort(&lwps);
1673 1664                          list_print(&lwps);
1674 1665                  }
1675 1666                  if (opts.o_outpmode & OPT_USERS) {
1676 1667                          list_getsize(&users);
1677 1668                          list_sort(&users);
1678 1669                          list_print(&users);
1679 1670                          list_clear(&users);
1680 1671                  }
1681 1672                  if (opts.o_outpmode & OPT_TASKS) {
1682 1673                          list_getsize(&tasks);
1683 1674                          list_sort(&tasks);
1684 1675                          list_print(&tasks);
1685 1676                          list_clear(&tasks);
1686 1677                  }
1687 1678                  if (opts.o_outpmode & OPT_PROJECTS) {
1688 1679                          list_getsize(&projects);
1689 1680                          list_sort(&projects);
1690 1681                          list_print(&projects);
1691 1682                          list_clear(&projects);
1692 1683                  }
1693 1684                  if (opts.o_outpmode & OPT_ZONES) {
1694 1685                          list_getsize(&zones);
1695 1686                          list_sort(&zones);
1696 1687                          list_print(&zones);
1697 1688                          list_clear(&zones);
1698 1689                  }
1699 1690                  if (opts.o_count == 1)
1700 1691                          break;
1701 1692                  /*
1702 1693                   * If poll() returns -1 and sets errno to EINTR here because
1703 1694                   * the process received a signal, it is Ok to abort this
1704 1695                   * timeout and loop around because we check the signals at the
1705 1696                   * top of the loop.
1706 1697                   */
1707 1698                  if (opts.o_outpmode & OPT_TTY) {
1708 1699                          if (poll(&pollset, (nfds_t)1, timeout) > 0) {
1709 1700                                  if (read(STDIN_FILENO, &key, 1) == 1) {
1710 1701                                          if (tolower(key) == 'q')
1711 1702                                                  break;
1712 1703                                  }
1713 1704                          }
1714 1705                  } else {
1715 1706                          (void) sleep(opts.o_interval);
1716 1707                  }
1717 1708          } while (opts.o_count == (-1) || --opts.o_count);
1718 1709  
1719 1710          if (opts.o_outpmode & OPT_TTY)
1720 1711                  (void) putchar('\r');
1721 1712          return (0);
1722 1713  }
  
    | 
      ↓ open down ↓ | 
    207 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX