home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / A / PS / PROCPS-0.000 / PROCPS-0 / procps-0.97 / ps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-25  |  18.6 KB  |  665 lines

  1. /*
  2.  * ps.c                - show process status
  3.  *
  4.  * Copyright (c) 1992 Branko Lankester
  5.  *
  6.  * Snarfed and HEAVILY modified for procps
  7.  * by Michael K. Johnson, johnsonm@sunsite.unc.edu.  What is used is what
  8.  * is required to have a common interface.
  9.  *
  10.  * Modified 1994/05/25 Michael Shields <mjshield@nyx.cs.du.edu>
  11.  * Added support for multiple, comma-delimited pids on command line.
  12.  *
  13.  * Changes Copyright (C) 1993, 1994 Michael K. Johnson
  14.  * See file COPYING for copyright details.
  15.  */
  16.  
  17. #include <sys/types.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <ctype.h>
  21. #include <unistd.h>
  22. #include <string.h>
  23. #include <fcntl.h>
  24. #include <limits.h>
  25. #include <time.h>
  26. #include <sys/ioctl.h>
  27. #include <pwd.h>
  28. #include <linux/sched.h>
  29. #include <linux/tty.h>
  30. #include "ps.h"
  31. #include "psdata.h"
  32.  
  33.  
  34. #define        PS_D        0        /* default format (short) */
  35. #define        PS_L        1        /* long format */
  36. #define        PS_U        2        /* user format */
  37. #define        PS_J        3        /* jobs format */
  38. #define        PS_S        4        /* signal format */
  39. #define        PS_V        5        /* vm format */
  40. #define        PS_M        6        /* mem. stuff */
  41. #define        PS_X        7        /* regs etc., for testing */
  42.  
  43. char *hdrs[] = {
  44. "  PID TTY STAT  TIME COMMAND",
  45. " F    UID   PID  PPID PRI NI SIZE  RSS WCHAN      STAT TTY   TIME COMMAND",
  46. "USER       PID %CPU %MEM SIZE  RSS TTY STAT START   TIME COMMAND",
  47. " PPID   PID  PGID   SID TTY TPGID  STAT   UID   TIME COMMAND",
  48. "  UID   PID SIGNAL   BLOCKED  IGNORED  CATCHED  STAT TTY   TIME COMMAND",
  49. "  PID TTY STAT  TIME  PAGEIN TSIZ DSIZ  RSS   LIM %MEM COMMAND",
  50. "  PID TTY MAJFLT MINFLT  TRS  DRS SIZE SWAP  RSS SHRD  LIB  DT COMMAND",
  51. "NR   PID    STACK      ESP      EIP TMOUT ALARM STAT TTY   TIME COMMAND"
  52. };
  53.  
  54. int maxcols=0;
  55.  
  56. struct tree_node *node;
  57. int nodes = 0;
  58. int maxnodes = 0;
  59.  
  60. extern void (*fmt_fnc[])();        /* forward declaration */
  61. char *prtime(char *s, unsigned long t, unsigned long rel);
  62. void read_globals();
  63. void usage(void);
  64. void show_procs(unsigned int maxcmd, int no_header);
  65. void show_time(char *s, struct ps_proc * this);
  66. void add_node(char *s, struct ps_proc *task);
  67. int node_cmp(const void *s1, const void *s2);
  68. void show_tree(int n, int depth, char *continued);
  69. void show_forest( void );
  70. int set_maxcmd(int w_opts);
  71.  
  72. int sort_depth=0;
  73. int sort_direction[10];     /* storage for 10 levels, but 4 would be plenty!*/
  74. int (*sort_function[10])(void* a, void* b);
  75. int parse_sort_opt(char*);
  76. int parse_long_sort(char*);
  77.  
  78. /*
  79.  * command line options
  80.  */
  81. int CL_fmt = 0;
  82. int CL_all = 0;
  83. int CL_kern_comm = 0;
  84. int CL_no_ctty = 0;
  85. int CL_run_only = 0;
  86. char *CL_ctty = 0;
  87. pid_t *CL_pids = NULL;        /* a zero-terminated list, dynamically allocated */
  88. int CL_show_env = 0;
  89. int CL_num_outp = 0;        /* numeric fields for user or wchan */
  90. int CL_pg_shift = 2;        /* default: show k instead of pages */
  91. int CL_Sum = 0;
  92. int CL_sort = 1;
  93. int CL_forest = 0;
  94.  
  95. /* Globals */
  96. int GL_current_time;
  97. unsigned int GL_main_mem;
  98. long GL_time_now;
  99. int GL_wchan_nout = 0;
  100.  
  101. int main(int argc, char **argv)
  102. {
  103.     char *p;
  104. #define MX_OP 15
  105.     char fmt_ord[MX_OP]="Up";  /* initialize to default fmt sort */
  106.     int width = 0;
  107.     unsigned int maxcmd;
  108.     int no_header = 0;
  109.     int psdbsucc = 0;
  110.     int user_ord = 0;
  111.     int next_arg = 0;
  112.     int toppid = 0;
  113.  
  114.     if (argc > 1) do
  115.     {
  116.         --argc;
  117.         ++argv;  /* shift to line args. At top of loop because of argv[0] */
  118.         for (p = *argv; *p; ++p) {
  119.             switch (*p) {
  120.                 case '-':               /* "--" ==> long name options */
  121.                   if (*(p+1) == '-') {
  122.                     if (strncmp(p+2,"sort",4)==0) {
  123.                       if (parse_long_sort(p+7) == -1)
  124.                         usage();
  125.                       user_ord = 1;
  126.                       break;
  127.                     } else if (strncmp(p+2, "help", 4) == 0) {
  128.                       dump_keys();
  129.                       usage();
  130.                       exit(0);
  131.                     } else if (*(p+2) != '\0') { /* just '-- '; not an error */
  132.                       fprintf(stderr,
  133.                               "ps: unknown long name option -- %s\n",p+1);
  134.                       usage(); /* long_name not found or parse error */
  135.                     }
  136.                   }
  137.                   break;
  138.                 case 'l': CL_fmt = PS_L; strncpy(fmt_ord,"Pp",MX_OP); break;
  139.                 case 'u': CL_fmt = PS_U; strncpy(fmt_ord,"up",MX_OP); break;
  140.                 case 'j': CL_fmt = PS_J; strncpy(fmt_ord,"gPp",MX_OP); break;
  141.                 case 's': CL_fmt = PS_S; strncpy(fmt_ord,"p",MX_OP); break;
  142.                 case 'v': CL_fmt = PS_V; strncpy(fmt_ord,"p",MX_OP); break;
  143.                 case 'm': CL_fmt = PS_M; strncpy(fmt_ord,"s",MX_OP); break;
  144.                 case 'X': CL_fmt = PS_X; strncpy(fmt_ord,"p",MX_OP); break; /* regs */
  145.                 case 'f': CL_forest = 1; break;
  146.                 case 'a': CL_all = 1; break;
  147.                 case 'c': CL_kern_comm = 1; break;
  148.                 case 'x': CL_no_ctty = 1; break;
  149.                 case 't': CL_ctty = p + 1; next_arg = 1; break;
  150.                 case 'r': CL_run_only = 1; break;
  151.                 case 'e': CL_show_env = 1; break;
  152.                 case 'w': ++width; break;
  153.                 case 'h': no_header = 1; break;
  154.                 case 'n': CL_num_outp = 1; GL_wchan_nout = 1; break;
  155.                 case 'S': CL_Sum = 1; break;
  156.                 case 'p': CL_pg_shift = 0; break;
  157.                 case 'g': break;   /* old flag, ignore */ 
  158.                 case 'o': CL_sort = !CL_sort; break; /* off or on by default?*/
  159.                 case 'O': if (parse_sort_opt(p+1) == -1) usage(); user_ord = 1; next_arg = 1; break;
  160.                 default:
  161.                 /* Step through, reading comma-delimited pids and allocating space for them. */
  162.                     if (isdigit(*p)) {
  163.                         while (*p) {
  164.                             CL_pids = xrealloc(CL_pids, (toppid + 2) * sizeof(pid_t));
  165.                             CL_pids[toppid++] = atoi(p);
  166.                             while (isdigit(*p))
  167.                                     p++;
  168.                             if (*p == ',')
  169.                                 p++;
  170.                         }
  171.                         CL_pids[toppid] = 0;
  172.                         next_arg = 1;
  173.                     }
  174.                     if (*p)
  175.                         usage();
  176.             }
  177.             if (next_arg) {
  178.                 next_arg = 0;
  179.                 break;       /* end loop over chars in this argument */
  180.             }
  181.         }
  182.     } while (argc > 1);
  183.  
  184.     if (CL_fmt == PS_L) {
  185.       if (open_psdb()) {
  186.         GL_wchan_nout = 1;
  187.       } else {
  188.         psdbsucc = 1;
  189.       }
  190.     }
  191.     maxcmd = set_maxcmd(width);
  192.     read_globals();
  193.     if (CL_sort && !user_ord)
  194.         parse_sort_opt(fmt_ord);
  195.     show_procs(maxcmd, no_header);
  196.     if (psdbsucc) close_psdb();
  197.     return 0;
  198. }
  199.  
  200.  
  201. void usage(void)
  202. {
  203.     fprintf(stderr,
  204.             "usage:  ps -acehjlnrsSuvwx{t<tty>|#|O[-]u[-]U..} \\\n"
  205.             "           --sort:[-]key1,[-]key2,...\n"
  206.             "           --help gives you this message\n");
  207.     exit(1);
  208. }
  209.  
  210.  
  211. /*
  212.  * set maximum chars displayed on a line
  213.  */
  214. int set_maxcmd(int w_opts)
  215. {
  216.     struct winsize win;
  217.     
  218.     maxcols = 80;
  219.     if (ioctl(1, TIOCGWINSZ, &win) != -1 && win.ws_col > 0)
  220.         maxcols = win.ws_col;
  221.  
  222.     switch (w_opts) {
  223.         case 0: break;
  224.         case 1: maxcols += 52; break;
  225.         case 2: maxcols *= 2; break;
  226.         default: maxcols = MAXCMD;
  227.     }
  228.     return maxcols - strlen(hdrs[CL_fmt]) + 7;
  229. }
  230.  
  231.  
  232. int print_cmdline(char *cmdline, int maxcmd)
  233. {
  234.   int i = 0;
  235.   if(CL_kern_comm) {
  236.     char *endp;
  237.     if(cmdline[0] == '(') {
  238.       endp = strchr(cmdline,')');
  239.       if (endp != NULL) {
  240.         cmdline++;      /* get rid of '(' */
  241.         *endp = 0; /* get rid of ')' */
  242.       }
  243.     } else { /* command line doesn't start with a '(' */
  244.       endp = strchr(cmdline,' ');
  245.       if (endp != NULL ) {
  246.         *endp = 0;
  247.       }
  248.     }
  249.   } else {
  250.     /* Now, let's munge all the unprintables out */
  251.     for(i=0; i<maxcmd,cmdline[i] != (char) 0; i++)
  252.       if (!isprint(cmdline[i]))
  253.           cmdline[i] = ' ';
  254.     if (i >= maxcmd)
  255.       cmdline[maxcmd] = (char) 0;
  256.   }
  257.   fputs(cmdline, stdout);
  258.   return maxcmd - i;
  259. }
  260.  
  261.  
  262. void print_env(int pid, int maxenv) {
  263.     char c, buf[22];
  264.     FILE* environ;
  265.  
  266.     fputs(" + ", stdout); maxenv -= 3;
  267.     if (maxenv > 0) {
  268.     sprintf(buf, "/proc/%d/environ", pid);
  269.         environ = fopen(buf, "r");
  270.         while (maxenv-- > 0) {
  271.             c = fgetc(environ);
  272.             putchar(isprint(c)?c:' ');
  273.         }
  274.     }
  275. }
  276.  
  277.  
  278. void show_procs(unsigned int maxcmd, int no_header)
  279. {
  280.     struct ps_proc_head *ph;
  281.     struct ps_proc *this, **arr_ver;
  282.     int tty = 0, uid, i, space_left;
  283.     char s[80];
  284.  
  285.     uid = getuid();
  286.  
  287.     if (CL_ctty)
  288.       if ((tty = tty_to_dev(CL_ctty))==-1) {
  289.           fprintf(stderr, "the name `%s' is not a tty\n", CL_ctty);
  290.           exit(1);
  291.       }
  292.  
  293.     if (!CL_pids)
  294.       ph = take_snapshot((CL_all | (uid==0)), CL_fmt==PS_U, CL_no_ctty,
  295.                            CL_fmt==PS_M, CL_run_only, uid, tty);
  296.     else
  297.       ph = get_processes(CL_pids, CL_fmt == PS_M);
  298.  
  299.     if (!ph->count) {
  300.       fprintf(stderr, "No processes available\n");
  301.       exit(1);
  302.     }
  303.  
  304.     this = ph->head;                                 /* start at top of list */
  305.  
  306.     arr_ver = xmalloc(ph->count * sizeof (struct ps_proc*));/* allocate array */
  307.  
  308.     for(i=0; this != NULL; this = this->next, i++)/* copy into array version */
  309.         arr_ver[i] = this;
  310.  
  311.     if (!CL_forest && CL_sort)          /* run qsort on the array with multi-level compare */
  312.         qsort(arr_ver, ph->count, sizeof this, (void *) mult_lvl_cmp);
  313.  
  314.     if (!no_header)
  315.         puts(hdrs[CL_fmt]);
  316.     for (i = 0; i < ph->count; ++i) {
  317.       this=arr_ver[i];
  318.       (fmt_fnc[CL_fmt])(s, this);
  319.       if (CL_fmt != PS_V && CL_fmt != PS_M)
  320.         show_time(s+strlen(s), this);
  321.       if (CL_forest)
  322.         add_node(s, this);        
  323.       else        
  324.       {
  325.         printf( "%s", s );
  326.         space_left = print_cmdline(*(this->cmdline) ? this->cmdline : this->cmd, maxcmd);
  327.         if (CL_show_env)
  328.             print_env(this->pid, space_left);
  329.         puts(""); /* newline */
  330.       }
  331.     }
  332.     if (CL_forest)
  333.         show_forest();
  334.     free (arr_ver);
  335. }
  336.  
  337. void
  338. add_node(char *s, struct ps_proc *task)
  339. {
  340.     if (maxnodes == 0) {
  341.             maxnodes = 64;
  342.         node = (struct tree_node *)
  343.             malloc(sizeof(struct tree_node) * maxnodes);
  344.     }
  345.     if (nodes > maxnodes) {
  346.             maxnodes *= 2;
  347.         node = (struct tree_node *)
  348.             realloc(node, sizeof(struct tree_node) * maxnodes);
  349.     }
  350.     node[nodes].proc = task;
  351.     node[nodes].pid = task->pid;
  352.     node[nodes].ppid =task->ppid;
  353.     node[nodes].line = strdup(s);
  354.     node[nodes].cmd = *(task->cmdline) ? task->cmdline : task->cmd;
  355.     node[nodes].children = 0;
  356.     node[nodes].have_parent = 0;
  357.     nodes++;
  358. }
  359.  
  360. int
  361. node_cmp(const void *s1, const void *s2)
  362. {
  363.     struct tree_node *n1 = (struct tree_node *) s1;
  364.     struct tree_node *n2 = (struct tree_node *) s2;
  365.  
  366.     return n1->pid - n2->pid;
  367. }
  368.  
  369. void
  370. show_tree(int n, int depth, char *continued)
  371. {
  372.     int i;
  373.     int cols;
  374.     int space_left;
  375.  
  376.     cols = printf("%s", node[n].line);
  377.  
  378.     for (i = 0; i < depth; i++) 
  379.     {
  380.         if (cols + 4 >= maxcols - 1)
  381.             break;
  382.         if (i == depth - 1)
  383.             printf(" \\_ ");
  384.         else if (continued[i])
  385.             printf(" |  ");
  386.         else
  387.             printf("    ");
  388.         cols += 4;
  389.     }
  390.     /*printf("%-.*s\n", maxcols - cols - 1, node[n].cmd);*/
  391.     space_left = print_cmdline( node[n].cmd, maxcols - cols );
  392.     if (CL_show_env)
  393.     print_env(node[n].pid, space_left);
  394.     puts(""); /* newline */
  395.     for (i = 0; i < node[n].children; i++) 
  396.     {
  397.         continued[depth] = i != node[n].children - 1;
  398.         show_tree(node[n].child[i], depth + 1, continued);
  399.     }
  400. }
  401.  
  402. void
  403. show_forest(void)
  404. {
  405.     register int i, j;
  406.     int parent;
  407.     char continued[1024];
  408.  
  409.     if (CL_sort)
  410.             qsort((void *) node, nodes, sizeof(struct tree_node), (void*)node_mult_lvl_cmp);
  411.             
  412.     for (i = 0; i < nodes; i++) {
  413.         if (node[i].ppid > 1 && node[i].pid != node[i].ppid) 
  414.         {
  415.            parent = -1;
  416.            for ( j=0; j<nodes; j++ )
  417.                    if (node[j].pid==node[i].ppid)
  418.                            parent = j;
  419.         }
  420.         else
  421.             parent = -1;
  422.         if (parent >= 0) 
  423.         {
  424.             node[i].have_parent++;
  425.             if (node[parent].children == 0) {
  426.                 node[parent].child = (int *) malloc(16 * sizeof(int *));
  427.                 node[parent].maxchildren = 16;
  428.             }
  429.             else if (node[parent].children == node[parent].maxchildren) {
  430.                 node[parent].maxchildren *= 2;
  431.                 node[parent].child = (int *) realloc(node[parent].child,
  432.                                                      node[parent].maxchildren
  433.                                                      * sizeof(int *));
  434.             }
  435.             node[parent].child[node[parent].children++] = i;
  436.         }
  437.     }
  438.  
  439.     for (i = 0; i < nodes; i++) {
  440.         if (!node[i].have_parent)
  441.             show_tree(i, 0, continued);
  442.     }
  443. }
  444.  
  445. void show_short(char *s, struct ps_proc *this)
  446. {
  447.     sprintf(s, "%5d %3s %s",
  448.         this->pid,
  449.         this->ttyc,
  450.         status(this));
  451. }
  452.  
  453. void show_long(char *s, struct ps_proc *this)
  454. {
  455.   char wchanb[10];
  456.  
  457.   if(GL_wchan_nout)
  458.     sprintf(wchanb, "%-9x", this->wchan);
  459.   else
  460.     sprintf(wchanb, "%-9.9s", wchan(this->wchan));
  461. /*sprintf(s, "%2x %5d %5d %5d %3d %2d %4d %4d %-10.10s %s %3s ",*/
  462.   sprintf(s, "%3x %5d %5d %5d %3d %2d %4d %4d %-10.10s %s %3s ",
  463.          this->flags, /* the used_math element will /always/ be set,
  464.                          because crt0.s checks the math emulation,
  465.                          so it isn't worth including here, which is
  466.                          why I didn't include it in the output format
  467.                          from the stat file... */
  468.          this->uid,
  469.          this->pid,
  470.          this->ppid,
  471.          2*PZERO-this->counter,
  472.          PZERO - this->priority, /* get standard unix nice value... */
  473.          this->vsize / 1024,
  474.          this->rss * 4,
  475.          wchanb,
  476.          status(this),
  477.          this->ttyc);
  478. }
  479.  
  480. void show_jobs(char *s, struct ps_proc *this)
  481. {
  482.     sprintf(s, "%5d %5d %5d %5d %3s %5d  %s %5d ",
  483.         this->ppid,
  484.         this->pid,
  485.         this->pgrp,
  486.         this->session,
  487.         this->ttyc,
  488.         this->tpgid,
  489.         status(this),
  490.         this->uid);
  491. }
  492.  
  493. void show_user(char *s, struct ps_proc *this)
  494. {
  495.   int pmem, total_time, seconds;
  496.   time_t start;
  497.   unsigned int pcpu;
  498.  
  499.   if (CL_num_outp)
  500.     s += sprintf(s, "%5d    ", this->uid);
  501.   else
  502.     s += sprintf(s, "%-8s ", this->user);
  503.   seconds = (((GL_current_time * 100) - this->start_time) / HZ);
  504.   start = GL_time_now - seconds;
  505.   total_time = (this->utime + this->stime +
  506.                 (CL_Sum ? this->cutime + this->cstime : 0));
  507.   pcpu = seconds ?
  508.          (total_time * 10) / seconds :
  509.          0;
  510.   if (pcpu > 999) pcpu = 999;
  511.   pmem = this->rss * 1000 / (GL_main_mem / 4096);
  512.   sprintf(s, "%5d %2u.%u %2d.%d %4d %4d %2s %s%.6s ",
  513.          this->pid,
  514.          pcpu / 10, pcpu % 10,
  515.          pmem / 10, pmem % 10,
  516.          this->vsize / 1024,
  517.          this->rss * 4,
  518.          this->ttyc,
  519.          status(this),
  520.          ctime(&start) + (GL_time_now - start > 3600*24 ? 4 : 10));
  521. }
  522.  
  523. void show_sig(char *s, struct ps_proc *this)
  524. {
  525.  
  526.     sprintf(s, "%5d %5d %08x %08x %08x %08x %s %3s ",
  527.         this->uid,
  528.         this->pid,
  529.         this->signal,
  530.         this->blocked,
  531.         this->sigignore,
  532.         this->sigcatch,
  533.         status(this),
  534.         this->ttyc);
  535. }
  536.  
  537. void show_vm(char *s, struct ps_proc *this)
  538. {
  539.     int pmem;
  540.  
  541.     s += sprintf(s,"%5d %3s %s",
  542.            this->pid,
  543.            this->ttyc,
  544.            status(this));
  545.     show_time(s, this);
  546.     s += strlen(s);
  547.     s += sprintf(s, " %6d %4d %4d %4d ",
  548.            this->maj_flt + (CL_Sum ? this->cmaj_flt : 0),
  549.            this->end_code / 1024,
  550.            (this->vsize - this->end_code) / 1024,
  551.            this->rss * 4);
  552.     if(this->rss_rlim == RLIM_INFINITY)
  553.       s += sprintf(s, "   xx ");
  554.     else
  555.       s += sprintf(s, "%5d ", this->rss_rlim / 1024);
  556.     pmem = this->rss * 1000 / (GL_main_mem / 4096);
  557.     sprintf(s, "%2d.%d ", pmem / 10, pmem % 10);
  558. }
  559.  
  560.  
  561. void show_m(char *s, struct ps_proc *this)
  562. {
  563.  
  564.   sprintf(s, "%5d %3s %6d %6d %4d %4d %4d %4d %4d %4d %4d %3d ", 
  565.          this->pid,
  566.          this->ttyc,
  567.          this->maj_flt + (CL_Sum ? this->cmaj_flt : 0),
  568.          this->min_flt + (CL_Sum ? this->cmin_flt : 0),
  569.          this->statm.trs << CL_pg_shift,
  570.          this->statm.drs << CL_pg_shift,
  571.          this->statm.size << CL_pg_shift,
  572.          (this->statm.size - this->statm.resident) << CL_pg_shift,
  573.          this->statm.resident << CL_pg_shift,
  574.          this->statm.share << CL_pg_shift,
  575.          this->statm.lrs << CL_pg_shift,
  576.          this->statm.dt);
  577. }
  578.  
  579. void show_regs(char *s, struct ps_proc *this)
  580. {
  581.     char time1[16];
  582.     char time2[16];
  583.  
  584.     s += sprintf(s, "%2d %5d %8x %8x %8x %s %s %s %3s ",
  585.         this->start_code >> 26,
  586.         this->pid,
  587.         this->start_stack,
  588.         this->kstk_esp,
  589.         this->kstk_eip,
  590.         prtime(time1, this->timeout, GL_current_time * 100),
  591.         prtime(time2, this->it_real_value, 0),
  592.         status(this),
  593.         this->ttyc);
  594. }
  595.  
  596. char *prtime(char *s, unsigned long t, unsigned long rel)
  597. {
  598.     if (t == 0) {
  599.         sprintf(s, "     ");
  600.         return s;
  601.     }
  602.     if ((long) t == -1) {
  603.         sprintf(s, "   xx");
  604.         return s;
  605.     }
  606.     if ((long) (t -= rel) < 0)
  607.         t = 0;
  608.     
  609.     if (t > 9999)
  610.         sprintf(s, "%5lu", t / 100);
  611.     else
  612.         sprintf(s, "%2lu.%02lu", t / 100, t % 100);
  613.     return s;
  614. }
  615.  
  616. void (*fmt_fnc[])() = {
  617.     show_short,
  618.     show_long,
  619.     show_user,
  620.     show_jobs,
  621.     show_sig,
  622.     show_vm,
  623.     show_m,
  624.     show_regs
  625. };
  626.  
  627.  
  628. void show_time(char *s, struct ps_proc * this)
  629. {
  630.     unsigned t;
  631.     t = (this->utime + this->stime) / HZ;
  632.     if (CL_Sum) t += (this->cutime + this->cstime) / HZ;
  633.     sprintf(s, "%3d:%02d ", t / 60, t % 60);
  634. }
  635.  
  636.  
  637. void read_globals()
  638. {
  639.   char uptime[30], memory[300];
  640.   int fd;
  641.  
  642.   fd = open("/proc/uptime", O_RDONLY, 0);
  643.   if (fd == -1) {
  644.     fprintf(stderr, "Error: /proc must be mounted\n"
  645.       "  Make sure that a directory /proc exists, then include the following\n"
  646.       "  line in your /etc/fstab file:\n"
  647.       "      /proc   /proc   proc    defaults\n"
  648.       "  Then the next time you boot, ps should work.  In the meantime, do:\n"
  649.       "      mount /proc /proc -t proc\n");
  650.     exit(1);
  651.   }
  652.   read(fd,uptime,29);
  653.   close(fd);
  654.   GL_current_time = atoi(uptime);
  655.   fd = open("/proc/meminfo", O_RDONLY, 0);
  656.   if(fd == -1) {
  657.     perror("ps.c:/proc/meminfo");
  658.     exit(1);
  659.   }
  660.   read(fd,memory,299);
  661.   close(fd);
  662.   sscanf(memory, "%*s %*s %*s %*s %*s %*s %u", &GL_main_mem);
  663.   GL_time_now = time(0L);
  664. }
  665.