aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-01-05 03:26:41 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-01-05 03:26:41 +0000
commit5fee2e1a79dc6fc05658821a86b0e7b5678a90dd (patch)
tree97524fe62e963beeddb96b11576d3f96a6d85d8b
parent9cd30d30a0d7340524ba8223dc9d4088eb93a1d6 (diff)
downloadbusybox-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.c2
-rw-r--r--include/libbb.h4
-rw-r--r--libbb/procps.c7
-rw-r--r--procps/Config.in15
-rw-r--r--procps/ps.c216
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};
1042procps_status_t* alloc_procps_scan(int flags); 1044procps_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
102config 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
109config 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
102config RENICE 117config 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
33typedef 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
41struct 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 */
67static 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
82static 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
125static inline unsigned get_HZ_by_waiting(void)
126{
127 /* Better method? */
128 return 100;
129}
130#endif
131
132static 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
21static void func_user(char *buf, int size, const procps_status_t *ps) 158static 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
214static 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
228static 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
77static void func_label(char *buf, int size, const procps_status_t *ps) 242static 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
89static void func_etime(char *buf, int size, const procps_status_t *ps)
90{
91 elapled time [[dd-]hh:]mm:ss
92}
93
94static void func_time(char *buf, int size, const procps_status_t *ps)
95{
96 cumulative time [[dd-]hh:]mm:ss
97}
98
99static void func_pcpu(char *buf, int size, const procps_status_t *ps) 254static void func_pcpu(char *buf, int size, const procps_status_t *ps)
100{ 255{
101} 256}
102*/ 257*/
103 258
104typedef 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
112static const ps_out_t out_spec[] = { 259static 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
143struct 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
161static ps_out_t* new_out_t(void) 287static ps_out_t* new_out_t(void)
162{ 288{
163 int i = out_cnt++; 289 int i = out_cnt++;