diff options
Diffstat (limited to 'procps/ps.c')
-rw-r--r-- | procps/ps.c | 185 |
1 files changed, 68 insertions, 117 deletions
diff --git a/procps/ps.c b/procps/ps.c index 3e83a3e03..742d1715e 100644 --- a/procps/ps.c +++ b/procps/ps.c | |||
@@ -15,26 +15,26 @@ | |||
15 | //config: ps gives a snapshot of the current processes. | 15 | //config: ps gives a snapshot of the current processes. |
16 | //config: | 16 | //config: |
17 | //config:config FEATURE_PS_WIDE | 17 | //config:config FEATURE_PS_WIDE |
18 | //config: bool "Enable wide output option (-w)" | 18 | //config: bool "Enable wide output (-w)" |
19 | //config: default y | 19 | //config: default y |
20 | //config: depends on PS && !DESKTOP | 20 | //config: depends on (PS || MINIPS) && !DESKTOP |
21 | //config: help | 21 | //config: help |
22 | //config: Support argument 'w' for wide output. | 22 | //config: Support argument 'w' for wide output. |
23 | //config: If given once, 132 chars are printed, and if given more | 23 | //config: If given once, 132 chars are printed, and if given more |
24 | //config: than once, the length is unlimited. | 24 | //config: than once, the length is unlimited. |
25 | //config: | 25 | //config: |
26 | //config:config FEATURE_PS_LONG | 26 | //config:config FEATURE_PS_LONG |
27 | //config: bool "Enable long output option (-l)" | 27 | //config: bool "Enable long output (-l)" |
28 | //config: default y | 28 | //config: default y |
29 | //config: depends on PS && !DESKTOP | 29 | //config: depends on (PS || MINIPS) && !DESKTOP |
30 | //config: help | 30 | //config: help |
31 | //config: Support argument 'l' for long output. | 31 | //config: Support argument 'l' for long output. |
32 | //config: Adds fields PPID, RSS, START, TIME & TTY | 32 | //config: Adds fields PPID, RSS, START, TIME & TTY |
33 | //config: | 33 | //config: |
34 | //config:config FEATURE_PS_TIME | 34 | //config:config FEATURE_PS_TIME |
35 | //config: bool "Support -o time and -o etime output specifiers" | 35 | //config: bool "Enable -o time and -o etime specifiers" |
36 | //config: default y | 36 | //config: default y |
37 | //config: depends on PS && DESKTOP | 37 | //config: depends on (PS || MINIPS) && DESKTOP |
38 | //config: select PLATFORM_LINUX | 38 | //config: select PLATFORM_LINUX |
39 | //config: | 39 | //config: |
40 | //config:config FEATURE_PS_UNUSUAL_SYSTEMS | 40 | //config:config FEATURE_PS_UNUSUAL_SYSTEMS |
@@ -46,13 +46,16 @@ | |||
46 | //config: (if you are on Linux 2.4.0+ and use ELF, you don't need this) | 46 | //config: (if you are on Linux 2.4.0+ and use ELF, you don't need this) |
47 | //config: | 47 | //config: |
48 | //config:config FEATURE_PS_ADDITIONAL_COLUMNS | 48 | //config:config FEATURE_PS_ADDITIONAL_COLUMNS |
49 | //config: bool "Support -o rgroup, -o ruser, -o nice specifiers" | 49 | //config: bool "Enable -o rgroup, -o ruser, -o nice specifiers" |
50 | //config: default y | 50 | //config: default y |
51 | //config: depends on PS && DESKTOP | 51 | //config: depends on (PS || MINIPS) && DESKTOP |
52 | 52 | ||
53 | //applet:IF_PS(APPLET(ps, BB_DIR_BIN, BB_SUID_DROP)) | 53 | // APPLET_NOEXEC:name main location suid_type help |
54 | //applet:IF_PS( APPLET_NOEXEC(ps, ps, BB_DIR_BIN, BB_SUID_DROP, ps)) | ||
55 | //applet:IF_MINIPS(APPLET_NOEXEC(minips, ps, BB_DIR_BIN, BB_SUID_DROP, ps)) | ||
54 | 56 | ||
55 | //kbuild:lib-$(CONFIG_PS) += ps.o | 57 | //kbuild:lib-$(CONFIG_PS) += ps.o |
58 | //kbuild:lib-$(CONFIG_MINIPS) += ps.o | ||
56 | 59 | ||
57 | //usage:#if ENABLE_DESKTOP | 60 | //usage:#if ENABLE_DESKTOP |
58 | //usage: | 61 | //usage: |
@@ -144,12 +147,6 @@ static unsigned long get_uptime(void) | |||
144 | #endif | 147 | #endif |
145 | 148 | ||
146 | #if ENABLE_DESKTOP | 149 | #if ENABLE_DESKTOP |
147 | |||
148 | #include <sys/times.h> /* for times() */ | ||
149 | #ifndef AT_CLKTCK | ||
150 | # define AT_CLKTCK 17 | ||
151 | #endif | ||
152 | |||
153 | /* TODO: | 150 | /* TODO: |
154 | * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html | 151 | * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html |
155 | * specifies (for XSI-conformant systems) following default columns | 152 | * specifies (for XSI-conformant systems) following default columns |
@@ -186,7 +183,9 @@ struct globals { | |||
186 | char *buffer; | 183 | char *buffer; |
187 | unsigned terminal_width; | 184 | unsigned terminal_width; |
188 | #if ENABLE_FEATURE_PS_TIME | 185 | #if ENABLE_FEATURE_PS_TIME |
186 | # if ENABLE_FEATURE_PS_UNUSUAL_SYSTEMS || !defined(__linux__) | ||
189 | unsigned kernel_HZ; | 187 | unsigned kernel_HZ; |
188 | # endif | ||
190 | unsigned long seconds_since_boot; | 189 | unsigned long seconds_since_boot; |
191 | #endif | 190 | #endif |
192 | } FIX_ALIASING; | 191 | } FIX_ALIASING; |
@@ -197,91 +196,15 @@ struct globals { | |||
197 | #define need_flags (G.need_flags ) | 196 | #define need_flags (G.need_flags ) |
198 | #define buffer (G.buffer ) | 197 | #define buffer (G.buffer ) |
199 | #define terminal_width (G.terminal_width ) | 198 | #define terminal_width (G.terminal_width ) |
200 | #define kernel_HZ (G.kernel_HZ ) | ||
201 | #define INIT_G() do { setup_common_bufsiz(); } while (0) | 199 | #define INIT_G() do { setup_common_bufsiz(); } while (0) |
202 | 200 | ||
203 | #if ENABLE_FEATURE_PS_TIME | 201 | #if ENABLE_FEATURE_PS_TIME |
204 | /* for ELF executables, notes are pushed before environment and args */ | 202 | # if ENABLE_FEATURE_PS_UNUSUAL_SYSTEMS || !defined(__linux__) |
205 | static uintptr_t find_elf_note(uintptr_t findme) | 203 | # define get_kernel_HZ() (G.kernel_HZ) |
206 | { | 204 | # else |
207 | uintptr_t *ep = (uintptr_t *) environ; | 205 | /* non-ancient Linux standardized on 100 for "times" freq */ |
208 | 206 | # define get_kernel_HZ() ((unsigned)100) | |
209 | while (*ep++) | 207 | # endif |
210 | continue; | ||
211 | while (*ep) { | ||
212 | if (ep[0] == findme) { | ||
213 | return ep[1]; | ||
214 | } | ||
215 | ep += 2; | ||
216 | } | ||
217 | return -1; | ||
218 | } | ||
219 | |||
220 | #if ENABLE_FEATURE_PS_UNUSUAL_SYSTEMS | ||
221 | static unsigned get_HZ_by_waiting(void) | ||
222 | { | ||
223 | struct timeval tv1, tv2; | ||
224 | unsigned t1, t2, r, hz; | ||
225 | unsigned cnt = cnt; /* for compiler */ | ||
226 | int diff; | ||
227 | |||
228 | r = 0; | ||
229 | |||
230 | /* Wait for times() to reach new tick */ | ||
231 | t1 = times(NULL); | ||
232 | do { | ||
233 | t2 = times(NULL); | ||
234 | } while (t2 == t1); | ||
235 | gettimeofday(&tv2, NULL); | ||
236 | |||
237 | do { | ||
238 | t1 = t2; | ||
239 | tv1.tv_usec = tv2.tv_usec; | ||
240 | |||
241 | /* Wait exactly one times() tick */ | ||
242 | do { | ||
243 | t2 = times(NULL); | ||
244 | } while (t2 == t1); | ||
245 | gettimeofday(&tv2, NULL); | ||
246 | |||
247 | /* Calculate ticks per sec, rounding up to even */ | ||
248 | diff = tv2.tv_usec - tv1.tv_usec; | ||
249 | if (diff <= 0) diff += 1000000; | ||
250 | hz = 1000000u / (unsigned)diff; | ||
251 | hz = (hz+1) & ~1; | ||
252 | |||
253 | /* Count how many same hz values we saw */ | ||
254 | if (r != hz) { | ||
255 | r = hz; | ||
256 | cnt = 0; | ||
257 | } | ||
258 | cnt++; | ||
259 | } while (cnt < 3); /* exit if saw 3 same values */ | ||
260 | |||
261 | return r; | ||
262 | } | ||
263 | #else | ||
264 | static inline unsigned get_HZ_by_waiting(void) | ||
265 | { | ||
266 | /* Better method? */ | ||
267 | return 100; | ||
268 | } | ||
269 | #endif | ||
270 | |||
271 | static unsigned get_kernel_HZ(void) | ||
272 | { | ||
273 | if (kernel_HZ) | ||
274 | return kernel_HZ; | ||
275 | |||
276 | /* Works for ELF only, Linux 2.4.0+ */ | ||
277 | kernel_HZ = find_elf_note(AT_CLKTCK); | ||
278 | if (kernel_HZ == (unsigned)-1) | ||
279 | kernel_HZ = get_HZ_by_waiting(); | ||
280 | |||
281 | G.seconds_since_boot = get_uptime(); | ||
282 | |||
283 | return kernel_HZ; | ||
284 | } | ||
285 | #endif | 208 | #endif |
286 | 209 | ||
287 | /* Print value to buf, max size+1 chars (including trailing '\0') */ | 210 | /* Print value to buf, max size+1 chars (including trailing '\0') */ |
@@ -379,52 +302,71 @@ static void func_tty(char *buf, int size, const procps_status_t *ps) | |||
379 | #endif | 302 | #endif |
380 | 303 | ||
381 | #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS | 304 | #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS |
382 | |||
383 | static void func_rgroup(char *buf, int size, const procps_status_t *ps) | 305 | static void func_rgroup(char *buf, int size, const procps_status_t *ps) |
384 | { | 306 | { |
385 | safe_strncpy(buf, get_cached_groupname(ps->rgid), size+1); | 307 | safe_strncpy(buf, get_cached_groupname(ps->rgid), size+1); |
386 | } | 308 | } |
387 | |||
388 | static void func_ruser(char *buf, int size, const procps_status_t *ps) | 309 | static void func_ruser(char *buf, int size, const procps_status_t *ps) |
389 | { | 310 | { |
390 | safe_strncpy(buf, get_cached_username(ps->ruid), size+1); | 311 | safe_strncpy(buf, get_cached_username(ps->ruid), size+1); |
391 | } | 312 | } |
392 | |||
393 | static void func_nice(char *buf, int size, const procps_status_t *ps) | 313 | static void func_nice(char *buf, int size, const procps_status_t *ps) |
394 | { | 314 | { |
395 | sprintf(buf, "%*d", size, ps->niceness); | 315 | sprintf(buf, "%*d", size, ps->niceness); |
396 | } | 316 | } |
397 | |||
398 | #endif | 317 | #endif |
399 | 318 | ||
400 | #if ENABLE_FEATURE_PS_TIME | 319 | #if ENABLE_FEATURE_PS_TIME |
320 | static void format_time(char *buf, int size, unsigned long tt) | ||
321 | { | ||
322 | unsigned ff; | ||
401 | 323 | ||
324 | /* Used to show "14453:50" if tt is large. Ugly. | ||
325 | * procps-ng 3.3.10 uses "[[dd-]hh:]mm:ss" format. | ||
326 | * TODO: switch to that? | ||
327 | */ | ||
328 | |||
329 | /* Formatting for 5-char TIME column. | ||
330 | * NB: "size" is not always 5: ELAPSED is wider (7), | ||
331 | * not taking advantage of that (yet?). | ||
332 | */ | ||
333 | ff = tt % 60; | ||
334 | tt /= 60; | ||
335 | if (tt < 60) { | ||
336 | snprintf(buf, size+1, "%2u:%02u", (unsigned)tt, ff); | ||
337 | return; | ||
338 | } | ||
339 | ff = tt % 60; | ||
340 | tt /= 60; | ||
341 | if (tt < 24) { | ||
342 | snprintf(buf, size+1, "%2uh%02u", (unsigned)tt, ff); | ||
343 | return; | ||
344 | } | ||
345 | ff = tt % 24; | ||
346 | tt /= 24; | ||
347 | if (tt < 100) { | ||
348 | snprintf(buf, size+1, "%2ud%02u", (unsigned)tt, ff); | ||
349 | return; | ||
350 | } | ||
351 | snprintf(buf, size+1, "%4lud", tt); | ||
352 | } | ||
402 | static void func_etime(char *buf, int size, const procps_status_t *ps) | 353 | static void func_etime(char *buf, int size, const procps_status_t *ps) |
403 | { | 354 | { |
404 | /* elapsed time [[dd-]hh:]mm:ss; here only mm:ss */ | 355 | /* elapsed time [[dd-]hh:]mm:ss; here only mm:ss */ |
405 | unsigned long mm; | 356 | unsigned long mm; |
406 | unsigned ss; | ||
407 | 357 | ||
408 | mm = ps->start_time / get_kernel_HZ(); | 358 | mm = ps->start_time / get_kernel_HZ(); |
409 | /* must be after get_kernel_HZ()! */ | ||
410 | mm = G.seconds_since_boot - mm; | 359 | mm = G.seconds_since_boot - mm; |
411 | ss = mm % 60; | 360 | format_time(buf, size, mm); |
412 | mm /= 60; | ||
413 | snprintf(buf, size+1, "%3lu:%02u", mm, ss); | ||
414 | } | 361 | } |
415 | |||
416 | static void func_time(char *buf, int size, const procps_status_t *ps) | 362 | static void func_time(char *buf, int size, const procps_status_t *ps) |
417 | { | 363 | { |
418 | /* cumulative time [[dd-]hh:]mm:ss; here only mm:ss */ | 364 | /* cumulative time [[dd-]hh:]mm:ss; here only mm:ss */ |
419 | unsigned long mm; | 365 | unsigned long mm; |
420 | unsigned ss; | ||
421 | 366 | ||
422 | mm = (ps->utime + ps->stime) / get_kernel_HZ(); | 367 | mm = (ps->utime + ps->stime) / get_kernel_HZ(); |
423 | ss = mm % 60; | 368 | format_time(buf, size, mm); |
424 | mm /= 60; | ||
425 | snprintf(buf, size+1, "%3lu:%02u", mm, ss); | ||
426 | } | 369 | } |
427 | |||
428 | #endif | 370 | #endif |
429 | 371 | ||
430 | #if ENABLE_SELINUX | 372 | #if ENABLE_SELINUX |
@@ -465,7 +407,7 @@ static const ps_out_t out_spec[] = { | |||
465 | // { 5 , "pcpu" ,"%CPU" ,func_pcpu ,PSSCAN_ }, | 407 | // { 5 , "pcpu" ,"%CPU" ,func_pcpu ,PSSCAN_ }, |
466 | #endif | 408 | #endif |
467 | #if ENABLE_FEATURE_PS_TIME | 409 | #if ENABLE_FEATURE_PS_TIME |
468 | { 6 , "time" ,"TIME" ,func_time ,PSSCAN_STIME | PSSCAN_UTIME }, | 410 | { 5 , "time" ,"TIME" ,func_time ,PSSCAN_STIME | PSSCAN_UTIME }, |
469 | #endif | 411 | #endif |
470 | #if !ENABLE_PLATFORM_MINGW32 | 412 | #if !ENABLE_PLATFORM_MINGW32 |
471 | { 6 , "tty" ,"TT" ,func_tty ,PSSCAN_TTY }, | 413 | { 6 , "tty" ,"TT" ,func_tty ,PSSCAN_TTY }, |
@@ -641,6 +583,12 @@ int ps_main(int argc UNUSED_PARAM, char **argv) | |||
641 | }; | 583 | }; |
642 | 584 | ||
643 | INIT_G(); | 585 | INIT_G(); |
586 | #if ENABLE_FEATURE_PS_TIME | ||
587 | G.seconds_since_boot = get_uptime(); | ||
588 | # if ENABLE_FEATURE_PS_UNUSUAL_SYSTEMS || !defined(__linux__) | ||
589 | G.kernel_HZ = bb_clk_tck(); /* this is sysconf(_SC_CLK_TCK) */ | ||
590 | # endif | ||
591 | #endif | ||
644 | 592 | ||
645 | // POSIX: | 593 | // POSIX: |
646 | // -a Write information for all processes associated with terminals | 594 | // -a Write information for all processes associated with terminals |
@@ -731,9 +679,12 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
731 | # if ENABLE_FEATURE_PS_WIDE | 679 | # if ENABLE_FEATURE_PS_WIDE |
732 | /* -w is a bit complicated */ | 680 | /* -w is a bit complicated */ |
733 | int w_count = 0; | 681 | int w_count = 0; |
734 | opt_complementary = "-:ww"; | 682 | make_all_argv_opts(argv); |
735 | opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l") | 683 | opts = getopt32(argv, "^" |
736 | "w", &w_count); | 684 | IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l")"w" |
685 | "\0" "ww", | ||
686 | &w_count | ||
687 | ); | ||
737 | /* if w is given once, GNU ps sets the width to 132, | 688 | /* if w is given once, GNU ps sets the width to 132, |
738 | * if w is given more than once, it is "unlimited" | 689 | * if w is given more than once, it is "unlimited" |
739 | */ | 690 | */ |
@@ -747,7 +698,7 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
747 | } | 698 | } |
748 | # else | 699 | # else |
749 | /* -w is not supported, only -Z and/or -T */ | 700 | /* -w is not supported, only -Z and/or -T */ |
750 | opt_complementary = "-"; | 701 | make_all_argv_opts(argv); |
751 | opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l")); | 702 | opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l")); |
752 | # endif | 703 | # endif |
753 | 704 | ||