source: MondoRescue/branches/stable/mindi-busybox/procps/top.c

Last change on this file was 1770, checked in by Bruno Cornec, 16 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

File size: 17.4 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * A tiny 'top' utility.
4 *
5 * This is written specifically for the linux /proc/<PID>/stat(m)
6 * files format.
7
8 * This reads the PIDs of all processes and their status and shows
9 * the status of processes (first ones that fit to screen) at given
10 * intervals.
11 *
12 * NOTES:
13 * - At startup this changes to /proc, all the reads are then
14 * relative to that.
15 *
16 * (C) Eero Tamminen <oak at welho dot com>
17 *
18 * Rewritten by Vladimir Oleynik (C) 2002 <dzo@simtreas.ru>
19 */
20
21/* Original code Copyrights */
22/*
23 * Copyright (c) 1992 Branko Lankester
24 * Copyright (c) 1992 Roger Binns
25 * Copyright (C) 1994-1996 Charles L. Blake.
26 * Copyright (C) 1992-1998 Michael K. Johnson
27 * May be distributed under the conditions of the
28 * GNU Library General Public License
29 */
30
31#include "libbb.h"
32
33
34typedef struct top_status_t {
35 unsigned long vsz;
36#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
37 unsigned long ticks;
38 unsigned pcpu; /* delta of ticks */
39#endif
40 unsigned pid, ppid;
41 unsigned uid;
42 char state[4];
43 char comm[COMM_LEN];
44} top_status_t;
45
46typedef struct jiffy_counts_t {
47 unsigned long long usr,nic,sys,idle,iowait,irq,softirq,steal;
48 unsigned long long total;
49 unsigned long long busy;
50} jiffy_counts_t;
51
52/* This structure stores some critical information from one frame to
53 the next. Used for finding deltas. */
54typedef struct save_hist {
55 unsigned long ticks;
56 unsigned pid;
57} save_hist;
58
59typedef int (*cmp_funcp)(top_status_t *P, top_status_t *Q);
60
61enum { SORT_DEPTH = 3 };
62
63struct globals {
64 top_status_t *top;
65 int ntop;
66#if ENABLE_FEATURE_USE_TERMIOS
67 struct termios initial_settings;
68#endif
69#if !ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
70 cmp_funcp sort_function;
71#else
72 cmp_funcp sort_function[SORT_DEPTH];
73 struct save_hist *prev_hist;
74 int prev_hist_count;
75 jiffy_counts_t jif, prev_jif;
76 /* int hist_iterations; */
77 unsigned total_pcpu;
78 /* unsigned long total_vsz; */
79#endif
80};
81#define G (*(struct globals*)&bb_common_bufsiz1)
82#define top (G.top )
83#define ntop (G.ntop )
84#if ENABLE_FEATURE_USE_TERMIOS
85#define initial_settings (G. initial_settings )
86#endif
87#define sort_function (G.sort_function )
88#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
89#define prev_hist (G.prev_hist )
90#define prev_hist_count (G.prev_hist_count )
91#define jif (G.jif )
92#define prev_jif (G.prev_jif )
93#define total_pcpu (G.total_pcpu )
94#endif
95
96#define OPT_BATCH_MODE (option_mask32 & 0x4)
97
98
99#if ENABLE_FEATURE_USE_TERMIOS
100static int pid_sort(top_status_t *P, top_status_t *Q)
101{
102 /* Buggy wrt pids with high bit set */
103 /* (linux pids are in [1..2^15-1]) */
104 return (Q->pid - P->pid);
105}
106#endif
107
108static int mem_sort(top_status_t *P, top_status_t *Q)
109{
110 /* We want to avoid unsigned->signed and truncation errors */
111 if (Q->vsz < P->vsz) return -1;
112 return Q->vsz != P->vsz; /* 0 if ==, 1 if > */
113}
114
115
116#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
117
118static int pcpu_sort(top_status_t *P, top_status_t *Q)
119{
120 /* Buggy wrt ticks with high bit set */
121 /* Affects only processes for which ticks overflow */
122 return (int)Q->pcpu - (int)P->pcpu;
123}
124
125static int time_sort(top_status_t *P, top_status_t *Q)
126{
127 /* We want to avoid unsigned->signed and truncation errors */
128 if (Q->ticks < P->ticks) return -1;
129 return Q->ticks != P->ticks; /* 0 if ==, 1 if > */
130}
131
132static int mult_lvl_cmp(void* a, void* b)
133{
134 int i, cmp_val;
135
136 for (i = 0; i < SORT_DEPTH; i++) {
137 cmp_val = (*sort_function[i])(a, b);
138 if (cmp_val != 0)
139 return cmp_val;
140 }
141 return 0;
142}
143
144
145static void get_jiffy_counts(void)
146{
147 FILE* fp = xfopen("stat", "r");
148 prev_jif = jif;
149 if (fscanf(fp, "cpu %lld %lld %lld %lld %lld %lld %lld %lld",
150 &jif.usr,&jif.nic,&jif.sys,&jif.idle,
151 &jif.iowait,&jif.irq,&jif.softirq,&jif.steal) < 4) {
152 bb_error_msg_and_die("failed to read /proc/stat");
153 }
154 fclose(fp);
155 jif.total = jif.usr + jif.nic + jif.sys + jif.idle
156 + jif.iowait + jif.irq + jif.softirq + jif.steal;
157 /* procps 2.x does not count iowait as busy time */
158 jif.busy = jif.total - jif.idle - jif.iowait;
159}
160
161
162static void do_stats(void)
163{
164 top_status_t *cur;
165 pid_t pid;
166 int i, last_i, n;
167 struct save_hist *new_hist;
168
169 get_jiffy_counts();
170 total_pcpu = 0;
171 /* total_vsz = 0; */
172 new_hist = xmalloc(sizeof(struct save_hist)*ntop);
173 /*
174 * Make a pass through the data to get stats.
175 */
176 /* hist_iterations = 0; */
177 i = 0;
178 for (n = 0; n < ntop; n++) {
179 cur = top + n;
180
181 /*
182 * Calculate time in cur process. Time is sum of user time
183 * and system time
184 */
185 pid = cur->pid;
186 new_hist[n].ticks = cur->ticks;
187 new_hist[n].pid = pid;
188
189 /* find matching entry from previous pass */
190 cur->pcpu = 0;
191 /* do not start at index 0, continue at last used one
192 * (brought hist_iterations from ~14000 down to 172) */
193 last_i = i;
194 if (prev_hist_count) do {
195 if (prev_hist[i].pid == pid) {
196 cur->pcpu = cur->ticks - prev_hist[i].ticks;
197 total_pcpu += cur->pcpu;
198 break;
199 }
200 i = (i+1) % prev_hist_count;
201 /* hist_iterations++; */
202 } while (i != last_i);
203 /* total_vsz += cur->vsz; */
204 }
205
206 /*
207 * Save cur frame's information.
208 */
209 free(prev_hist);
210 prev_hist = new_hist;
211 prev_hist_count = ntop;
212}
213#endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */
214
215#if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS && ENABLE_FEATURE_TOP_DECIMALS
216/* formats 7 char string (8 with terminating NUL) */
217static char *fmt_100percent_8(char pbuf[8], unsigned value, unsigned total)
218{
219 unsigned t;
220 if (value >= total) { /* 100% ? */
221 strcpy(pbuf, " 100% ");
222 return pbuf;
223 }
224 /* else generate " [N/space]N.N% " string */
225 value = 1000 * value / total;
226 t = value / 100;
227 value = value % 100;
228 pbuf[0] = ' ';
229 pbuf[1] = t ? t + '0' : ' ';
230 pbuf[2] = '0' + (value / 10);
231 pbuf[3] = '.';
232 pbuf[4] = '0' + (value % 10);
233 pbuf[5] = '%';
234 pbuf[6] = ' ';
235 pbuf[7] = '\0';
236 return pbuf;
237}
238#endif
239
240/* display generic info (meminfo / loadavg) */
241static unsigned long display_generic(int scr_width)
242{
243 FILE *fp;
244 char buf[80];
245 char scrbuf[80];
246 unsigned long total, used, mfree, shared, buffers, cached;
247#if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS
248 unsigned total_diff;
249#endif
250
251 /* read memory info */
252 fp = xfopen("meminfo", "r");
253
254 /*
255 * Old kernels (such as 2.4.x) had a nice summary of memory info that
256 * we could parse, however this is gone entirely in 2.6. Try parsing
257 * the old way first, and if that fails, parse each field manually.
258 *
259 * First, we read in the first line. Old kernels will have bogus
260 * strings we don't care about, whereas new kernels will start right
261 * out with MemTotal:
262 * -- PFM.
263 */
264 if (fscanf(fp, "MemTotal: %lu %s\n", &total, buf) != 2) {
265 fgets(buf, sizeof(buf), fp); /* skip first line */
266
267 fscanf(fp, "Mem: %lu %lu %lu %lu %lu %lu",
268 &total, &used, &mfree, &shared, &buffers, &cached);
269 /* convert to kilobytes */
270 used /= 1024;
271 mfree /= 1024;
272 shared /= 1024;
273 buffers /= 1024;
274 cached /= 1024;
275 total /= 1024;
276 } else {
277 /*
278 * Revert to manual parsing, which incidentally already has the
279 * sizes in kilobytes. This should be safe for both 2.4 and
280 * 2.6.
281 */
282
283 fscanf(fp, "MemFree: %lu %s\n", &mfree, buf);
284
285 /*
286 * MemShared: is no longer present in 2.6. Report this as 0,
287 * to maintain consistent behavior with normal procps.
288 */
289 if (fscanf(fp, "MemShared: %lu %s\n", &shared, buf) != 2)
290 shared = 0;
291
292 fscanf(fp, "Buffers: %lu %s\n", &buffers, buf);
293 fscanf(fp, "Cached: %lu %s\n", &cached, buf);
294
295 used = total - mfree;
296 }
297 fclose(fp);
298
299 /* output memory info */
300 if (scr_width > sizeof(scrbuf))
301 scr_width = sizeof(scrbuf);
302 snprintf(scrbuf, scr_width,
303 "Mem: %luK used, %luK free, %luK shrd, %luK buff, %luK cached",
304 used, mfree, shared, buffers, cached);
305 /* clear screen & go to top */
306 printf(OPT_BATCH_MODE ? "%s\n" : "\e[H\e[J%s\n", scrbuf);
307
308#if ENABLE_FEATURE_TOP_CPU_GLOBAL_PERCENTS
309 /*
310 * xxx% = (jif.xxx - prev_jif.xxx) / (jif.total - prev_jif.total) * 100%
311 */
312 /* using (unsigned) casts to make operations cheaper */
313 total_diff = ((unsigned)(jif.total - prev_jif.total) ? : 1);
314#if ENABLE_FEATURE_TOP_DECIMALS
315/* Generated code is approx +0.3k */
316#define CALC_STAT(xxx) char xxx[8]
317#define SHOW_STAT(xxx) fmt_100percent_8(xxx, (unsigned)(jif.xxx - prev_jif.xxx), total_diff)
318#define FMT "%s"
319#else
320#define CALC_STAT(xxx) unsigned xxx = 100 * (unsigned)(jif.xxx - prev_jif.xxx) / total_diff
321#define SHOW_STAT(xxx) xxx
322#define FMT "%4u%% "
323#endif
324 { /* need block: CALC_STAT are declarations */
325 CALC_STAT(usr);
326 CALC_STAT(sys);
327 CALC_STAT(nic);
328 CALC_STAT(idle);
329 CALC_STAT(iowait);
330 CALC_STAT(irq);
331 CALC_STAT(softirq);
332 //CALC_STAT(steal);
333
334 snprintf(scrbuf, scr_width,
335 /* Barely fits in 79 chars when in "decimals" mode. */
336 "CPU:"FMT"usr"FMT"sys"FMT"nice"FMT"idle"FMT"io"FMT"irq"FMT"softirq",
337 SHOW_STAT(usr), SHOW_STAT(sys), SHOW_STAT(nic), SHOW_STAT(idle),
338 SHOW_STAT(iowait), SHOW_STAT(irq), SHOW_STAT(softirq)
339 //, SHOW_STAT(steal) - what is this 'steal' thing?
340 // I doubt anyone wants to know it
341 );
342 }
343 puts(scrbuf);
344#undef SHOW_STAT
345#undef CALC_STAT
346#undef FMT
347#endif
348
349 /* read load average as a string */
350 buf[0] = '\0';
351 open_read_close("loadavg", buf, sizeof("N.NN N.NN N.NN")-1);
352 buf[sizeof("N.NN N.NN N.NN")-1] = '\0';
353 snprintf(scrbuf, scr_width, "Load average: %s", buf);
354 puts(scrbuf);
355
356 return total;
357}
358
359/* display process statuses */
360static void display_status(int count, int scr_width)
361{
362 enum {
363 BITS_PER_INT = sizeof(int)*8
364 };
365
366 top_status_t *s = top;
367 char vsz_str_buf[8];
368 unsigned long total_memory = display_generic(scr_width); /* or use total_vsz? */
369 /* xxx_shift and xxx_scale variables allow us to replace
370 * expensive divides with multiply and shift */
371 unsigned pmem_shift, pmem_scale, pmem_half;
372#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
373 unsigned pcpu_shift, pcpu_scale, pcpu_half;
374 unsigned busy_jifs;
375
376 /* what info of the processes is shown */
377 printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width,
378 " PID PPID USER STAT VSZ %MEM %CPU COMMAND");
379#define MIN_WIDTH \
380 sizeof( " PID PPID USER STAT VSZ %MEM %CPU C")
381#else
382
383 /* !CPU_USAGE_PERCENTAGE */
384 printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width,
385 " PID PPID USER STAT VSZ %MEM COMMAND");
386#define MIN_WIDTH \
387 sizeof( " PID PPID USER STAT VSZ %MEM C")
388#endif
389
390#if ENABLE_FEATURE_TOP_DECIMALS
391#define UPSCALE 1000
392#define CALC_STAT(name, val) div_t name = div((val), 10)
393#define SHOW_STAT(name) name.quot, '0'+name.rem
394#define FMT "%3u.%c"
395#else
396#define UPSCALE 100
397#define CALC_STAT(name, val) unsigned name = (val)
398#define SHOW_STAT(name) name
399#define FMT "%4u%%"
400#endif
401 /*
402 * MEM% = s->vsz/MemTotal
403 */
404 pmem_shift = BITS_PER_INT-11;
405 pmem_scale = UPSCALE*(1U<<(BITS_PER_INT-11)) / total_memory;
406 /* s->vsz is in kb. we want (s->vsz * pmem_scale) to never overflow */
407 while (pmem_scale >= 512) {
408 pmem_scale /= 4;
409 pmem_shift -= 2;
410 }
411 pmem_half = (1U << pmem_shift) / (ENABLE_FEATURE_TOP_DECIMALS? 20 : 2);
412#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
413 busy_jifs = jif.busy - prev_jif.busy;
414 /* This happens if there were lots of short-lived processes
415 * between two top updates (e.g. compilation) */
416 if (total_pcpu < busy_jifs) total_pcpu = busy_jifs;
417
418 /*
419 * CPU% = s->pcpu/sum(s->pcpu) * busy_cpu_ticks/total_cpu_ticks
420 * (pcpu is delta of sys+user time between samples)
421 */
422 /* (jif.xxx - prev_jif.xxx) and s->pcpu are
423 * in 0..~64000 range (HZ*update_interval).
424 * we assume that unsigned is at least 32-bit.
425 */
426 pcpu_shift = 6;
427 pcpu_scale = (UPSCALE*64*(uint16_t)busy_jifs ? : 1);
428 while (pcpu_scale < (1U<<(BITS_PER_INT-2))) {
429 pcpu_scale *= 4;
430 pcpu_shift += 2;
431 }
432 pcpu_scale /= ( (uint16_t)(jif.total-prev_jif.total)*total_pcpu ? : 1);
433 /* we want (s->pcpu * pcpu_scale) to never overflow */
434 while (pcpu_scale >= 1024) {
435 pcpu_scale /= 4;
436 pcpu_shift -= 2;
437 }
438 pcpu_half = (1U << pcpu_shift) / (ENABLE_FEATURE_TOP_DECIMALS? 20 : 2);
439 /* printf(" pmem_scale=%u pcpu_scale=%u ", pmem_scale, pcpu_scale); */
440#endif
441
442 /* Ok, all prelim data is ready, go thru the list */
443 while (count-- > 0) {
444 int col = scr_width;
445 CALC_STAT(pmem, (s->vsz*pmem_scale + pmem_half) >> pmem_shift);
446#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
447 CALC_STAT(pcpu, (s->pcpu*pcpu_scale + pcpu_half) >> pcpu_shift);
448#endif
449
450 if (s->vsz >= 100*1024)
451 sprintf(vsz_str_buf, "%6ldM", s->vsz/1024);
452 else
453 sprintf(vsz_str_buf, "%7ld", s->vsz);
454 // PID PPID USER STAT VSZ %MEM [%CPU] COMMAND
455 col -= printf("\n" "%5u%6u %-8.8s %s%s" FMT
456#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
457 FMT
458#endif
459 " ",
460 s->pid, s->ppid, get_cached_username(s->uid),
461 s->state, vsz_str_buf,
462 SHOW_STAT(pmem)
463#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
464 , SHOW_STAT(pcpu)
465#endif
466 );
467 if (col > 0) {
468 char buf[col + 1];
469 read_cmdline(buf, col, s->pid, s->comm);
470 fputs(buf, stdout);
471 }
472 /* printf(" %d/%d %lld/%lld", s->pcpu, total_pcpu,
473 jif.busy - prev_jif.busy, jif.total - prev_jif.total); */
474 s++;
475 }
476 /* printf(" %d", hist_iterations); */
477 putchar(OPT_BATCH_MODE ? '\n' : '\r');
478 fflush(stdout);
479}
480#undef UPSCALE
481#undef SHOW_STAT
482#undef CALC_STAT
483#undef FMT
484
485
486static void clearmems(void)
487{
488 clear_username_cache();
489 free(top);
490 top = 0;
491 ntop = 0;
492}
493
494
495#if ENABLE_FEATURE_USE_TERMIOS
496#include <termios.h>
497#include <signal.h>
498
499static void reset_term(void)
500{
501 tcsetattr(0, TCSANOW, (void *) &initial_settings);
502#if ENABLE_FEATURE_CLEAN_UP
503 clearmems();
504#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
505 free(prev_hist);
506#endif
507#endif /* FEATURE_CLEAN_UP */
508}
509
510static void sig_catcher(int sig ATTRIBUTE_UNUSED)
511{
512 reset_term();
513 exit(1);
514}
515#endif /* FEATURE_USE_TERMIOS */
516
517
518int top_main(int argc, char **argv);
519int top_main(int argc, char **argv)
520{
521 int count, lines, col;
522 unsigned interval = 5; /* default update rate is 5 seconds */
523 unsigned iterations = UINT_MAX; /* 2^32 iterations by default :) */
524 char *sinterval, *siterations;
525#if ENABLE_FEATURE_USE_TERMIOS
526 struct termios new_settings;
527 struct timeval tv;
528 fd_set readfds;
529 unsigned char c;
530#endif /* FEATURE_USE_TERMIOS */
531
532 interval = 5;
533
534 /* do normal option parsing */
535 opt_complementary = "-";
536 getopt32(argv, "d:n:b", &sinterval, &siterations);
537 if (option_mask32 & 0x1) interval = xatou(sinterval); // -d
538 if (option_mask32 & 0x2) iterations = xatou(siterations); // -n
539 //if (option_mask32 & 0x4) // -b
540
541 /* change to /proc */
542 xchdir("/proc");
543#if ENABLE_FEATURE_USE_TERMIOS
544 tcgetattr(0, (void *) &initial_settings);
545 memcpy(&new_settings, &initial_settings, sizeof(struct termios));
546 /* unbuffered input, turn off echo */
547 new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL);
548
549 signal(SIGTERM, sig_catcher);
550 signal(SIGINT, sig_catcher);
551 tcsetattr(0, TCSANOW, (void *) &new_settings);
552 atexit(reset_term);
553#endif /* FEATURE_USE_TERMIOS */
554
555#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
556 sort_function[0] = pcpu_sort;
557 sort_function[1] = mem_sort;
558 sort_function[2] = time_sort;
559#else
560 sort_function = mem_sort;
561#endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */
562
563 while (1) {
564 procps_status_t *p = NULL;
565
566 /* Default to 25 lines - 5 lines for status */
567 lines = 24 - 3 USE_FEATURE_TOP_CPU_GLOBAL_PERCENTS( - 1);
568 col = 79;
569#if ENABLE_FEATURE_USE_TERMIOS
570 get_terminal_width_height(0, &col, &lines);
571 if (lines < 5 || col < MIN_WIDTH) {
572 sleep(interval);
573 continue;
574 }
575 lines -= 3 USE_FEATURE_TOP_CPU_GLOBAL_PERCENTS( + 1);
576#endif /* FEATURE_USE_TERMIOS */
577
578 /* read process IDs & status for all the processes */
579 while ((p = procps_scan(p, 0
580 | PSSCAN_PID
581 | PSSCAN_PPID
582 | PSSCAN_VSZ
583 | PSSCAN_STIME
584 | PSSCAN_UTIME
585 | PSSCAN_STATE
586 | PSSCAN_COMM
587 | PSSCAN_SID
588 | PSSCAN_UIDGID
589 ))) {
590 int n = ntop;
591 top = xrealloc(top, (++ntop) * sizeof(*top));
592 top[n].pid = p->pid;
593 top[n].ppid = p->ppid;
594 top[n].vsz = p->vsz;
595#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
596 top[n].ticks = p->stime + p->utime;
597#endif
598 top[n].uid = p->uid;
599 strcpy(top[n].state, p->state);
600 strcpy(top[n].comm, p->comm);
601 }
602 if (ntop == 0) {
603 bb_error_msg_and_die("no process info in /proc");
604 }
605#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
606 if (!prev_hist_count) {
607 do_stats();
608 sleep(1);
609 clearmems();
610 continue;
611 }
612 do_stats();
613/* TODO: we don't need to sort all 10000 processes, we need to find top 24! */
614 qsort(top, ntop, sizeof(top_status_t), (void*)mult_lvl_cmp);
615#else
616 qsort(top, ntop, sizeof(top_status_t), (void*)sort_function);
617#endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */
618 count = lines;
619 if (OPT_BATCH_MODE || count > ntop) {
620 count = ntop;
621 }
622 /* show status for each of the processes */
623 display_status(count, col);
624#if ENABLE_FEATURE_USE_TERMIOS
625 tv.tv_sec = interval;
626 tv.tv_usec = 0;
627 FD_ZERO(&readfds);
628 FD_SET(0, &readfds);
629 select(1, &readfds, NULL, NULL, &tv);
630 if (FD_ISSET(0, &readfds)) {
631 if (read(0, &c, 1) <= 0) { /* signal */
632 return EXIT_FAILURE;
633 }
634 if (c == 'q' || c == initial_settings.c_cc[VINTR])
635 break;
636 if (c == 'M') {
637#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
638 sort_function[0] = mem_sort;
639 sort_function[1] = pcpu_sort;
640 sort_function[2] = time_sort;
641#else
642 sort_function = mem_sort;
643#endif
644 }
645#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
646 if (c == 'P') {
647 sort_function[0] = pcpu_sort;
648 sort_function[1] = mem_sort;
649 sort_function[2] = time_sort;
650 }
651 if (c == 'T') {
652 sort_function[0] = time_sort;
653 sort_function[1] = mem_sort;
654 sort_function[2] = pcpu_sort;
655 }
656#endif
657 if (c == 'N') {
658#if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
659 sort_function[0] = pid_sort;
660#else
661 sort_function = pid_sort;
662#endif
663 }
664 }
665 if (!--iterations)
666 break;
667#else
668 sleep(interval);
669#endif /* FEATURE_USE_TERMIOS */
670 clearmems();
671 }
672 if (ENABLE_FEATURE_CLEAN_UP)
673 clearmems();
674 putchar('\n');
675 return EXIT_SUCCESS;
676}
Note: See TracBrowser for help on using the repository browser.