diff options
Diffstat (limited to 'procps')
-rw-r--r-- | procps/kill.c | 6 | ||||
-rw-r--r-- | procps/ps.c | 28 | ||||
-rw-r--r-- | procps/top.c | 144 |
3 files changed, 115 insertions, 63 deletions
diff --git a/procps/kill.c b/procps/kill.c index 9b96b4c1a..18121f06f 100644 --- a/procps/kill.c +++ b/procps/kill.c | |||
@@ -82,7 +82,7 @@ do_it_now: | |||
82 | 82 | ||
83 | if (killall5) { | 83 | if (killall5) { |
84 | pid_t sid; | 84 | pid_t sid; |
85 | procps_status_t* p; | 85 | procps_status_t* p = NULL; |
86 | 86 | ||
87 | // Cannot happen anyway? We don't TERM ourself, we STOP | 87 | // Cannot happen anyway? We don't TERM ourself, we STOP |
88 | // /* kill(-1, sig) on Linux (at least 2.1.x) | 88 | // /* kill(-1, sig) on Linux (at least 2.1.x) |
@@ -94,8 +94,8 @@ do_it_now: | |||
94 | pid = getpid(); | 94 | pid = getpid(); |
95 | sid = getsid(pid); | 95 | sid = getsid(pid); |
96 | /* Now kill all processes except our session */ | 96 | /* Now kill all processes except our session */ |
97 | while ((p = procps_scan(0))!=0) { | 97 | while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_SID))) { |
98 | if (getsid(p->pid)!=sid && p->pid!=pid && p->pid!=1) | 98 | if (p->sid != sid && p->pid != pid && p->pid != 1) |
99 | kill(p->pid, signo); | 99 | kill(p->pid, signo); |
100 | } | 100 | } |
101 | /* And let them continue */ | 101 | /* And let them continue */ |
diff --git a/procps/ps.c b/procps/ps.c index 9d6e42d79..2ff6e77d4 100644 --- a/procps/ps.c +++ b/procps/ps.c | |||
@@ -11,7 +11,7 @@ | |||
11 | 11 | ||
12 | int ps_main(int argc, char **argv) | 12 | int ps_main(int argc, char **argv) |
13 | { | 13 | { |
14 | procps_status_t * p; | 14 | procps_status_t *p = NULL; |
15 | int i, len; | 15 | int i, len; |
16 | SKIP_SELINUX(const) int use_selinux = 0; | 16 | SKIP_SELINUX(const) int use_selinux = 0; |
17 | USE_SELINUX(security_context_t sid = NULL;) | 17 | USE_SELINUX(security_context_t sid = NULL;) |
@@ -50,7 +50,13 @@ int ps_main(int argc, char **argv) | |||
50 | else | 50 | else |
51 | puts(" PID Uid VmSize Stat Command"); | 51 | puts(" PID Uid VmSize Stat Command"); |
52 | 52 | ||
53 | while ((p = procps_scan(1)) != 0) { | 53 | while ((p = procps_scan(p, 0 |
54 | | PSSCAN_PID | ||
55 | | PSSCAN_UIDGID | ||
56 | | PSSCAN_STATE | ||
57 | | PSSCAN_RSS | ||
58 | | PSSCAN_CMD | ||
59 | ))) { | ||
54 | char *namecmd = p->cmd; | 60 | char *namecmd = p->cmd; |
55 | #if ENABLE_SELINUX | 61 | #if ENABLE_SELINUX |
56 | if (use_selinux) { | 62 | if (use_selinux) { |
@@ -71,13 +77,18 @@ int ps_main(int argc, char **argv) | |||
71 | } else { | 77 | } else { |
72 | safe_strncpy(sbuf, "unknown", 7); | 78 | safe_strncpy(sbuf, "unknown", 7); |
73 | } | 79 | } |
74 | len = printf("%5u %-32s %s ", (unsigned)p->pid, sbuf, p->state); | 80 | len = printf("%5u %-32s %s ", p->pid, sbuf, p->state); |
75 | } else | 81 | } else |
76 | #endif | 82 | #endif |
83 | { | ||
84 | const char *user = get_cached_username(p->uid); | ||
77 | if (p->rss == 0) | 85 | if (p->rss == 0) |
78 | len = printf("%5u %-8s %s ", (unsigned)p->pid, p->user, p->state); | 86 | len = printf("%5u %-8s %s ", |
87 | p->pid, user, p->state); | ||
79 | else | 88 | else |
80 | len = printf("%5u %-8s %6ld %s ", (unsigned)p->pid, p->user, p->rss, p->state); | 89 | len = printf("%5u %-8s %6ld %s ", |
90 | p->pid, user, p->rss, p->state); | ||
91 | } | ||
81 | 92 | ||
82 | i = terminal_width-len; | 93 | i = terminal_width-len; |
83 | 94 | ||
@@ -88,16 +99,15 @@ int ps_main(int argc, char **argv) | |||
88 | namecmd[i] = 0; | 99 | namecmd[i] = 0; |
89 | puts(namecmd); | 100 | puts(namecmd); |
90 | } else { | 101 | } else { |
91 | namecmd = p->short_cmd; | 102 | namecmd = p->comm; |
92 | if (i < 2) | 103 | if (i < 2) |
93 | i = 2; | 104 | i = 2; |
94 | if (strlen(namecmd) > ((size_t)i-2)) | 105 | if (strlen(namecmd) > ((size_t)i-2)) |
95 | namecmd[i-2] = 0; | 106 | namecmd[i-2] = 0; |
96 | printf("[%s]\n", namecmd); | 107 | printf("[%s]\n", namecmd); |
97 | } | 108 | } |
98 | /* no check needed, but to make valgrind happy.. */ | ||
99 | if (ENABLE_FEATURE_CLEAN_UP && p->cmd) | ||
100 | free(p->cmd); | ||
101 | } | 109 | } |
110 | if (ENABLE_FEATURE_CLEAN_UP) | ||
111 | clear_username_cache(); | ||
102 | return EXIT_SUCCESS; | 112 | return EXIT_SUCCESS; |
103 | } | 113 | } |
diff --git a/procps/top.c b/procps/top.c index c76fdc312..8d732d4b2 100644 --- a/procps/top.c +++ b/procps/top.c | |||
@@ -30,37 +30,76 @@ | |||
30 | 30 | ||
31 | #include "busybox.h" | 31 | #include "busybox.h" |
32 | 32 | ||
33 | typedef int (*cmp_t)(procps_status_t *P, procps_status_t *Q); | ||
34 | 33 | ||
35 | static procps_status_t *top; /* Hehe */ | 34 | typedef struct { |
35 | unsigned long rss; | ||
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 | static top_status_t *top; | ||
36 | static int ntop; | 46 | static int ntop; |
47 | /* This structure stores some critical information from one frame to | ||
48 | the next. Used for finding deltas. */ | ||
49 | struct save_hist { | ||
50 | unsigned long ticks; | ||
51 | unsigned pid; | ||
52 | }; | ||
53 | static struct save_hist *prev_hist; | ||
54 | static int prev_hist_count; | ||
55 | /* static int hist_iterations; */ | ||
56 | static unsigned total_pcpu; | ||
57 | /* static unsigned long total_rss; */ | ||
58 | |||
59 | |||
37 | #define OPT_BATCH_MODE (option_mask32 & 0x4) | 60 | #define OPT_BATCH_MODE (option_mask32 & 0x4) |
38 | 61 | ||
39 | #if ENABLE_FEATURE_USE_TERMIOS | 62 | #if ENABLE_FEATURE_USE_TERMIOS |
40 | static int pid_sort(procps_status_t *P, procps_status_t *Q) | 63 | static int pid_sort(top_status_t *P, top_status_t *Q) |
41 | { | 64 | { |
65 | /* Buggy wrt pids with high bit set */ | ||
66 | /* (linux pids are in [1..2^15-1]) */ | ||
42 | return (Q->pid - P->pid); | 67 | return (Q->pid - P->pid); |
43 | } | 68 | } |
44 | #endif | 69 | #endif |
45 | 70 | ||
46 | static int mem_sort(procps_status_t *P, procps_status_t *Q) | 71 | static int mem_sort(top_status_t *P, top_status_t *Q) |
47 | { | 72 | { |
48 | return (int)(Q->rss - P->rss); | 73 | /* We want to avoid unsigned->signed and truncation errors */ |
74 | if (Q->rss < P->rss) return -1; | ||
75 | return Q->rss != P->rss; /* 0 if ==, 1 if > */ | ||
49 | } | 76 | } |
50 | 77 | ||
51 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | 78 | |
79 | typedef int (*cmp_funcp)(top_status_t *P, top_status_t *Q); | ||
80 | |||
81 | #if !ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | ||
82 | |||
83 | static cmp_funcp sort_function; | ||
84 | |||
85 | #else | ||
52 | 86 | ||
53 | enum { SORT_DEPTH = 3 }; | 87 | enum { SORT_DEPTH = 3 }; |
54 | static cmp_t sort_function[SORT_DEPTH]; | ||
55 | 88 | ||
56 | static int pcpu_sort(procps_status_t *P, procps_status_t *Q) | 89 | static cmp_funcp sort_function[SORT_DEPTH]; |
90 | |||
91 | static int pcpu_sort(top_status_t *P, top_status_t *Q) | ||
57 | { | 92 | { |
58 | return (Q->pcpu - P->pcpu); | 93 | /* Buggy wrt ticks with high bit set */ |
94 | /* Affects only processes for which ticks overflow */ | ||
95 | return (int)Q->pcpu - (int)P->pcpu; | ||
59 | } | 96 | } |
60 | 97 | ||
61 | static int time_sort(procps_status_t *P, procps_status_t *Q) | 98 | static int time_sort(top_status_t *P, top_status_t *Q) |
62 | { | 99 | { |
63 | return (int)((Q->stime + Q->utime) - (P->stime + P->utime)); | 100 | /* We want to avoid unsigned->signed and truncation errors */ |
101 | if (Q->ticks < P->ticks) return -1; | ||
102 | return Q->ticks != P->ticks; /* 0 if ==, 1 if > */ | ||
64 | } | 103 | } |
65 | 104 | ||
66 | static int mult_lvl_cmp(void* a, void* b) { | 105 | static int mult_lvl_cmp(void* a, void* b) { |
@@ -74,24 +113,6 @@ static int mult_lvl_cmp(void* a, void* b) { | |||
74 | return 0; | 113 | return 0; |
75 | } | 114 | } |
76 | 115 | ||
77 | /* This structure stores some critical information from one frame to | ||
78 | the next. Mostly used for sorting. */ | ||
79 | struct save_hist { | ||
80 | int ticks; | ||
81 | pid_t pid; | ||
82 | }; | ||
83 | |||
84 | /* | ||
85 | * Calculates percent cpu usage for each task. | ||
86 | */ | ||
87 | |||
88 | static struct save_hist *prev_hist; | ||
89 | static int prev_hist_count; | ||
90 | /* static int hist_iterations; */ | ||
91 | |||
92 | |||
93 | static unsigned total_pcpu; | ||
94 | /* static unsigned long total_rss; */ | ||
95 | 116 | ||
96 | typedef struct { | 117 | typedef struct { |
97 | unsigned long long usr,nic,sys,idle,iowait,irq,softirq,steal; | 118 | unsigned long long usr,nic,sys,idle,iowait,irq,softirq,steal; |
@@ -115,11 +136,12 @@ static void get_jiffy_counts(void) | |||
115 | jif.busy = jif.total - jif.idle - jif.iowait; | 136 | jif.busy = jif.total - jif.idle - jif.iowait; |
116 | } | 137 | } |
117 | 138 | ||
139 | |||
118 | static void do_stats(void) | 140 | static void do_stats(void) |
119 | { | 141 | { |
120 | procps_status_t *cur; | 142 | top_status_t *cur; |
121 | pid_t pid; | 143 | pid_t pid; |
122 | int total_time, i, last_i, n; | 144 | int i, last_i, n; |
123 | struct save_hist *new_hist; | 145 | struct save_hist *new_hist; |
124 | 146 | ||
125 | get_jiffy_counts(); | 147 | get_jiffy_counts(); |
@@ -139,8 +161,7 @@ static void do_stats(void) | |||
139 | * and system time | 161 | * and system time |
140 | */ | 162 | */ |
141 | pid = cur->pid; | 163 | pid = cur->pid; |
142 | total_time = cur->stime + cur->utime; | 164 | new_hist[n].ticks = cur->ticks; |
143 | new_hist[n].ticks = total_time; | ||
144 | new_hist[n].pid = pid; | 165 | new_hist[n].pid = pid; |
145 | 166 | ||
146 | /* find matching entry from previous pass */ | 167 | /* find matching entry from previous pass */ |
@@ -150,13 +171,13 @@ static void do_stats(void) | |||
150 | last_i = i; | 171 | last_i = i; |
151 | if (prev_hist_count) do { | 172 | if (prev_hist_count) do { |
152 | if (prev_hist[i].pid == pid) { | 173 | if (prev_hist[i].pid == pid) { |
153 | cur->pcpu = total_time - prev_hist[i].ticks; | 174 | cur->pcpu = cur->ticks - prev_hist[i].ticks; |
175 | total_pcpu += cur->pcpu; | ||
154 | break; | 176 | break; |
155 | } | 177 | } |
156 | i = (i+1) % prev_hist_count; | 178 | i = (i+1) % prev_hist_count; |
157 | /* hist_iterations++; */ | 179 | /* hist_iterations++; */ |
158 | } while (i != last_i); | 180 | } while (i != last_i); |
159 | total_pcpu += cur->pcpu; | ||
160 | /* total_rss += cur->rss; */ | 181 | /* total_rss += cur->rss; */ |
161 | } | 182 | } |
162 | 183 | ||
@@ -167,10 +188,9 @@ static void do_stats(void) | |||
167 | prev_hist = new_hist; | 188 | prev_hist = new_hist; |
168 | prev_hist_count = ntop; | 189 | prev_hist_count = ntop; |
169 | } | 190 | } |
170 | #else | ||
171 | static cmp_t sort_function; | ||
172 | #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ | 191 | #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ |
173 | 192 | ||
193 | |||
174 | /* display generic info (meminfo / loadavg) */ | 194 | /* display generic info (meminfo / loadavg) */ |
175 | static unsigned long display_generic(int scr_width) | 195 | static unsigned long display_generic(int scr_width) |
176 | { | 196 | { |
@@ -265,7 +285,7 @@ static void display_status(int count, int scr_width) | |||
265 | bits_per_int = sizeof(int)*8 | 285 | bits_per_int = sizeof(int)*8 |
266 | }; | 286 | }; |
267 | 287 | ||
268 | procps_status_t *s = top; | 288 | top_status_t *s = top; |
269 | char rss_str_buf[8]; | 289 | char rss_str_buf[8]; |
270 | unsigned long total_memory = display_generic(scr_width); /* or use total_rss? */ | 290 | unsigned long total_memory = display_generic(scr_width); /* or use total_rss? */ |
271 | unsigned pmem_shift, pmem_scale; | 291 | unsigned pmem_shift, pmem_scale; |
@@ -333,14 +353,19 @@ static void display_status(int count, int scr_width) | |||
333 | sprintf(rss_str_buf, "%6ldM", s->rss/1024); | 353 | sprintf(rss_str_buf, "%6ldM", s->rss/1024); |
334 | else | 354 | else |
335 | sprintf(rss_str_buf, "%7ld", s->rss); | 355 | sprintf(rss_str_buf, "%7ld", s->rss); |
336 | USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE(pcpu = div((s->pcpu*pcpu_scale) >> pcpu_shift, 10);) | 356 | USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE( |
337 | col -= printf("\n%5u %-8s %s %s%6u%3u.%c" \ | 357 | pcpu = div((s->pcpu*pcpu_scale) >> pcpu_shift, 10); |
338 | USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE("%3u.%c") " ", | 358 | ) |
339 | (unsigned)s->pid, s->user, s->state, rss_str_buf, (unsigned)s->ppid, | 359 | col -= printf("\n%5u %-8s %s " |
360 | "%s%6u" | ||
361 | USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE("%3u.%c") | ||
362 | "%3u.%c ", | ||
363 | s->pid, get_cached_username(s->uid), s->state, | ||
364 | rss_str_buf, s->ppid, | ||
340 | USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE(pcpu.quot, '0'+pcpu.rem,) | 365 | USE_FEATURE_TOP_CPU_USAGE_PERCENTAGE(pcpu.quot, '0'+pcpu.rem,) |
341 | pmem.quot, '0'+pmem.rem); | 366 | pmem.quot, '0'+pmem.rem); |
342 | if (col > 0) | 367 | if (col > 0) |
343 | printf("%.*s", col, s->short_cmd); | 368 | printf("%.*s", col, s->comm); |
344 | /* printf(" %d/%d %lld/%lld", s->pcpu, total_pcpu, | 369 | /* printf(" %d/%d %lld/%lld", s->pcpu, total_pcpu, |
345 | jif.busy - prev_jif.busy, jif.total - prev_jif.total); */ | 370 | jif.busy - prev_jif.busy, jif.total - prev_jif.total); */ |
346 | s++; | 371 | s++; |
@@ -350,18 +375,20 @@ static void display_status(int count, int scr_width) | |||
350 | fflush(stdout); | 375 | fflush(stdout); |
351 | } | 376 | } |
352 | 377 | ||
378 | |||
353 | static void clearmems(void) | 379 | static void clearmems(void) |
354 | { | 380 | { |
381 | clear_username_cache(); | ||
355 | free(top); | 382 | free(top); |
356 | top = 0; | 383 | top = 0; |
357 | ntop = 0; | 384 | ntop = 0; |
358 | } | 385 | } |
359 | 386 | ||
387 | |||
360 | #if ENABLE_FEATURE_USE_TERMIOS | 388 | #if ENABLE_FEATURE_USE_TERMIOS |
361 | #include <termios.h> | 389 | #include <termios.h> |
362 | #include <signal.h> | 390 | #include <signal.h> |
363 | 391 | ||
364 | |||
365 | static struct termios initial_settings; | 392 | static struct termios initial_settings; |
366 | 393 | ||
367 | static void reset_term(void) | 394 | static void reset_term(void) |
@@ -427,7 +454,7 @@ int top_main(int argc, char **argv) | |||
427 | #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ | 454 | #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ |
428 | 455 | ||
429 | while (1) { | 456 | while (1) { |
430 | procps_status_t *p; | 457 | procps_status_t *p = NULL; |
431 | 458 | ||
432 | /* Default to 25 lines - 5 lines for status */ | 459 | /* Default to 25 lines - 5 lines for status */ |
433 | lines = 24 - 3; | 460 | lines = 24 - 3; |
@@ -442,11 +469,26 @@ int top_main(int argc, char **argv) | |||
442 | #endif /* FEATURE_USE_TERMIOS */ | 469 | #endif /* FEATURE_USE_TERMIOS */ |
443 | 470 | ||
444 | /* read process IDs & status for all the processes */ | 471 | /* read process IDs & status for all the processes */ |
445 | while ((p = procps_scan(0)) != 0) { | 472 | while ((p = procps_scan(p, 0 |
473 | | PSSCAN_PID | ||
474 | | PSSCAN_PPID | ||
475 | | PSSCAN_RSS | ||
476 | | PSSCAN_STIME | ||
477 | | PSSCAN_UTIME | ||
478 | | PSSCAN_STATE | ||
479 | | PSSCAN_COMM | ||
480 | | PSSCAN_SID | ||
481 | | PSSCAN_UIDGID | ||
482 | ))) { | ||
446 | int n = ntop; | 483 | int n = ntop; |
447 | 484 | top = xrealloc(top, (++ntop)*sizeof(top_status_t)); | |
448 | top = xrealloc(top, (++ntop)*sizeof(procps_status_t)); | 485 | top[n].pid = p->pid; |
449 | memcpy(top + n, p, sizeof(procps_status_t)); | 486 | top[n].ppid = p->ppid; |
487 | top[n].rss = p->rss; | ||
488 | top[n].ticks = p->stime + p->utime; | ||
489 | top[n].uid = p->uid; | ||
490 | strcpy(top[n].state, p->state); | ||
491 | strcpy(top[n].comm, p->comm); | ||
450 | } | 492 | } |
451 | if (ntop == 0) { | 493 | if (ntop == 0) { |
452 | bb_error_msg_and_die("can't find process info in /proc"); | 494 | bb_error_msg_and_die("can't find process info in /proc"); |
@@ -459,9 +501,9 @@ int top_main(int argc, char **argv) | |||
459 | continue; | 501 | continue; |
460 | } | 502 | } |
461 | do_stats(); | 503 | do_stats(); |
462 | qsort(top, ntop, sizeof(procps_status_t), (void*)mult_lvl_cmp); | 504 | qsort(top, ntop, sizeof(top_status_t), (void*)mult_lvl_cmp); |
463 | #else | 505 | #else |
464 | qsort(top, ntop, sizeof(procps_status_t), (void*)sort_function); | 506 | qsort(top, ntop, sizeof(top_status_t), (void*)sort_function); |
465 | #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ | 507 | #endif /* FEATURE_TOP_CPU_USAGE_PERCENTAGE */ |
466 | count = lines; | 508 | count = lines; |
467 | if (OPT_BATCH_MODE || count > ntop) { | 509 | if (OPT_BATCH_MODE || count > ntop) { |