home *** CD-ROM | disk | FTP | other *** search
/ Amiga GigaPD 3 / Amiga_GigaPD_v3_3of3.iso / netbsd / incoming / near-ps.c.z / near-ps.c
C/C++ Source or Header  |  1994-01-23  |  9KB  |  362 lines

  1. /*
  2.    It's:
  3.     A ps for NetBSD with /proc.  It's a quick nasty job, and probably
  4.     doesn't do what you want, but it does list processes.  Not to be
  5.     confused in any way with the traditional BSD ps.  Just compile
  6.     with cc, no flags particularly required.
  7.  
  8.     Without args, lists all processes.
  9.     ps -p pid ...   lists only specified processes.
  10.     ps -u user ...  lists only processes belonging to user
  11.         (name or uid).
  12.     ps -t tty ...    lists only processes on tty, as shown (e.g. "p4").
  13.  
  14.     There's only one format.  "FILE" is the size of the /proc "file"
  15.     file, which I guess is "the binary".  "MEM" is the size of the
  16.     /proc "mem" file - total process memory?  Both in 512-blocks.
  17.     "COMM" is just the file name, not the command w/ args.
  18.  
  19.     Defects:
  20.     times:    disregard microseconds.
  21.     start:    ctime[1..2] if > 12 hrs old, ctime[3] otherwise,
  22.             which probably isn't the way it's done (displaytime).
  23.     tty:    surely bogus assumptions about major/minor (parsestatus).
  24.  
  25.     Desireable format options might include a roll-your-own feature
  26.     as in AIX ps, where you specify the items and the format of the
  27.     output.  Or BSD-style flags, wretched as they may be, this is after
  28.     all BSD!  Sorting.
  29.  
  30.     Some clever person may be able to figure out how to obtain the
  31.     command argument list.
  32.  
  33.         enjoy,
  34.         Donn Cave, donn@cac.washington.edu
  35.  
  36.  */
  37. #include <stdio.h>
  38. #include <sys/types.h>
  39. #include <pwd.h>
  40. #include <dirent.h>
  41. #include <sys/stat.h>
  42.  
  43. /*
  44.     Attributes per process.  Started out mostly integer, but it
  45.     turned out they're mostly just converted back to text.  Several
  46.     have been commented out, because the sole format doesn't need
  47.     them.
  48.  */
  49. struct Process {
  50.     /* From "status" file. */
  51.     /*uid_t uid;*/  char uid[8];
  52.     /*pid_t pid;*/  char pid[8];
  53.     /*pid_t ppid;*/ char ppid[8];
  54. /*
  55.     gid_t gid;
  56.     pid_t pgid;
  57.     pid_t sid;
  58. */
  59.     unsigned short major, minor;
  60.     char tty[4];
  61.     time_t start;
  62.     time_t utime;
  63.     time_t stime;
  64.     char wmesg[16];
  65.     char comm[16];
  66.     /* From "file" file. */
  67.     int filesize;
  68.     /* From "mem" file. */
  69.     int memsize;
  70. };
  71.  
  72. /* Pick out a word.  Copy to ``buf'', return chars advanced.  */
  73. static int parseword (const char *w, char *buf, int size) {
  74.     register int i;
  75.     register const char *start, *cp;
  76.     cp = w;
  77.     for (; *cp == ' ' || *cp == ','; ++cp);
  78.     for (start = cp; *cp != ' ' && *cp != ',' && *cp != '\n'; ++cp);
  79.     i = cp - start;
  80.     if (i >= size) i = size - 1;
  81.     bcopy (start, buf, i);
  82.     buf[i] = 0;
  83.     return cp - w;
  84. }
  85.  
  86. /* Pick out an int.  Copy to ``i'', return chars advanced. */
  87. static int parseint (const char *cp, int *i) {
  88.     char buf[32];
  89.     int cs;
  90.     register int val = 0;
  91.     cs = parseword (cp, buf, sizeof (buf));
  92.     if (cs > 0) {
  93.         val = atoi (buf);
  94.     }
  95.     *i = val;
  96.     return cs;
  97. }
  98.  
  99. /* Pick out the useful fields in the ``status'' file. */
  100. static void parsestatus (const char *status, struct Process *p) {
  101.     const char *cp = status;
  102.     for (; *cp == ' '; ++cp);
  103.     { /* comm */
  104.     cp += parseword (cp, p->comm, sizeof (p->comm));
  105.     }
  106.     { /* pid */
  107.     cp += parseword (cp, p->pid, sizeof (p->pid));
  108.     }
  109.     { /* ppid */
  110.     cp += parseword (cp, p->ppid, sizeof (p->ppid));
  111.     }
  112.     { /* pgid (skip [useful field, actually  DC]) */
  113.     for (; *cp == ' '; ++cp);
  114.     for (; *cp != ' ' && *cp != '\n'; ++cp);
  115.     }
  116.     { /* sid (skip) */
  117.     for (; *cp == ' '; ++cp);
  118.     for (; *cp != ' ' && *cp != '\n'; ++cp);
  119.     }
  120.     { /* major,minor */
  121.     int a, i;
  122.     cp += parseint (cp, &a);
  123.     if (*cp != ',' || a < 0) p->major = 0;
  124.     else p->major = a;
  125.     cp += parseint (cp, &i);
  126.     if (i < 0) p->minor = 0;
  127.     else p->minor = i;
  128.     p->tty[0] = 0;
  129.     if (a >= 0 && i >= 0) {
  130.         /* This loses for sure. DC */
  131.         switch (a) {
  132.         case 12: sprintf (p->tty, "%02d", i); break;
  133.         case 13: sprintf (p->tty, "e%d", i); break;
  134.         case 4: sprintf (p->tty, "p%x", i); break;
  135.         }
  136.     }
  137.     }
  138.     { /* flags (skip) */
  139.     for (; *cp == ' '; ++cp);
  140.     for (; *cp != ' ' && *cp != '\n'; ++cp);
  141.     }
  142.     { /* start */
  143.     int i;
  144.     cp += parseint (cp, &i);
  145.     p->start = i;
  146.  
  147.     for (; *cp == ' '; ++cp);
  148.     for (; *cp != ' ' && *cp != '\n'; ++cp);
  149.     }
  150.     { /* utime */
  151.     int i;
  152.     cp += parseint (cp, &i);
  153.     p->utime = i;
  154.  
  155.     for (; *cp == ' '; ++cp);
  156.     for (; *cp != ' ' && *cp != '\n'; ++cp);
  157.     }
  158.     { /* stime */
  159.     int i;
  160.     cp += parseint (cp, &i);
  161.     p->stime = i;
  162.  
  163.     for (; *cp == ' '; ++cp);
  164.     for (; *cp != ' ' && *cp != '\n'; ++cp);
  165.     }
  166.     { /* wmesg */
  167.     cp += parseword (cp, p->wmesg, sizeof (p->wmesg));
  168.     }
  169.     { /* uid */
  170.     cp += parseword (cp, p->uid, sizeof (p->uid));
  171.     }
  172.      /* gid (skip) */
  173.      /* groups (skip) */
  174. }
  175.  
  176. /* Shorten ctime() string.  Copy to buf, no size check. */
  177. static void displaytime (char *buf, time_t now, time_t then) {
  178.     int diff = now - then;
  179.     char *cp = ctime (&then);
  180.     int wc, w0;
  181.  
  182.     if (diff > 60*60*12) {    /* Old process */
  183.         wc = 2;        /* get two words */
  184.         w0 = 1;        /* starting at 1  - Jan 1 */
  185.     }
  186.     else {
  187.         wc = 1;        /* get one word */
  188.         w0 = 3;        /* starting at 3 - 00:00:00 */
  189.     }
  190.  
  191.     for (; *cp == ' '; ++cp);
  192.     for (; w0 > 0; --w0) {
  193.         for (; *cp != ' ' && *cp != '\n'; ++cp);
  194.         for (; *cp == ' '; ++cp);
  195.     }
  196.     for (;;) {
  197.         for (; *cp != ' ' && *cp != '\n';) *buf++ = *cp++;
  198.         if (--wc > 0) {
  199.             *buf++ = ' ';
  200.             for (; *cp == ' '; ++cp);
  201.         }
  202.         else {
  203.             *buf = 0;
  204.             break;
  205.         }
  206.     }
  207. }
  208.  
  209. /*
  210.      Selection list  ... for users or pids from the command line.
  211.  */
  212. struct selent {
  213.     char *val;
  214.     struct selent *next;
  215. };
  216.  
  217. static struct selent *list = 0;
  218.  
  219. static void addsel (const char *v, int vlen) {
  220.     struct selent *ent;
  221.     /* Fastidious programmers: please don't look. */
  222.     ent = (struct selent *) malloc (sizeof (struct selent) + vlen + 1);
  223.     ent->val = (char *) ent + sizeof (struct selent);
  224.  
  225.     bcopy (v, ent->val, vlen);
  226.     ent->val[vlen] = 0;
  227.     ent->next = list;
  228.     list = ent;
  229. }
  230.  
  231. /* Pick out and add words from a selection list.  I gather POSIX ps may
  232.    take a string of space or comma delimited values, at least that's how
  233.    some latter-day SysV ps implementations look. */
  234. static void addsels (const char *arg) {
  235.     register int i;
  236.     register const char *cp = arg;
  237.     for (;;) {
  238.     const char *start;
  239.     for (; *cp == ' '; ++cp);
  240.     if (!*cp) break;
  241.     for (i = 0, start = cp; *cp != ' ' && *cp; ++cp, ++i);
  242.     addsel (start, i);
  243.     }
  244. }
  245.  
  246. static int checksel (const char *val) {
  247.     struct selent *ent;
  248.     for (ent = list; ent; ent = ent->next) {
  249.     if (strcmp (val, ent->val) == 0) return 1;
  250.     }
  251.     return 0;
  252. }
  253.  
  254. main (int argc, char **argv) {
  255.     time_t now;
  256.     DIR *procfs;
  257.     struct dirent *d;
  258.     int doproc, douser, dotty, uidok;
  259.     char *arg;
  260.  
  261.     /*    The chdir() may save strain on the / inode ... a problem
  262.     with user loads ca. 1000, ask me. */
  263.     if (chdir ("/proc") < 0 || (procfs = opendir (".")) == 0) {
  264.     perror ("/proc");
  265.     exit (1);
  266.     }
  267.  
  268.     dotty = doproc = douser = 0;
  269.     /* Someone may want to convert this to "getopt". */
  270.     for (++argv; arg = *argv; ++argv) {
  271.     if (*arg == '-') {
  272.         for (++arg; *arg; ++arg) {
  273.         switch (*arg) {
  274.         case 'u' : douser = 1; doproc = 0; dotty = 0; break;
  275.         case 'p' : doproc = 1; douser = 0; dotty = 0; break;
  276.         case 't' : dotty = 1; douser = 0; doproc = 0; break;
  277.         }
  278.         }
  279.     }
  280.     else {
  281.         if (doproc || douser || dotty) {
  282.         addsels (arg);
  283.         }
  284.         else {
  285.         fprintf (stderr, "%s: invalid argument\n", arg);
  286.         }
  287.     }
  288.     }
  289.  
  290.     now = time (0);
  291.     setpwent ();
  292.     /* 123456781234512345 12345 12345 1234567890 12345678 12312312  */
  293.     puts ("USER      PID PPID  FILE   MEM WMESG      START    TT   CPU  COMM");
  294.     while (d = readdir (procfs)) {
  295.     char line[256];
  296.     struct Process p;
  297.     FILE *pstatus;
  298.     struct passwd *pw;
  299.     char pfile[64];
  300.     char *name;
  301.     char start[12];
  302.     int seconds, minutes;
  303.     struct stat st;
  304.  
  305.     /* Skip ".", "..", and "curproc". */
  306.     if (d->d_name[0] < '0' || d->d_name[0] > '9') continue;
  307.     if (doproc) {
  308.         if (!checksel (d->d_name)) continue;
  309.     }
  310.     sprintf (pfile, "%s/status", d->d_name);
  311.     if (!(pstatus = fopen (pfile, "r")) ||
  312.         !fgets (line, sizeof (line), pstatus))
  313.     {
  314.         perror (pfile);
  315.         continue;
  316.     }
  317.     fclose (pstatus);
  318.     parsestatus (line, &p);
  319.     if (dotty && !checksel (p.tty)) continue;
  320.     /* Check now to see if UID matches user arg. */
  321.     uidok = douser && checksel (p.uid);
  322.     pw = getpwuid (atoi (p.uid));
  323.     if (pw) name = pw->pw_name;
  324.     else name = p.uid;
  325.     if (douser) {
  326.         if (!uidok && !checksel (name)) continue;
  327.     }
  328.  
  329.     sprintf (pfile, "%s/file", d->d_name);
  330.     if (stat (pfile, &st) < 0) {
  331.         /*perror (pfile);*/
  332.         /* pagedaemon/swapper "device not configured" */
  333.         p.filesize = 0;
  334.     }
  335.     else {
  336.         p.filesize = st.st_size;
  337.     }
  338.  
  339.     sprintf (pfile, "%s/mem", d->d_name);
  340.     if (stat (pfile, &st) < 0) {
  341.         perror (pfile);
  342.         p.memsize = 0;
  343.     }
  344.     else {
  345.         p.memsize = st.st_size;
  346.     }
  347.  
  348.     seconds = p.utime + p.stime;
  349.     minutes = seconds / 60;
  350.     seconds -= minutes * 60;
  351.     displaytime (start, now, p.start);
  352.     printf ("%-8.8s%5s%5s %5d %5d %-10.10s %-8s %-3.3s%3d:%02d %s\n",
  353.             name, p.pid, p.ppid,
  354.             (p.filesize + 511)/512,
  355.             (p.memsize + 511)/512,
  356.             p.wmesg, start, p.tty,
  357.             minutes, seconds, p.comm);
  358.     }
  359.     endpwent ();
  360.     exit (0);
  361. }
  362.