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

  1. /*
  2.  * top.c        - show top CPU processes
  3.  *
  4.  * Copyright (c) 1992 Branko Lankester
  5.  * Copyright (c) 1992 Roger Binns
  6.  *
  7.  * Snarfed and HEAVILY modified for the YAPPS (yet another /proc ps)
  8.  * by Michael K. Johnson, johnsonm@sunsite.unc.edu.  What is used is what
  9.  * is required to have a common interface.
  10.  *
  11.  * Modified Michael K Johnson's ps to make it a top program.
  12.  * Also borrowed elements of Roger Binns kmem based top program.
  13.  * Changes made by Robert J. Nation (nation@rocket.sanders.lockheed.com)
  14.  * 1/93
  15.  *
  16.  * Modified by Michael K. Johnson to be more efficient in cpu use
  17.  * 2/21/93
  18.  *
  19.  * Changed top line to use uptime for the load average.  Also
  20.  * added SIGTSTP handling.  J. Cowley, 19 Mar 1993.
  21.  *
  22.  * Modified quite a bit by Michael Shields (mjshield@nyx.cs.du.edu)
  23.  * 1994/04/02.  Secure mode added.  "d" option added.  Argument parsing
  24.  * improved.  Switched order of tick display to user, system, nice, idle,
  25.  * because it makes more sense that way.  Style regularized (to K&R,
  26.  * more or less).  Cleaned up much throughout.  Added cumulative mode.
  27.  * Help screen improved.
  28.  *
  29.  * Fixed kill buglet brought to my attention by Rob Hooft.
  30.  * Problem was mixing of stdio and read()/write().  Added
  31.  * getnum() to solve problem.
  32.  * 12/30/93 Michael K. Johnson
  33.  *
  34.  * Added toggling output of idle processes via 'i' key.
  35.  * 3/29/94 Gregory K. Nickonov
  36.  *
  37.  * Fixed buglet where rawmode wasn't getting restored.
  38.  * Added defaults for signal to send and nice value to use.
  39.  * 5/4/94 Jon Tombs.
  40.  *
  41.  * Modified 1994/04/25 Michael Shields <mjshield@nyx.cs.du.edu>
  42.  * Merged previous changes to 0.8 into 0.95.
  43.  * Allowed the use of symbolic names (e.g., "HUP") for signal input.
  44.  * Rewrote getnum() into getstr(), getint(), getsig(), etc.
  45.  */
  46.  
  47.  
  48. #include <sys/types.h>
  49. #include <stdio.h>
  50. #include <stdlib.h>
  51. #include <unistd.h>
  52. #include <string.h>
  53. #include <fcntl.h>
  54. #include <time.h>
  55. #include <sys/ioctl.h>
  56. #include <pwd.h>
  57. #include <linux/sched.h>
  58. #include <linux/tty.h>
  59. #include <termcap.h>
  60. #include <termios.h>
  61. #include <signal.h>
  62. #include <sys/time.h>
  63. #include <sys/resource.h>
  64. #include <ctype.h>
  65. #include <setjmp.h>
  66.  
  67. #include "sysinfo.h"
  68. #include "ps.h"
  69. #include "whattime.h"
  70. #include "signals.h"
  71.  
  72.  
  73. /* This structure stores some critical information from one frame to
  74.    the next. */
  75. struct save_hist {
  76.     int ticks;
  77.     int pid;
  78.     int pcpu;
  79.     int utime;
  80.     int stime;
  81. };
  82.  
  83.  
  84. /* The original terminal attributes. */
  85. struct termio Savetty;
  86. /* The new terminal attributes. */
  87. struct termio Rawtty;
  88.  
  89. /* Cached termcap entries. */
  90. char *cm, *cl, *clrtobot, *clrtoeol, *ho;
  91.  
  92. /* Current window size.  Note that it is legal to set Display_procs
  93.    larger than can fit; if the window is later resized, all will be ok.
  94.    In other words: Display_procs is the specified max number of
  95.    processes to display (zero for infinite), and Maxlines is the actual
  96.    number. */
  97. int Lines, Cols, Maxlines, Display_procs;
  98.  
  99. /* Maximum length of the command line of a process. */
  100. unsigned Maxcmd;
  101.  
  102. /* The top of the main loop. */
  103. jmp_buf redraw_jmp;
  104.  
  105. /* Information about each task. */
  106. struct save_hist New_save_hist[NR_TASKS];
  107.  
  108. /* Controls how long we sleep between screen updates.  Accurate to
  109.    microseconds. */
  110. float Sleeptime = 5;
  111.  
  112. /* Mode flags. */
  113. int Secure = 0;
  114. int Cumulative = 0;
  115. int Noidle = 0;
  116.  
  117.  
  118. /* The header printed at the top of the process list.  It would make
  119.    sense if TIME became (say) CTIME in cumulative mode, but that's not
  120.    how ps does it. */
  121. #define HEADER \
  122.     "  PID USER     PRI  NI SIZE  RES SHRD STAT %CPU %MEM  TIME COMMAND"
  123.  
  124. /* The response to the interactive 'h' command. */
  125. #define HELP_SCREEN "\
  126. Interactive commands are:\n\
  127. \n\
  128. ^L\tRedraw the screen\n\
  129. h or ?\tPrint this list\n\
  130. i\tToggle displaying of idle proceses\n\
  131. k\tKill a task (with any signal)\n\
  132. n or #\tSet the number of process to show\n\
  133. q\tQuit\n\
  134. r\tRenice a task\n\
  135. S\tToggle cumulative mode\n\
  136. s\tSet the delay in seconds between updates\n"
  137. #define SECURE_HELP_SCREEN "\
  138. Interactive commands available in secure mode are:\n\
  139. \n\
  140. ^L\tRedraw the screen\n\
  141. h or ?\tPrint this list\n\
  142. i\tToggle displaying of idle proceses\n\
  143. n or #\tSet the number of process to show\n\
  144. q\tQuit\n\
  145. S\tToggle cumulative mode\n"
  146.  
  147. /* Number of lines not to use for displaying processes. */
  148. #define HEADER_LINES 7
  149.  
  150. /* String to use in error messages. */
  151. #define PROGNAME "top"
  152.  
  153.  
  154. /* Clear the screen. */
  155. #define clear_screen() \
  156.     printf("%s", cl)
  157.  
  158. /* Show an error in the context of the spiffy full-screen display. */
  159. #define SHOWMESSAGE(x) do {             \
  160.     printf("%s%s", tgoto(cm, 0, 5), clrtoeol);    \
  161.     printf x;                    \
  162.     fflush(stdout);                \
  163.     sleep(2);                    \
  164. } while (0)
  165.  
  166.  
  167. void end(void);
  168. void stop(void);
  169. void window_size(void);
  170. void show_procs(struct ps_proc_head *ph);
  171. float get_elapsed_time(void);
  172. unsigned show_meminfo(void);
  173. void do_stats(struct ps_proc_head *ph, float elapsed_time,int pass);
  174. void do_key(char c);
  175. int getnum(void);
  176. char *getstr(void);
  177. int getsig(void);
  178. float getfloat(void);
  179.    
  180.  
  181. int
  182. main(int argc, char **argv)
  183. {
  184.     /* For the snapshot. */
  185.     struct ps_proc_head *ph;
  186.     float elapsed_time;
  187.     /* For select(2). */
  188.     struct timeval tv;
  189.     fd_set in;
  190.     /* For parsing arguments. */
  191.     char *cp;
  192.     /* The key read in. */
  193.     char c;
  194.  
  195.     char *termtype;
  196.     struct termio newtty;
  197.  
  198.     /*
  199.      * Parse arguments.
  200.      */
  201.     argv++;
  202.     while (*argv) {
  203.         cp = *argv++;
  204.     while (*cp) {
  205.         switch (*cp) {
  206.         case 'd':
  207.         if (sscanf(cp+1, "%f", &Sleeptime) != 1) {
  208.             fprintf(stderr, PROGNAME ": Bad delay time `%s'\n", cp+1);
  209.             exit(1);
  210.         }
  211.         goto breakargv;
  212.         break;
  213.         case 'q':
  214.         if (!getuid())
  215.             /* Why not -20, which the manpage says is the highest?
  216.                Would that interfere with the kernel? */
  217.             if (setpriority(PRIO_PROCESS, getpid(), -15)) {
  218.                 /* We check this just for paranoia.  It's not
  219.                    fatal, and shouldn't happen. */
  220.                 perror(PROGNAME ": setpriority() failed");
  221.             }
  222.         Sleeptime = 0;
  223.         break;
  224.         case 'S':
  225.             Cumulative = 1;
  226.             break;
  227.         case 'i':
  228.         Noidle = 1;
  229.         break;
  230.         case 's':
  231.         Secure = 1;
  232.         break;
  233.         case '-':
  234.         break; /* Just ignore it */
  235.         default:
  236.         fprintf(stderr, PROGNAME ": Unknown argument `%c'\n", *cp);
  237.         exit(1);
  238.         }
  239.         cp++;
  240.     }
  241.     breakargv:
  242.     }
  243.  
  244.     /*
  245.      * Set up the terminal attributes.
  246.      */
  247.     termtype = getenv("TERM");
  248.     if (!termtype) { 
  249.     /* In theory, $TERM should never not be set, but in practice,
  250.        some gettys don't.  Fortunately, vt100 is nearly always
  251.        correct (or pretty close). */
  252.     termtype = "VT100";
  253.     /* fprintf(stderr, PROGNAME ": $TERM not set\n"); */
  254.     /* exit(1); */
  255.     }
  256.     close(0);
  257.     if (open("/dev/tty", O_RDONLY)) {
  258.     perror(PROGNAME ": stdin is not there\n");
  259.     exit(errno);
  260.     }
  261.     if (ioctl(0, TCGETA, &Savetty) == -1) {
  262.     perror(PROGNAME ": ioctl() failed");
  263.     exit(errno);
  264.     }
  265.     newtty = Savetty;
  266.     newtty.c_lflag &= ~ICANON;
  267.     newtty.c_lflag &= ~ECHO;
  268.     newtty.c_cc[VMIN] = 1;
  269.     newtty.c_cc[VTIME] = 0;
  270.     if (ioctl(0, TCSETAF, &newtty) == -1) {
  271.     printf("cannot put tty into raw mode\n");
  272.     exit(1);
  273.     }
  274.     ioctl(0, TCGETA, &Rawtty);
  275.  
  276.     /*
  277.      * Get termcap entries and window size.
  278.      */
  279.     tgetent(NULL, termtype);
  280.     cm = tgetstr("cm", 0);
  281.     clrtobot = tgetstr("cd", 0);
  282.     cl = tgetstr("cl", 0);
  283.     clrtoeol = tgetstr("ce", 0);
  284.     ho = tgetstr("ho", 0);
  285.     window_size();
  286.  
  287.     /*
  288.      * Set up signal handlers.
  289.      */
  290.     signal(SIGHUP, (void *)(int) end);
  291.     signal(SIGINT, (void *)(int) end);
  292.     signal(SIGTSTP, (void *)(int) stop);
  293.     signal(SIGWINCH, (void *)(int) window_size);
  294.  
  295.     /* first time through, just collect process stats */
  296.     ph = take_snapshot(1, 1, 1, 1, 0, 0, 0);
  297.     elapsed_time = get_elapsed_time();
  298.     do_stats(ph, elapsed_time, 0);
  299.     sleep(1);
  300.  
  301.     /* loop, collecting process info and sleeping */
  302.     while(1) {
  303.     if (setjmp(redraw_jmp))
  304.         clear_screen();
  305.  
  306.     /* display the tasks */
  307.     show_procs(ph);
  308.     
  309.     /* sleep & wait for keyboard input */
  310.     tv.tv_sec = Sleeptime;
  311.     tv.tv_usec = (Sleeptime - (int)Sleeptime) * 1000000;
  312.     FD_ZERO(&in);
  313.     FD_SET(0, &in);
  314.     if (select(16, &in, 0, 0, &tv) > 0 && read(0, &c, 1) == 1)
  315.         do_key(c);
  316.     }
  317. }
  318.  
  319.  
  320.  
  321. /*
  322.  * Normal end of execution.
  323.  */
  324. void
  325. end(void)
  326. {
  327.     ioctl(0, TCSETAF, &Savetty);
  328.     printf("%s\r\n", tgoto(cm, 0, Lines - 1));
  329.     exit(0);
  330. }
  331.  
  332.  
  333. /*
  334.  * SIGTSTP catcher.
  335.  */
  336. void
  337. stop(void)
  338. {
  339.     /* Reset terminal. */
  340.     ioctl(0, TCSETAF, &Savetty);
  341.     printf("%s", tgoto(cm, 0, Lines - 3));
  342.     fflush(stdout);
  343.     raise(SIGTSTP);
  344.     /* Later... */
  345.     ioctl(0, TCSETAF, &Rawtty);
  346.     signal(SIGTSTP, (void *)(int) stop);
  347.     longjmp(redraw_jmp, 1);
  348. }
  349.  
  350.  
  351. /*
  352.  * Reads the window size and clear the window.  This is called on setup,
  353.  * and also catches SIGWINCHs, and adjusts Maxlines.  Basically, this is
  354.  * the central place for window size stuff.
  355.  */
  356. void
  357. window_size(void)
  358. {
  359.     struct winsize ws;
  360.  
  361.     if (ioctl(1, TIOCGWINSZ, &ws) != -1) {
  362.     Cols = ws.ws_col;
  363.     Lines = ws.ws_row;
  364.     } else {
  365.     Cols = tgetnum("co");
  366.     Lines = tgetnum("li");
  367.     }
  368.     Maxlines = Display_procs ? Display_procs : Lines - HEADER_LINES;
  369.     if (Maxlines > Lines - HEADER_LINES)
  370.         Maxlines = Lines - HEADER_LINES;
  371.     Maxcmd = Cols - strlen(HEADER) + 7;
  372.     clear_screen();
  373. }
  374.  
  375.  
  376. /*
  377.  * Get a string from the user; the base of getint(), et al.  This really
  378.  * ought to handle long input lines and errors better.  NB: The pointer
  379.  * returned is a statically allocated buffer, so don't expect it to
  380.  * persist between calls.
  381.  */
  382. char *
  383. getstr(void)
  384. {
  385.     static char line[BUFSIZ];        /* BUFSIZ from <stdio.h>; arbitrary */
  386.     int i = 0;
  387.  
  388.     /* Must make sure that buffered IO doesn't kill us. */
  389.     fflush(stdout);
  390.     fflush(stdin);            /* Not POSIX but ok */
  391.  
  392.     do {
  393.     read(STDIN_FILENO, &line[i], 1);
  394.     } while (line[i++] != '\n' && i < sizeof(line));
  395.     line[--i] = 0;
  396.  
  397.     return(line);
  398. }
  399.  
  400.  
  401. /*
  402.  * Get an integer from the user.  Display an error message and return -1
  403.  * if it's invalid; else return the number.
  404.  */
  405. int
  406. getint(void)
  407. {
  408.     char *line;
  409.     int i;
  410.     int r;
  411.  
  412.     line = getstr();
  413.  
  414.     for (i = 0; line[i]; i++) {
  415.     if (!isdigit(line[i])) {
  416.             SHOWMESSAGE(("That's not a number!"));
  417.             return(-1);
  418.         }
  419.     }
  420.  
  421.     /* An empty line is a legal error (hah!). */
  422.     if (!line[0])
  423.         return (-1);
  424.  
  425.     sscanf(line, "%d", &r);
  426.     return(r);
  427. }
  428.  
  429.  
  430. /*
  431.  * Get a float from the user.  Just like getint().
  432.  */
  433. float
  434. getfloat(void)
  435. {
  436.     char *line;
  437.     int i;
  438.     float r;
  439.  
  440.     line = getstr();
  441.  
  442.     for (i = 0; line[i]; i++) {
  443.     if (!isdigit(line[i])) {
  444.             SHOWMESSAGE(("That's not a number!"));
  445.             return(-1);
  446.         }
  447.     }
  448.  
  449.     /* An empty line is a legal error (hah!). */
  450.     if (!line[0])
  451.         return (-1);
  452.  
  453.     sscanf(line, "%f", &r);
  454.     return(r);
  455. }
  456.  
  457.  
  458. /*
  459.  * Get a signal number or name from the user.  Return the number, or -1
  460.  * on error.
  461.  */
  462. int
  463. getsig(void)
  464. {
  465.     char *line;
  466.  
  467.     /* This is easy. */
  468.     line = getstr();
  469.     return(get_signal2(line));
  470. }
  471.  
  472.  
  473. /*
  474.  * This is the real program!  Read process info and display it.
  475.  */
  476. void
  477. show_procs(struct ps_proc_head *ph)
  478. {
  479.     struct ps_proc *this, *best;
  480.     int count, top;
  481.     int index, best_index;
  482.     float elapsed_time;
  483.     unsigned int main_mem;
  484.  
  485.     /* Display the load averages. */
  486.     printf("%s%s%s\n", ho, sprint_uptime(), clrtoeol);
  487.  
  488.     /* Get the process info. */
  489.     ph = refresh_snapshot(ph, 1, 1, 1, 1, 0, 0, 0);
  490.     /* Immediately find out the elapsed time for the frame. */
  491.     elapsed_time = get_elapsed_time();
  492.  
  493.     /* Display the system stats and calculate percent CPU time. */
  494.     do_stats(ph, elapsed_time, 1);
  495.  
  496.     /* Display the memory and swap space usage. */
  497.     main_mem = show_meminfo();
  498.     printf("%s%s", HEADER, clrtoeol);
  499.     
  500.     /*
  501.      * Finally!  Loop through to find the top task, and display it.
  502.      * Lather, rinse, repeat.
  503.      */
  504.     count = 0;
  505.     top = 100;
  506.     while ((count < Maxlines) && (top >= 0)) {
  507.     /* Find the top of the remaining processes. */
  508.     top = -1;
  509.     this = ph->head;
  510.     best = this;
  511.     best_index = 0;
  512.     index = 0;
  513.     while (this) {
  514.         if (New_save_hist[index].pcpu > top) {
  515.         top = New_save_hist[index].pcpu;
  516.         best = this;
  517.         best_index = index;
  518.         }
  519.         index++;
  520.         this = this->next;
  521.     }
  522.     count++;
  523.     if (top >= 0) {
  524.         int pcpu, pmem;
  525.         unsigned int t;
  526.         char *cmdptr;
  527.         char *stat;
  528.  
  529.         stat = status(best);
  530.  
  531.         if (!Noidle || (*stat != 'S' && *stat != 'Z')) {
  532.  
  533.         /*
  534.          * Show task info.
  535.          */
  536.         pcpu = New_save_hist[best_index].pcpu;
  537.         pmem = best->rss * 1000 / (main_mem / 4096);
  538.         printf("\n%5d %-8s %3d %3d %4d %4d %4d %s %2d.%d %2d.%d", 
  539.                best->pid, best->user, 2 * PZERO - best->counter,
  540.                PZERO - best->priority, best->vsize / 1024,
  541.                best->rss * 4, best->statm.share << 2, stat,
  542.                pcpu / 10, pcpu % 10, pmem / 10, pmem % 10);
  543.  
  544.         /*
  545.          * Show total CPU time.
  546.          */
  547.         t = (best->utime + best->stime) / HZ;
  548.         if (Cumulative)
  549.             t += (best->cutime + best->cstime) / HZ;
  550.         printf("%3d:%02d ", t / 60, t % 60);
  551.         
  552.         /*
  553.          * Show command line.
  554.          */
  555.         if (*best->cmdline)
  556.             cmdptr = best->cmdline;
  557.         else
  558.             cmdptr = best->cmd;
  559.         if (strlen(cmdptr) > Maxcmd)
  560.             cmdptr[Maxcmd - 1] = 0;
  561.         printf("%s%s", cmdptr, clrtoeol);
  562.         }
  563.     }
  564.  
  565.     New_save_hist[best_index].pcpu = -1;
  566.     }
  567.     printf("%s%s", clrtobot, tgoto(cm, 0, 5));
  568.  
  569.     fflush(stdout);
  570. }
  571.  
  572.  
  573. /*
  574.  * Finds the current time (in microseconds) and calculates the time
  575.  * elapsed since the last update. This is essential for computing
  576.  * percent CPU usage.
  577.  */
  578. float
  579. get_elapsed_time(void)
  580. {
  581.     struct timeval time;
  582.     static struct timeval oldtime;
  583.     struct timezone timez;
  584.     float elapsed_time;
  585.  
  586.     gettimeofday(&time, &timez);
  587.     elapsed_time = (time.tv_sec - oldtime.tv_sec)
  588.                + (float) (time.tv_usec - oldtime.tv_usec) / 1000000.0;
  589.     oldtime.tv_sec = time.tv_sec;
  590.     oldtime.tv_usec = time.tv_usec;
  591.     return(elapsed_time);
  592. }
  593.  
  594.  
  595. /*
  596.  * Reads the memory info and displays it.  Returns the total memory
  597.  * available, for use in percent memory usage calculations.
  598.  */
  599. unsigned
  600. show_meminfo(void)
  601. {
  602.   char memory[1024];
  603.   static int fd;
  604.   unsigned int main_mem, used_mem, free_mem, shared_mem, buf_mem;
  605.   unsigned int swap_mem, used_swap, free_swap;
  606.  
  607.   fd = open("/proc/meminfo", O_RDONLY, 0);
  608.   if (fd == -1) {
  609.       perror(PROGNAME ": Couldn't open /proc/meminfo");
  610.       end();
  611.   }
  612.   read(fd, memory, sizeof(memory) - 1);
  613.   close(fd);
  614.   sscanf(memory, "%*s %*s %*s %*s %*s %*s %u %u %u %u %u %*s %u %u %u",
  615.      &main_mem, &used_mem, &free_mem, &shared_mem, &buf_mem,
  616.      &swap_mem, &used_swap, &free_swap);
  617.   printf("Mem:  %5dK av, %5dK used, %5dK free, %5dK shrd, %5dK buff%s\n",
  618.      main_mem / 1024, used_mem / 1024, free_mem / 1024, 
  619.      shared_mem / 1024, buf_mem / 1024, clrtoeol);
  620.   printf("Swap: %5dK av, %5dK used, %5dK free%s\n%s\n",
  621.      swap_mem / 1024, used_swap / 1024, free_swap / 1024,
  622.      clrtoeol, clrtoeol);
  623.   return(main_mem);
  624. }
  625.  
  626.  
  627. /*
  628.  * Calculates the number of tasks in each state (running, sleeping, etc.).
  629.  * Calculates the CPU time in each state (system, user, nice, etc).
  630.  * Calculates percent cpu usage for each task.
  631.  */
  632. void
  633. do_stats(struct ps_proc_head *ph, float elapsed_time, int pass)
  634. {
  635.     struct ps_proc *this;
  636.     int index, total_time, i;
  637.     int sleeping = 0, stopped = 0, zombie = 0, running = 0;
  638.     int system_ticks = 0, user_ticks = 0, nice_ticks = 0, idle_ticks = 1000;
  639.     static int prev_count = 0;
  640.     static struct save_hist save_hist[NR_TASKS];
  641.     int stime, utime;
  642.  
  643.     if (ph->count >NR_TASKS) {
  644.     printf(PROGNAME ": Help!  Too many tasks!\n");
  645.     end();
  646.     }
  647.  
  648.     /*
  649.      * Make a pass through the data to get stats.
  650.      */
  651.     index = 0;
  652.     this = ph->head;
  653.     while (this) {
  654.         switch (this->state) {
  655.         case 'S':
  656.         case 'D':
  657.         sleeping++;
  658.         break;
  659.     case 'T':
  660.         stopped++;
  661.         break;
  662.     case 'Z':
  663.         zombie++;
  664.         break;
  665.     case 'R':
  666.         running++;
  667.         break;
  668.     default:
  669.         /* Don't know how to handle this one. */
  670.         break;
  671.     }
  672.  
  673.     /*
  674.      * Calculate time in this process.  Time is sum of user time
  675.      * (utime) plus system time (stime).
  676.      */
  677.     total_time = this->utime + this->stime;
  678.     New_save_hist[index].ticks = total_time;
  679.     New_save_hist[index].pid = this->pid;
  680.     stime = this->stime;
  681.     utime = this->utime;
  682.     New_save_hist[index].stime = stime;
  683.     New_save_hist[index].utime = utime;
  684.     /* find matching entry from previous pass*/
  685.     i = 0;
  686.     while (i < prev_count) {
  687.         if (save_hist[i].pid == this->pid) {
  688.         total_time -= save_hist[i].ticks;
  689.         stime -= save_hist[i].stime;
  690.         utime -= save_hist[i].utime;
  691.  
  692.         i = NR_TASKS;
  693.         }
  694.         i++;
  695.     }
  696.  
  697.     /*
  698.      * Calculate percent cpu time for this task.
  699.      */
  700.     New_save_hist[index].pcpu = (total_time * 10) / elapsed_time;
  701.     if (New_save_hist[index].pcpu > 999)
  702.         New_save_hist[index].pcpu = 999;
  703.  
  704.     /*
  705.      * Calculate time in idle, system, user and niced tasks.
  706.      */
  707.     idle_ticks -= New_save_hist[index].pcpu;
  708.     system_ticks += stime;
  709.     user_ticks += utime;
  710.     if (this->priority < PZERO)
  711.         nice_ticks += New_save_hist[index].pcpu;
  712.  
  713.     index++;
  714.     this = this->next;
  715.     }
  716.  
  717.     if (idle_ticks < 0)
  718.     idle_ticks = 0;
  719.     system_ticks = (system_ticks * 10) / elapsed_time;      
  720.     user_ticks = (user_ticks * 10) / elapsed_time;
  721.  
  722.     /*
  723.      * Display stats.
  724.      */
  725.     if (pass>0) {
  726.     printf("%d processes: %d sleeping, %d running, %d zombie, "
  727.            "%d stopped%s\n",
  728.            ph->count, sleeping, running, zombie, stopped, clrtoeol);
  729.     printf("CPU states: %2d.%d%% user, %2d.%d%% system,"
  730.            " %2d.%d%% nice, %2d.%d%% idle%s\n",
  731.            user_ticks / 10, user_ticks % 10,
  732.            system_ticks / 10, system_ticks % 10,
  733.            nice_ticks / 10, nice_ticks % 10,
  734.            idle_ticks / 10, idle_ticks % 10, clrtoeol);
  735.     }
  736.  
  737.     /*
  738.      * Save this frame's information.
  739.      */
  740.     for (i = 0; i < ph->count; i++) {
  741.     /* copy the relevant info for the next pass */
  742.     save_hist[i].pid = New_save_hist[i].pid;
  743.     save_hist[i].ticks = New_save_hist[i].ticks;
  744.     save_hist[i].stime = New_save_hist[i].stime;
  745.     save_hist[i].utime = New_save_hist[i].utime;
  746.     }
  747.     prev_count = ph->count;
  748. }
  749.  
  750.  
  751. /*
  752.  * Process keyboard input.
  753.  */
  754. void
  755. do_key(char c)
  756. {
  757.     int numinput;
  758.  
  759.     /*
  760.      * First the commands which don't require a terminal mode switch.
  761.      */
  762.     if (c == 'q')
  763.     end();
  764.     else if (c == 12) {
  765.     clear_screen();
  766.     return;
  767.     }
  768.  
  769.     /*
  770.      * Switch the terminal to normal mode.  (Will the original
  771.      * attributes always be normal?  Does it matter?  I suppose the
  772.      * shell will be set up the way the user wants it.)
  773.      */
  774.     ioctl(0, TCSETA, &Savetty);
  775.  
  776.     /*
  777.      * Handle the rest of the commands.
  778.      */
  779.     switch (c) {
  780.     case 'h':
  781.     printf("%s%s\nProc-Top Revision 0\n", cl, ho);
  782.     printf("Secure mode %s; cumulative mode %s; noidle mode %s\n\n",
  783.            Secure ? "on" : "off", Cumulative ? "on" : "off",
  784.            Noidle ? "on" : "off");
  785.     printf("%s\n\nPress any key to continue\n",
  786.            Secure ? SECURE_HELP_SCREEN : HELP_SCREEN);
  787.     ioctl(0, TCSETA, &Rawtty);
  788.     (void) getchar();
  789.     break;
  790.     case 'i':
  791.         Noidle = !Noidle;
  792.         SHOWMESSAGE(("No-idle mode %s", Noidle ? "on" : "off"));
  793.         break;
  794.     case 'k':
  795.     if (Secure)
  796.         SHOWMESSAGE(("\aCan't kill in secure mode"));
  797.     else {
  798.         int pid, signal;
  799.  
  800.         printf("PID to kill: ");
  801.         pid = getint();
  802.         if (pid == -1)
  803.             break;
  804.         printf("%s%sKill PID %d with signal [15]: ",
  805.                tgoto(cm, 0, 5), clrtoeol, pid);
  806.         signal = getsig();
  807.         if (signal == -1)
  808.             signal = SIGTERM;
  809.         if (kill(pid, signal))
  810.         SHOWMESSAGE(("\aKill of PID %d with %d failed: %s",
  811.                  pid, signal, strerror(errno)));
  812.     }
  813.     break;
  814.     case 'n':
  815.     case '#':
  816.     printf("Processes to display (0 for unlimited): ");
  817.     numinput = getint();
  818.     if (numinput != -1) {
  819.         Display_procs = numinput;
  820.         window_size();
  821.     }
  822.     break;
  823.     case 'r':
  824.     if (Secure)
  825.         SHOWMESSAGE(("\aCan't renice in secure mode"));
  826.     else {
  827.         int pid, val;
  828.  
  829.         printf("PID to renice: ");
  830.         pid = getint();
  831.         if (pid == -1)
  832.             break;
  833.         printf("%s%sRenice PID %d to value: ",
  834.                tgoto(cm, 0, 5), clrtoeol, pid);
  835.         val = getint();
  836.         if (val == -1)
  837.             val = 10;
  838.         if (setpriority(PRIO_PROCESS, pid, val))
  839.         SHOWMESSAGE(("\aRenice of PID %d to %d failed: %s",
  840.                  pid, val, strerror(errno)));
  841.     }
  842.     break;
  843.     case 'S':
  844.         Cumulative = !Cumulative;
  845.         SHOWMESSAGE(("Cumulative mode %s", Cumulative ? "on" : "off"));
  846.         break;
  847.     case 's':
  848.     if (Secure)
  849.         SHOWMESSAGE(("\aCan't change delay in secure mode"));
  850.     else {
  851.         printf("Delay between updates: ");
  852.         numinput = getfloat();
  853.         if (numinput != -1)
  854.             Sleeptime = numinput;
  855.     }
  856.     break;
  857.     default:
  858.     SHOWMESSAGE(("\aUnknown command `%c' -- hit `h' for help", c));
  859.     }
  860.  
  861.     /*
  862.      * Return to raw mode.
  863.      */
  864.     ioctl(0, TCSETA, &Rawtty);
  865.     return;
  866. }
  867.