aboutsummaryrefslogtreecommitdiff
path: root/procps/ps.c
diff options
context:
space:
mode:
Diffstat (limited to 'procps/ps.c')
-rw-r--r--procps/ps.c185
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__)
205static 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
221static 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
264static inline unsigned get_HZ_by_waiting(void)
265{
266 /* Better method? */
267 return 100;
268}
269#endif
270
271static 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
383static void func_rgroup(char *buf, int size, const procps_status_t *ps) 305static 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
388static void func_ruser(char *buf, int size, const procps_status_t *ps) 309static 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
393static void func_nice(char *buf, int size, const procps_status_t *ps) 313static 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
320static 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}
402static void func_etime(char *buf, int size, const procps_status_t *ps) 353static 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
416static void func_time(char *buf, int size, const procps_status_t *ps) 362static 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