home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / bin / ps / ps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-01  |  11.1 KB  |  492 lines

  1. /*-
  2.  * Copyright (c) 1990 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. char copyright[] =
  36. "@(#) Copyright (c) 1990 The Regents of the University of California.\n\
  37.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)ps.c    5.43 (Berkeley) 7/1/91";
  42. #endif /* not lint */
  43.  
  44. #include <sys/param.h>
  45. #include <sys/user.h>
  46. #include <sys/time.h>
  47. #include <sys/resource.h>
  48. #include <sys/proc.h>
  49. #include <sys/stat.h>
  50. #include <sys/ioctl.h>
  51. #include <sys/kinfo.h>
  52. #include <nlist.h>
  53. #include <kvm.h>
  54. #include <errno.h>
  55. #include <unistd.h>
  56. #include <stdio.h>
  57. #include <stdlib.h>
  58. #include <string.h>
  59. #include <paths.h>
  60. #include "ps.h"
  61.  
  62. #ifdef SPPWAIT
  63. #define NEWVM
  64. #endif
  65.  
  66. KINFO *kinfo;
  67. struct varent *vhead, *vtail;
  68.  
  69. int    eval;            /* exit value */
  70. int    rawcpu;            /* -C */
  71. int    sumrusage;        /* -S */
  72. int    termwidth;        /* width of screen (0 == infinity) */
  73. int    totwidth;        /* calculated width of requested variables */
  74.  
  75. static int needuser, needcomm;
  76.  
  77. enum sort { DEFAULT, SORTMEM, SORTCPU } sortby = DEFAULT;
  78.  
  79. uid_t    getuid();
  80. char    *ttyname();
  81.  
  82. char dfmt[] = "pid tt state time command";
  83. char jfmt[] = "user pid ppid pgid sess jobc state tt time command";
  84. char lfmt[] = "uid pid ppid cpu pri nice vsz rss wchan state tt time command";
  85. char   o1[] = "pid";
  86. char   o2[] = "tt state time command";
  87. char ufmt[] = "user pid %cpu %mem vsz rss tt state start time command";
  88. char vfmt[] =
  89.     "pid state time sl re pagein vsz rss lim tsiz trs %cpu %mem command";
  90.  
  91. main(argc, argv)
  92.     int argc;
  93.     char **argv;
  94. {
  95.     extern char *optarg;
  96.     extern int optind;
  97.     register struct proc *p;
  98.     register size_t nentries;
  99.     register struct varent *vent;
  100.     register int i;
  101.     struct winsize ws;
  102.     dev_t ttydev;
  103.     int all, ch, flag, fmt, lineno, pid, prtheader, uid, what, xflg;
  104.     int pscomp();
  105.     char *nlistf, *memf, *swapf;
  106.     char *kludge_oldps_options();
  107.  
  108.     if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&ws) == -1 &&
  109.          ioctl(STDERR_FILENO, TIOCGWINSZ, (char *)&ws) == -1 &&
  110.          ioctl(STDIN_FILENO,  TIOCGWINSZ, (char *)&ws) == -1) ||
  111.          ws.ws_col == 0)
  112.         termwidth = 79;
  113.     else
  114.         termwidth = ws.ws_col - 1;
  115.  
  116.     if (argc > 1)
  117.         argv[1] = kludge_oldps_options(argv[1]);
  118.  
  119.     fmt = 0;
  120.     all = xflg = 0;
  121.     pid = uid = -1;
  122.     ttydev = NODEV;
  123.     memf = nlistf = swapf = NULL;
  124.     while ((ch = getopt(argc, argv,
  125.         "aCghjLlM:mN:O:o:p:rSTt:uvW:wx")) != EOF)
  126.         switch((char)ch) {
  127.         case 'a':
  128.             all = 1;
  129.             break;
  130.         case 'C':
  131.             rawcpu = 1;
  132.             break;
  133.         case 'g':
  134.             break;    /* no-op */
  135.         case 'h':
  136.             prtheader = ws.ws_row > 5 ? ws.ws_row : 22;
  137.             break;
  138.         case 'j':
  139.             parsefmt(jfmt);
  140.             fmt = 1;
  141.             jfmt[0] = '\0';
  142.             break;
  143.         case 'L': 
  144.             showkey();
  145.             exit(0);
  146.         case 'l':
  147.             parsefmt(lfmt);
  148.             fmt = 1;
  149.             lfmt[0] = '\0';
  150.             break;
  151.         case 'M':
  152.             memf = optarg;
  153.             break;
  154.         case 'm':
  155.             sortby = SORTMEM;
  156.             break;
  157.         case 'N':
  158.             nlistf = optarg;
  159.             break;
  160.         case 'O':
  161.             parsefmt(o1);
  162.             parsefmt(optarg);
  163.             parsefmt(o2);
  164.             o1[0] = o2[0] = '\0';
  165.             fmt = 1;
  166.             break;
  167.         case 'o':
  168.             parsefmt(optarg);
  169.             fmt = 1;
  170.             break;
  171.         case 'p':
  172.             pid = atoi(optarg);
  173.             xflg = 1;
  174.             break;
  175.         case 'r':
  176.             sortby = SORTCPU;
  177.             break;
  178.         case 'S':
  179.             sumrusage = 1;
  180.             break;
  181.         case 'T':
  182.             if ((optarg = ttyname(STDIN_FILENO)) == NULL)
  183.                 err("stdin: not a terminal");
  184.             /* FALLTHROUGH */
  185.         case 't': {
  186.             char *ttypath;
  187.             struct stat stbuf;
  188.             char pathbuf[MAXPATHLEN];
  189.  
  190.             if (strcmp(optarg, "co") == 0)
  191.                 ttypath = _PATH_CONSOLE;
  192.             else if (*optarg != '/')
  193.                 (void) sprintf(ttypath = pathbuf, "%s%s",
  194.                     _PATH_TTY, optarg);
  195.             else
  196.                 ttypath = optarg;
  197.             if (stat(ttypath, &stbuf) == -1)
  198.                 err("%s: %s", ttypath, strerror(errno));
  199.             if (!S_ISCHR(stbuf.st_mode))
  200.                 err("%s: not a terminal", ttypath);
  201.             ttydev = stbuf.st_rdev;
  202.             break;
  203.         }
  204.         case 'u':
  205.             parsefmt(ufmt);
  206.             sortby = SORTCPU;
  207.             fmt = 1;
  208.             ufmt[0] = '\0';
  209.             break;
  210.         case 'v':
  211.             parsefmt(vfmt);
  212.             sortby = SORTMEM;
  213.             fmt = 1;
  214.             vfmt[0] = '\0';
  215.             break;
  216.         case 'W':
  217.             swapf = optarg;
  218.             break;
  219.         case 'w':
  220.             if (termwidth < 131)
  221.                 termwidth = 131;
  222.             else
  223.                 termwidth = UNLIMITED;
  224.             break;
  225.         case 'x':
  226.             xflg = 1;
  227.             break;
  228.         case '?':
  229.         default:
  230.             usage();
  231.         }
  232.     argc -= optind;
  233.     argv += optind;
  234.  
  235. #define    BACKWARD_COMPATIBILITY
  236. #ifdef    BACKWARD_COMPATIBILITY
  237.     if (*argv) {
  238.  
  239.         nlistf = *argv;
  240.         if (*++argv) {
  241.             memf = *argv;
  242.             if (*++argv)
  243.                 swapf = *argv;
  244.         }
  245.     }
  246. #endif
  247.     if (kvm_openfiles(nlistf, memf, swapf) == -1)
  248.         err("kvm_openfiles: %s", kvm_geterr());
  249.  
  250.     if (!fmt)
  251.         parsefmt(dfmt);
  252.  
  253.     if (!all && ttydev == NODEV && pid == -1)  /* XXX - should be cleaner */
  254.         uid = getuid();
  255.  
  256.     /*
  257.      * scan requested variables, noting what structures are needed,
  258.      * and adjusting header widths as appropiate.
  259.      */
  260.     scanvars();
  261.     /*
  262.      * get proc list
  263.      */
  264.     if (uid != -1) {
  265.         what = KINFO_PROC_UID;
  266.         flag = uid;
  267.     } else if (ttydev != NODEV) {
  268.         what = KINFO_PROC_TTY;
  269.         flag = ttydev;
  270.     } else if (pid != -1) {
  271.         what = KINFO_PROC_PID;
  272.         flag = pid;
  273.     } else
  274.         what = KINFO_PROC_ALL;
  275.     /*
  276.      * select procs
  277.      */
  278.     if ((nentries = kvm_getprocs(what, flag)) == -1)
  279.         err("%s", kvm_geterr());
  280.     kinfo = malloc(nentries * sizeof(KINFO));
  281.     if (kinfo == NULL)
  282.         err("%s", strerror(errno));
  283.     for (nentries = 0; p = kvm_nextproc(); ++nentries) {
  284.         kinfo[nentries].ki_p = p;
  285.         kinfo[nentries].ki_e = kvm_geteproc(p);
  286.         if (needuser)
  287.             saveuser(&kinfo[nentries]);
  288.     }
  289.     /*
  290.      * print header
  291.      */
  292.     printheader();
  293.     if (nentries == 0)
  294.         exit(0);
  295.     /*
  296.      * sort proc list
  297.      */
  298.     qsort((void *)kinfo, nentries, sizeof(KINFO), pscomp);
  299.     /*
  300.      * for each proc, call each variable output function.
  301.      */
  302.     for (i = lineno = 0; i < nentries; i++) {
  303.         if (xflg == 0 && (kinfo[i].ki_e->e_tdev == NODEV ||
  304.             (kinfo[i].ki_p->p_flag & SCTTY ) == 0))
  305.             continue;
  306.         for (vent = vhead; vent; vent = vent->next) {
  307.             (*vent->var->oproc)(&kinfo[i], vent->var, vent->next);
  308.             if (vent->next != NULL)
  309.                 (void) putchar(' ');
  310.         }
  311.         (void) putchar('\n');
  312.         if (prtheader && lineno++ == prtheader-4) {
  313.             (void) putchar('\n');
  314.             printheader();
  315.             lineno = 0;
  316.         }
  317.     }
  318.     exit(eval);
  319. }
  320.  
  321. scanvars()
  322. {
  323.     register struct varent *vent;
  324.     register VAR *v;
  325.     register int i;
  326.  
  327.     for (vent = vhead; vent; vent = vent->next) {
  328.         v = vent->var;
  329.         i = strlen(v->header);
  330.         if (v->width < i)
  331.             v->width = i;
  332.         totwidth += v->width + 1;    /* +1 for space */
  333.         if (v->flag & USER)
  334.             needuser = 1;
  335.         if (v->flag & COMM)
  336.             needcomm = 1;
  337.     }
  338.     totwidth--;
  339. }
  340.  
  341.  
  342. /* XXX - redo */
  343. saveuser(ki)
  344.     KINFO *ki;
  345. {
  346.     register struct usave *usp;
  347.     register struct user *up;
  348.  
  349.     if ((usp = calloc(1, sizeof(struct usave))) == NULL)
  350.         err("%s", strerror(errno));
  351.     up = kvm_getu(ki->ki_p);
  352.     /*
  353.      * save arguments if needed
  354.      */
  355.     ki->ki_args = needcomm ? strdup(kvm_getargs(ki->ki_p, up)) : NULL;
  356.     if (up != NULL) {
  357.         ki->ki_u = usp;
  358.         /*
  359.          * save important fields
  360.          */
  361. #ifdef NEWVM
  362.         usp->u_start = up->u_stats.p_start;
  363.         usp->u_ru = up->u_stats.p_ru;
  364.         usp->u_cru = up->u_stats.p_cru;
  365. #else
  366.         usp->u_procp = up->u_procp;
  367.         usp->u_start = up->u_start;
  368.         usp->u_ru = up->u_ru;
  369.         usp->u_cru = up->u_cru;
  370.         usp->u_acflag = up->u_acflag;
  371. #endif
  372.     } else
  373.         free(usp);
  374. }
  375.  
  376. pscomp(k1, k2)
  377.     KINFO *k1, *k2;
  378. {
  379.     int i;
  380. #ifdef NEWVM
  381. #define VSIZE(k) ((k)->ki_e->e_vm.vm_dsize + (k)->ki_e->e_vm.vm_ssize + \
  382.           (k)->ki_e->e_vm.vm_tsize)
  383. #else
  384. #define VSIZE(k) ((k)->ki_p->p_dsize + (k)->ki_p->p_ssize + (k)->ki_e->e_xsize)
  385. #endif
  386.  
  387.     if (sortby == SORTCPU)
  388.         return (getpcpu(k2) - getpcpu(k1));
  389.     if (sortby == SORTMEM)
  390.         return (VSIZE(k2) - VSIZE(k1));
  391.     i =  k1->ki_e->e_tdev - k2->ki_e->e_tdev;
  392.     if (i == 0)
  393.         i = k1->ki_p->p_pid - k2->ki_p->p_pid;
  394.     return (i);
  395. }
  396.  
  397. /*
  398.  * ICK (all for getopt), would rather hide the ugliness
  399.  * here than taint the main code.
  400.  *
  401.  *  ps foo -> ps -foo
  402.  *  ps 34 -> ps -p34
  403.  *
  404.  * The old convention that 't' with no trailing tty arg means the users
  405.  * tty, is only supported if argv[1] doesn't begin with a '-'.  This same
  406.  * feature is available with the option 'T', which takes no argument.
  407.  */
  408. char *
  409. kludge_oldps_options(s)
  410.     char *s;
  411. {
  412.     size_t len;
  413.     char *newopts, *ns, *cp;
  414.  
  415.     len = strlen(s);
  416.     if ((newopts = ns = malloc(len + 2)) == NULL)
  417.         err("%s", strerror(errno));
  418.     /*
  419.      * options begin with '-'
  420.      */
  421.     if (*s != '-')
  422.         *ns++ = '-';    /* add option flag */
  423.     /*
  424.      * gaze to end of argv[1]
  425.      */
  426.     cp = s + len - 1;
  427.     /*
  428.      * if last letter is a 't' flag with no argument (in the context
  429.      * of the oldps options -- option string NOT starting with a '-' --
  430.      * then convert to 'T' (meaning *this* terminal, i.e. ttyname(0)).
  431.      */
  432.     if (*cp == 't' && *s != '-')
  433.         *cp = 'T';
  434.     else {
  435.         /*
  436.          * otherwise check for trailing number, which *may* be a
  437.          * pid.
  438.          */
  439.         while (cp >= s && isdigit(*cp))
  440.             --cp;
  441.     }
  442.     cp++;
  443.     bcopy(s, ns, (size_t)(cp - s));    /* copy up to trailing number */
  444.     ns += cp - s;
  445.     /*
  446.      * if there's a trailing number, and not a preceding 'p' (pid) or
  447.      * 't' (tty) flag, then assume it's a pid and insert a 'p' flag.
  448.      */
  449.     if (isdigit(*cp) && (cp == s || cp[-1] != 't' && cp[-1] != 'p' &&
  450.         (cp - 1 == s || cp[-2] != 't')))
  451.         *ns++ = 'p';
  452.     (void) strcpy(ns, cp);        /* and append the number */
  453.  
  454.     return (newopts);
  455. }
  456.  
  457. #if __STDC__
  458. #include <stdarg.h>
  459. #else
  460. #include <varargs.h>
  461. #endif
  462.  
  463. void
  464. #if __STDC__
  465. err(const char *fmt, ...)
  466. #else
  467. err(fmt, va_alist)
  468.     char *fmt;
  469.         va_dcl
  470. #endif
  471. {
  472.     va_list ap;
  473. #if __STDC__
  474.     va_start(ap, fmt);
  475. #else
  476.     va_start(ap);
  477. #endif
  478.     (void)fprintf(stderr, "ps: ");
  479.     (void)vfprintf(stderr, fmt, ap);
  480.     va_end(ap);
  481.     (void)fprintf(stderr, "\n");
  482.     exit(1);
  483.     /* NOTREACHED */
  484. }
  485.  
  486. usage()
  487. {
  488.     (void) fprintf(stderr,
  489. "usage: ps [-aChjlmrSTuvwx] [-O|o fmt] [-p pid] [-t tty]\n\t  [-M core] [-N system] [-W swap]\n       ps [-L]\n");
  490.     exit(1);
  491. }
  492.