aboutsummaryrefslogtreecommitdiff
path: root/procps
diff options
context:
space:
mode:
Diffstat (limited to 'procps')
-rw-r--r--procps/free.c7
-rw-r--r--procps/fuser.c3
-rw-r--r--procps/iostat.c3
-rw-r--r--procps/kill.c10
-rw-r--r--procps/mpstat.c1
-rw-r--r--procps/pgrep.c6
-rw-r--r--procps/pidof.c4
-rw-r--r--procps/pmap.c4
-rw-r--r--procps/powertop.c14
-rw-r--r--procps/ps.c185
-rw-r--r--procps/pstree.c6
-rw-r--r--procps/pwdx.c6
-rw-r--r--procps/sysctl.c64
-rw-r--r--procps/top.c19
-rw-r--r--procps/uptime.c2
-rw-r--r--procps/watch.c6
16 files changed, 160 insertions, 180 deletions
diff --git a/procps/free.c b/procps/free.c
index 618664e08..b57e4a322 100644
--- a/procps/free.c
+++ b/procps/free.c
@@ -15,7 +15,7 @@
15//config: memory in the system, as well as the buffers used by the kernel. 15//config: memory in the system, as well as the buffers used by the kernel.
16//config: The shared memory column should be ignored; it is obsolete. 16//config: The shared memory column should be ignored; it is obsolete.
17 17
18//applet:IF_FREE(APPLET(free, BB_DIR_USR_BIN, BB_SUID_DROP)) 18//applet:IF_FREE(APPLET_NOEXEC(free, free, BB_DIR_USR_BIN, BB_SUID_DROP, free))
19 19
20//kbuild:lib-$(CONFIG_FREE) += free.o 20//kbuild:lib-$(CONFIG_FREE) += free.o
21 21
@@ -47,7 +47,10 @@ struct globals {
47#endif 47#endif
48} FIX_ALIASING; 48} FIX_ALIASING;
49#define G (*(struct globals*)bb_common_bufsiz1) 49#define G (*(struct globals*)bb_common_bufsiz1)
50#define INIT_G() do { setup_common_bufsiz(); } while (0) 50#define INIT_G() do { \
51 setup_common_bufsiz(); \
52 /* NB: noexec applet - globals not zeroed */ \
53} while (0)
51 54
52 55
53static unsigned long long scale(unsigned long d) 56static unsigned long long scale(unsigned long d)
diff --git a/procps/fuser.c b/procps/fuser.c
index 2585a4203..418f57b57 100644
--- a/procps/fuser.c
+++ b/procps/fuser.c
@@ -299,8 +299,7 @@ int fuser_main(int argc UNUSED_PARAM, char **argv)
299 break; 299 break;
300 } 300 }
301 301
302 opt_complementary = "-1"; /* at least one param */ 302 getopt32(argv, "^" OPTION_STRING "\0" "-1"/*at least one arg*/);
303 getopt32(argv, OPTION_STRING);
304 argv += optind; 303 argv += optind;
305 304
306 pp = argv; 305 pp = argv;
diff --git a/procps/iostat.c b/procps/iostat.c
index 6a39c324f..050625f57 100644
--- a/procps/iostat.c
+++ b/procps/iostat.c
@@ -418,8 +418,7 @@ int iostat_main(int argc UNUSED_PARAM, char **argv)
418 418
419 /* Parse and process arguments */ 419 /* Parse and process arguments */
420 /* -k and -m are mutually exclusive */ 420 /* -k and -m are mutually exclusive */
421 opt_complementary = "k--m:m--k"; 421 opt = getopt32(argv, "^" "cdtzkm" "\0" "k--m:m--k");
422 opt = getopt32(argv, "cdtzkm");
423 if (!(opt & (OPT_c + OPT_d))) 422 if (!(opt & (OPT_c + OPT_d)))
424 /* Default is -cd */ 423 /* Default is -cd */
425 opt |= OPT_c + OPT_d; 424 opt |= OPT_c + OPT_d;
diff --git a/procps/kill.c b/procps/kill.c
index 09beefb2d..0ddae2f70 100644
--- a/procps/kill.c
+++ b/procps/kill.c
@@ -32,10 +32,10 @@
32//config: in its own session, so it won't kill the shell that is running 32//config: in its own session, so it won't kill the shell that is running
33//config: the script it was called from. 33//config: the script it was called from.
34 34
35//applet:IF_KILL(APPLET(kill, BB_DIR_BIN, BB_SUID_DROP)) 35//applet:IF_KILL( APPLET_NOFORK(kill, kill, BB_DIR_BIN, BB_SUID_DROP, kill))
36// APPLET_ODDNAME:name main location suid_type help 36// APPLET_NOFORK:name main location suid_type help
37//applet:IF_KILLALL( APPLET_ODDNAME(killall, kill, BB_DIR_USR_BIN, BB_SUID_DROP, killall)) 37//applet:IF_KILLALL( APPLET_NOFORK(killall, kill, BB_DIR_USR_BIN, BB_SUID_DROP, killall))
38//applet:IF_KILLALL5(APPLET_ODDNAME(killall5, kill, BB_DIR_USR_SBIN, BB_SUID_DROP, killall5)) 38//applet:IF_KILLALL5(APPLET_NOFORK(killall5, kill, BB_DIR_USR_SBIN, BB_SUID_DROP, killall5))
39 39
40//kbuild:lib-$(CONFIG_KILL) += kill.o 40//kbuild:lib-$(CONFIG_KILL) += kill.o
41//kbuild:lib-$(CONFIG_KILLALL) += kill.o 41//kbuild:lib-$(CONFIG_KILLALL) += kill.o
@@ -87,7 +87,7 @@
87 * + we can't use xfunc here 87 * + we can't use xfunc here
88 * + we can't use applet_name 88 * + we can't use applet_name
89 * + we can't use bb_show_usage 89 * + we can't use bb_show_usage
90 * (Above doesn't apply for killall[5] cases) 90 * (doesn't apply for killall[5], still should be careful b/c NOFORK)
91 * 91 *
92 * kill %n gets translated into kill ' -<process group>' by shell (note space!) 92 * kill %n gets translated into kill ' -<process group>' by shell (note space!)
93 * This is needed to avoid collision with kill -9 ... syntax 93 * This is needed to avoid collision with kill -9 ... syntax
diff --git a/procps/mpstat.c b/procps/mpstat.c
index 05a3f3ff3..c6279f9d8 100644
--- a/procps/mpstat.c
+++ b/procps/mpstat.c
@@ -8,6 +8,7 @@
8 */ 8 */
9 9
10//applet:IF_MPSTAT(APPLET(mpstat, BB_DIR_BIN, BB_SUID_DROP)) 10//applet:IF_MPSTAT(APPLET(mpstat, BB_DIR_BIN, BB_SUID_DROP))
11/* shouldn't be noexec: "mpstat INTERVAL" runs indefinitely */
11 12
12//kbuild:lib-$(CONFIG_MPSTAT) += mpstat.o 13//kbuild:lib-$(CONFIG_MPSTAT) += mpstat.o
13 14
diff --git a/procps/pgrep.c b/procps/pgrep.c
index a3ca9e295..a16a6e959 100644
--- a/procps/pgrep.c
+++ b/procps/pgrep.c
@@ -18,9 +18,13 @@
18//config: help 18//config: help
19//config: Send signals to processes by name. 19//config: Send signals to processes by name.
20 20
21//applet:IF_PGREP(APPLET(pgrep, BB_DIR_USR_BIN, BB_SUID_DROP)) 21//applet:IF_PGREP(APPLET_ODDNAME(pgrep, pgrep, BB_DIR_USR_BIN, BB_SUID_DROP, pgrep))
22// APPLET_ODDNAME:name main location suid_type help 22// APPLET_ODDNAME:name main location suid_type help
23//applet:IF_PKILL(APPLET_ODDNAME(pkill, pgrep, BB_DIR_USR_BIN, BB_SUID_DROP, pkill)) 23//applet:IF_PKILL(APPLET_ODDNAME(pkill, pgrep, BB_DIR_USR_BIN, BB_SUID_DROP, pkill))
24/* can't be noexec: can find _itself_ under wrong name, since after fork only,
25 * /proc/PID/cmdline and comm are wrong! Can fix comm (prctl(PR_SET_NAME)),
26 * but cmdline?
27 */
24 28
25//kbuild:lib-$(CONFIG_PGREP) += pgrep.o 29//kbuild:lib-$(CONFIG_PGREP) += pgrep.o
26//kbuild:lib-$(CONFIG_PKILL) += pgrep.o 30//kbuild:lib-$(CONFIG_PKILL) += pgrep.o
diff --git a/procps/pidof.c b/procps/pidof.c
index 41247a02c..98d7949f8 100644
--- a/procps/pidof.c
+++ b/procps/pidof.c
@@ -30,6 +30,10 @@
30//config: of the pidof, in other words the calling shell or shell script. 30//config: of the pidof, in other words the calling shell or shell script.
31 31
32//applet:IF_PIDOF(APPLET(pidof, BB_DIR_BIN, BB_SUID_DROP)) 32//applet:IF_PIDOF(APPLET(pidof, BB_DIR_BIN, BB_SUID_DROP))
33/* can't be noexec: can find _itself_ under wrong name, since after fork only,
34 * /proc/PID/cmdline and comm are wrong! Can fix comm (prctl(PR_SET_NAME)),
35 * but cmdline?
36 */
33 37
34//kbuild:lib-$(CONFIG_PIDOF) += pidof.o 38//kbuild:lib-$(CONFIG_PIDOF) += pidof.o
35 39
diff --git a/procps/pmap.c b/procps/pmap.c
index c8f728897..5c2d1ad59 100644
--- a/procps/pmap.c
+++ b/procps/pmap.c
@@ -18,7 +18,7 @@
18//kbuild:lib-$(CONFIG_PMAP) += pmap.o 18//kbuild:lib-$(CONFIG_PMAP) += pmap.o
19 19
20//usage:#define pmap_trivial_usage 20//usage:#define pmap_trivial_usage
21//usage: "[-xq] PID" 21//usage: "[-xq] PID..."
22//usage:#define pmap_full_usage "\n\n" 22//usage:#define pmap_full_usage "\n\n"
23//usage: "Display process memory usage" 23//usage: "Display process memory usage"
24//usage: "\n" 24//usage: "\n"
@@ -96,7 +96,7 @@ int pmap_main(int argc UNUSED_PARAM, char **argv)
96 unsigned opts; 96 unsigned opts;
97 int ret; 97 int ret;
98 98
99 opts = getopt32(argv, "xq"); 99 opts = getopt32(argv, "^" "xq" "\0" "-1"); /* min one arg */
100 argv += optind; 100 argv += optind;
101 101
102 ret = 0; 102 ret = 0;
diff --git a/procps/powertop.c b/procps/powertop.c
index ebd659bdb..5d522bf91 100644
--- a/procps/powertop.c
+++ b/procps/powertop.c
@@ -8,11 +8,6 @@
8 * 8 *
9 * Licensed under GPLv2, see file LICENSE in this source tree. 9 * Licensed under GPLv2, see file LICENSE in this source tree.
10 */ 10 */
11
12//applet:IF_POWERTOP(APPLET(powertop, BB_DIR_USR_SBIN, BB_SUID_DROP))
13
14//kbuild:lib-$(CONFIG_POWERTOP) += powertop.o
15
16//config:config POWERTOP 11//config:config POWERTOP
17//config: bool "powertop (9.1 kb)" 12//config: bool "powertop (9.1 kb)"
18//config: default y 13//config: default y
@@ -27,6 +22,10 @@
27//config: Without this, powertop will only refresh display every 10 seconds. 22//config: Without this, powertop will only refresh display every 10 seconds.
28//config: No keyboard commands will work, only ^C to terminate. 23//config: No keyboard commands will work, only ^C to terminate.
29 24
25//applet:IF_POWERTOP(APPLET(powertop, BB_DIR_USR_SBIN, BB_SUID_DROP))
26
27//kbuild:lib-$(CONFIG_POWERTOP) += powertop.o
28
30// XXX This should be configurable 29// XXX This should be configurable
31#define ENABLE_FEATURE_POWERTOP_PROCIRQ 1 30#define ENABLE_FEATURE_POWERTOP_PROCIRQ 1
32 31
@@ -718,7 +717,7 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv)
718 set_termios_to_raw(STDIN_FILENO, &G.init_settings, TERMIOS_CLEAR_ISIG); 717 set_termios_to_raw(STDIN_FILENO, &G.init_settings, TERMIOS_CLEAR_ISIG);
719 bb_signals(BB_FATAL_SIGS, sig_handler); 718 bb_signals(BB_FATAL_SIGS, sig_handler);
720 /* So we don't forget to reset term settings */ 719 /* So we don't forget to reset term settings */
721 atexit(reset_term); 720 die_func = reset_term;
722#endif 721#endif
723 722
724 /* Collect initial data */ 723 /* Collect initial data */
@@ -855,6 +854,9 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv)
855 } /* for (;;) */ 854 } /* for (;;) */
856 855
857 bb_putchar('\n'); 856 bb_putchar('\n');
857#if ENABLE_FEATURE_POWERTOP_INTERACTIVE
858 reset_term();
859#endif
858 860
859 return EXIT_SUCCESS; 861 return EXIT_SUCCESS;
860} 862}
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
diff --git a/procps/pstree.c b/procps/pstree.c
index 212cda23c..4fda1c21c 100644
--- a/procps/pstree.c
+++ b/procps/pstree.c
@@ -9,14 +9,13 @@
9 * 9 *
10 * Licensed under GPLv2, see file LICENSE in this source tree. 10 * Licensed under GPLv2, see file LICENSE in this source tree.
11 */ 11 */
12
13//config:config PSTREE 12//config:config PSTREE
14//config: bool "pstree (9.4 kb)" 13//config: bool "pstree (9.4 kb)"
15//config: default y 14//config: default y
16//config: help 15//config: help
17//config: Display a tree of processes. 16//config: Display a tree of processes.
18 17
19//applet:IF_PSTREE(APPLET(pstree, BB_DIR_USR_BIN, BB_SUID_DROP)) 18//applet:IF_PSTREE(APPLET_NOEXEC(pstree, pstree, BB_DIR_USR_BIN, BB_SUID_DROP, pstree))
20 19
21//kbuild:lib-$(CONFIG_PSTREE) += pstree.o 20//kbuild:lib-$(CONFIG_PSTREE) += pstree.o
22 21
@@ -387,8 +386,7 @@ int pstree_main(int argc UNUSED_PARAM, char **argv)
387 386
388 G.output_width = get_terminal_width(0); 387 G.output_width = get_terminal_width(0);
389 388
390 opt_complementary = "?1"; 389 getopt32(argv, "^" "p" "\0" "?1");
391 getopt32(argv, "p");
392 argv += optind; 390 argv += optind;
393 391
394 if (argv[0]) { 392 if (argv[0]) {
diff --git a/procps/pwdx.c b/procps/pwdx.c
index dac238950..c72cf804a 100644
--- a/procps/pwdx.c
+++ b/procps/pwdx.c
@@ -14,7 +14,7 @@
14//config: help 14//config: help
15//config: Report current working directory of a process 15//config: Report current working directory of a process
16 16
17//applet:IF_PWDX(APPLET(pwdx, BB_DIR_USR_BIN, BB_SUID_DROP)) 17//applet:IF_PWDX(APPLET_NOFORK(pwdx, pwdx, BB_DIR_USR_BIN, BB_SUID_DROP, pwdx))
18 18
19//kbuild:lib-$(CONFIG_PWDX) += pwdx.o 19//kbuild:lib-$(CONFIG_PWDX) += pwdx.o
20 20
@@ -28,8 +28,7 @@
28int pwdx_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 28int pwdx_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
29int pwdx_main(int argc UNUSED_PARAM, char **argv) 29int pwdx_main(int argc UNUSED_PARAM, char **argv)
30{ 30{
31 opt_complementary = "-1"; 31 getopt32(argv, "^" "" "\0" "-1");
32 getopt32(argv, "");
33 argv += optind; 32 argv += optind;
34 33
35 do { 34 do {
@@ -50,6 +49,7 @@ int pwdx_main(int argc UNUSED_PARAM, char **argv)
50 49
51 sprintf(buf, "/proc/%u/cwd", pid); 50 sprintf(buf, "/proc/%u/cwd", pid);
52 51
52 /* NOFORK: only one alloc is allowed; must free */
53 s = xmalloc_readlink(buf); 53 s = xmalloc_readlink(buf);
54 // "pwdx /proc/1" says "/proc/1: DIR", not "1: DIR" 54 // "pwdx /proc/1" says "/proc/1: DIR", not "1: DIR"
55 printf("%s: %s\n", *argv, s ? s : strerror(errno == ENOENT ? ESRCH : errno)); 55 printf("%s: %s\n", *argv, s ? s : strerror(errno == ENOENT ? ESRCH : errno));
diff --git a/procps/sysctl.c b/procps/sysctl.c
index b17f5e896..827e09cce 100644
--- a/procps/sysctl.c
+++ b/procps/sysctl.c
@@ -16,22 +16,22 @@
16//config: help 16//config: help
17//config: Configure kernel parameters at runtime. 17//config: Configure kernel parameters at runtime.
18 18
19//applet:IF_BB_SYSCTL(APPLET(sysctl, BB_DIR_SBIN, BB_SUID_DROP)) 19//applet:IF_BB_SYSCTL(APPLET_NOEXEC(sysctl, sysctl, BB_DIR_SBIN, BB_SUID_DROP, sysctl))
20 20
21//kbuild:lib-$(CONFIG_BB_SYSCTL) += sysctl.o 21//kbuild:lib-$(CONFIG_BB_SYSCTL) += sysctl.o
22 22
23//usage:#define sysctl_trivial_usage 23//usage:#define sysctl_trivial_usage
24//usage: "[OPTIONS] [KEY[=VALUE]]..." 24//usage: "-p [-enq] [FILE...] / [-enqaw] [KEY[=VALUE]]..."
25//usage:#define sysctl_full_usage "\n\n" 25//usage:#define sysctl_full_usage "\n\n"
26//usage: "Show/set kernel parameters\n" 26//usage: "Show/set kernel parameters\n"
27//usage: "\n -p Set values from FILEs (default /etc/sysctl.conf)"
27//usage: "\n -e Don't warn about unknown keys" 28//usage: "\n -e Don't warn about unknown keys"
28//usage: "\n -n Don't show key names" 29//usage: "\n -n Don't show key names"
30//usage: "\n -q Quiet"
29//usage: "\n -a Show all values" 31//usage: "\n -a Show all values"
30/* Same as -a, no need to show it */ 32/* Same as -a, no need to show it */
31/* //usage: "\n -A Show all values in table form" */ 33/* //usage: "\n -A Show all values in table form" */
32//usage: "\n -w Set values" 34//usage: "\n -w Set values"
33//usage: "\n -p FILE Set values from FILE (default /etc/sysctl.conf)"
34//usage: "\n -q Set values silently"
35//usage: 35//usage:
36//usage:#define sysctl_example_usage 36//usage:#define sysctl_example_usage
37//usage: "sysctl [-n] [-e] variable...\n" 37//usage: "sysctl [-n] [-e] variable...\n"
@@ -48,7 +48,7 @@ enum {
48 FLAG_TABLE_FORMAT = 1 << 2, /* not implemented */ 48 FLAG_TABLE_FORMAT = 1 << 2, /* not implemented */
49 FLAG_SHOW_ALL = 1 << 3, 49 FLAG_SHOW_ALL = 1 << 3,
50 FLAG_PRELOAD_FILE = 1 << 4, 50 FLAG_PRELOAD_FILE = 1 << 4,
51/* TODO: procps 3.2.8 seems to not require -w for KEY=VAL to work: */ 51 /* NB: procps 3.2.8 does not require -w for KEY=VAL to work, it only rejects non-KEY=VAL form */
52 FLAG_WRITE = 1 << 5, 52 FLAG_WRITE = 1 << 5,
53 FLAG_QUIET = 1 << 6, 53 FLAG_QUIET = 1 << 6,
54}; 54};
@@ -104,6 +104,7 @@ static int sysctl_act_on_setting(char *setting)
104 int fd, retval = EXIT_SUCCESS; 104 int fd, retval = EXIT_SUCCESS;
105 char *cptr, *outname; 105 char *cptr, *outname;
106 char *value = value; /* for compiler */ 106 char *value = value; /* for compiler */
107 bool writing = (option_mask32 & FLAG_WRITE);
107 108
108 outname = xstrdup(setting); 109 outname = xstrdup(setting);
109 110
@@ -114,8 +115,10 @@ static int sysctl_act_on_setting(char *setting)
114 cptr++; 115 cptr++;
115 } 116 }
116 117
117 if (option_mask32 & FLAG_WRITE) { 118 cptr = strchr(setting, '=');
118 cptr = strchr(setting, '='); 119 if (cptr)
120 writing = 1;
121 if (writing) {
119 if (cptr == NULL) { 122 if (cptr == NULL) {
120 bb_error_msg("error: '%s' must be of the form name=value", 123 bb_error_msg("error: '%s' must be of the form name=value",
121 outname); 124 outname);
@@ -147,7 +150,7 @@ static int sysctl_act_on_setting(char *setting)
147 break; 150 break;
148 default: 151 default:
149 bb_perror_msg("error %sing key '%s'", 152 bb_perror_msg("error %sing key '%s'",
150 option_mask32 & FLAG_WRITE ? 153 writing ?
151 "sett" : "read", 154 "sett" : "read",
152 outname); 155 outname);
153 break; 156 break;
@@ -156,7 +159,7 @@ static int sysctl_act_on_setting(char *setting)
156 goto end; 159 goto end;
157 } 160 }
158 161
159 if (option_mask32 & FLAG_WRITE) { 162 if (writing) {
160//TODO: procps 3.2.7 writes "value\n", note trailing "\n" 163//TODO: procps 3.2.7 writes "value\n", note trailing "\n"
161 xwrite_str(fd, value); 164 xwrite_str(fd, value);
162 close(fd); 165 close(fd);
@@ -238,23 +241,33 @@ static int sysctl_handle_preload_file(const char *filename)
238{ 241{
239 char *token[2]; 242 char *token[2];
240 parser_t *parser; 243 parser_t *parser;
244 int parse_flags;
241 245
242 parser = config_open(filename); 246 parser = config_open(filename);
243 /* Must do it _after_ config_open(): */ 247 /* Must do it _after_ config_open(): */
244 xchdir("/proc/sys"); 248 xchdir("/proc/sys");
245 /* xchroot("/proc/sys") - if you are paranoid */
246 249
247//TODO: ';' is comment char too 250 parse_flags = 0;
248//TODO: comment may be only at line start. "var=1 #abc" - "1 #abc" is the value 251 parse_flags &= ~PARSE_COLLAPSE; // NO (var==val is not var=val) - treat consecutive delimiters as one
249// (but _whitespace_ from ends should be trimmed first (and we do it right)) 252 parse_flags &= ~PARSE_TRIM; // NO - trim leading and trailing delimiters
250//TODO: "var==1" is mishandled (must use "=1" as a value, but uses "1") 253 parse_flags |= PARSE_GREEDY; // YES - last token takes entire remainder of the line
251// can it be fixed by removing PARSE_COLLAPSE bit? 254 parse_flags &= ~PARSE_MIN_DIE; // NO - die if < min tokens found
252 while (config_read(parser, token, 2, 2, "# \t=", PARSE_NORMAL)) { 255 parse_flags &= ~PARSE_EOL_COMMENTS; // NO (only first char) - comments are recognized even if not first char
256 parse_flags |= PARSE_ALT_COMMENTS;// YES - two comment chars: ';' and '#'
257 /* <space><tab><space>#comment is also comment, not strictly 1st char only */
258 parse_flags |= PARSE_WS_COMMENTS; // YES - comments are recognized even if there is whitespace before
259 while (config_read(parser, token, 2, 2, ";#=", parse_flags)) {
253 char *tp; 260 char *tp;
261
262 trim(token[1]);
263 tp = trim(token[0]);
254 sysctl_dots_to_slashes(token[0]); 264 sysctl_dots_to_slashes(token[0]);
255 tp = xasprintf("%s=%s", token[0], token[1]); 265 /* ^^^converted in-place. tp still points to NUL */
256 sysctl_act_recursive(tp); 266 /* now, add "=TOKEN1" */
257 free(tp); 267 *tp++ = '=';
268 overlapping_strcpy(tp, token[1]);
269
270 sysctl_act_on_setting(token[0]);
258 } 271 }
259 if (ENABLE_FEATURE_CLEAN_UP) 272 if (ENABLE_FEATURE_CLEAN_UP)
260 config_close(parser); 273 config_close(parser);
@@ -273,12 +286,19 @@ int sysctl_main(int argc UNUSED_PARAM, char **argv)
273 option_mask32 = opt; 286 option_mask32 = opt;
274 287
275 if (opt & FLAG_PRELOAD_FILE) { 288 if (opt & FLAG_PRELOAD_FILE) {
289 int cur_dir_fd;
276 option_mask32 |= FLAG_WRITE; 290 option_mask32 |= FLAG_WRITE;
277 /* xchdir("/proc/sys") is inside */ 291 if (!*argv)
278 return sysctl_handle_preload_file(*argv ? *argv : "/etc/sysctl.conf"); 292 *--argv = (char*)"/etc/sysctl.conf";
293 cur_dir_fd = xopen(".", O_RDONLY | O_DIRECTORY);
294 do {
295 /* xchdir("/proc/sys") is inside */
296 sysctl_handle_preload_file(*argv);
297 xfchdir(cur_dir_fd); /* files can be relative, must restore cwd */
298 } while (*++argv);
299 return 0; /* procps-ng 3.3.10 does not flag parse errors */
279 } 300 }
280 xchdir("/proc/sys"); 301 xchdir("/proc/sys");
281 /* xchroot("/proc/sys") - if you are paranoid */
282 if (opt & (FLAG_TABLE_FORMAT | FLAG_SHOW_ALL)) { 302 if (opt & (FLAG_TABLE_FORMAT | FLAG_SHOW_ALL)) {
283 return sysctl_act_recursive("."); 303 return sysctl_act_recursive(".");
284 } 304 }
diff --git a/procps/top.c b/procps/top.c
index 015d1ab74..f97ded5d6 100644
--- a/procps/top.c
+++ b/procps/top.c
@@ -116,7 +116,6 @@
116//kbuild:lib-$(CONFIG_TOP) += top.o 116//kbuild:lib-$(CONFIG_TOP) += top.o
117 117
118#include "libbb.h" 118#include "libbb.h"
119#include "common_bufsiz.h"
120 119
121 120
122typedef struct top_status_t { 121typedef struct top_status_t {
@@ -154,6 +153,8 @@ typedef int (*cmp_funcp)(top_status_t *P, top_status_t *Q);
154 153
155enum { SORT_DEPTH = 3 }; 154enum { SORT_DEPTH = 3 };
156 155
156/* Screens wider than this are unlikely */
157enum { LINE_BUF_SIZE = 512 - 64 };
157 158
158struct globals { 159struct globals {
159 top_status_t *top; 160 top_status_t *top;
@@ -192,10 +193,9 @@ struct globals {
192#if ENABLE_FEATURE_TOP_INTERACTIVE 193#if ENABLE_FEATURE_TOP_INTERACTIVE
193 char kbd_input[KEYCODE_BUFFER_SIZE]; 194 char kbd_input[KEYCODE_BUFFER_SIZE];
194#endif 195#endif
195 char line_buf[80]; 196 char line_buf[LINE_BUF_SIZE];
196}; //FIX_ALIASING; - large code growth 197};
197enum { LINE_BUF_SIZE = COMMON_BUFSIZE - offsetof(struct globals, line_buf) }; 198#define G (*ptr_to_globals)
198#define G (*(struct globals*)bb_common_bufsiz1)
199#define top (G.top ) 199#define top (G.top )
200#define ntop (G.ntop ) 200#define ntop (G.ntop )
201#define sort_field (G.sort_field ) 201#define sort_field (G.sort_field )
@@ -213,8 +213,7 @@ enum { LINE_BUF_SIZE = COMMON_BUFSIZE - offsetof(struct globals, line_buf) };
213#define total_pcpu (G.total_pcpu ) 213#define total_pcpu (G.total_pcpu )
214#define line_buf (G.line_buf ) 214#define line_buf (G.line_buf )
215#define INIT_G() do { \ 215#define INIT_G() do { \
216 setup_common_bufsiz(); \ 216 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
217 BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
218 BUILD_BUG_ON(LINE_BUF_SIZE <= 80); \ 217 BUILD_BUG_ON(LINE_BUF_SIZE <= 80); \
219} while (0) 218} while (0)
220 219
@@ -1110,15 +1109,14 @@ int top_main(int argc UNUSED_PARAM, char **argv)
1110#endif 1109#endif
1111 1110
1112 /* all args are options; -n NUM */ 1111 /* all args are options; -n NUM */
1113 opt_complementary = "-"; /* options can be specified w/o dash */ 1112 make_all_argv_opts(argv); /* options can be specified w/o dash */
1114 col = getopt32(argv, "d:n:b"IF_FEATURE_TOPMEM("m"), &str_interval, &str_iterations); 1113 col = getopt32(argv, "d:n:b"IF_FEATURE_TOPMEM("m"), &str_interval, &str_iterations);
1115#if ENABLE_FEATURE_TOPMEM 1114#if ENABLE_FEATURE_TOPMEM
1116 if (col & OPT_m) /* -m (busybox specific) */ 1115 if (col & OPT_m) /* -m (busybox specific) */
1117 scan_mask = TOPMEM_MASK; 1116 scan_mask = TOPMEM_MASK;
1118#endif 1117#endif
1119 if (col & OPT_d) { 1118 if (col & OPT_d) {
1120 /* work around for "-d 1" -> "-d -1" done by getopt32 1119 /* work around for "-d 1" -> "-d -1" done by make_all_argv_opts() */
1121 * (opt_complementary == "-" does this) */
1122 if (str_interval[0] == '-') 1120 if (str_interval[0] == '-')
1123 str_interval++; 1121 str_interval++;
1124 /* Need to limit it to not overflow poll timeout */ 1122 /* Need to limit it to not overflow poll timeout */
@@ -1148,6 +1146,7 @@ int top_main(int argc UNUSED_PARAM, char **argv)
1148 else { 1146 else {
1149 /* Turn on unbuffered input; turn off echoing, ^C ^Z etc */ 1147 /* Turn on unbuffered input; turn off echoing, ^C ^Z etc */
1150 set_termios_to_raw(STDIN_FILENO, &initial_settings, TERMIOS_CLEAR_ISIG); 1148 set_termios_to_raw(STDIN_FILENO, &initial_settings, TERMIOS_CLEAR_ISIG);
1149 die_func = reset_term;
1151 } 1150 }
1152 1151
1153 bb_signals(BB_FATAL_SIGS, sig_catcher); 1152 bb_signals(BB_FATAL_SIGS, sig_catcher);
diff --git a/procps/uptime.c b/procps/uptime.c
index 24b2b39df..b0ee8391b 100644
--- a/procps/uptime.c
+++ b/procps/uptime.c
@@ -27,7 +27,7 @@
27//config: help 27//config: help
28//config: Display the number of users currently logged on. 28//config: Display the number of users currently logged on.
29 29
30//applet:IF_UPTIME(APPLET(uptime, BB_DIR_USR_BIN, BB_SUID_DROP)) 30//applet:IF_UPTIME(APPLET_NOEXEC(uptime, uptime, BB_DIR_USR_BIN, BB_SUID_DROP, uptime))
31 31
32//kbuild:lib-$(CONFIG_UPTIME) += uptime.o 32//kbuild:lib-$(CONFIG_UPTIME) += uptime.o
33 33
diff --git a/procps/watch.c b/procps/watch.c
index 2bb7cca90..6fc9f7db7 100644
--- a/procps/watch.c
+++ b/procps/watch.c
@@ -62,9 +62,9 @@ int watch_main(int argc UNUSED_PARAM, char **argv)
62 xopen("/dev/null", O_RDONLY); 62 xopen("/dev/null", O_RDONLY);
63#endif 63#endif
64 64
65 opt_complementary = "-1"; // at least one param; -n NUM 65 // "+": stop at first non-option (procps 3.x only); -n NUM
66 // "+": stop at first non-option (procps 3.x only) 66 // at least one param
67 opt = getopt32(argv, "+dtn:+", &period); 67 opt = getopt32(argv, "^+" "dtn:+" "\0" "-1", &period);
68 argv += optind; 68 argv += optind;
69 69
70 // watch from both procps 2.x and 3.x does concatenation. Example: 70 // watch from both procps 2.x and 3.x does concatenation. Example: