Print this page
    
2989 Eliminate use of LOGNAME_MAX in ON
1166 useradd have warning with name more 8 chars
    
      
        | Split | Close | 
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/cmd/w/w.c
          +++ new/usr/src/cmd/w/w.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.
  
    | ↓ open down ↓ | 11 lines elided | ↑ open up ↑ | 
  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 + * Copyright (c) 2013 Gary Mills
       23 + *
  22   24   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23   25   * Use is subject to license terms.
  24   26   */
  25   27  
  26   28  /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
  27   29  /*        All Rights Reserved   */
  28   30  
  29   31  /*
  30   32   * University Copyright- Copyright (c) 1982, 1986, 1988
  31   33   * The Regents of the University of California
  32   34   * All Rights Reserved
  33   35   *
  34   36   * University Acknowledgment- Portions of this document are derived from
  35   37   * software developed by the University of California, Berkeley, and its
  36   38   * contributors.
  37   39   */
  38   40  
  39   41  /*
  40   42   * This is the new w command which takes advantage of
  41   43   * the /proc interface to gain access to the information
  42   44   * of all the processes currently on the system.
  43   45   *
  44   46   * This program also implements 'uptime'.
  45   47   *
  46   48   * Maintenance note:
  47   49   *
  48   50   * Much of this code is replicated in whodo.c.  If you're
  49   51   * fixing bugs here, then you should probably fix 'em there too.
  50   52   */
  51   53  
  52   54  #include <stdio.h>
  53   55  #include <string.h>
  54   56  #include <stdarg.h>
  55   57  #include <stdlib.h>
  56   58  #include <ctype.h>
  57   59  #include <fcntl.h>
  58   60  #include <time.h>
  59   61  #include <errno.h>
  60   62  #include <sys/types.h>
  61   63  #include <utmpx.h>
  
    | ↓ open down ↓ | 30 lines elided | ↑ open up ↑ | 
  62   64  #include <sys/stat.h>
  63   65  #include <dirent.h>
  64   66  #include <procfs.h>             /* /proc header file */
  65   67  #include <locale.h>
  66   68  #include <unistd.h>
  67   69  #include <sys/loadavg.h>
  68   70  #include <limits.h>
  69   71  #include <priv_utils.h>
  70   72  
  71   73  /*
  72      - * utmpx defines wider fields for user and line.  For compatibility of output,
  73      - * we are limiting these to the old maximums in utmp. Define UTMPX_NAMELEN
  74      - * to use the full lengths.
       74 + * Use the full lengths from utmpx for user and line.
  75   75   */
  76      -#ifndef UTMPX_NAMELEN
  77      -/* XXX - utmp - fix name length */
  78      -#define NMAX            (_POSIX_LOGIN_NAME_MAX - 1)
  79      -#define LMAX            12
  80      -#else   /* UTMPX_NAMELEN */
  81   76  static struct utmpx dummy;
  82   77  #define NMAX            (sizeof (dummy.ut_user))
  83   78  #define LMAX            (sizeof (dummy.ut_line))
  84      -#endif /* UTMPX_NAMELEN */
  85   79  
       80 +/* Print minimum field widths. */
       81 +#define LOGIN_WIDTH     8
       82 +#define LINE_WIDTH      12
       83 +
  86   84  #define DIV60(t)        ((t+30)/60)     /* x/60 rounded */
  87   85  
  88   86  #ifdef ERR
  89   87  #undef ERR
  90   88  #endif
  91   89  #define ERR             (-1)
  92   90  
  93   91  #define HSIZE           256             /* size of process hash table   */
  94   92  #define PROCDIR         "/proc"
  95   93  #define INITPROCESS     (pid_t)1        /* init process pid */
  96   94  #define NONE            'n'             /* no state */
  97   95  #define RUNNING         'r'             /* runnable process */
  98   96  #define ZOMBIE          'z'             /* zombie process */
  99   97  #define VISITED         'v'             /* marked node as visited */
 100   98  #define PRINTF(a)       if (printf a < 0) { \
 101   99                  perror((gettext("%s: printf failed"), prog)); \
 102  100                  exit(1); }
 103  101  
 104  102  struct uproc {
 105  103          pid_t   p_upid;                 /* process id */
 106  104          char    p_state;                /* numeric value of process state */
 107  105          dev_t   p_ttyd;                 /* controlling tty of process */
 108  106          time_t  p_time;                 /* seconds of user & system time */
 109  107          time_t  p_ctime;                /* seconds of child user & sys time */
 110  108          int     p_igintr;               /* 1 = ignores SIGQUIT and SIGINT */
 111  109          char    p_comm[PRARGSZ+1];      /* command */
 112  110          char    p_args[PRARGSZ+1];      /* command line arguments */
 113  111          struct uproc    *p_child,       /* first child pointer */
 114  112                          *p_sibling,     /* sibling pointer */
 115  113                          *p_pgrpl,       /* pgrp link */
 116  114                          *p_link;        /* hash table chain pointer */
 117  115  };
 118  116  
 119  117  /*
 120  118   *      define hash table for struct uproc
 121  119   *      Hash function uses process id
 122  120   *      and the size of the hash table(HSIZE)
 123  121   *      to determine process index into the table.
 124  122   */
 125  123  static struct uproc     pr_htbl[HSIZE];
 126  124  
 127  125  static struct   uproc   *findhash(pid_t);
 128  126  static time_t   findidle(char *);
 129  127  static void     clnarglist(char *);
 130  128  static void     showtotals(struct uproc *);
 131  129  static void     calctotals(struct uproc *);
 132  130  static void     prttime(time_t, char *);
 133  131  static void     prtat(time_t *time);
 134  132  static void     checkampm(char *str);
 135  133  
 136  134  static char     *prog;          /* pointer to invocation name */
 137  135  static int      header = 1;     /* true if -h flag: don't print heading */
 138  136  static int      lflag = 1;      /* set if -l flag; 0 for -s flag: short form */
 139  137  static char     *sel_user;      /* login of particular user selected */
 140  138  static char     firstchar;      /* first char of name of prog invoked as */
 141  139  static int      login;          /* true if invoked as login shell */
 142  140  static time_t   now;            /* current time of day */
 143  141  static time_t   uptime;         /* time of last reboot & elapsed time since */
 144  142  static int      nusers;         /* number of users logged in now */
 145  143  static time_t   idle;           /* number of minutes user is idle */
 146  144  static time_t   jobtime;        /* total cpu time visible */
 147  145  static char     doing[520];     /* process attached to terminal */
 148  146  static time_t   proctime;       /* cpu time of process in doing */
 149  147  static pid_t    curpid, empty;
 150  148  static int      add_times;      /* boolean: add the cpu times or not */
 151  149  
 152  150  #if SIGQUIT > SIGINT
 153  151  #define ACTSIZE SIGQUIT
 154  152  #else
 155  153  #define ACTSIZE SIGINT
 156  154  #endif
 157  155  
 158  156  int
 159  157  main(int argc, char *argv[])
 160  158  {
 161  159          struct utmpx    *ut;
 162  160          struct utmpx    *utmpbegin;
 163  161          struct utmpx    *utmpend;
 164  162          struct utmpx    *utp;
 165  163          struct uproc    *up, *parent, *pgrp;
 166  164          struct psinfo   info;
 167  165          struct sigaction actinfo[ACTSIZE];
 168  166          struct pstatus  statinfo;
 169  167          size_t          size;
 170  168          struct stat     sbuf;
 171  169          DIR             *dirp;
 172  170          struct  dirent  *dp;
 173  171          char            pname[64];
 174  172          char            *fname;
 175  173          int             procfd;
 176  174          char            *cp;
 177  175          int             i;
 178  176          int             days, hrs, mins;
 179  177          int             entries;
 180  178          double          loadavg[3];
 181  179  
 182  180          /*
 183  181           * This program needs the proc_owner privilege
 184  182           */
 185  183          (void) __init_suid_priv(PU_CLEARLIMITSET, PRIV_PROC_OWNER,
 186  184              (char *)NULL);
 187  185  
 188  186          (void) setlocale(LC_ALL, "");
 189  187  #if !defined(TEXT_DOMAIN)
 190  188  #define TEXT_DOMAIN "SYS_TEST"
 191  189  #endif
 192  190          (void) textdomain(TEXT_DOMAIN);
 193  191  
 194  192          login = (argv[0][0] == '-');
 195  193          cp = strrchr(argv[0], '/');
 196  194          firstchar = login ? argv[0][1] : (cp == 0) ? argv[0][0] : cp[1];
 197  195          prog = argv[0];
 198  196  
 199  197          while (argc > 1) {
 200  198                  if (argv[1][0] == '-') {
 201  199                          for (i = 1; argv[1][i]; i++) {
 202  200                                  switch (argv[1][i]) {
 203  201  
 204  202                                  case 'h':
 205  203                                          header = 0;
 206  204                                          break;
 207  205  
 208  206                                  case 'l':
 209  207                                          lflag++;
 210  208                                          break;
 211  209                                  case 's':
 212  210                                          lflag = 0;
 213  211                                          break;
 214  212  
 215  213                                  case 'u':
 216  214                                  case 'w':
 217  215                                          firstchar = argv[1][i];
 218  216                                          break;
 219  217  
 220  218                                  default:
 221  219                                          (void) fprintf(stderr, gettext(
 222  220                                              "%s: bad flag %s\n"),
 223  221                                              prog, argv[1]);
 224  222                                          exit(1);
 225  223                                  }
 226  224                          }
 227  225                  } else {
 228  226                          if (!isalnum(argv[1][0]) || argc > 2) {
 229  227                                  (void) fprintf(stderr, gettext(
 230  228                                      "usage: %s [ -hlsuw ] [ user ]\n"), prog);
 231  229                                  exit(1);
 232  230                          } else
 233  231                                  sel_user = argv[1];
 234  232                  }
 235  233                  argc--; argv++;
 236  234          }
 237  235  
 238  236          /*
 239  237           * read the UTMP_FILE (contains information about each logged in user)
 240  238           */
 241  239          if (stat(UTMPX_FILE, &sbuf) == ERR) {
 242  240                  (void) fprintf(stderr, gettext("%s: stat error of %s: %s\n"),
 243  241                      prog, UTMPX_FILE, strerror(errno));
 244  242                  exit(1);
 245  243          }
 246  244          entries = sbuf.st_size / sizeof (struct futmpx);
 247  245          size = sizeof (struct utmpx) * entries;
 248  246          if ((ut = malloc(size)) == NULL) {
 249  247                  (void) fprintf(stderr, gettext("%s: malloc error of %s: %s\n"),
 250  248                      prog, UTMPX_FILE, strerror(errno));
 251  249                  exit(1);
 252  250          }
 253  251  
 254  252          (void) utmpxname(UTMPX_FILE);
 255  253  
 256  254          utmpbegin = ut;
 257  255          utmpend = (struct utmpx *)((char *)utmpbegin + size);
 258  256  
 259  257          setutxent();
 260  258          while ((ut < utmpend) && ((utp = getutxent()) != NULL))
 261  259                  (void) memcpy(ut++, utp, sizeof (*ut));
 262  260          endutxent();
 263  261  
 264  262          (void) time(&now);      /* get current time */
 265  263  
 266  264          if (header) {   /* print a header */
 267  265                  prtat(&now);
 268  266                  for (ut = utmpbegin; ut < utmpend; ut++) {
 269  267                          if (ut->ut_type == USER_PROCESS) {
 270  268                                  if (!nonuser(*ut))
 271  269                                          nusers++;
 272  270                          } else if (ut->ut_type == BOOT_TIME) {
 273  271                                  uptime = now - ut->ut_xtime;
 274  272                                  uptime += 30;
 275  273                                  days = uptime / (60*60*24);
 276  274                                  uptime %= (60*60*24);
 277  275                                  hrs = uptime / (60*60);
 278  276                                  uptime %= (60*60);
 279  277                                  mins = uptime / 60;
 280  278  
 281  279                                  PRINTF((gettext("  up")));
 282  280                                  if (days > 0)
 283  281                                          PRINTF((gettext(
 284  282                                              " %d day(s),"), days));
 285  283                                  if (hrs > 0 && mins > 0) {
 286  284                                          PRINTF((" %2d:%02d,", hrs, mins));
 287  285                                  } else {
 288  286                                          if (hrs > 0)
 289  287                                                  PRINTF((gettext(
 290  288                                                      " %d hr(s),"), hrs));
 291  289                                          if (mins > 0)
 292  290                                                  PRINTF((gettext(
 293  291                                                      " %d min(s),"), mins));
 294  292                                  }
 295  293                          }
 296  294                  }
 297  295  
 298  296                  ut = utmpbegin; /* rewind utmp data */
 299  297                  PRINTF((((nusers == 1) ?
 300  298                      gettext("  %d user") : gettext("  %d users")), nusers));
 301  299                  /*
 302  300                   * Print 1, 5, and 15 minute load averages.
 303  301                   */
 304  302                  (void) getloadavg(loadavg, 3);
 305  303                  PRINTF((gettext(",  load average: %.2f, %.2f, %.2f\n"),
 306  304                      loadavg[LOADAVG_1MIN], loadavg[LOADAVG_5MIN],
 307  305                      loadavg[LOADAVG_15MIN]));
 308  306  
 309  307                  if (firstchar == 'u')   /* uptime command */
 310  308                          exit(0);
 311  309  
 312  310                  if (lflag) {
 313  311                          PRINTF((dcgettext(NULL, "User     tty           "
 314  312                              "login@  idle   JCPU   PCPU  what\n", LC_TIME)));
 315  313                  } else {
 316  314                          PRINTF((dcgettext(NULL,
 317  315                              "User     tty           idle   what\n", LC_TIME)));
 318  316                  }
 319  317  
 320  318                  if (fflush(stdout) == EOF) {
 321  319                          perror((gettext("%s: fflush failed\n"), prog));
 322  320                          exit(1);
 323  321                  }
 324  322          }
 325  323  
 326  324          /*
 327  325           * loop through /proc, reading info about each process
 328  326           * and build the parent/child tree
 329  327           */
 330  328          if (!(dirp = opendir(PROCDIR))) {
 331  329                  (void) fprintf(stderr, gettext("%s: could not open %s: %s\n"),
 332  330                      prog, PROCDIR, strerror(errno));
 333  331                  exit(1);
 334  332          }
 335  333  
 336  334          while ((dp = readdir(dirp)) != NULL) {
 337  335                  if (dp->d_name[0] == '.')
 338  336                          continue;
 339  337  retry:
 340  338                  (void) sprintf(pname, "%s/%s/", PROCDIR, dp->d_name);
 341  339                  fname = pname + strlen(pname);
 342  340                  (void) strcpy(fname, "psinfo");
 343  341                  if ((procfd = open(pname, O_RDONLY)) < 0)
 344  342                          continue;
 345  343                  if (read(procfd, &info, sizeof (info)) != sizeof (info)) {
 346  344                          int err = errno;
 347  345                          (void) close(procfd);
 348  346                          if (err == EAGAIN)
 349  347                                  goto retry;
 350  348                          if (err != ENOENT)
 351  349                                  (void) fprintf(stderr, gettext(
 352  350                                      "%s: read() failed on %s: %s \n"),
 353  351                                      prog, pname, strerror(err));
 354  352                          continue;
 355  353                  }
 356  354                  (void) close(procfd);
 357  355  
 358  356                  up = findhash(info.pr_pid);
 359  357                  up->p_ttyd = info.pr_ttydev;
 360  358                  up->p_state = (info.pr_nlwp == 0? ZOMBIE : RUNNING);
 361  359                  up->p_time = 0;
 362  360                  up->p_ctime = 0;
 363  361                  up->p_igintr = 0;
 364  362                  (void) strncpy(up->p_comm, info.pr_fname,
 365  363                      sizeof (info.pr_fname));
 366  364                  up->p_args[0] = 0;
 367  365  
 368  366                  if (up->p_state != NONE && up->p_state != ZOMBIE) {
 369  367                          (void) strcpy(fname, "status");
 370  368  
 371  369                          /* now we need the proc_owner privilege */
 372  370                          (void) __priv_bracket(PRIV_ON);
 373  371  
 374  372                          procfd = open(pname, O_RDONLY);
 375  373  
 376  374                          /* drop proc_owner privilege after open */
 377  375                          (void) __priv_bracket(PRIV_OFF);
 378  376  
 379  377                          if (procfd < 0)
 380  378                                  continue;
 381  379  
 382  380                          if (read(procfd, &statinfo, sizeof (statinfo))
 383  381                              != sizeof (statinfo)) {
 384  382                                  int err = errno;
 385  383                                  (void) close(procfd);
 386  384                                  if (err == EAGAIN)
 387  385                                          goto retry;
 388  386                                  if (err != ENOENT)
 389  387                                          (void) fprintf(stderr, gettext(
 390  388                                              "%s: read() failed on %s: %s \n"),
 391  389                                              prog, pname, strerror(err));
 392  390                                  continue;
 393  391                          }
 394  392                          (void) close(procfd);
 395  393  
 396  394                          up->p_time = statinfo.pr_utime.tv_sec +
 397  395                              statinfo.pr_stime.tv_sec;   /* seconds */
 398  396                          up->p_ctime = statinfo.pr_cutime.tv_sec +
 399  397                              statinfo.pr_cstime.tv_sec;
 400  398  
 401  399                          (void) strcpy(fname, "sigact");
 402  400  
 403  401                          /* now we need the proc_owner privilege */
 404  402                          (void) __priv_bracket(PRIV_ON);
 405  403  
 406  404                          procfd = open(pname, O_RDONLY);
 407  405  
 408  406                          /* drop proc_owner privilege after open */
 409  407                          (void) __priv_bracket(PRIV_OFF);
 410  408  
 411  409                          if (procfd < 0)
 412  410                                  continue;
 413  411  
 414  412                          if (read(procfd, actinfo, sizeof (actinfo))
 415  413                              != sizeof (actinfo)) {
 416  414                                  int err = errno;
 417  415                                  (void) close(procfd);
 418  416                                  if (err == EAGAIN)
 419  417                                          goto retry;
 420  418                                  if (err != ENOENT)
 421  419                                          (void) fprintf(stderr, gettext(
 422  420                                              "%s: read() failed on %s: %s \n"),
 423  421                                              prog, pname, strerror(err));
 424  422                                  continue;
 425  423                          }
 426  424                          (void) close(procfd);
 427  425  
 428  426                          up->p_igintr =
 429  427                              actinfo[SIGINT-1].sa_handler == SIG_IGN &&
 430  428                              actinfo[SIGQUIT-1].sa_handler == SIG_IGN;
 431  429  
 432  430                          /*
 433  431                           * Process args.
 434  432                           */
 435  433                          up->p_args[0] = 0;
 436  434                          clnarglist(info.pr_psargs);
 437  435                          (void) strcat(up->p_args, info.pr_psargs);
 438  436                          if (up->p_args[0] == 0 ||
 439  437                              up->p_args[0] == '-' && up->p_args[1] <= ' ' ||
 440  438                              up->p_args[0] == '?') {
 441  439                                  (void) strcat(up->p_args, " (");
 442  440                                  (void) strcat(up->p_args, up->p_comm);
 443  441                                  (void) strcat(up->p_args, ")");
 444  442                          }
 445  443                  }
 446  444  
 447  445                  /*
 448  446                   * link pgrp together in case parents go away
 449  447                   * Pgrp chain is a single linked list originating
 450  448                   * from the pgrp leader to its group member.
 451  449                   */
 452  450                  if (info.pr_pgid != info.pr_pid) {      /* not pgrp leader */
 453  451                          pgrp = findhash(info.pr_pgid);
 454  452                          up->p_pgrpl = pgrp->p_pgrpl;
 455  453                          pgrp->p_pgrpl = up;
 456  454                  }
 457  455                  parent = findhash(info.pr_ppid);
 458  456  
 459  457                  /* if this is the new member, link it in */
 460  458                  if (parent->p_upid != INITPROCESS) {
 461  459                          if (parent->p_child) {
 462  460                                  up->p_sibling = parent->p_child;
 463  461                                  up->p_child = 0;
 464  462                          }
 465  463                          parent->p_child = up;
 466  464                  }
 467  465          }
 468  466  
 469  467          /* revert to non-privileged user after opening */
 470  468          (void) __priv_relinquish();
 471  469  
 472  470          (void) closedir(dirp);
 473  471          (void) time(&now);      /* get current time */
 474  472  
 475  473          /*
  
    | ↓ open down ↓ | 380 lines elided | ↑ open up ↑ | 
 476  474           * loop through utmpx file, printing process info
 477  475           * about each logged in user
 478  476           */
 479  477          for (ut = utmpbegin; ut < utmpend; ut++) {
 480  478                  if (ut->ut_type != USER_PROCESS)
 481  479                          continue;
 482  480                  if (sel_user && strncmp(ut->ut_name, sel_user, NMAX) != 0)
 483  481                          continue;       /* we're looking for somebody else */
 484  482  
 485  483                  /* print login name of the user */
 486      -                PRINTF(("%-*.*s ", NMAX, NMAX, ut->ut_name));
      484 +                PRINTF(("%-*.*s ", LOGIN_WIDTH, NMAX, ut->ut_name));
 487  485  
 488  486                  /* print tty user is on */
 489  487                  if (lflag) {
 490      -                        PRINTF(("%-*.*s", LMAX, LMAX, ut->ut_line));
      488 +                        PRINTF(("%-*.*s", LINE_WIDTH, LMAX, ut->ut_line));
 491  489                  } else {
 492  490                          if (ut->ut_line[0] == 'p' && ut->ut_line[1] == 't' &&
 493  491                              ut->ut_line[2] == 's' && ut->ut_line[3] == '/') {
 494  492                                  PRINTF(("%-*.3s", LMAX, &ut->ut_line[4]));
 495  493                          } else {
 496      -                                PRINTF(("%-*.*s", LMAX, LMAX, ut->ut_line));
      494 +                                PRINTF(("%-*.*s", LINE_WIDTH, LMAX,
      495 +                                    ut->ut_line));
 497  496                          }
 498  497                  }
 499  498  
 500  499                  /* print when the user logged in */
 501  500                  if (lflag) {
 502  501                          time_t tim = ut->ut_xtime;
 503  502                          prtat(&tim);
 504  503                  }
 505  504  
 506  505                  /* print idle time */
 507  506                  idle = findidle(ut->ut_line);
 508  507                  if (idle >= 36 * 60) {
 509  508                          PRINTF((dcgettext(NULL, "%2ddays ", LC_TIME),
 510  509                              (idle + 12 * 60) / (24 * 60)));
 511  510                  } else
 512  511                          prttime(idle, " ");
 513  512                  showtotals(findhash(ut->ut_pid));
 514  513          }
 515  514          if (fclose(stdout) == EOF) {
 516  515                  perror((gettext("%s: fclose failed"), prog));
 517  516                  exit(1);
 518  517          }
 519  518          return (0);
 520  519  }
 521  520  
 522  521  /*
 523  522   *  Prints the CPU time for all processes & children,
 524  523   *  and the cpu time for interesting process,
 525  524   *  and what the user is doing.
 526  525   */
 527  526  static void
 528  527  showtotals(struct uproc *up)
 529  528  {
 530  529          jobtime = 0;
 531  530          proctime = 0;
 532  531          empty = 1;
 533  532          curpid = -1;
 534  533          add_times = 1;
 535  534  
 536  535          calctotals(up);
 537  536  
 538  537          if (lflag) {
 539  538                  /* print CPU time for all processes & children */
 540  539                  /* and need to convert clock ticks to seconds first */
 541  540                  prttime((time_t)jobtime, " ");
 542  541  
 543  542                  /* print cpu time for interesting process */
 544  543                  /* and need to convert clock ticks to seconds first */
 545  544                  prttime((time_t)proctime, " ");
 546  545          }
 547  546          /* what user is doing, current process */
 548  547          PRINTF((" %-.32s\n", doing));
 549  548  }
 550  549  
 551  550  /*
 552  551   *  This recursive routine descends the process
 553  552   *  tree starting from the given process pointer(up).
 554  553   *  It used depth-first search strategy and also marked
 555  554   *  each node as visited as it traversed down the tree.
 556  555   *  It calculates the process time for all processes &
 557  556   *  children.  It also finds the interesting process
 558  557   *  and determines its cpu time and command.
 559  558   */
 560  559  static void
 561  560  calctotals(struct uproc *up)
 562  561  {
 563  562          struct uproc   *zp;
 564  563  
 565  564          /*
 566  565           * Once a node has been visited, stop adding cpu times
 567  566           * for its children so they don't get totalled twice.
 568  567           * Still look for the interesting job for this utmp
 569  568           * entry, however.
 570  569           */
 571  570          if (up->p_state == VISITED)
 572  571                  add_times = 0;
 573  572          up->p_state = VISITED;
 574  573          if (up->p_state == NONE || up->p_state == ZOMBIE)
 575  574                  return;
 576  575  
 577  576          if (empty && !up->p_igintr) {
 578  577                  empty = 0;
 579  578                  curpid = -1;
 580  579          }
 581  580  
 582  581          if (up->p_upid > curpid && (!up->p_igintr || empty)) {
 583  582                  curpid = up->p_upid;
 584  583                  if (lflag)
 585  584                          (void) strcpy(doing, up->p_args);
 586  585                  else
 587  586                          (void) strcpy(doing, up->p_comm);
 588  587          }
 589  588  
 590  589          if (add_times == 1) {
 591  590                  jobtime += up->p_time + up->p_ctime;
 592  591                  proctime += up->p_time;
 593  592          }
 594  593  
 595  594          /* descend for its children */
 596  595          if (up->p_child) {
 597  596                  calctotals(up->p_child);
 598  597                  for (zp = up->p_child->p_sibling; zp; zp = zp->p_sibling)
 599  598                          calctotals(zp);
 600  599          }
 601  600  }
 602  601  
 603  602  /*
 604  603   *   Findhash  finds the appropriate entry in the process
 605  604   *   hash table (pr_htbl) for the given pid in case that
 606  605   *   pid exists on the hash chain. It returns back a pointer
 607  606   *   to that uproc structure. If this is a new pid, it allocates
 608  607   *   a new node, initializes it, links it into the chain (after
 609  608   *   head) and returns a structure pointer.
 610  609   */
 611  610  static struct uproc *
 612  611  findhash(pid_t pid)
 613  612  {
 614  613          struct uproc *up, *tp;
 615  614  
 616  615          tp = up = &pr_htbl[pid % HSIZE];
 617  616          if (up->p_upid == 0) {                  /* empty slot */
 618  617                  up->p_upid = pid;
 619  618                  up->p_state = NONE;
 620  619                  up->p_child = up->p_sibling = up->p_pgrpl = up->p_link = 0;
 621  620                  return (up);
 622  621          }
 623  622          if (up->p_upid == pid) {                /* found in hash table */
 624  623                  return (up);
 625  624          }
 626  625          for (tp = up->p_link; tp; tp = tp->p_link) {    /* follow chain */
 627  626                  if (tp->p_upid == pid)
 628  627                          return (tp);
 629  628          }
 630  629          tp = malloc(sizeof (*tp));              /* add new node */
 631  630          if (!tp) {
 632  631                  (void) fprintf(stderr, gettext("%s: out of memory!: %s\n"),
 633  632                      prog, strerror(errno));
 634  633                  exit(1);
 635  634          }
 636  635          (void) memset(tp, 0, sizeof (*tp));
 637  636          tp->p_upid = pid;
 638  637          tp->p_state = NONE;
 639  638          tp->p_child = tp->p_sibling = tp->p_pgrpl = 0;
 640  639          tp->p_link = up->p_link;                /* insert after head */
 641  640          up->p_link = tp;
 642  641          return (tp);
 643  642  }
 644  643  
 645  644  #define HR      (60 * 60)
 646  645  #define DAY     (24 * HR)
 647  646  #define MON     (30 * DAY)
 648  647  
 649  648  /*
 650  649   * prttime prints a time in hours and minutes or minutes and seconds.
 651  650   * The character string tail is printed at the end, obvious
 652  651   * strings to pass are "", " ", or "am".
 653  652   */
 654  653  static void
 655  654  prttime(time_t tim, char *tail)
 656  655  {
 657  656          if (tim >= 60) {
 658  657                  PRINTF((dcgettext(NULL, "%3d:%02d", LC_TIME),
 659  658                      (int)tim/60, (int)tim%60));
 660  659          } else if (tim > 0) {
 661  660                  PRINTF((dcgettext(NULL, "    %2d", LC_TIME), (int)tim));
 662  661          } else {
 663  662                  PRINTF(("      "));
 664  663          }
 665  664          PRINTF(("%s", tail));
 666  665  }
 667  666  
 668  667  /*
 669  668   * prints a 12 hour time given a pointer to a time of day
 670  669   */
 671  670  static void
 672  671  prtat(time_t *time)
 673  672  {
 674  673          struct tm       *p;
 675  674  
 676  675          p = localtime(time);
 677  676          if (now - *time <= 18 * HR) {
 678  677                  char timestr[50];
 679  678                  (void) strftime(timestr, sizeof (timestr),
 680  679                      dcgettext(NULL, "%l:%M""%p", LC_TIME), p);
 681  680                  checkampm(timestr);
 682  681                  PRINTF((" %s", timestr));
 683  682          } else if (now - *time <= 7 * DAY) {
 684  683                  char weekdaytime[20];
 685  684  
 686  685                  (void) strftime(weekdaytime, sizeof (weekdaytime),
 687  686                      dcgettext(NULL, "%a%l%p", LC_TIME), p);
 688  687                  checkampm(weekdaytime);
 689  688                  PRINTF((" %s", weekdaytime));
 690  689          } else {
 691  690                  char monthtime[20];
 692  691  
 693  692                  (void) strftime(monthtime, sizeof (monthtime),
 694  693                      dcgettext(NULL, "%e%b%y", LC_TIME), p);
 695  694                  PRINTF((" %s", monthtime));
 696  695          }
 697  696  }
 698  697  
 699  698  /*
 700  699   * find & return number of minutes current tty has been idle
 701  700   */
 702  701  static time_t
 703  702  findidle(char *devname)
 704  703  {
 705  704          struct stat stbuf;
 706  705          time_t lastaction, diff;
 707  706          char ttyname[64];
 708  707  
 709  708          (void) strcpy(ttyname, "/dev/");
 710  709          (void) strcat(ttyname, devname);
 711  710          if (stat(ttyname, &stbuf) != -1) {
 712  711                  lastaction = stbuf.st_atime;
 713  712                  diff = now - lastaction;
 714  713                  diff = DIV60(diff);
 715  714                  if (diff < 0)
 716  715                          diff = 0;
 717  716          } else
 718  717                  diff = 0;
 719  718          return (diff);
 720  719  }
 721  720  
 722  721  /*
 723  722   * given a pointer to the argument string get rid of unsavory characters.
 724  723   */
 725  724  static void
 726  725  clnarglist(char *arglist)
 727  726  {
 728  727          char    *c;
 729  728          int     err = 0;
 730  729  
 731  730          /* get rid of unsavory characters */
 732  731          for (c = arglist; *c != NULL; c++) {
 733  732                  if ((*c < ' ') || (*c > 0176)) {
 734  733                          if (err++ > 5) {
 735  734                                  *arglist = NULL;
 736  735                                  break;
 737  736                          }
 738  737                          *c = '?';
 739  738                  }
 740  739          }
 741  740  }
 742  741  
 743  742  /* replaces all occurences of AM/PM with am/pm */
 744  743  static void
 745  744  checkampm(char *str)
 746  745  {
 747  746          char *ampm;
 748  747          while ((ampm = strstr(str, "AM")) != NULL ||
 749  748              (ampm = strstr(str, "PM")) != NULL) {
 750  749                  *ampm = tolower(*ampm);
 751  750                  *(ampm+1) = tolower(*(ampm+1));
 752  751          }
 753  752  }
  
    | ↓ open down ↓ | 247 lines elided | ↑ open up ↑ | 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX