aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2006-11-05 00:45:47 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2006-11-05 00:45:47 +0000
commit9494919ea5116075e16daac1355265b023419cdc (patch)
treea6743775e25864bf7f1e656283752df7d988de36
parentaae0311356b4458e3a62fb19af656e00323e3bf1 (diff)
downloadbusybox-w32-9494919ea5116075e16daac1355265b023419cdc.tar.gz
busybox-w32-9494919ea5116075e16daac1355265b023419cdc.tar.bz2
busybox-w32-9494919ea5116075e16daac1355265b023419cdc.zip
ps: implement POSIX-like options, most notably -o
(activated by CONFIG_DESKTOP)
-rw-r--r--include/usage.h15
-rw-r--r--procps/ps.c275
2 files changed, 290 insertions, 0 deletions
diff --git a/include/usage.h b/include/usage.h
index 46bb9eca4..7174ad414 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -2377,6 +2377,18 @@ USE_FEATURE_MDEV_CONFIG( \
2377 "$ printf \"Val=%d\\n\" 5\n" \ 2377 "$ printf \"Val=%d\\n\" 5\n" \
2378 "Val=5\n" 2378 "Val=5\n"
2379 2379
2380
2381#if ENABLE_DESKTOP
2382
2383#define ps_trivial_usage \
2384 ""
2385#define ps_full_usage \
2386 "Report process status\n" \
2387 "\nOptions:" \
2388 "\n\t-o col1,col2=header\tSelect columns for display" \
2389
2390#else /* !ENABLE_DESKTOP */
2391
2380#if !defined CONFIG_SELINUX && !ENABLE_FEATURE_PS_WIDE 2392#if !defined CONFIG_SELINUX && !ENABLE_FEATURE_PS_WIDE
2381#define USAGE_PS "\n\tThis version of ps accepts no options." 2393#define USAGE_PS "\n\tThis version of ps accepts no options."
2382#else 2394#else
@@ -2396,6 +2408,8 @@ USE_FEATURE_MDEV_CONFIG( \
2396 USE_SELINUX("\n\t-c\tshow SE Linux context") \ 2408 USE_SELINUX("\n\t-c\tshow SE Linux context") \
2397 USAGE_PS_WIDE("\n\tw\twide output") 2409 USAGE_PS_WIDE("\n\tw\twide output")
2398 2410
2411#endif /* ENABLE_DESKTOP */
2412
2399#define ps_example_usage \ 2413#define ps_example_usage \
2400 "$ ps\n" \ 2414 "$ ps\n" \
2401 " PID Uid Gid State Command\n" \ 2415 " PID Uid Gid State Command\n" \
@@ -2409,6 +2423,7 @@ USE_FEATURE_MDEV_CONFIG( \
2409 " 745 root root S [getty]\n" \ 2423 " 745 root root S [getty]\n" \
2410 " 2990 andersen andersen R ps\n" 2424 " 2990 andersen andersen R ps\n"
2411 2425
2426
2412#define pwd_trivial_usage \ 2427#define pwd_trivial_usage \
2413 "" 2428 ""
2414#define pwd_full_usage \ 2429#define pwd_full_usage \
diff --git a/procps/ps.c b/procps/ps.c
index 2ff6e77d4..3cb86e49c 100644
--- a/procps/ps.c
+++ b/procps/ps.c
@@ -9,6 +9,279 @@
9 9
10#include "busybox.h" 10#include "busybox.h"
11 11
12#if ENABLE_DESKTOP
13
14/* Print value to buf, max size+1 chars (including trailing '\0') */
15
16void func_user(char *buf, int size, const procps_status_t *ps)
17{
18 safe_strncpy(buf, get_cached_username(ps->uid), size+1);
19}
20
21void func_comm(char *buf, int size, const procps_status_t *ps)
22{
23 safe_strncpy(buf, ps->comm, size+1);
24}
25
26void func_args(char *buf, int size, const procps_status_t *ps)
27{
28 buf[0] = '\0';
29 if (ps->cmd)
30 safe_strncpy(buf, ps->cmd, size+1);
31 else if (size >= 2)
32 snprintf(buf, size+1, "[%.*s]", size-2, ps->comm);
33}
34
35void func_pid(char *buf, int size, const procps_status_t *ps)
36{
37 snprintf(buf, size+1, "%*u", size, ps->pid);
38}
39
40void func_ppid(char *buf, int size, const procps_status_t *ps)
41{
42 snprintf(buf, size+1, "%*u", size, ps->ppid);
43}
44
45void func_pgid(char *buf, int size, const procps_status_t *ps)
46{
47 snprintf(buf, size+1, "%*u", size, ps->pgid);
48}
49
50void func_rss(char *buf, int size, const procps_status_t *ps)
51{
52 char buf5[5];
53 smart_ulltoa5( ((unsigned long long)ps->rss) << 10, buf5);
54 snprintf(buf, size+1, "%.*s", size, buf5);
55}
56
57/*
58void func_nice(char *buf, int size, const procps_status_t *ps)
59{
60 ps->???
61}
62
63void func_etime(char *buf, int size, const procps_status_t *ps)
64{
65 elapled time [[dd-]hh:]mm:ss
66}
67
68void func_time(char *buf, int size, const procps_status_t *ps)
69{
70 cumulative time [[dd-]hh:]mm:ss
71}
72
73void func_pcpu(char *buf, int size, const procps_status_t *ps)
74{
75}
76
77void func_tty(char *buf, int size, const procps_status_t *ps)
78{
79}
80*/
81
82typedef struct {
83 char name[8];
84 const char *header;
85 void (*f)(char *buf, int size, const procps_status_t *ps);
86 int ps_flags;
87 int width;
88} ps_out_t;
89
90static const ps_out_t out_spec[] = {
91// Mandated by POSIX:
92 { "user" ,"USER" ,func_user ,PSSCAN_UIDGID,8 },
93 { "comm" ,"COMMAND",func_comm ,PSSCAN_COMM ,16 },
94 { "args" ,"COMMAND",func_args ,PSSCAN_CMD|PSSCAN_COMM,256 },
95 { "pid" ,"PID" ,func_pid ,PSSCAN_PID ,5 },
96 { "ppid" ,"PPID" ,func_ppid ,PSSCAN_PPID ,5 },
97 { "pgid" ,"PGID" ,func_pgid ,PSSCAN_PGID ,5 },
98// { "etime" ,"ELAPSED",func_etime ,PSSCAN_ ,sizeof("ELAPSED")-1 },
99// { "group" ,"GROUP" ,func_group ,PSSCAN_UIDGID,sizeof("GROUP" )-1 },
100// { "nice" ,"NI" ,func_nice ,PSSCAN_ ,sizeof("NI" )-1 },
101// { "pcpu" ,"%CPU" ,func_pcpu ,PSSCAN_ ,sizeof("%CPU" )-1 },
102// { "rgroup","RGROUP" ,func_rgroup,PSSCAN_UIDGID,sizeof("RGROUP" )-1 },
103// { "ruser" ,"RUSER" ,func_ruser ,PSSCAN_UIDGID,sizeof("RUSER" )-1 },
104// { "time" ,"TIME" ,func_time ,PSSCAN_ ,sizeof("TIME" )-1 },
105// { "tty" ,"TT" ,func_tty ,PSSCAN_ ,sizeof("TT" )-1 },
106// { "vsz" ,"VSZ" ,func_vsz ,PSSCAN_VSZ ,4 },
107// Not mandated by POSIX:
108 { "rss" ,"RSS" ,func_rss ,PSSCAN_RSS ,4 },
109};
110
111#define VEC_SIZE(v) ( sizeof(v) / sizeof((v)[0]) )
112
113static ps_out_t* out;
114static int out_cnt;
115static int print_header;
116static int ps_flags;
117static char *buffer;
118static unsigned terminal_width;
119
120
121static ps_out_t* new_out_t(void)
122{
123 int i = out_cnt++;
124 out = xrealloc(out, out_cnt * sizeof(*out));
125 return &out[i];
126}
127
128static const ps_out_t* find_out_spec(const char *name)
129{
130 int i;
131 for (i = 0; i < VEC_SIZE(out_spec); i++) {
132 if (!strcmp(name, out_spec[i].name))
133 return &out_spec[i];
134 }
135 bb_error_msg_and_die("bad -o argument '%s'", name);
136}
137
138static void parse_o(char* opt)
139{
140 ps_out_t* new;
141 // POSIX: "-o is blank- or comma-separated list" (FIXME)
142 char *comma, *equal;
143 while (1) {
144 comma = strchr(opt, ',');
145 equal = strchr(opt, '=');
146 if (comma && (!equal || equal > comma)) {
147 *comma = '\0';
148 *new_out_t() = *find_out_spec(opt);
149 *comma = ',';
150 opt = comma + 1;
151 continue;
152 }
153 break;
154 }
155 new = new_out_t();
156 if (equal)
157 *equal = '\0';
158 *new = *find_out_spec(opt);
159 if (equal) {
160 *equal = '=';
161 new->header = equal + 1;
162 // POSIX: the field widths shall be ... at least as wide as
163 // the header text (default or overridden value).
164 // If the header text is null, such as -o user=,
165 // the field width shall be at least as wide as the
166 // default header text
167 if (new->header[0]) {
168 new->width = strlen(new->header);
169 print_header = 1;
170 }
171 } else
172 print_header = 1;
173}
174
175static void post_process(void)
176{
177 int i;
178 int width = 0;
179 for (i = 0; i < out_cnt; i++) {
180 ps_flags |= out[i].ps_flags;
181 if (out[i].header[0]) {
182 print_header = 1;
183 }
184 width += out[i].width + 1; /* "FIELD " */
185 }
186 buffer = xmalloc(width + 1); /* for trailing \0 */
187}
188
189static void format_header(void)
190{
191 int i;
192 ps_out_t* op;
193 char *p = buffer;
194 if (!print_header)
195 return;
196 i = 0;
197 if (out_cnt) {
198 while (1) {
199 op = &out[i];
200 if (++i == out_cnt) /* do not pad last field */
201 break;
202 p += sprintf(p, "%-*s ", op->width, op->header);
203 }
204 strcpy(p, op->header);
205 }
206 printf("%.*s\n", terminal_width, buffer);
207}
208
209static void format_process(const procps_status_t *ps)
210{
211 int i, len;
212 char *p = buffer;
213 i = 0;
214 if (out_cnt) while (1) {
215 out[i].f(p, out[i].width, ps);
216 // POSIX: Any field need not be meaningful in all
217 // implementations. In such a case a hyphen ( '-' )
218 // should be output in place of the field value.
219 if (!*p) {
220 *p++ = '-';
221 *p = '\0';
222 }
223 len = strlen(p);
224 p += len;
225 len = out[i].width - len + 1;
226 if (++i == out_cnt) /* do not pad last field */
227 break;
228 while (len--)
229 *p++ = ' ';
230 *p = '\0';
231 }
232 printf("%.*s\n", terminal_width, buffer);
233}
234
235/* Cannot be const: parse_o() will choke */
236static char default_o[] = "pid,user" /* TODO: ,vsz,stat */ ",args";
237
238int ps_main(int argc, char **argv)
239{
240 procps_status_t *p;
241 llist_t* opt_o = NULL;
242
243 // POSIX:
244 // -a Write information for all processes associated with terminals
245 // Implementations may omit session leaders from this list
246 // -A Write information for all processes
247 // -d Write information for all processes, except session leaders
248 // -e Write information for all processes (equivalent to -A.)
249 // -f Generate a full listing
250 // -l Generate a long listing
251 // -o col1,col2,col3=header
252 // Select which columns to distplay
253 /* We allow (and ignore) most of the above. FIXME */
254 opt_complementary = "o::";
255 getopt32(argc, argv, "o:aAdefl", &opt_o);
256 if (opt_o) {
257 opt_o = rev_llist(opt_o);
258 do {
259 parse_o(opt_o->data);
260 opt_o = opt_o->link;
261 } while (opt_o);
262 } else
263 parse_o(default_o);
264 post_process();
265
266 terminal_width = INT_MAX;
267 if (isatty(1)) {
268 get_terminal_width_height(1, &terminal_width, NULL);
269 terminal_width--;
270 }
271 format_header();
272
273 p = NULL;
274 while ((p = procps_scan(p, ps_flags))) {
275 format_process(p);
276 }
277
278 return EXIT_SUCCESS;
279}
280
281
282#else /* !ENABLE_DESKTOP */
283
284
12int ps_main(int argc, char **argv) 285int ps_main(int argc, char **argv)
13{ 286{
14 procps_status_t *p = NULL; 287 procps_status_t *p = NULL;
@@ -111,3 +384,5 @@ int ps_main(int argc, char **argv)
111 clear_username_cache(); 384 clear_username_cache();
112 return EXIT_SUCCESS; 385 return EXIT_SUCCESS;
113} 386}
387
388#endif