Annotation of /trunk/mkinitrd-magellan/busybox/procps/ps.c
Parent Directory | Revision Log
Revision 1520 -
(hide annotations)
(download)
Wed Sep 7 18:39:43 2011 UTC (12 years, 8 months ago) by niro
File MIME type: text/plain
File size: 16153 byte(s)
Wed Sep 7 18:39:43 2011 UTC (12 years, 8 months ago) by niro
File MIME type: text/plain
File size: 16153 byte(s)
-fixed build against linux-3.0
1 | niro | 532 | /* vi: set sw=4 ts=4: */ |
2 | /* | ||
3 | * Mini ps implementation(s) for busybox | ||
4 | * | ||
5 | * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> | ||
6 | niro | 816 | * Fix for SELinux Support:(c)2007 Hiroshi Shinji <shiroshi@my.email.ne.jp> |
7 | * (c)2007 Yuichi Nakamura <ynakam@hitachisoft.jp> | ||
8 | niro | 532 | * |
9 | * Licensed under the GPL version 2, see the file LICENSE in this tarball. | ||
10 | */ | ||
11 | |||
12 | niro | 816 | #include "libbb.h" |
13 | niro | 532 | |
14 | niro | 816 | /* Absolute maximum on output line length */ |
15 | enum { MAX_WIDTH = 2*1024 }; | ||
16 | |||
17 | niro | 532 | #if ENABLE_DESKTOP |
18 | |||
19 | niro | 1520 | #include <sys/sysinfo.h> |
20 | niro | 816 | #include <sys/times.h> /* for times() */ |
21 | #ifndef AT_CLKTCK | ||
22 | #define AT_CLKTCK 17 | ||
23 | #endif | ||
24 | |||
25 | |||
26 | #if ENABLE_SELINUX | ||
27 | #define SELINUX_O_PREFIX "label," | ||
28 | niro | 984 | #define DEFAULT_O_STR (SELINUX_O_PREFIX "pid,user" IF_FEATURE_PS_TIME(",time") ",args") |
29 | niro | 816 | #else |
30 | niro | 984 | #define DEFAULT_O_STR ("pid,user" IF_FEATURE_PS_TIME(",time") ",args") |
31 | niro | 816 | #endif |
32 | |||
33 | typedef struct { | ||
34 | uint16_t width; | ||
35 | niro | 984 | char name6[6]; |
36 | niro | 816 | 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 | niro | 1123 | } FIX_ALIASING; |
54 | niro | 816 | #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 | niro | 984 | #define INIT_G() do { } while (0) |
65 | niro | 816 | |
66 | #if ENABLE_FEATURE_PS_TIME | ||
67 | /* for ELF executables, notes are pushed before environment and args */ | ||
68 | static ptrdiff_t find_elf_note(ptrdiff_t findme) | ||
69 | { | ||
70 | ptrdiff_t *ep = (ptrdiff_t *) environ; | ||
71 | |||
72 | while (*ep++); | ||
73 | while (*ep) { | ||
74 | if (ep[0] == findme) { | ||
75 | return ep[1]; | ||
76 | } | ||
77 | ep += 2; | ||
78 | } | ||
79 | return -1; | ||
80 | } | ||
81 | |||
82 | #if ENABLE_FEATURE_PS_UNUSUAL_SYSTEMS | ||
83 | static unsigned get_HZ_by_waiting(void) | ||
84 | { | ||
85 | struct timeval tv1, tv2; | ||
86 | unsigned t1, t2, r, hz; | ||
87 | unsigned cnt = cnt; /* for compiler */ | ||
88 | int diff; | ||
89 | |||
90 | r = 0; | ||
91 | |||
92 | /* Wait for times() to reach new tick */ | ||
93 | t1 = times(NULL); | ||
94 | do { | ||
95 | t2 = times(NULL); | ||
96 | } while (t2 == t1); | ||
97 | gettimeofday(&tv2, NULL); | ||
98 | |||
99 | do { | ||
100 | t1 = t2; | ||
101 | tv1.tv_usec = tv2.tv_usec; | ||
102 | |||
103 | /* Wait exactly one times() tick */ | ||
104 | do { | ||
105 | t2 = times(NULL); | ||
106 | } while (t2 == t1); | ||
107 | gettimeofday(&tv2, NULL); | ||
108 | |||
109 | /* Calculate ticks per sec, rounding up to even */ | ||
110 | diff = tv2.tv_usec - tv1.tv_usec; | ||
111 | if (diff <= 0) diff += 1000000; | ||
112 | hz = 1000000u / (unsigned)diff; | ||
113 | hz = (hz+1) & ~1; | ||
114 | |||
115 | /* Count how many same hz values we saw */ | ||
116 | if (r != hz) { | ||
117 | r = hz; | ||
118 | cnt = 0; | ||
119 | } | ||
120 | cnt++; | ||
121 | } while (cnt < 3); /* exit if saw 3 same values */ | ||
122 | |||
123 | return r; | ||
124 | } | ||
125 | #else | ||
126 | static inline unsigned get_HZ_by_waiting(void) | ||
127 | { | ||
128 | /* Better method? */ | ||
129 | return 100; | ||
130 | } | ||
131 | #endif | ||
132 | |||
133 | static unsigned get_kernel_HZ(void) | ||
134 | { | ||
135 | //char buf[64]; | ||
136 | struct sysinfo info; | ||
137 | |||
138 | if (kernel_HZ) | ||
139 | return kernel_HZ; | ||
140 | |||
141 | /* Works for ELF only, Linux 2.4.0+ */ | ||
142 | kernel_HZ = find_elf_note(AT_CLKTCK); | ||
143 | if (kernel_HZ == (unsigned)-1) | ||
144 | kernel_HZ = get_HZ_by_waiting(); | ||
145 | |||
146 | niro | 1123 | //if (open_read_close("/proc/uptime", buf, sizeof(buf)) <= 0) |
147 | niro | 984 | // bb_perror_msg_and_die("can't read %s", "/proc/uptime"); |
148 | niro | 816 | //buf[sizeof(buf)-1] = '\0'; |
149 | ///sscanf(buf, "%llu", &seconds_since_boot); | ||
150 | sysinfo(&info); | ||
151 | seconds_since_boot = info.uptime; | ||
152 | |||
153 | return kernel_HZ; | ||
154 | } | ||
155 | #endif | ||
156 | |||
157 | niro | 532 | /* Print value to buf, max size+1 chars (including trailing '\0') */ |
158 | |||
159 | niro | 816 | static void func_user(char *buf, int size, const procps_status_t *ps) |
160 | niro | 532 | { |
161 | niro | 816 | #if 1 |
162 | niro | 532 | safe_strncpy(buf, get_cached_username(ps->uid), size+1); |
163 | niro | 816 | #else |
164 | /* "compatible" version, but it's larger */ | ||
165 | /* procps 2.18 shows numeric UID if name overflows the field */ | ||
166 | /* TODO: get_cached_username() returns numeric string if | ||
167 | * user has no passwd record, we will display it | ||
168 | * left-justified here; too long usernames are shown | ||
169 | * as _right-justified_ IDs. Is it worth fixing? */ | ||
170 | const char *user = get_cached_username(ps->uid); | ||
171 | if (strlen(user) <= size) | ||
172 | safe_strncpy(buf, user, size+1); | ||
173 | else | ||
174 | sprintf(buf, "%*u", size, (unsigned)ps->uid); | ||
175 | #endif | ||
176 | niro | 532 | } |
177 | |||
178 | niro | 984 | static void func_group(char *buf, int size, const procps_status_t *ps) |
179 | { | ||
180 | safe_strncpy(buf, get_cached_groupname(ps->gid), size+1); | ||
181 | } | ||
182 | |||
183 | niro | 816 | static void func_comm(char *buf, int size, const procps_status_t *ps) |
184 | niro | 532 | { |
185 | safe_strncpy(buf, ps->comm, size+1); | ||
186 | } | ||
187 | |||
188 | niro | 816 | static void func_args(char *buf, int size, const procps_status_t *ps) |
189 | niro | 532 | { |
190 | niro | 984 | read_cmdline(buf, size+1, ps->pid, ps->comm); |
191 | niro | 532 | } |
192 | |||
193 | niro | 816 | static void func_pid(char *buf, int size, const procps_status_t *ps) |
194 | niro | 532 | { |
195 | niro | 816 | sprintf(buf, "%*u", size, ps->pid); |
196 | niro | 532 | } |
197 | |||
198 | niro | 816 | static void func_ppid(char *buf, int size, const procps_status_t *ps) |
199 | niro | 532 | { |
200 | niro | 816 | sprintf(buf, "%*u", size, ps->ppid); |
201 | niro | 532 | } |
202 | |||
203 | niro | 816 | static void func_pgid(char *buf, int size, const procps_status_t *ps) |
204 | niro | 532 | { |
205 | niro | 816 | sprintf(buf, "%*u", size, ps->pgid); |
206 | niro | 532 | } |
207 | |||
208 | niro | 816 | static void put_lu(char *buf, int size, unsigned long u) |
209 | niro | 532 | { |
210 | niro | 816 | char buf4[5]; |
211 | |||
212 | /* see http://en.wikipedia.org/wiki/Tera */ | ||
213 | smart_ulltoa4(u, buf4, " mgtpezy"); | ||
214 | buf4[4] = '\0'; | ||
215 | sprintf(buf, "%.*s", size, buf4); | ||
216 | niro | 532 | } |
217 | |||
218 | niro | 816 | static void func_vsz(char *buf, int size, const procps_status_t *ps) |
219 | niro | 532 | { |
220 | niro | 816 | put_lu(buf, size, ps->vsz); |
221 | niro | 532 | } |
222 | |||
223 | niro | 816 | static void func_rss(char *buf, int size, const procps_status_t *ps) |
224 | niro | 532 | { |
225 | niro | 816 | put_lu(buf, size, ps->rss); |
226 | niro | 532 | } |
227 | |||
228 | niro | 816 | static void func_tty(char *buf, int size, const procps_status_t *ps) |
229 | niro | 532 | { |
230 | niro | 816 | buf[0] = '?'; |
231 | buf[1] = '\0'; | ||
232 | if (ps->tty_major) /* tty field of "0" means "no tty" */ | ||
233 | snprintf(buf, size+1, "%u,%u", ps->tty_major, ps->tty_minor); | ||
234 | niro | 532 | } |
235 | |||
236 | niro | 984 | #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS |
237 | |||
238 | static void func_rgroup(char *buf, int size, const procps_status_t *ps) | ||
239 | { | ||
240 | safe_strncpy(buf, get_cached_groupname(ps->rgid), size+1); | ||
241 | } | ||
242 | |||
243 | static void func_ruser(char *buf, int size, const procps_status_t *ps) | ||
244 | { | ||
245 | safe_strncpy(buf, get_cached_username(ps->ruid), size+1); | ||
246 | } | ||
247 | |||
248 | static void func_nice(char *buf, int size, const procps_status_t *ps) | ||
249 | { | ||
250 | sprintf(buf, "%*d", size, ps->niceness); | ||
251 | } | ||
252 | |||
253 | niro | 1123 | #endif |
254 | niro | 984 | |
255 | niro | 816 | #if ENABLE_FEATURE_PS_TIME |
256 | niro | 1123 | |
257 | niro | 816 | static void func_etime(char *buf, int size, const procps_status_t *ps) |
258 | niro | 532 | { |
259 | niro | 816 | /* elapsed time [[dd-]hh:]mm:ss; here only mm:ss */ |
260 | unsigned long mm; | ||
261 | unsigned ss; | ||
262 | |||
263 | mm = ps->start_time / get_kernel_HZ(); | ||
264 | /* must be after get_kernel_HZ()! */ | ||
265 | mm = seconds_since_boot - mm; | ||
266 | ss = mm % 60; | ||
267 | mm /= 60; | ||
268 | snprintf(buf, size+1, "%3lu:%02u", mm, ss); | ||
269 | niro | 532 | } |
270 | |||
271 | niro | 816 | static void func_time(char *buf, int size, const procps_status_t *ps) |
272 | niro | 532 | { |
273 | niro | 816 | /* cumulative time [[dd-]hh:]mm:ss; here only mm:ss */ |
274 | unsigned long mm; | ||
275 | unsigned ss; | ||
276 | |||
277 | mm = (ps->utime + ps->stime) / get_kernel_HZ(); | ||
278 | ss = mm % 60; | ||
279 | mm /= 60; | ||
280 | snprintf(buf, size+1, "%3lu:%02u", mm, ss); | ||
281 | niro | 532 | } |
282 | niro | 1123 | |
283 | niro | 816 | #endif |
284 | |||
285 | #if ENABLE_SELINUX | ||
286 | static void func_label(char *buf, int size, const procps_status_t *ps) | ||
287 | { | ||
288 | safe_strncpy(buf, ps->context ? ps->context : "unknown", size+1); | ||
289 | } | ||
290 | #endif | ||
291 | |||
292 | /* | ||
293 | static void func_nice(char *buf, int size, const procps_status_t *ps) | ||
294 | { | ||
295 | ps->??? | ||
296 | } | ||
297 | |||
298 | static void func_pcpu(char *buf, int size, const procps_status_t *ps) | ||
299 | { | ||
300 | } | ||
301 | niro | 532 | */ |
302 | |||
303 | static const ps_out_t out_spec[] = { | ||
304 | // Mandated by POSIX: | ||
305 | niro | 816 | { 8 , "user" ,"USER" ,func_user ,PSSCAN_UIDGID }, |
306 | niro | 984 | { 8 , "group" ,"GROUP" ,func_group ,PSSCAN_UIDGID }, |
307 | niro | 816 | { 16 , "comm" ,"COMMAND",func_comm ,PSSCAN_COMM }, |
308 | niro | 984 | { MAX_WIDTH , "args" ,"COMMAND",func_args ,PSSCAN_COMM }, |
309 | niro | 816 | { 5 , "pid" ,"PID" ,func_pid ,PSSCAN_PID }, |
310 | { 5 , "ppid" ,"PPID" ,func_ppid ,PSSCAN_PPID }, | ||
311 | { 5 , "pgid" ,"PGID" ,func_pgid ,PSSCAN_PGID }, | ||
312 | #if ENABLE_FEATURE_PS_TIME | ||
313 | { sizeof("ELAPSED")-1, "etime" ,"ELAPSED",func_etime ,PSSCAN_START_TIME }, | ||
314 | #endif | ||
315 | niro | 984 | #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS |
316 | { 5 , "nice" ,"NI" ,func_nice ,PSSCAN_NICE }, | ||
317 | { 8 , "rgroup","RGROUP" ,func_rgroup,PSSCAN_RUIDGID }, | ||
318 | { 8 , "ruser" ,"RUSER" ,func_ruser ,PSSCAN_RUIDGID }, | ||
319 | // { 5 , "pcpu" ,"%CPU" ,func_pcpu ,PSSCAN_ }, | ||
320 | #endif | ||
321 | niro | 816 | #if ENABLE_FEATURE_PS_TIME |
322 | { 6 , "time" ,"TIME" ,func_time ,PSSCAN_STIME | PSSCAN_UTIME }, | ||
323 | #endif | ||
324 | { 6 , "tty" ,"TT" ,func_tty ,PSSCAN_TTY }, | ||
325 | { 4 , "vsz" ,"VSZ" ,func_vsz ,PSSCAN_VSZ }, | ||
326 | // Not mandated by POSIX, but useful: | ||
327 | { 4 , "rss" ,"RSS" ,func_rss ,PSSCAN_RSS }, | ||
328 | #if ENABLE_SELINUX | ||
329 | { 35 , "label" ,"LABEL" ,func_label ,PSSCAN_CONTEXT }, | ||
330 | #endif | ||
331 | niro | 532 | }; |
332 | |||
333 | static ps_out_t* new_out_t(void) | ||
334 | { | ||
335 | niro | 816 | out = xrealloc_vector(out, 2, out_cnt); |
336 | return &out[out_cnt++]; | ||
337 | niro | 532 | } |
338 | |||
339 | static const ps_out_t* find_out_spec(const char *name) | ||
340 | { | ||
341 | niro | 816 | unsigned i; |
342 | niro | 1123 | #if ENABLE_DESKTOP |
343 | char buf[ARRAY_SIZE(out_spec)*7 + 1]; | ||
344 | char *p = buf; | ||
345 | #endif | ||
346 | |||
347 | niro | 816 | for (i = 0; i < ARRAY_SIZE(out_spec); i++) { |
348 | niro | 1123 | if (strncmp(name, out_spec[i].name6, 6) == 0) |
349 | niro | 532 | return &out_spec[i]; |
350 | niro | 1123 | #if ENABLE_DESKTOP |
351 | p += sprintf(p, "%.6s,", out_spec[i].name6); | ||
352 | #endif | ||
353 | niro | 532 | } |
354 | niro | 1123 | #if ENABLE_DESKTOP |
355 | p[-1] = '\0'; | ||
356 | bb_error_msg_and_die("bad -o argument '%s', supported arguments: %s", name, buf); | ||
357 | #else | ||
358 | bb_error_msg_and_die("bad -o argument '%s'"); | ||
359 | #endif | ||
360 | niro | 532 | } |
361 | |||
362 | static void parse_o(char* opt) | ||
363 | { | ||
364 | ps_out_t* new; | ||
365 | // POSIX: "-o is blank- or comma-separated list" (FIXME) | ||
366 | char *comma, *equal; | ||
367 | while (1) { | ||
368 | comma = strchr(opt, ','); | ||
369 | equal = strchr(opt, '='); | ||
370 | if (comma && (!equal || equal > comma)) { | ||
371 | *comma = '\0'; | ||
372 | *new_out_t() = *find_out_spec(opt); | ||
373 | *comma = ','; | ||
374 | opt = comma + 1; | ||
375 | continue; | ||
376 | } | ||
377 | break; | ||
378 | } | ||
379 | niro | 816 | // opt points to last spec in comma separated list. |
380 | // This one can have =HEADER part. | ||
381 | niro | 532 | new = new_out_t(); |
382 | if (equal) | ||
383 | *equal = '\0'; | ||
384 | *new = *find_out_spec(opt); | ||
385 | if (equal) { | ||
386 | *equal = '='; | ||
387 | new->header = equal + 1; | ||
388 | // POSIX: the field widths shall be ... at least as wide as | ||
389 | // the header text (default or overridden value). | ||
390 | // If the header text is null, such as -o user=, | ||
391 | // the field width shall be at least as wide as the | ||
392 | // default header text | ||
393 | if (new->header[0]) { | ||
394 | new->width = strlen(new->header); | ||
395 | print_header = 1; | ||
396 | } | ||
397 | } else | ||
398 | print_header = 1; | ||
399 | } | ||
400 | |||
401 | niro | 984 | static void alloc_line_buffer(void) |
402 | niro | 532 | { |
403 | int i; | ||
404 | int width = 0; | ||
405 | for (i = 0; i < out_cnt; i++) { | ||
406 | niro | 816 | need_flags |= out[i].ps_flags; |
407 | niro | 532 | if (out[i].header[0]) { |
408 | print_header = 1; | ||
409 | } | ||
410 | width += out[i].width + 1; /* "FIELD " */ | ||
411 | niro | 984 | if ((int)(width - terminal_width) > 0) { |
412 | /* The rest does not fit on the screen */ | ||
413 | //out[i].width -= (width - terminal_width - 1); | ||
414 | out_cnt = i + 1; | ||
415 | break; | ||
416 | } | ||
417 | niro | 532 | } |
418 | niro | 816 | #if ENABLE_SELINUX |
419 | if (!is_selinux_enabled()) | ||
420 | need_flags &= ~PSSCAN_CONTEXT; | ||
421 | #endif | ||
422 | niro | 532 | buffer = xmalloc(width + 1); /* for trailing \0 */ |
423 | } | ||
424 | |||
425 | static void format_header(void) | ||
426 | { | ||
427 | int i; | ||
428 | ps_out_t* op; | ||
429 | niro | 816 | char *p; |
430 | |||
431 | niro | 532 | if (!print_header) |
432 | return; | ||
433 | niro | 816 | p = buffer; |
434 | niro | 532 | i = 0; |
435 | if (out_cnt) { | ||
436 | while (1) { | ||
437 | op = &out[i]; | ||
438 | if (++i == out_cnt) /* do not pad last field */ | ||
439 | break; | ||
440 | p += sprintf(p, "%-*s ", op->width, op->header); | ||
441 | } | ||
442 | strcpy(p, op->header); | ||
443 | } | ||
444 | printf("%.*s\n", terminal_width, buffer); | ||
445 | } | ||
446 | |||
447 | static void format_process(const procps_status_t *ps) | ||
448 | { | ||
449 | int i, len; | ||
450 | char *p = buffer; | ||
451 | i = 0; | ||
452 | if (out_cnt) while (1) { | ||
453 | out[i].f(p, out[i].width, ps); | ||
454 | // POSIX: Any field need not be meaningful in all | ||
455 | // implementations. In such a case a hyphen ( '-' ) | ||
456 | // should be output in place of the field value. | ||
457 | if (!p[0]) { | ||
458 | p[0] = '-'; | ||
459 | p[1] = '\0'; | ||
460 | } | ||
461 | len = strlen(p); | ||
462 | p += len; | ||
463 | len = out[i].width - len + 1; | ||
464 | if (++i == out_cnt) /* do not pad last field */ | ||
465 | break; | ||
466 | p += sprintf(p, "%*s", len, ""); | ||
467 | } | ||
468 | printf("%.*s\n", terminal_width, buffer); | ||
469 | } | ||
470 | |||
471 | niro | 816 | int ps_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
472 | int ps_main(int argc UNUSED_PARAM, char **argv) | ||
473 | niro | 532 | { |
474 | procps_status_t *p; | ||
475 | llist_t* opt_o = NULL; | ||
476 | niro | 984 | int opt; |
477 | enum { | ||
478 | OPT_Z = (1 << 0), | ||
479 | OPT_o = (1 << 1), | ||
480 | OPT_a = (1 << 2), | ||
481 | OPT_A = (1 << 3), | ||
482 | OPT_d = (1 << 4), | ||
483 | OPT_e = (1 << 5), | ||
484 | OPT_f = (1 << 6), | ||
485 | OPT_l = (1 << 7), | ||
486 | OPT_T = (1 << 8) * ENABLE_FEATURE_SHOW_THREADS, | ||
487 | }; | ||
488 | niro | 532 | |
489 | niro | 984 | INIT_G(); |
490 | |||
491 | niro | 532 | // POSIX: |
492 | // -a Write information for all processes associated with terminals | ||
493 | // Implementations may omit session leaders from this list | ||
494 | // -A Write information for all processes | ||
495 | // -d Write information for all processes, except session leaders | ||
496 | niro | 984 | // -e Write information for all processes (equivalent to -A) |
497 | niro | 532 | // -f Generate a full listing |
498 | // -l Generate a long listing | ||
499 | // -o col1,col2,col3=header | ||
500 | niro | 816 | // Select which columns to display |
501 | niro | 984 | /* We allow (and ignore) most of the above. FIXME. |
502 | * -T is picked for threads (POSIX hasn't it standardized). | ||
503 | * procps v3.2.7 supports -T and shows tids as SPID column, | ||
504 | * it also supports -L where it shows tids as LWP column. | ||
505 | */ | ||
506 | niro | 532 | opt_complementary = "o::"; |
507 | niro | 984 | opt = getopt32(argv, "Zo:aAdefl"IF_FEATURE_SHOW_THREADS("T"), &opt_o); |
508 | niro | 532 | if (opt_o) { |
509 | do { | ||
510 | niro | 816 | parse_o(llist_pop(&opt_o)); |
511 | niro | 532 | } while (opt_o); |
512 | niro | 816 | } else { |
513 | /* Below: parse_o() needs char*, NOT const char*... */ | ||
514 | #if ENABLE_SELINUX | ||
515 | niro | 984 | if (!(opt & OPT_Z) || !is_selinux_enabled()) { |
516 | niro | 816 | /* no -Z or no SELinux: do not show LABEL */ |
517 | strcpy(default_o, DEFAULT_O_STR + sizeof(SELINUX_O_PREFIX)-1); | ||
518 | } else | ||
519 | #endif | ||
520 | { | ||
521 | strcpy(default_o, DEFAULT_O_STR); | ||
522 | } | ||
523 | niro | 532 | parse_o(default_o); |
524 | niro | 816 | } |
525 | niro | 984 | #if ENABLE_FEATURE_SHOW_THREADS |
526 | if (opt & OPT_T) | ||
527 | need_flags |= PSSCAN_TASKS; | ||
528 | #endif | ||
529 | niro | 532 | |
530 | niro | 816 | /* Was INT_MAX, but some libc's go belly up with printf("%.*s") |
531 | * and such large widths */ | ||
532 | terminal_width = MAX_WIDTH; | ||
533 | niro | 532 | if (isatty(1)) { |
534 | niro | 816 | get_terminal_width_height(0, &terminal_width, NULL); |
535 | if (--terminal_width > MAX_WIDTH) | ||
536 | terminal_width = MAX_WIDTH; | ||
537 | niro | 532 | } |
538 | niro | 984 | alloc_line_buffer(); |
539 | niro | 532 | format_header(); |
540 | |||
541 | p = NULL; | ||
542 | niro | 984 | while ((p = procps_scan(p, need_flags)) != NULL) { |
543 | niro | 532 | format_process(p); |
544 | } | ||
545 | |||
546 | return EXIT_SUCCESS; | ||
547 | } | ||
548 | |||
549 | |||
550 | #else /* !ENABLE_DESKTOP */ | ||
551 | |||
552 | |||
553 | niro | 816 | int ps_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
554 | int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | ||
555 | niro | 532 | { |
556 | niro | 984 | procps_status_t *p; |
557 | int psscan_flags = PSSCAN_PID | PSSCAN_UIDGID | ||
558 | | PSSCAN_STATE | PSSCAN_VSZ | PSSCAN_COMM; | ||
559 | niro | 1123 | unsigned terminal_width IF_NOT_FEATURE_PS_WIDE(= 79); |
560 | enum { | ||
561 | OPT_Z = (1 << 0) * ENABLE_SELINUX, | ||
562 | OPT_T = (1 << ENABLE_SELINUX) * ENABLE_FEATURE_SHOW_THREADS, | ||
563 | }; | ||
564 | int opts = 0; | ||
565 | /* If we support any options, parse argv */ | ||
566 | #if ENABLE_SELINUX || ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_PS_WIDE | ||
567 | niro | 984 | # if ENABLE_FEATURE_PS_WIDE |
568 | niro | 1123 | /* -w is a bit complicated */ |
569 | niro | 984 | int w_count = 0; |
570 | niro | 532 | opt_complementary = "-:ww"; |
571 | niro | 984 | opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")"w", &w_count); |
572 | niro | 532 | /* if w is given once, GNU ps sets the width to 132, |
573 | * if w is given more than once, it is "unlimited" | ||
574 | */ | ||
575 | if (w_count) { | ||
576 | niro | 984 | terminal_width = (w_count == 1) ? 132 : MAX_WIDTH; |
577 | niro | 532 | } else { |
578 | niro | 816 | get_terminal_width_height(0, &terminal_width, NULL); |
579 | niro | 532 | /* Go one less... */ |
580 | niro | 816 | if (--terminal_width > MAX_WIDTH) |
581 | terminal_width = MAX_WIDTH; | ||
582 | niro | 532 | } |
583 | niro | 1123 | # else |
584 | /* -w is not supported, only -Z and/or -T */ | ||
585 | opt_complementary = "-"; | ||
586 | opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")); | ||
587 | niro | 984 | # endif |
588 | niro | 1123 | #endif |
589 | |||
590 | #if ENABLE_SELINUX | ||
591 | if ((opts & OPT_Z) && is_selinux_enabled()) { | ||
592 | niro | 984 | psscan_flags = PSSCAN_PID | PSSCAN_CONTEXT |
593 | | PSSCAN_STATE | PSSCAN_COMM; | ||
594 | niro | 816 | puts(" PID CONTEXT STAT COMMAND"); |
595 | niro | 1123 | } else |
596 | #endif | ||
597 | { | ||
598 | niro | 816 | puts(" PID USER VSZ STAT COMMAND"); |
599 | niro | 1123 | } |
600 | if (opts & OPT_T) { | ||
601 | psscan_flags |= PSSCAN_TASKS; | ||
602 | } | ||
603 | niro | 532 | |
604 | niro | 984 | p = NULL; |
605 | while ((p = procps_scan(p, psscan_flags)) != NULL) { | ||
606 | niro | 1123 | int len; |
607 | niro | 532 | #if ENABLE_SELINUX |
608 | niro | 984 | if (psscan_flags & PSSCAN_CONTEXT) { |
609 | niro | 816 | len = printf("%5u %-32.32s %s ", |
610 | p->pid, | ||
611 | p->context ? p->context : "unknown", | ||
612 | p->state); | ||
613 | niro | 532 | } else |
614 | #endif | ||
615 | { | ||
616 | const char *user = get_cached_username(p->uid); | ||
617 | niro | 816 | //if (p->vsz == 0) |
618 | // len = printf("%5u %-8.8s %s ", | ||
619 | // p->pid, user, p->state); | ||
620 | //else | ||
621 | { | ||
622 | char buf6[6]; | ||
623 | smart_ulltoa5(p->vsz, buf6, " mgtpezy"); | ||
624 | buf6[5] = '\0'; | ||
625 | len = printf("%5u %-8.8s %s %s ", | ||
626 | p->pid, user, buf6, p->state); | ||
627 | } | ||
628 | niro | 532 | } |
629 | |||
630 | niro | 816 | { |
631 | int sz = terminal_width - len; | ||
632 | char buf[sz + 1]; | ||
633 | read_cmdline(buf, sz, p->pid, p->comm); | ||
634 | puts(buf); | ||
635 | niro | 532 | } |
636 | } | ||
637 | if (ENABLE_FEATURE_CLEAN_UP) | ||
638 | clear_username_cache(); | ||
639 | return EXIT_SUCCESS; | ||
640 | } | ||
641 | |||
642 | niro | 1123 | #endif /* !ENABLE_DESKTOP */ |