source: MondoRescue/branches/3.3/mindi-busybox/procps/ps.c@ 3865

Last change on this file since 3865 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 21.1 KB
Line 
1/* 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 * Fix for SELinux Support:(c)2007 Hiroshi Shinji <shiroshi@my.email.ne.jp>
7 * (c)2007 Yuichi Nakamura <ynakam@hitachisoft.jp>
8 *
9 * Licensed under GPLv2, see file LICENSE in this source tree.
10 */
11
12//usage:#if ENABLE_DESKTOP
13//usage:
14//usage:#define ps_trivial_usage
15//usage: "[-o COL1,COL2=HEADER]" IF_FEATURE_SHOW_THREADS(" [-T]")
16//usage:#define ps_full_usage "\n\n"
17//usage: "Show list of processes\n"
18//usage: "\n -o COL1,COL2=HEADER Select columns for display"
19//usage: IF_FEATURE_SHOW_THREADS(
20//usage: "\n -T Show threads"
21//usage: )
22//usage:
23//usage:#else /* !ENABLE_DESKTOP */
24//usage:
25//usage:#if !ENABLE_SELINUX && !ENABLE_FEATURE_PS_WIDE
26//usage:#define USAGE_PS "\nThis version of ps accepts no options"
27//usage:#else
28//usage:#define USAGE_PS ""
29//usage:#endif
30//usage:
31//usage:#define ps_trivial_usage
32//usage: ""
33//usage:#define ps_full_usage "\n\n"
34//usage: "Show list of processes\n"
35//usage: USAGE_PS
36//usage: IF_SELINUX(
37//usage: "\n -Z Show selinux context"
38//usage: )
39//usage: IF_FEATURE_PS_WIDE(
40//usage: "\n w Wide output"
41//usage: )
42//usage: IF_FEATURE_PS_LONG(
43//usage: "\n l Long output"
44//usage: )
45//usage: IF_FEATURE_SHOW_THREADS(
46//usage: "\n T Show threads"
47//usage: )
48//usage:
49//usage:#endif /* ENABLE_DESKTOP */
50//usage:
51//usage:#define ps_example_usage
52//usage: "$ ps\n"
53//usage: " PID Uid Gid State Command\n"
54//usage: " 1 root root S init\n"
55//usage: " 2 root root S [kflushd]\n"
56//usage: " 3 root root S [kupdate]\n"
57//usage: " 4 root root S [kpiod]\n"
58//usage: " 5 root root S [kswapd]\n"
59//usage: " 742 andersen andersen S [bash]\n"
60//usage: " 743 andersen andersen S -bash\n"
61//usage: " 745 root root S [getty]\n"
62//usage: " 2990 andersen andersen R ps\n"
63
64#include "libbb.h"
65#include "common_bufsiz.h"
66#ifdef __linux__
67# include <sys/sysinfo.h>
68#endif
69
70/* Absolute maximum on output line length */
71enum { MAX_WIDTH = 2*1024 };
72
73#if ENABLE_FEATURE_PS_TIME || ENABLE_FEATURE_PS_LONG
74static unsigned long get_uptime(void)
75{
76#ifdef __linux__
77 struct sysinfo info;
78 if (sysinfo(&info) < 0)
79 return 0;
80 return info.uptime;
81#elif 1
82 unsigned long uptime;
83 char buf[sizeof(uptime)*3 + 2];
84 /* /proc/uptime is "UPTIME_SEC.NN IDLE_SEC.NN\n"
85 * (where IDLE is cumulative over all CPUs)
86 */
87 if (open_read_close("/proc/uptime", buf, sizeof(buf)) <= 0)
88 bb_perror_msg_and_die("can't read '%s'", "/proc/uptime");
89 buf[sizeof(buf)-1] = '\0';
90 sscanf(buf, "%lu", &uptime);
91 return uptime;
92#else
93 struct timespec ts;
94 if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0)
95 return 0;
96 return ts.tv_sec;
97#endif
98}
99#endif
100
101#if ENABLE_DESKTOP
102
103#include <sys/times.h> /* for times() */
104#ifndef AT_CLKTCK
105# define AT_CLKTCK 17
106#endif
107
108/* TODO:
109 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html
110 * specifies (for XSI-conformant systems) following default columns
111 * (l and f mark columns shown with -l and -f respectively):
112 * F l Flags (octal and additive) associated with the process (??)
113 * S l The state of the process
114 * UID f,l The user ID; the login name is printed with -f
115 * PID The process ID
116 * PPID f,l The parent process
117 * C f,l Processor utilization
118 * PRI l The priority of the process; higher numbers mean lower priority
119 * NI l Nice value
120 * ADDR l The address of the process
121 * SZ l The size in blocks of the core image of the process
122 * WCHAN l The event for which the process is waiting or sleeping
123 * STIME f Starting time of the process
124 * TTY The controlling terminal for the process
125 * TIME The cumulative execution time for the process
126 * CMD The command name; the full command line is shown with -f
127 */
128typedef struct {
129 uint16_t width;
130 char name6[6];
131 const char *header;
132 void (*f)(char *buf, int size, const procps_status_t *ps);
133 int ps_flags;
134} ps_out_t;
135
136struct globals {
137 ps_out_t* out;
138 int out_cnt;
139 int print_header;
140 int need_flags;
141 char *buffer;
142 unsigned terminal_width;
143#if ENABLE_FEATURE_PS_TIME
144 unsigned kernel_HZ;
145 unsigned long seconds_since_boot;
146#endif
147} FIX_ALIASING;
148#define G (*(struct globals*)bb_common_bufsiz1)
149#define out (G.out )
150#define out_cnt (G.out_cnt )
151#define print_header (G.print_header )
152#define need_flags (G.need_flags )
153#define buffer (G.buffer )
154#define terminal_width (G.terminal_width )
155#define kernel_HZ (G.kernel_HZ )
156#define INIT_G() do { setup_common_bufsiz(); } while (0)
157
158#if ENABLE_FEATURE_PS_TIME
159/* for ELF executables, notes are pushed before environment and args */
160static uintptr_t find_elf_note(uintptr_t findme)
161{
162 uintptr_t *ep = (uintptr_t *) environ;
163
164 while (*ep++)
165 continue;
166 while (*ep) {
167 if (ep[0] == findme) {
168 return ep[1];
169 }
170 ep += 2;
171 }
172 return -1;
173}
174
175#if ENABLE_FEATURE_PS_UNUSUAL_SYSTEMS
176static unsigned get_HZ_by_waiting(void)
177{
178 struct timeval tv1, tv2;
179 unsigned t1, t2, r, hz;
180 unsigned cnt = cnt; /* for compiler */
181 int diff;
182
183 r = 0;
184
185 /* Wait for times() to reach new tick */
186 t1 = times(NULL);
187 do {
188 t2 = times(NULL);
189 } while (t2 == t1);
190 gettimeofday(&tv2, NULL);
191
192 do {
193 t1 = t2;
194 tv1.tv_usec = tv2.tv_usec;
195
196 /* Wait exactly one times() tick */
197 do {
198 t2 = times(NULL);
199 } while (t2 == t1);
200 gettimeofday(&tv2, NULL);
201
202 /* Calculate ticks per sec, rounding up to even */
203 diff = tv2.tv_usec - tv1.tv_usec;
204 if (diff <= 0) diff += 1000000;
205 hz = 1000000u / (unsigned)diff;
206 hz = (hz+1) & ~1;
207
208 /* Count how many same hz values we saw */
209 if (r != hz) {
210 r = hz;
211 cnt = 0;
212 }
213 cnt++;
214 } while (cnt < 3); /* exit if saw 3 same values */
215
216 return r;
217}
218#else
219static inline unsigned get_HZ_by_waiting(void)
220{
221 /* Better method? */
222 return 100;
223}
224#endif
225
226static unsigned get_kernel_HZ(void)
227{
228 if (kernel_HZ)
229 return kernel_HZ;
230
231 /* Works for ELF only, Linux 2.4.0+ */
232 kernel_HZ = find_elf_note(AT_CLKTCK);
233 if (kernel_HZ == (unsigned)-1)
234 kernel_HZ = get_HZ_by_waiting();
235
236 G.seconds_since_boot = get_uptime();
237
238 return kernel_HZ;
239}
240#endif
241
242/* Print value to buf, max size+1 chars (including trailing '\0') */
243
244static void func_user(char *buf, int size, const procps_status_t *ps)
245{
246#if 1
247 safe_strncpy(buf, get_cached_username(ps->uid), size+1);
248#else
249 /* "compatible" version, but it's larger */
250 /* procps 2.18 shows numeric UID if name overflows the field */
251 /* TODO: get_cached_username() returns numeric string if
252 * user has no passwd record, we will display it
253 * left-justified here; too long usernames are shown
254 * as _right-justified_ IDs. Is it worth fixing? */
255 const char *user = get_cached_username(ps->uid);
256 if (strlen(user) <= size)
257 safe_strncpy(buf, user, size+1);
258 else
259 sprintf(buf, "%*u", size, (unsigned)ps->uid);
260#endif
261}
262
263static void func_group(char *buf, int size, const procps_status_t *ps)
264{
265 safe_strncpy(buf, get_cached_groupname(ps->gid), size+1);
266}
267
268static void func_comm(char *buf, int size, const procps_status_t *ps)
269{
270 safe_strncpy(buf, ps->comm, size+1);
271}
272
273static void func_state(char *buf, int size, const procps_status_t *ps)
274{
275 safe_strncpy(buf, ps->state, size+1);
276}
277
278static void func_args(char *buf, int size, const procps_status_t *ps)
279{
280 read_cmdline(buf, size+1, ps->pid, ps->comm);
281}
282
283static void func_pid(char *buf, int size, const procps_status_t *ps)
284{
285 sprintf(buf, "%*u", size, ps->pid);
286}
287
288static void func_ppid(char *buf, int size, const procps_status_t *ps)
289{
290 sprintf(buf, "%*u", size, ps->ppid);
291}
292
293static void func_pgid(char *buf, int size, const procps_status_t *ps)
294{
295 sprintf(buf, "%*u", size, ps->pgid);
296}
297
298static void put_lu(char *buf, int size, unsigned long u)
299{
300 char buf4[5];
301
302 /* see http://en.wikipedia.org/wiki/Tera */
303 smart_ulltoa4(u, buf4, " mgtpezy")[0] = '\0';
304 sprintf(buf, "%.*s", size, buf4);
305}
306
307static void func_vsz(char *buf, int size, const procps_status_t *ps)
308{
309 put_lu(buf, size, ps->vsz);
310}
311
312static void func_rss(char *buf, int size, const procps_status_t *ps)
313{
314 put_lu(buf, size, ps->rss);
315}
316
317static void func_tty(char *buf, int size, const procps_status_t *ps)
318{
319 buf[0] = '?';
320 buf[1] = '\0';
321 if (ps->tty_major) /* tty field of "0" means "no tty" */
322 snprintf(buf, size+1, "%u,%u", ps->tty_major, ps->tty_minor);
323}
324
325#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS
326
327static void func_rgroup(char *buf, int size, const procps_status_t *ps)
328{
329 safe_strncpy(buf, get_cached_groupname(ps->rgid), size+1);
330}
331
332static void func_ruser(char *buf, int size, const procps_status_t *ps)
333{
334 safe_strncpy(buf, get_cached_username(ps->ruid), size+1);
335}
336
337static void func_nice(char *buf, int size, const procps_status_t *ps)
338{
339 sprintf(buf, "%*d", size, ps->niceness);
340}
341
342#endif
343
344#if ENABLE_FEATURE_PS_TIME
345
346static void func_etime(char *buf, int size, const procps_status_t *ps)
347{
348 /* elapsed time [[dd-]hh:]mm:ss; here only mm:ss */
349 unsigned long mm;
350 unsigned ss;
351
352 mm = ps->start_time / get_kernel_HZ();
353 /* must be after get_kernel_HZ()! */
354 mm = G.seconds_since_boot - mm;
355 ss = mm % 60;
356 mm /= 60;
357 snprintf(buf, size+1, "%3lu:%02u", mm, ss);
358}
359
360static void func_time(char *buf, int size, const procps_status_t *ps)
361{
362 /* cumulative time [[dd-]hh:]mm:ss; here only mm:ss */
363 unsigned long mm;
364 unsigned ss;
365
366 mm = (ps->utime + ps->stime) / get_kernel_HZ();
367 ss = mm % 60;
368 mm /= 60;
369 snprintf(buf, size+1, "%3lu:%02u", mm, ss);
370}
371
372#endif
373
374#if ENABLE_SELINUX
375static void func_label(char *buf, int size, const procps_status_t *ps)
376{
377 safe_strncpy(buf, ps->context ? ps->context : "unknown", size+1);
378}
379#endif
380
381/*
382static void func_nice(char *buf, int size, const procps_status_t *ps)
383{
384 ps->???
385}
386
387static void func_pcpu(char *buf, int size, const procps_status_t *ps)
388{
389}
390*/
391
392static const ps_out_t out_spec[] = {
393/* Mandated by http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html: */
394 { 8 , "user" ,"USER" ,func_user ,PSSCAN_UIDGID },
395 { 8 , "group" ,"GROUP" ,func_group ,PSSCAN_UIDGID },
396 { 16 , "comm" ,"COMMAND",func_comm ,PSSCAN_COMM },
397 { MAX_WIDTH , "args" ,"COMMAND",func_args ,PSSCAN_COMM },
398 { 5 , "pid" ,"PID" ,func_pid ,PSSCAN_PID },
399 { 5 , "ppid" ,"PPID" ,func_ppid ,PSSCAN_PPID },
400 { 5 , "pgid" ,"PGID" ,func_pgid ,PSSCAN_PGID },
401#if ENABLE_FEATURE_PS_TIME
402 { sizeof("ELAPSED")-1, "etime" ,"ELAPSED",func_etime ,PSSCAN_START_TIME },
403#endif
404#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS
405 { 5 , "nice" ,"NI" ,func_nice ,PSSCAN_NICE },
406 { 8 , "rgroup","RGROUP" ,func_rgroup,PSSCAN_RUIDGID },
407 { 8 , "ruser" ,"RUSER" ,func_ruser ,PSSCAN_RUIDGID },
408// { 5 , "pcpu" ,"%CPU" ,func_pcpu ,PSSCAN_ },
409#endif
410#if ENABLE_FEATURE_PS_TIME
411 { 6 , "time" ,"TIME" ,func_time ,PSSCAN_STIME | PSSCAN_UTIME },
412#endif
413 { 6 , "tty" ,"TT" ,func_tty ,PSSCAN_TTY },
414 { 4 , "vsz" ,"VSZ" ,func_vsz ,PSSCAN_VSZ },
415/* Not mandated, but useful: */
416 { 4 , "stat" ,"STAT" ,func_state ,PSSCAN_STATE },
417 { 4 , "rss" ,"RSS" ,func_rss ,PSSCAN_RSS },
418#if ENABLE_SELINUX
419 { 35 , "label" ,"LABEL" ,func_label ,PSSCAN_CONTEXT },
420#endif
421};
422
423static ps_out_t* new_out_t(void)
424{
425 out = xrealloc_vector(out, 2, out_cnt);
426 return &out[out_cnt++];
427}
428
429static const ps_out_t* find_out_spec(const char *name)
430{
431 unsigned i;
432 char buf[ARRAY_SIZE(out_spec)*7 + 1];
433 char *p = buf;
434
435 for (i = 0; i < ARRAY_SIZE(out_spec); i++) {
436 if (strncmp(name, out_spec[i].name6, 6) == 0)
437 return &out_spec[i];
438 p += sprintf(p, "%.6s,", out_spec[i].name6);
439 }
440 p[-1] = '\0';
441 bb_error_msg_and_die("bad -o argument '%s', supported arguments: %s", name, buf);
442}
443
444static void parse_o(char* opt)
445{
446 ps_out_t* new;
447 // POSIX: "-o is blank- or comma-separated list" (FIXME)
448 char *comma, *equal;
449 while (1) {
450 comma = strchr(opt, ',');
451 equal = strchr(opt, '=');
452 if (comma && (!equal || equal > comma)) {
453 *comma = '\0';
454 *new_out_t() = *find_out_spec(opt);
455 *comma = ',';
456 opt = comma + 1;
457 continue;
458 }
459 break;
460 }
461 // opt points to last spec in comma separated list.
462 // This one can have =HEADER part.
463 new = new_out_t();
464 if (equal)
465 *equal = '\0';
466 *new = *find_out_spec(opt);
467 if (equal) {
468 *equal = '=';
469 new->header = equal + 1;
470 // POSIX: the field widths shall be ... at least as wide as
471 // the header text (default or overridden value).
472 // If the header text is null, such as -o user=,
473 // the field width shall be at least as wide as the
474 // default header text
475 if (new->header[0]) {
476 new->width = strlen(new->header);
477 print_header = 1;
478 }
479 } else
480 print_header = 1;
481}
482
483static void alloc_line_buffer(void)
484{
485 int i;
486 int width = 0;
487 for (i = 0; i < out_cnt; i++) {
488 need_flags |= out[i].ps_flags;
489 if (out[i].header[0]) {
490 print_header = 1;
491 }
492 width += out[i].width + 1; /* "FIELD " */
493 if ((int)(width - terminal_width) > 0) {
494 /* The rest does not fit on the screen */
495 //out[i].width -= (width - terminal_width - 1);
496 out_cnt = i + 1;
497 break;
498 }
499 }
500#if ENABLE_SELINUX
501 if (!is_selinux_enabled())
502 need_flags &= ~PSSCAN_CONTEXT;
503#endif
504 buffer = xmalloc(width + 1); /* for trailing \0 */
505}
506
507static void format_header(void)
508{
509 int i;
510 ps_out_t* op;
511 char *p;
512
513 if (!print_header)
514 return;
515 p = buffer;
516 i = 0;
517 if (out_cnt) {
518 while (1) {
519 op = &out[i];
520 if (++i == out_cnt) /* do not pad last field */
521 break;
522 p += sprintf(p, "%-*s ", op->width, op->header);
523 }
524 strcpy(p, op->header);
525 }
526 printf("%.*s\n", terminal_width, buffer);
527}
528
529static void format_process(const procps_status_t *ps)
530{
531 int i, len;
532 char *p = buffer;
533 i = 0;
534 if (out_cnt) while (1) {
535 out[i].f(p, out[i].width, ps);
536 // POSIX: Any field need not be meaningful in all
537 // implementations. In such a case a hyphen ( '-' )
538 // should be output in place of the field value.
539 if (!p[0]) {
540 p[0] = '-';
541 p[1] = '\0';
542 }
543 len = strlen(p);
544 p += len;
545 len = out[i].width - len + 1;
546 if (++i == out_cnt) /* do not pad last field */
547 break;
548 p += sprintf(p, "%*s", len, "");
549 }
550 printf("%.*s\n", terminal_width, buffer);
551}
552
553#if ENABLE_SELINUX
554# define SELINUX_O_PREFIX "label,"
555# define DEFAULT_O_STR (SELINUX_O_PREFIX "pid,user" IF_FEATURE_PS_TIME(",time") ",args")
556#else
557# define DEFAULT_O_STR ("pid,user" IF_FEATURE_PS_TIME(",time") ",args")
558#endif
559
560int ps_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
561int ps_main(int argc UNUSED_PARAM, char **argv)
562{
563 procps_status_t *p;
564 llist_t* opt_o = NULL;
565 char default_o[sizeof(DEFAULT_O_STR)];
566 int opt;
567 enum {
568 OPT_Z = (1 << 0),
569 OPT_o = (1 << 1),
570 OPT_a = (1 << 2),
571 OPT_A = (1 << 3),
572 OPT_d = (1 << 4),
573 OPT_e = (1 << 5),
574 OPT_f = (1 << 6),
575 OPT_l = (1 << 7),
576 OPT_T = (1 << 8) * ENABLE_FEATURE_SHOW_THREADS,
577 };
578
579 INIT_G();
580
581 // POSIX:
582 // -a Write information for all processes associated with terminals
583 // Implementations may omit session leaders from this list
584 // -A Write information for all processes
585 // -d Write information for all processes, except session leaders
586 // -e Write information for all processes (equivalent to -A)
587 // -f Generate a full listing
588 // -l Generate a long listing
589 // -o col1,col2,col3=header
590 // Select which columns to display
591 /* We allow (and ignore) most of the above. FIXME.
592 * -T is picked for threads (POSIX hasn't standardized it).
593 * procps v3.2.7 supports -T and shows tids as SPID column,
594 * it also supports -L where it shows tids as LWP column.
595 */
596 opt_complementary = "o::";
597 opt = getopt32(argv, "Zo:aAdefl"IF_FEATURE_SHOW_THREADS("T"), &opt_o);
598 if (opt_o) {
599 do {
600 parse_o(llist_pop(&opt_o));
601 } while (opt_o);
602 } else {
603 /* Below: parse_o() needs char*, NOT const char*,
604 * can't pass it constant string. Need to make a copy first.
605 */
606#if ENABLE_SELINUX
607 if (!(opt & OPT_Z) || !is_selinux_enabled()) {
608 /* no -Z or no SELinux: do not show LABEL */
609 strcpy(default_o, DEFAULT_O_STR + sizeof(SELINUX_O_PREFIX)-1);
610 } else
611#endif
612 {
613 strcpy(default_o, DEFAULT_O_STR);
614 }
615 parse_o(default_o);
616 }
617#if ENABLE_FEATURE_SHOW_THREADS
618 if (opt & OPT_T)
619 need_flags |= PSSCAN_TASKS;
620#endif
621
622 /* Was INT_MAX, but some libc's go belly up with printf("%.*s")
623 * and such large widths */
624 terminal_width = MAX_WIDTH;
625 if (isatty(1)) {
626 terminal_width = get_terminal_width(0);
627 if (--terminal_width > MAX_WIDTH)
628 terminal_width = MAX_WIDTH;
629 }
630 alloc_line_buffer();
631 format_header();
632
633 p = NULL;
634 while ((p = procps_scan(p, need_flags)) != NULL) {
635 format_process(p);
636 }
637
638 return EXIT_SUCCESS;
639}
640
641
642#else /* !ENABLE_DESKTOP */
643
644
645int ps_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
646int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
647{
648 procps_status_t *p;
649 int psscan_flags = PSSCAN_PID | PSSCAN_UIDGID
650 | PSSCAN_STATE | PSSCAN_VSZ | PSSCAN_COMM;
651 unsigned terminal_width IF_NOT_FEATURE_PS_WIDE(= 79);
652 enum {
653 OPT_Z = (1 << 0) * ENABLE_SELINUX,
654 OPT_T = (1 << ENABLE_SELINUX) * ENABLE_FEATURE_SHOW_THREADS,
655 OPT_l = (1 << ENABLE_SELINUX) * (1 << ENABLE_FEATURE_SHOW_THREADS) * ENABLE_FEATURE_PS_LONG,
656 };
657#if ENABLE_FEATURE_PS_LONG
658 time_t now = now; /* for compiler */
659 unsigned long uptime = uptime;
660#endif
661 /* If we support any options, parse argv */
662#if ENABLE_SELINUX || ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_PS_WIDE || ENABLE_FEATURE_PS_LONG
663 int opts = 0;
664# if ENABLE_FEATURE_PS_WIDE
665 /* -w is a bit complicated */
666 int w_count = 0;
667 opt_complementary = "-:ww";
668 opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l")
669 "w", &w_count);
670 /* if w is given once, GNU ps sets the width to 132,
671 * if w is given more than once, it is "unlimited"
672 */
673 if (w_count) {
674 terminal_width = (w_count == 1) ? 132 : MAX_WIDTH;
675 } else {
676 terminal_width = get_terminal_width(0);
677 /* Go one less... */
678 if (--terminal_width > MAX_WIDTH)
679 terminal_width = MAX_WIDTH;
680 }
681# else
682 /* -w is not supported, only -Z and/or -T */
683 opt_complementary = "-";
684 opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l"));
685# endif
686
687# if ENABLE_SELINUX
688 if ((opts & OPT_Z) && is_selinux_enabled()) {
689 psscan_flags = PSSCAN_PID | PSSCAN_CONTEXT
690 | PSSCAN_STATE | PSSCAN_COMM;
691 puts(" PID CONTEXT STAT COMMAND");
692 } else
693# endif
694 if (opts & OPT_l) {
695 psscan_flags = PSSCAN_STATE | PSSCAN_UIDGID | PSSCAN_PID | PSSCAN_PPID
696 | PSSCAN_TTY | PSSCAN_STIME | PSSCAN_UTIME | PSSCAN_COMM
697 | PSSCAN_VSZ | PSSCAN_RSS;
698/* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html
699 * mandates for -l:
700 * -F Flags (?)
701 * S State
702 * UID,PID,PPID
703 * -C CPU usage
704 * -PRI The priority of the process; higher numbers mean lower priority
705 * -NI Nice value
706 * -ADDR The address of the process (?)
707 * SZ The size in blocks of the core image
708 * -WCHAN The event for which the process is waiting or sleeping
709 * TTY
710 * TIME The cumulative execution time
711 * CMD
712 * We don't show fields marked with '-'.
713 * We show VSZ and RSS instead of SZ.
714 * We also show STIME (standard says that -f shows it, -l doesn't).
715 */
716 puts("S UID PID PPID VSZ RSS TTY STIME TIME CMD");
717# if ENABLE_FEATURE_PS_LONG
718 now = time(NULL);
719 uptime = get_uptime();
720# endif
721 }
722 else {
723 puts(" PID USER VSZ STAT COMMAND");
724 }
725 if (opts & OPT_T) {
726 psscan_flags |= PSSCAN_TASKS;
727 }
728#endif
729
730 p = NULL;
731 while ((p = procps_scan(p, psscan_flags)) != NULL) {
732 int len;
733#if ENABLE_SELINUX
734 if (psscan_flags & PSSCAN_CONTEXT) {
735 len = printf("%5u %-32.32s %s ",
736 p->pid,
737 p->context ? p->context : "unknown",
738 p->state);
739 } else
740#endif
741 {
742 char buf6[6];
743 smart_ulltoa5(p->vsz, buf6, " mgtpezy")[0] = '\0';
744#if ENABLE_FEATURE_PS_LONG
745 if (opts & OPT_l) {
746 char bufr[6], stime_str[6];
747 char tty[2 * sizeof(int)*3 + 2];
748 char *endp;
749 unsigned sut = (p->stime + p->utime) / 100;
750 unsigned elapsed = uptime - (p->start_time / 100);
751 time_t start = now - elapsed;
752 struct tm *tm = localtime(&start);
753
754 smart_ulltoa5(p->rss, bufr, " mgtpezy")[0] = '\0';
755
756 if (p->tty_major == 136)
757 /* It should be pts/N, not ptsN, but N > 9
758 * will overflow field width...
759 */
760 endp = stpcpy(tty, "pts");
761 else
762 if (p->tty_major == 4) {
763 endp = stpcpy(tty, "tty");
764 if (p->tty_minor >= 64) {
765 p->tty_minor -= 64;
766 *endp++ = 'S';
767 }
768 }
769 else
770 endp = tty + sprintf(tty, "%d:", p->tty_major);
771 strcpy(endp, utoa(p->tty_minor));
772
773 strftime(stime_str, 6, (elapsed >= (24 * 60 * 60)) ? "%b%d" : "%H:%M", tm);
774 stime_str[5] = '\0';
775 // S UID PID PPID VSZ RSS TTY STIME TIME CMD
776 len = printf("%c %5u %5u %5u %5s %5s %-5s %s %02u:%02u:%02u ",
777 p->state[0], p->uid, p->pid, p->ppid, buf6, bufr, tty,
778 stime_str, sut / 3600, (sut % 3600) / 60, sut % 60);
779 } else
780#endif
781 {
782 const char *user = get_cached_username(p->uid);
783 len = printf("%5u %-8.8s %s %s ",
784 p->pid, user, buf6, p->state);
785 }
786 }
787
788 {
789 int sz = terminal_width - len;
790 if (sz >= 0) {
791 char buf[sz + 1];
792 read_cmdline(buf, sz, p->pid, p->comm);
793 puts(buf);
794 }
795 }
796 }
797 if (ENABLE_FEATURE_CLEAN_UP)
798 clear_username_cache();
799 return EXIT_SUCCESS;
800}
801
802#endif /* !ENABLE_DESKTOP */
Note: See TracBrowser for help on using the repository browser.