diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-01-05 03:26:41 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-01-05 03:26:41 +0000 |
commit | 5fee2e1a79dc6fc05658821a86b0e7b5678a90dd (patch) | |
tree | 97524fe62e963beeddb96b11576d3f96a6d85d8b | |
parent | 9cd30d30a0d7340524ba8223dc9d4088eb93a1d6 (diff) | |
download | busybox-w32-5fee2e1a79dc6fc05658821a86b0e7b5678a90dd.tar.gz busybox-w32-5fee2e1a79dc6fc05658821a86b0e7b5678a90dd.tar.bz2 busybox-w32-5fee2e1a79dc6fc05658821a86b0e7b5678a90dd.zip |
ps: add conditional support for -o [e]time
-rw-r--r-- | applets/applet_tables.c | 2 | ||||
-rw-r--r-- | include/libbb.h | 4 | ||||
-rw-r--r-- | libbb/procps.c | 7 | ||||
-rw-r--r-- | procps/Config.in | 15 | ||||
-rw-r--r-- | procps/ps.c | 216 |
5 files changed, 195 insertions, 49 deletions
diff --git a/applets/applet_tables.c b/applets/applet_tables.c index 3945f7c51..3353f3662 100644 --- a/applets/applet_tables.c +++ b/applets/applet_tables.c | |||
@@ -71,7 +71,7 @@ int main(int argc, char **argv) | |||
71 | 71 | ||
72 | puts("/* This is a generated file, don't edit */"); | 72 | puts("/* This is a generated file, don't edit */"); |
73 | 73 | ||
74 | puts("const char applet_names[] ALIGN1 = \"\" \n"); | 74 | puts("const char applet_names[] ALIGN1 = \"\"\n"); |
75 | for (i = 0; i < NUM_APPLETS; i++) { | 75 | for (i = 0; i < NUM_APPLETS; i++) { |
76 | printf("\"%s\" \"\\0\"\n", applets[i].name); | 76 | printf("\"%s\" \"\\0\"\n", applets[i].name); |
77 | } | 77 | } |
diff --git a/include/libbb.h b/include/libbb.h index fef8fe2e0..33e73b27b 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -990,6 +990,7 @@ typedef struct procps_status_t { | |||
990 | * it is memset(0) for each process in procps_scan() */ | 990 | * it is memset(0) for each process in procps_scan() */ |
991 | unsigned long vsz, rss; /* we round it to kbytes */ | 991 | unsigned long vsz, rss; /* we round it to kbytes */ |
992 | unsigned long stime, utime; | 992 | unsigned long stime, utime; |
993 | unsigned long start_time; | ||
993 | unsigned pid; | 994 | unsigned pid; |
994 | unsigned ppid; | 995 | unsigned ppid; |
995 | unsigned pgid; | 996 | unsigned pgid; |
@@ -1032,11 +1033,12 @@ enum { | |||
1032 | PSSCAN_SMAPS = (1 << 15) * ENABLE_FEATURE_TOPMEM, | 1033 | PSSCAN_SMAPS = (1 << 15) * ENABLE_FEATURE_TOPMEM, |
1033 | PSSCAN_ARGVN = (1 << 16) * (ENABLE_PGREP | ENABLE_PKILL), | 1034 | PSSCAN_ARGVN = (1 << 16) * (ENABLE_PGREP | ENABLE_PKILL), |
1034 | USE_SELINUX(PSSCAN_CONTEXT = 1 << 17,) | 1035 | USE_SELINUX(PSSCAN_CONTEXT = 1 << 17,) |
1036 | PSSCAN_START_TIME = 1 << 18, | ||
1035 | /* These are all retrieved from proc/NN/stat in one go: */ | 1037 | /* These are all retrieved from proc/NN/stat in one go: */ |
1036 | PSSCAN_STAT = PSSCAN_PPID | PSSCAN_PGID | PSSCAN_SID | 1038 | PSSCAN_STAT = PSSCAN_PPID | PSSCAN_PGID | PSSCAN_SID |
1037 | | PSSCAN_COMM | PSSCAN_STATE | 1039 | | PSSCAN_COMM | PSSCAN_STATE |
1038 | | PSSCAN_VSZ | PSSCAN_RSS | 1040 | | PSSCAN_VSZ | PSSCAN_RSS |
1039 | | PSSCAN_STIME | PSSCAN_UTIME | 1041 | | PSSCAN_STIME | PSSCAN_UTIME | PSSCAN_START_TIME |
1040 | | PSSCAN_TTY, | 1042 | | PSSCAN_TTY, |
1041 | }; | 1043 | }; |
1042 | procps_status_t* alloc_procps_scan(int flags); | 1044 | procps_status_t* alloc_procps_scan(int flags); |
diff --git a/libbb/procps.c b/libbb/procps.c index 6bc16d166..015ad80ef 100644 --- a/libbb/procps.c +++ b/libbb/procps.c | |||
@@ -243,7 +243,8 @@ procps_status_t *procps_scan(procps_status_t* sp, int flags) | |||
243 | "%lu %lu " /* utime, stime */ | 243 | "%lu %lu " /* utime, stime */ |
244 | "%*s %*s %*s " /* cutime, cstime, priority */ | 244 | "%*s %*s %*s " /* cutime, cstime, priority */ |
245 | "%ld " /* nice */ | 245 | "%ld " /* nice */ |
246 | "%*s %*s %*s " /* timeout, it_real_value, start_time */ | 246 | "%*s %*s " /* timeout, it_real_value */ |
247 | "%lu " /* start_time */ | ||
247 | "%lu " /* vsize */ | 248 | "%lu " /* vsize */ |
248 | "%lu " /* rss */ | 249 | "%lu " /* rss */ |
249 | /* "%lu %lu %lu %lu %lu %lu " rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ | 250 | /* "%lu %lu %lu %lu %lu %lu " rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ |
@@ -254,6 +255,7 @@ procps_status_t *procps_scan(procps_status_t* sp, int flags) | |||
254 | &sp->pgid, &sp->sid, &tty, | 255 | &sp->pgid, &sp->sid, &tty, |
255 | &sp->utime, &sp->stime, | 256 | &sp->utime, &sp->stime, |
256 | &tasknice, | 257 | &tasknice, |
258 | &sp->start_time, | ||
257 | &vsz, | 259 | &vsz, |
258 | &rss); | 260 | &rss); |
259 | if (n != 10) | 261 | if (n != 10) |
@@ -280,7 +282,8 @@ procps_status_t *procps_scan(procps_status_t* sp, int flags) | |||
280 | sp->stime = fast_strtoul_10(&cp); | 282 | sp->stime = fast_strtoul_10(&cp); |
281 | cp = skip_fields(cp, 3); /* cutime, cstime, priority */ | 283 | cp = skip_fields(cp, 3); /* cutime, cstime, priority */ |
282 | tasknice = fast_strtoul_10(&cp); | 284 | tasknice = fast_strtoul_10(&cp); |
283 | cp = skip_fields(cp, 3); /* timeout, it_real_value, start_time */ | 285 | cp = skip_fields(cp, 2); /* timeout, it_real_value */ |
286 | sp->start_time = fast_strtoul_10(&cp); | ||
284 | /* vsz is in bytes and we want kb */ | 287 | /* vsz is in bytes and we want kb */ |
285 | sp->vsz = fast_strtoul_10(&cp) >> 10; | 288 | sp->vsz = fast_strtoul_10(&cp) >> 10; |
286 | /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */ | 289 | /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */ |
diff --git a/procps/Config.in b/procps/Config.in index 7e7ee7922..585893ed8 100644 --- a/procps/Config.in +++ b/procps/Config.in | |||
@@ -99,6 +99,21 @@ config FEATURE_PS_WIDE | |||
99 | If given once, 132 chars are printed and given more than | 99 | If given once, 132 chars are printed and given more than |
100 | one, the length is unlimited. | 100 | one, the length is unlimited. |
101 | 101 | ||
102 | config FEATURE_PS_TIME | ||
103 | bool "Enable time and elapsed time output" | ||
104 | default n | ||
105 | depends on PS && DESKTOP | ||
106 | help | ||
107 | Support -o time and -o etime output specifiers. | ||
108 | |||
109 | config FEATURE_PS_UNUSUAL_SYSTEMS | ||
110 | bool "Support Linux prior to 2.4.0 and non-ELF systems" | ||
111 | default n | ||
112 | depends on FEATURE_PS_TIME | ||
113 | help | ||
114 | Include support for measuring HZ on old kernels and non-ELF systems | ||
115 | (if you are on Linux 2.4.0+ and use ELF, you don't need this) | ||
116 | |||
102 | config RENICE | 117 | config RENICE |
103 | bool "renice" | 118 | bool "renice" |
104 | default n | 119 | default n |
diff --git a/procps/ps.c b/procps/ps.c index 08922ebb6..a6c35f101 100644 --- a/procps/ps.c +++ b/procps/ps.c | |||
@@ -16,6 +16,143 @@ enum { MAX_WIDTH = 2*1024 }; | |||
16 | 16 | ||
17 | #if ENABLE_DESKTOP | 17 | #if ENABLE_DESKTOP |
18 | 18 | ||
19 | #include <sys/times.h> /* for times() */ | ||
20 | //#include <sys/sysinfo.h> /* for sysinfo() */ | ||
21 | #ifndef AT_CLKTCK | ||
22 | #define AT_CLKTCK 17 | ||
23 | #endif | ||
24 | |||
25 | |||
26 | #if ENABLE_SELINUX | ||
27 | #define SELINIX_O_PREFIX "label," | ||
28 | #define DEFAULT_O_STR (SELINIX_O_PREFIX "pid,user" USE_FEATURE_PS_TIME(",time")) | ||
29 | #else | ||
30 | #define DEFAULT_O_STR ("pid,user" USE_FEATURE_PS_TIME(",time")) | ||
31 | #endif | ||
32 | |||
33 | typedef struct { | ||
34 | uint16_t width; | ||
35 | char name[6]; | ||
36 | const char *header; | ||
37 | void (*f)(char *buf, int size, const procps_status_t *ps); | ||
38 | int ps_flags; | ||
39 | } ps_out_t; | ||
40 | |||
41 | struct globals { | ||
42 | ps_out_t* out; | ||
43 | int out_cnt; | ||
44 | int print_header; | ||
45 | int need_flags; | ||
46 | char *buffer; | ||
47 | unsigned terminal_width; | ||
48 | #if ENABLE_FEATURE_PS_TIME | ||
49 | unsigned kernel_HZ; | ||
50 | unsigned long long seconds_since_boot; | ||
51 | #endif | ||
52 | char default_o[sizeof(DEFAULT_O_STR)]; | ||
53 | }; | ||
54 | #define G (*(struct globals*)&bb_common_bufsiz1) | ||
55 | #define out (G.out ) | ||
56 | #define out_cnt (G.out_cnt ) | ||
57 | #define print_header (G.print_header ) | ||
58 | #define need_flags (G.need_flags ) | ||
59 | #define buffer (G.buffer ) | ||
60 | #define terminal_width (G.terminal_width ) | ||
61 | #define kernel_HZ (G.kernel_HZ ) | ||
62 | #define seconds_since_boot (G.seconds_since_boot) | ||
63 | #define default_o (G.default_o ) | ||
64 | |||
65 | #if ENABLE_FEATURE_PS_TIME | ||
66 | /* for ELF executables, notes are pushed before environment and args */ | ||
67 | static ptrdiff_t find_elf_note(ptrdiff_t findme) | ||
68 | { | ||
69 | ptrdiff_t *ep = (ptrdiff_t *) environ; | ||
70 | |||
71 | while (*ep++); | ||
72 | while (*ep) { | ||
73 | if (ep[0] == findme) { | ||
74 | return ep[1]; | ||
75 | } | ||
76 | ep += 2; | ||
77 | } | ||
78 | return -1; | ||
79 | } | ||
80 | |||
81 | #if ENABLE_FEATURE_PS_UNUSUAL_SYSTEMS | ||
82 | static unsigned get_HZ_by_waiting(void) | ||
83 | { | ||
84 | struct timeval tv1, tv2; | ||
85 | unsigned t1, t2, r, hz; | ||
86 | unsigned cnt = cnt; /* for compiler */ | ||
87 | int diff; | ||
88 | |||
89 | r = 0; | ||
90 | |||
91 | /* Wait for times() to reach new tick */ | ||
92 | t1 = times(NULL); | ||
93 | do { | ||
94 | t2 = times(NULL); | ||
95 | } while (t2 == t1); | ||
96 | gettimeofday(&tv2, NULL); | ||
97 | |||
98 | do { | ||
99 | t1 = t2; | ||
100 | tv1.tv_usec = tv2.tv_usec; | ||
101 | |||
102 | /* Wait exactly one times() tick */ | ||
103 | do { | ||
104 | t2 = times(NULL); | ||
105 | } while (t2 == t1); | ||
106 | gettimeofday(&tv2, NULL); | ||
107 | |||
108 | /* Calculate ticks per sec, rounding up to even */ | ||
109 | diff = tv2.tv_usec - tv1.tv_usec; | ||
110 | if (diff <= 0) diff += 1000000; | ||
111 | hz = 1000000u / (unsigned)diff; | ||
112 | hz = (hz+1) & ~1; | ||
113 | |||
114 | /* Count how many same hz values we saw */ | ||
115 | if (r != hz) { | ||
116 | r = hz; | ||
117 | cnt = 0; | ||
118 | } | ||
119 | cnt++; | ||
120 | } while (cnt < 3); /* exit if saw 3 same values */ | ||
121 | |||
122 | return r; | ||
123 | } | ||
124 | #else | ||
125 | static inline unsigned get_HZ_by_waiting(void) | ||
126 | { | ||
127 | /* Better method? */ | ||
128 | return 100; | ||
129 | } | ||
130 | #endif | ||
131 | |||
132 | static unsigned get_kernel_HZ(void) | ||
133 | { | ||
134 | //char buf[64]; | ||
135 | struct sysinfo info; | ||
136 | |||
137 | if (kernel_HZ) | ||
138 | return kernel_HZ; | ||
139 | |||
140 | /* Works for ELF only, Linux 2.4.0+ */ | ||
141 | kernel_HZ = find_elf_note(AT_CLKTCK); | ||
142 | if (kernel_HZ == (unsigned)-1) | ||
143 | kernel_HZ = get_HZ_by_waiting(); | ||
144 | |||
145 | //if (open_read_close("/proc/uptime", buf, sizeof(buf) <= 0) | ||
146 | // bb_perror_msg_and_die("cannot read %s", "/proc/uptime"); | ||
147 | //buf[sizeof(buf)-1] = '\0'; | ||
148 | ///sscanf(buf, "%llu", &seconds_since_boot); | ||
149 | sysinfo(&info); | ||
150 | seconds_since_boot = info.uptime; | ||
151 | |||
152 | return kernel_HZ; | ||
153 | } | ||
154 | #endif | ||
155 | |||
19 | /* Print value to buf, max size+1 chars (including trailing '\0') */ | 156 | /* Print value to buf, max size+1 chars (including trailing '\0') */ |
20 | 157 | ||
21 | static void func_user(char *buf, int size, const procps_status_t *ps) | 158 | static void func_user(char *buf, int size, const procps_status_t *ps) |
@@ -73,6 +210,34 @@ static void func_tty(char *buf, int size, const procps_status_t *ps) | |||
73 | snprintf(buf, size+1, "%u,%u", ps->tty_major, ps->tty_minor); | 210 | snprintf(buf, size+1, "%u,%u", ps->tty_major, ps->tty_minor); |
74 | } | 211 | } |
75 | 212 | ||
213 | #if ENABLE_FEATURE_PS_TIME | ||
214 | static void func_etime(char *buf, int size, const procps_status_t *ps) | ||
215 | { | ||
216 | /* elapsed time [[dd-]hh:]mm:ss; here only mm:ss */ | ||
217 | unsigned long mm; | ||
218 | unsigned ss; | ||
219 | |||
220 | mm = ps->start_time / get_kernel_HZ(); | ||
221 | /* must be after get_kernel_HZ()! */ | ||
222 | mm = seconds_since_boot - mm; | ||
223 | ss = mm % 60; | ||
224 | mm /= 60; | ||
225 | snprintf(buf, size+1, "%3lu:%02u", mm, ss); | ||
226 | } | ||
227 | |||
228 | static void func_time(char *buf, int size, const procps_status_t *ps) | ||
229 | { | ||
230 | /* cumulative time [[dd-]hh:]mm:ss; here only mm:ss */ | ||
231 | unsigned long mm; | ||
232 | unsigned ss; | ||
233 | |||
234 | mm = (ps->utime + ps->stime) / get_kernel_HZ(); | ||
235 | ss = mm % 60; | ||
236 | mm /= 60; | ||
237 | snprintf(buf, size+1, "%3lu:%02u", mm, ss); | ||
238 | } | ||
239 | #endif | ||
240 | |||
76 | #if ENABLE_SELINUX | 241 | #if ENABLE_SELINUX |
77 | static void func_label(char *buf, int size, const procps_status_t *ps) | 242 | static void func_label(char *buf, int size, const procps_status_t *ps) |
78 | { | 243 | { |
@@ -86,29 +251,11 @@ static void func_nice(char *buf, int size, const procps_status_t *ps) | |||
86 | ps->??? | 251 | ps->??? |
87 | } | 252 | } |
88 | 253 | ||
89 | static void func_etime(char *buf, int size, const procps_status_t *ps) | ||
90 | { | ||
91 | elapled time [[dd-]hh:]mm:ss | ||
92 | } | ||
93 | |||
94 | static void func_time(char *buf, int size, const procps_status_t *ps) | ||
95 | { | ||
96 | cumulative time [[dd-]hh:]mm:ss | ||
97 | } | ||
98 | |||
99 | static void func_pcpu(char *buf, int size, const procps_status_t *ps) | 254 | static void func_pcpu(char *buf, int size, const procps_status_t *ps) |
100 | { | 255 | { |
101 | } | 256 | } |
102 | */ | 257 | */ |
103 | 258 | ||
104 | typedef struct { | ||
105 | uint16_t width; | ||
106 | char name[6]; | ||
107 | const char *header; | ||
108 | void (*f)(char *buf, int size, const procps_status_t *ps); | ||
109 | int ps_flags; | ||
110 | } ps_out_t; | ||
111 | |||
112 | static const ps_out_t out_spec[] = { | 259 | static const ps_out_t out_spec[] = { |
113 | // Mandated by POSIX: | 260 | // Mandated by POSIX: |
114 | { 8 , "user" ,"USER" ,func_user ,PSSCAN_UIDGID }, | 261 | { 8 , "user" ,"USER" ,func_user ,PSSCAN_UIDGID }, |
@@ -117,13 +264,17 @@ static const ps_out_t out_spec[] = { | |||
117 | { 5 , "pid" ,"PID" ,func_pid ,PSSCAN_PID }, | 264 | { 5 , "pid" ,"PID" ,func_pid ,PSSCAN_PID }, |
118 | { 5 , "ppid" ,"PPID" ,func_ppid ,PSSCAN_PPID }, | 265 | { 5 , "ppid" ,"PPID" ,func_ppid ,PSSCAN_PPID }, |
119 | { 5 , "pgid" ,"PGID" ,func_pgid ,PSSCAN_PGID }, | 266 | { 5 , "pgid" ,"PGID" ,func_pgid ,PSSCAN_PGID }, |
120 | // { sizeof("ELAPSED")-1, "etime" ,"ELAPSED",func_etime ,PSSCAN_ }, | 267 | #if ENABLE_FEATURE_PS_TIME |
268 | { sizeof("ELAPSED")-1, "etime" ,"ELAPSED",func_etime ,PSSCAN_START_TIME }, | ||
269 | #endif | ||
121 | // { sizeof("GROUP" )-1, "group" ,"GROUP" ,func_group ,PSSCAN_UIDGID }, | 270 | // { sizeof("GROUP" )-1, "group" ,"GROUP" ,func_group ,PSSCAN_UIDGID }, |
122 | // { sizeof("NI" )-1, "nice" ,"NI" ,func_nice ,PSSCAN_ }, | 271 | // { sizeof("NI" )-1, "nice" ,"NI" ,func_nice ,PSSCAN_ }, |
123 | // { sizeof("%CPU" )-1, "pcpu" ,"%CPU" ,func_pcpu ,PSSCAN_ }, | 272 | // { sizeof("%CPU" )-1, "pcpu" ,"%CPU" ,func_pcpu ,PSSCAN_ }, |
124 | // { sizeof("RGROUP" )-1, "rgroup","RGROUP" ,func_rgroup,PSSCAN_UIDGID }, | 273 | // { sizeof("RGROUP" )-1, "rgroup","RGROUP" ,func_rgroup,PSSCAN_UIDGID }, |
125 | // { sizeof("RUSER" )-1, "ruser" ,"RUSER" ,func_ruser ,PSSCAN_UIDGID }, | 274 | // { sizeof("RUSER" )-1, "ruser" ,"RUSER" ,func_ruser ,PSSCAN_UIDGID }, |
126 | // { sizeof("TIME" )-1, "time" ,"TIME" ,func_time ,PSSCAN_ }, | 275 | #if ENABLE_FEATURE_PS_TIME |
276 | { 6 , "time" ,"TIME" ,func_time ,PSSCAN_STIME | PSSCAN_UTIME }, | ||
277 | #endif | ||
127 | { 6 , "tty" ,"TT" ,func_tty ,PSSCAN_TTY }, | 278 | { 6 , "tty" ,"TT" ,func_tty ,PSSCAN_TTY }, |
128 | { 4 , "vsz" ,"VSZ" ,func_vsz ,PSSCAN_VSZ }, | 279 | { 4 , "vsz" ,"VSZ" ,func_vsz ,PSSCAN_VSZ }, |
129 | // Not mandated by POSIX, but useful: | 280 | // Not mandated by POSIX, but useful: |
@@ -133,31 +284,6 @@ static const ps_out_t out_spec[] = { | |||
133 | #endif | 284 | #endif |
134 | }; | 285 | }; |
135 | 286 | ||
136 | #if ENABLE_SELINUX | ||
137 | #define SELINIX_O_PREFIX "label," | ||
138 | #define DEFAULT_O_STR SELINIX_O_PREFIX "pid,user" /* TODO: ,vsz,stat */ ",args" | ||
139 | #else | ||
140 | #define DEFAULT_O_STR "pid,user" /* TODO: ,vsz,stat */ ",args" | ||
141 | #endif | ||
142 | |||
143 | struct globals { | ||
144 | ps_out_t* out; | ||
145 | int out_cnt; | ||
146 | int print_header; | ||
147 | int need_flags; | ||
148 | char *buffer; | ||
149 | unsigned terminal_width; | ||
150 | char default_o[sizeof(DEFAULT_O_STR)]; | ||
151 | }; | ||
152 | #define G (*(struct globals*)&bb_common_bufsiz1) | ||
153 | #define out (G.out ) | ||
154 | #define out_cnt (G.out_cnt ) | ||
155 | #define print_header (G.print_header ) | ||
156 | #define need_flags (G.need_flags ) | ||
157 | #define buffer (G.buffer ) | ||
158 | #define terminal_width (G.terminal_width) | ||
159 | #define default_o (G.default_o ) | ||
160 | |||
161 | static ps_out_t* new_out_t(void) | 287 | static ps_out_t* new_out_t(void) |
162 | { | 288 | { |
163 | int i = out_cnt++; | 289 | int i = out_cnt++; |