blob: 2bef38dd498ae797b8804309e6d44bf62bb20516 [file] [log] [blame]
Eric Andersen420b2082002-09-17 22:14:58 +00001/*
2 * A tiny 'top' utility.
3 *
Eric Andersen08a72202002-09-30 20:52:10 +00004 * This is written specifically for the linux /proc/<PID>/stat(m)
5 * files format.
6
7 * This reads the PIDs of all processes and their status and shows
8 * the status of processes (first ones that fit to screen) at given
9 * intervals.
Eric Andersenc7bda1c2004-03-15 08:29:22 +000010 *
Eric Andersen420b2082002-09-17 22:14:58 +000011 * NOTES:
12 * - At startup this changes to /proc, all the reads are then
13 * relative to that.
Eric Andersenc7bda1c2004-03-15 08:29:22 +000014 *
Eric Andersen420b2082002-09-17 22:14:58 +000015 * (C) Eero Tamminen <oak at welho dot com>
Eric Andersen08a72202002-09-30 20:52:10 +000016 *
Eric Andersenaff114c2004-04-14 17:51:38 +000017 * Rewritten by Vladimir Oleynik (C) 2002 <dzo@simtreas.ru>
Eric Andersen420b2082002-09-17 22:14:58 +000018 */
Eric Andersen08a72202002-09-30 20:52:10 +000019
20/* Original code Copyrights */
21/*
22 * Copyright (c) 1992 Branko Lankester
23 * Copyright (c) 1992 Roger Binns
24 * Copyright (C) 1994-1996 Charles L. Blake.
25 * Copyright (C) 1992-1998 Michael K. Johnson
26 * May be distributed under the conditions of the
27 * GNU Library General Public License
28 */
29
30#include <sys/types.h>
Eric Andersen420b2082002-09-17 22:14:58 +000031#include <stdio.h>
32#include <stdlib.h>
33#include <unistd.h>
Eric Andersen420b2082002-09-17 22:14:58 +000034#include <string.h>
35#include <sys/ioctl.h>
Eric Andersen08a72202002-09-30 20:52:10 +000036/* get page info */
37#include <asm/page.h>
Eric Andersen420b2082002-09-17 22:14:58 +000038#include "busybox.h"
39
Eric Andersen08a72202002-09-30 20:52:10 +000040//#define FEATURE_CPU_USAGE_PERCENTAGE /* + 2k */
Eric Andersen420b2082002-09-17 22:14:58 +000041
Eric Andersen08a72202002-09-30 20:52:10 +000042#ifdef FEATURE_CPU_USAGE_PERCENTAGE
43#include <time.h>
44#include <sys/time.h>
45#include <fcntl.h>
46#include <netinet/in.h> /* htons */
47#endif
48
49
Eric Andersen44608e92002-10-22 12:21:15 +000050typedef int (*cmp_t)(procps_status_t *P, procps_status_t *Q);
Eric Andersen08a72202002-09-30 20:52:10 +000051
Eric Andersen44608e92002-10-22 12:21:15 +000052static procps_status_t *top; /* Hehe */
Eric Andersen08a72202002-09-30 20:52:10 +000053static int ntop;
54
55
Eric Andersen44608e92002-10-22 12:21:15 +000056static int pid_sort (procps_status_t *P, procps_status_t *Q)
Eric Andersen08a72202002-09-30 20:52:10 +000057{
58 int p = P->pid;
59 int q = Q->pid;
60
61 if( p < q ) return -1;
62 if( p > q ) return 1;
63 return 0;
64}
65
Eric Andersen44608e92002-10-22 12:21:15 +000066static int mem_sort (procps_status_t *P, procps_status_t *Q)
Eric Andersen08a72202002-09-30 20:52:10 +000067{
68 long p = P->rss;
69 long q = Q->rss;
70
71 if( p > q ) return -1;
72 if( p < q ) return 1;
73 return 0;
74}
75
76#ifdef FEATURE_CPU_USAGE_PERCENTAGE
77
78#define sort_depth 3
79static cmp_t sort_function[sort_depth];
80
Eric Andersen44608e92002-10-22 12:21:15 +000081static int pcpu_sort (procps_status_t *P, procps_status_t *Q)
Eric Andersen08a72202002-09-30 20:52:10 +000082{
83 int p = P->pcpu;
84 int q = Q->pcpu;
85
86 if( p > q ) return -1;
87 if( p < q ) return 1;
88 return 0;
89}
90
Eric Andersen44608e92002-10-22 12:21:15 +000091static int time_sort (procps_status_t *P, procps_status_t *Q)
Eric Andersen08a72202002-09-30 20:52:10 +000092{
93 long p = P->stime;
94 long q = Q->stime;
95
96 p += P->utime;
97 q += Q->utime;
98 if( p > q ) return -1;
99 if( p < q ) return 1;
100 return 0;
101}
102
103int mult_lvl_cmp(void* a, void* b) {
104 int i, cmp_val;
105
106 for(i = 0; i < sort_depth; i++) {
107 cmp_val = (*sort_function[i])(a, b);
108 if (cmp_val != 0)
109 return cmp_val;
110 }
111 return 0;
112}
113
114/* This structure stores some critical information from one frame to
115 the next. mostly used for sorting. Added cumulative and resident fields. */
116struct save_hist {
117 int ticks;
118 int pid;
119 int utime;
120 int stime;
121};
122
123/*
124 * Calculates percent cpu usage for each task.
125 */
126
127static struct save_hist *save_history;
128
129static unsigned long Hertz;
130
131/***********************************************************************
132 * Some values in /proc are expressed in units of 1/HZ seconds, where HZ
133 * is the kernel clock tick rate. One of these units is called a jiffy.
134 * The HZ value used in the kernel may vary according to hacker desire.
135 * According to Linus Torvalds, this is not true. He considers the values
Eric Andersenaff114c2004-04-14 17:51:38 +0000136 * in /proc as being in architecture-dependent units that have no relation
Eric Andersen08a72202002-09-30 20:52:10 +0000137 * to the kernel clock tick rate. Examination of the kernel source code
138 * reveals that opinion as wishful thinking.
139 *
140 * In any case, we need the HZ constant as used in /proc. (the real HZ value
141 * may differ, but we don't care) There are several ways we could get HZ:
142 *
143 * 1. Include the kernel header file. If it changes, recompile this library.
144 * 2. Use the sysconf() function. When HZ changes, recompile the C library!
145 * 3. Ask the kernel. This is obviously correct...
146 *
147 * Linus Torvalds won't let us ask the kernel, because he thinks we should
148 * not know the HZ value. Oh well, we don't have to listen to him.
149 * Someone smuggled out the HZ value. :-)
150 *
151 * This code should work fine, even if Linus fixes the kernel to match his
152 * stated behavior. The code only fails in case of a partial conversion.
153 *
154 */
155
156#define FILE_TO_BUF(filename, fd) do{ \
157 if (fd == -1 && (fd = open(filename, O_RDONLY)) == -1) { \
Manuel Novoa III cad53642003-03-19 09:13:01 +0000158 bb_perror_msg_and_die("/proc not be mounted?"); \
Eric Andersen08a72202002-09-30 20:52:10 +0000159 } \
160 lseek(fd, 0L, SEEK_SET); \
161 if ((local_n = read(fd, buf, sizeof buf - 1)) < 0) { \
Manuel Novoa III cad53642003-03-19 09:13:01 +0000162 bb_perror_msg_and_die("%s", filename); \
Eric Andersen08a72202002-09-30 20:52:10 +0000163 } \
164 buf[local_n] = '\0'; \
165}while(0)
166
167#define FILE_TO_BUF2(filename, fd) do{ \
168 lseek(fd, 0L, SEEK_SET); \
169 if ((local_n = read(fd, buf, sizeof buf - 1)) < 0) { \
Manuel Novoa III cad53642003-03-19 09:13:01 +0000170 bb_perror_msg_and_die("%s", filename); \
Eric Andersen08a72202002-09-30 20:52:10 +0000171 } \
172 buf[local_n] = '\0'; \
173}while(0)
174
175static void init_Hertz_value(void) {
176 unsigned long user_j, nice_j, sys_j, other_j; /* jiffies (clock ticks) */
177 double up_1, up_2, seconds;
178 unsigned long jiffies, h;
179 char buf[80];
180 int uptime_fd = -1;
181 int stat_fd = -1;
182
183 long smp_num_cpus = sysconf(_SC_NPROCESSORS_CONF);
184
185 if(smp_num_cpus<1) smp_num_cpus=1;
186 do {
187 int local_n;
188
189 FILE_TO_BUF("uptime", uptime_fd);
190 up_1 = strtod(buf, 0);
191 FILE_TO_BUF("stat", stat_fd);
192 sscanf(buf, "cpu %lu %lu %lu %lu", &user_j, &nice_j, &sys_j, &other_j);
193 FILE_TO_BUF2("uptime", uptime_fd);
194 up_2 = strtod(buf, 0);
195 } while((long)( (up_2-up_1)*1000.0/up_1 )); /* want under 0.1% error */
196
197 close(uptime_fd);
198 close(stat_fd);
199
200 jiffies = user_j + nice_j + sys_j + other_j;
201 seconds = (up_1 + up_2) / 2;
202 h = (unsigned long)( (double)jiffies/seconds/smp_num_cpus );
203 /* actual values used by 2.4 kernels: 32 64 100 128 1000 1024 1200 */
204 switch(h){
205 case 30 ... 34 : Hertz = 32; break; /* ia64 emulator */
206 case 48 ... 52 : Hertz = 50; break;
207 case 58 ... 62 : Hertz = 60; break;
208 case 63 ... 65 : Hertz = 64; break; /* StrongARM /Shark */
209 case 95 ... 105 : Hertz = 100; break; /* normal Linux */
210 case 124 ... 132 : Hertz = 128; break; /* MIPS, ARM */
211 case 195 ... 204 : Hertz = 200; break; /* normal << 1 */
212 case 253 ... 260 : Hertz = 256; break;
213 case 295 ... 304 : Hertz = 300; break; /* 3 cpus */
214 case 393 ... 408 : Hertz = 400; break; /* normal << 2 */
215 case 495 ... 504 : Hertz = 500; break; /* 5 cpus */
216 case 595 ... 604 : Hertz = 600; break; /* 6 cpus */
217 case 695 ... 704 : Hertz = 700; break; /* 7 cpus */
218 case 790 ... 808 : Hertz = 800; break; /* normal << 3 */
219 case 895 ... 904 : Hertz = 900; break; /* 9 cpus */
220 case 990 ... 1010 : Hertz = 1000; break; /* ARM */
221 case 1015 ... 1035 : Hertz = 1024; break; /* Alpha, ia64 */
222 case 1095 ... 1104 : Hertz = 1100; break; /* 11 cpus */
223 case 1180 ... 1220 : Hertz = 1200; break; /* Alpha */
224 default:
225 /* If 32-bit or big-endian (not Alpha or ia64), assume HZ is 100. */
226 Hertz = (sizeof(long)==sizeof(int) || htons(999)==999) ? 100UL : 1024UL;
227 }
228}
229
230static void do_stats(void)
231{
232 struct timeval t;
233 static struct timeval oldtime;
234 struct timezone timez;
235 float elapsed_time;
236
Eric Andersen44608e92002-10-22 12:21:15 +0000237 procps_status_t *cur;
Eric Andersen08a72202002-09-30 20:52:10 +0000238 int total_time, i, n;
239 static int prev_count;
240 int systime, usrtime, pid;
241
242 struct save_hist *New_save_hist;
243
244 /*
245 * Finds the current time (in microseconds) and calculates the time
246 * elapsed since the last update.
247 */
248 gettimeofday(&t, &timez);
249 elapsed_time = (t.tv_sec - oldtime.tv_sec)
250 + (float) (t.tv_usec - oldtime.tv_usec) / 1000000.0;
251 oldtime.tv_sec = t.tv_sec;
252 oldtime.tv_usec = t.tv_usec;
253
254 New_save_hist = alloca(sizeof(struct save_hist)*ntop);
255 /*
256 * Make a pass through the data to get stats.
257 */
258 for(n = 0; n < ntop; n++) {
259 cur = top + n;
260
261 /*
262 * Calculate time in cur process. Time is sum of user time
263 * (usrtime) plus system time (systime).
264 */
265 systime = cur->stime;
266 usrtime = cur->utime;
267 pid = cur->pid;
268 total_time = systime + usrtime;
269 New_save_hist[n].ticks = total_time;
270 New_save_hist[n].pid = pid;
271 New_save_hist[n].stime = systime;
272 New_save_hist[n].utime = usrtime;
273
274 /* find matching entry from previous pass */
275 for (i = 0; i < prev_count; i++) {
276 if (save_history[i].pid == pid) {
277 total_time -= save_history[i].ticks;
278 systime -= save_history[i].stime;
279 usrtime -= save_history[i].utime;
280 break;
281 }
282 }
283
284 /*
285 * Calculate percent cpu time for cur task.
286 */
287 i = (total_time * 10 * 100/Hertz) / elapsed_time;
288 if (i > 999)
289 i = 999;
290 cur->pcpu = i;
291
292 }
293
294 /*
295 * Save cur frame's information.
296 */
297 free(save_history);
298 save_history = memcpy(xmalloc(sizeof(struct save_hist)*n), New_save_hist,
299 sizeof(struct save_hist)*n);
300 prev_count = n;
Eric Andersen44608e92002-10-22 12:21:15 +0000301 qsort(top, n, sizeof(procps_status_t), (void*)mult_lvl_cmp);
Eric Andersen08a72202002-09-30 20:52:10 +0000302}
303#else
304static cmp_t sort_function;
305#endif /* FEATURE_CPU_USAGE_PERCENTAGE */
306
Eric Andersen420b2082002-09-17 22:14:58 +0000307/* display generic info (meminfo / loadavg) */
Eric Andersen08a72202002-09-30 20:52:10 +0000308static unsigned long display_generic(void)
Eric Andersen420b2082002-09-17 22:14:58 +0000309{
310 FILE *fp;
311 char buf[80];
312 float avg1, avg2, avg3;
313 unsigned long total, used, mfree, shared, buffers, cached;
Eric Andersen7857c032003-10-11 18:47:20 +0000314 unsigned int needs_conversion = 1;
Eric Andersen420b2082002-09-17 22:14:58 +0000315
316 /* read memory info */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000317 fp = bb_xfopen("meminfo", "r");
Eric Andersen420b2082002-09-17 22:14:58 +0000318
Eric Andersen7857c032003-10-11 18:47:20 +0000319 /*
320 * Old kernels (such as 2.4.x) had a nice summary of memory info that
321 * we could parse, however this is gone entirely in 2.6. Try parsing
322 * the old way first, and if that fails, parse each field manually.
323 *
324 * First, we read in the first line. Old kernels will have bogus
325 * strings we don't care about, whereas new kernels will start right
326 * out with MemTotal:
327 * -- PFM.
328 */
329 if (fscanf(fp, "MemTotal: %lu %s\n", &total, buf) != 2) {
330 fgets(buf, sizeof(buf), fp); /* skip first line */
331
332 fscanf(fp, "Mem: %lu %lu %lu %lu %lu %lu",
333 &total, &used, &mfree, &shared, &buffers, &cached);
334 } else {
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000335 /*
Eric Andersen7857c032003-10-11 18:47:20 +0000336 * Revert to manual parsing, which incidentally already has the
337 * sizes in kilobytes. This should be safe for both 2.4 and
338 * 2.6.
339 */
340 needs_conversion = 0;
341
342 fscanf(fp, "MemFree: %lu %s\n", &mfree, buf);
343
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000344 /*
Eric Andersen7857c032003-10-11 18:47:20 +0000345 * MemShared: is no longer present in 2.6. Report this as 0,
346 * to maintain consistent behavior with normal procps.
347 */
348 if (fscanf(fp, "MemShared: %lu %s\n", &shared, buf) != 2)
349 shared = 0;
350
351 fscanf(fp, "Buffers: %lu %s\n", &buffers, buf);
352 fscanf(fp, "Cached: %lu %s\n", &cached, buf);
353
354 used = total - mfree;
Eric Andersen420b2082002-09-17 22:14:58 +0000355 }
356 fclose(fp);
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000357
Eric Andersen420b2082002-09-17 22:14:58 +0000358 /* read load average */
Manuel Novoa III cad53642003-03-19 09:13:01 +0000359 fp = bb_xfopen("loadavg", "r");
Eric Andersen420b2082002-09-17 22:14:58 +0000360 if (fscanf(fp, "%f %f %f", &avg1, &avg2, &avg3) != 3) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000361 bb_error_msg_and_die("failed to read '%s'", "loadavg");
Eric Andersen420b2082002-09-17 22:14:58 +0000362 }
363 fclose(fp);
364
Eric Andersen7857c032003-10-11 18:47:20 +0000365 if (needs_conversion) {
366 /* convert to kilobytes */
367 used /= 1024;
368 mfree /= 1024;
369 shared /= 1024;
370 buffers /= 1024;
371 cached /= 1024;
372 total /= 1024;
373 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000374
Eric Andersen420b2082002-09-17 22:14:58 +0000375 /* output memory info and load average */
Eric Andersen08a72202002-09-30 20:52:10 +0000376 /* clear screen & go to top */
377 printf("\e[H\e[J" "Mem: "
378 "%ldK used, %ldK free, %ldK shrd, %ldK buff, %ldK cached\n",
379 used, mfree, shared, buffers, cached);
380 printf("Load average: %.2f, %.2f, %.2f "
381 "(State: S=sleeping R=running, W=waiting)\n",
Eric Andersen420b2082002-09-17 22:14:58 +0000382 avg1, avg2, avg3);
Eric Andersen7857c032003-10-11 18:47:20 +0000383 return total;
Eric Andersen420b2082002-09-17 22:14:58 +0000384}
385
386
387/* display process statuses */
Eric Andersen08a72202002-09-30 20:52:10 +0000388static void display_status(int count, int col)
Eric Andersen420b2082002-09-17 22:14:58 +0000389{
Eric Andersen44608e92002-10-22 12:21:15 +0000390 procps_status_t *s = top;
Eric Andersen08a72202002-09-30 20:52:10 +0000391 char rss_str_buf[8];
392 unsigned long total_memory = display_generic();
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000393
Eric Andersen08a72202002-09-30 20:52:10 +0000394#ifdef FEATURE_CPU_USAGE_PERCENTAGE
Eric Andersen420b2082002-09-17 22:14:58 +0000395 /* what info of the processes is shown */
Eric Andersen08a72202002-09-30 20:52:10 +0000396 printf("\n\e[7m PID USER STATUS RSS PPID %%CPU %%MEM COMMAND\e[0m\n");
397#else
398 printf("\n\e[7m PID USER STATUS RSS PPID %%MEM COMMAND\e[0m\n");
399#endif
Eric Andersen420b2082002-09-17 22:14:58 +0000400
401 while (count--) {
Eric Andersen44608e92002-10-22 12:21:15 +0000402 char *namecmd = s->short_cmd;
Eric Andersen08a72202002-09-30 20:52:10 +0000403 int pmem;
Eric Andersen420b2082002-09-17 22:14:58 +0000404
Eric Andersen08a72202002-09-30 20:52:10 +0000405 pmem = 1000.0 * s->rss / total_memory;
406 if (pmem > 999) pmem = 999;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000407
Eric Andersen08a72202002-09-30 20:52:10 +0000408 if(s->rss > 10*1024)
409 sprintf(rss_str_buf, "%6ldM", s->rss/1024);
Manuel Novoa III d4993302002-09-18 19:27:10 +0000410 else
Eric Andersen08a72202002-09-30 20:52:10 +0000411 sprintf(rss_str_buf, "%7ld", s->rss);
412#ifdef FEATURE_CPU_USAGE_PERCENTAGE
Glenn L McGrathf6bba3d2003-12-08 20:31:25 +0000413 printf("%5d %-8s %s %s %5d %2d.%d %2u.%u ",
Eric Andersen08a72202002-09-30 20:52:10 +0000414 s->pid, s->user, s->state, rss_str_buf, s->ppid,
Glenn L McGrathf6bba3d2003-12-08 20:31:25 +0000415 s->pcpu/10, s->pcpu%10, pmem/10, pmem%10);
416#else
417 printf("%5d %-8s %s %s %5d %2u.%u ",
418 s->pid, s->user, s->state, rss_str_buf, s->ppid,
Eric Andersen08a72202002-09-30 20:52:10 +0000419 pmem/10, pmem%10);
Glenn L McGrathf6bba3d2003-12-08 20:31:25 +0000420#endif
Eric Andersen08a72202002-09-30 20:52:10 +0000421 if(strlen(namecmd) > col)
422 namecmd[col] = 0;
423 printf("%s\n", namecmd);
Eric Andersen420b2082002-09-17 22:14:58 +0000424 s++;
Eric Andersen08a72202002-09-30 20:52:10 +0000425 }
Eric Andersen44608e92002-10-22 12:21:15 +0000426}
427
428static void clearmems(void)
429{
Eric Andersen08a72202002-09-30 20:52:10 +0000430 free(top);
Eric Andersen08a72202002-09-30 20:52:10 +0000431 top = 0;
Eric Andersen08a72202002-09-30 20:52:10 +0000432 ntop = 0;
433}
434
435#if defined CONFIG_FEATURE_USE_TERMIOS
436#include <termios.h>
437#include <sys/time.h>
438#include <signal.h>
439
440
441static struct termios initial_settings;
442
443static void reset_term(void)
444{
445 tcsetattr(0, TCSANOW, (void *) &initial_settings);
446#ifdef CONFIG_FEATURE_CLEAN_UP
447 clearmems();
448#ifdef FEATURE_CPU_USAGE_PERCENTAGE
449 free(save_history);
450#endif
451#endif /* CONFIG_FEATURE_CLEAN_UP */
452}
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000453
Eric Andersen08a72202002-09-30 20:52:10 +0000454static void sig_catcher (int sig)
455{
456 reset_term();
457}
458#endif /* CONFIG_FEATURE_USE_TERMIOS */
459
460
Eric Andersen420b2082002-09-17 22:14:58 +0000461int top_main(int argc, char **argv)
462{
Eric Andersen08a72202002-09-30 20:52:10 +0000463 int opt, interval, lines, col;
464#if defined CONFIG_FEATURE_USE_TERMIOS
465 struct termios new_settings;
466 struct timeval tv;
467 fd_set readfds;
468 unsigned char c;
469 struct sigaction sa;
Eric Andersen08a72202002-09-30 20:52:10 +0000470#endif /* CONFIG_FEATURE_USE_TERMIOS */
471
Eric Andersen420b2082002-09-17 22:14:58 +0000472 /* Default update rate is 5 seconds */
473 interval = 5;
Eric Andersen420b2082002-09-17 22:14:58 +0000474
475 /* do normal option parsing */
476 while ((opt = getopt(argc, argv, "d:")) > 0) {
477 switch (opt) {
478 case 'd':
479 interval = atoi(optarg);
480 break;
481 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +0000482 bb_show_usage();
Eric Andersen420b2082002-09-17 22:14:58 +0000483 }
484 }
485
Eric Andersen08a72202002-09-30 20:52:10 +0000486 /* Default to 25 lines - 5 lines for status */
487 lines = 25 - 5;
488 /* Default CMD format size */
489#ifdef FEATURE_CPU_USAGE_PERCENTAGE
490 col = 35 - 6;
491#else
492 col = 35;
Eric Andersen420b2082002-09-17 22:14:58 +0000493#endif
Eric Andersen44608e92002-10-22 12:21:15 +0000494 /* change to /proc */
Eric Andersen420b2082002-09-17 22:14:58 +0000495 if (chdir("/proc") < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000496 bb_perror_msg_and_die("chdir('/proc')");
Eric Andersen420b2082002-09-17 22:14:58 +0000497 }
Eric Andersen08a72202002-09-30 20:52:10 +0000498#if defined CONFIG_FEATURE_USE_TERMIOS
499 tcgetattr(0, (void *) &initial_settings);
500 memcpy(&new_settings, &initial_settings, sizeof(struct termios));
501 new_settings.c_lflag &= ~(ISIG | ICANON); /* unbuffered input */
502 /* Turn off echoing */
503 new_settings.c_lflag &= ~(ECHO | ECHONL);
504
505 signal (SIGTERM, sig_catcher);
506 sigaction (SIGTERM, (struct sigaction *) 0, &sa);
507 sa.sa_flags |= SA_RESTART;
508 sa.sa_flags &= ~SA_INTERRUPT;
509 sigaction (SIGTERM, &sa, (struct sigaction *) 0);
510 sigaction (SIGINT, &sa, (struct sigaction *) 0);
511 tcsetattr(0, TCSANOW, (void *) &new_settings);
512 atexit(reset_term);
Eric Andersen8efe9672003-09-15 08:33:45 +0000513
514 get_terminal_width_height(0, &col, &lines);
515 if (lines > 4) {
516 lines -= 5;
Eric Andersen08a72202002-09-30 20:52:10 +0000517#ifdef FEATURE_CPU_USAGE_PERCENTAGE
Eric Andersen8efe9672003-09-15 08:33:45 +0000518 col = col - 80 + 35 - 6;
Eric Andersen08a72202002-09-30 20:52:10 +0000519#else
Eric Andersen8efe9672003-09-15 08:33:45 +0000520 col = col - 80 + 35;
Eric Andersen08a72202002-09-30 20:52:10 +0000521#endif
522 }
Eric Andersen08a72202002-09-30 20:52:10 +0000523#endif /* CONFIG_FEATURE_USE_TERMIOS */
524#ifdef FEATURE_CPU_USAGE_PERCENTAGE
525 sort_function[0] = pcpu_sort;
526 sort_function[1] = mem_sort;
527 sort_function[2] = time_sort;
528#else
529 sort_function = mem_sort;
530#endif
531 while (1) {
532 /* read process IDs & status for all the processes */
Eric Andersen44608e92002-10-22 12:21:15 +0000533 procps_status_t * p;
534
Eric Andersen9e480452003-07-03 10:07:04 +0000535#ifdef CONFIG_SELINUX
536 while ((p = procps_scan(0, 0, NULL) ) != 0) {
537#else
Eric Andersen44608e92002-10-22 12:21:15 +0000538 while ((p = procps_scan(0)) != 0) {
Eric Andersen9e480452003-07-03 10:07:04 +0000539#endif
Eric Andersen44608e92002-10-22 12:21:15 +0000540 int n = ntop;
541
542 top = xrealloc(top, (++ntop)*sizeof(procps_status_t));
543 memcpy(top + n, p, sizeof(procps_status_t));
544 }
545 if (ntop == 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000546 bb_perror_msg_and_die("scandir('/proc')");
Eric Andersen420b2082002-09-17 22:14:58 +0000547 }
Eric Andersen08a72202002-09-30 20:52:10 +0000548#ifdef FEATURE_CPU_USAGE_PERCENTAGE
549 if(!Hertz) {
550 init_Hertz_value();
551 do_stats();
552 sleep(1);
553 clearmems();
554 continue;
Eric Andersen420b2082002-09-17 22:14:58 +0000555 }
Eric Andersen08a72202002-09-30 20:52:10 +0000556 do_stats();
557#else
Eric Andersen44608e92002-10-22 12:21:15 +0000558 qsort(top, ntop, sizeof(procps_status_t), (void*)sort_function);
Eric Andersen08a72202002-09-30 20:52:10 +0000559#endif
560 opt = lines;
561 if (opt > ntop) {
562 opt = ntop;
563 }
564 /* show status for each of the processes */
565 display_status(opt, col);
566#if defined CONFIG_FEATURE_USE_TERMIOS
567 tv.tv_sec = interval;
568 tv.tv_usec = 0;
569 FD_ZERO (&readfds);
570 FD_SET (0, &readfds);
571 select (1, &readfds, NULL, NULL, &tv);
572 if (FD_ISSET (0, &readfds)) {
573 if (read (0, &c, 1) <= 0) { /* signal */
Eric Andersen420b2082002-09-17 22:14:58 +0000574 return EXIT_FAILURE;
575 }
Eric Andersen08a72202002-09-30 20:52:10 +0000576 if(c == 'q' || c == initial_settings.c_cc[VINTR])
577 return EXIT_SUCCESS;
578 if(c == 'M') {
579#ifdef FEATURE_CPU_USAGE_PERCENTAGE
580 sort_function[0] = mem_sort;
581 sort_function[1] = pcpu_sort;
582 sort_function[2] = time_sort;
583#else
584 sort_function = mem_sort;
585#endif
586 }
587#ifdef FEATURE_CPU_USAGE_PERCENTAGE
588 if(c == 'P') {
589 sort_function[0] = pcpu_sort;
590 sort_function[1] = mem_sort;
591 sort_function[2] = time_sort;
592 }
593 if(c == 'T') {
594 sort_function[0] = time_sort;
595 sort_function[1] = mem_sort;
596 sort_function[2] = pcpu_sort;
597 }
598#endif
599 if(c == 'N') {
600#ifdef FEATURE_CPU_USAGE_PERCENTAGE
601 sort_function[0] = pid_sort;
602#else
603 sort_function = pid_sort;
604#endif
605 }
606 }
607#else
Eric Andersen420b2082002-09-17 22:14:58 +0000608 sleep(interval);
Eric Andersen08a72202002-09-30 20:52:10 +0000609#endif /* CONFIG_FEATURE_USE_TERMIOS */
610 clearmems();
Eric Andersen420b2082002-09-17 22:14:58 +0000611 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000612
Eric Andersen420b2082002-09-17 22:14:58 +0000613 return EXIT_SUCCESS;
614}