busybox/procps/ps.c

808 lines
23 KiB
C
Raw Permalink Normal View History

/* vi: set sw=4 ts=4: */
1999-10-20 13:35:35 +05:30
/*
* Mini ps implementation(s) for busybox
1999-10-20 13:35:35 +05:30
*
* Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
* Fix for SELinux Support:(c)2007 Hiroshi Shinji <shiroshi@my.email.ne.jp>
2008-02-04 03:34:19 +05:30
* (c)2007 Yuichi Nakamura <ynakam@hitachisoft.jp>
*
* Licensed under GPLv2, see file LICENSE in this source tree.
*/
//config:config PS
//config: bool "ps (11 kb)"
//config: default y
//config: help
//config: ps gives a snapshot of the current processes.
//config:
//config:config FEATURE_PS_WIDE
//config: bool "Enable wide output (-w)"
//config: default y
//config: depends on (PS || MINIPS) && !DESKTOP
//config: help
//config: Support argument 'w' for wide output.
//config: If given once, 132 chars are printed, and if given more
//config: than once, the length is unlimited.
//config:
//config:config FEATURE_PS_LONG
//config: bool "Enable long output (-l)"
//config: default y
//config: depends on (PS || MINIPS) && !DESKTOP
//config: help
//config: Support argument 'l' for long output.
//config: Adds fields PPID, RSS, START, TIME & TTY
//config:
//config:config FEATURE_PS_TIME
//config: bool "Enable -o time and -o etime specifiers"
//config: default y
//config: depends on (PS || MINIPS) && DESKTOP
//config:
//config:config FEATURE_PS_UNUSUAL_SYSTEMS
//config: bool "Support Linux prior to 2.4.0 and non-ELF systems"
//config: default n
//config: depends on FEATURE_PS_TIME
//config: help
//config: Include support for measuring HZ on old kernels and non-ELF systems
//config: (if you are on Linux 2.4.0+ and use ELF, you don't need this)
//config:
//config:config FEATURE_PS_ADDITIONAL_COLUMNS
//config: bool "Enable -o rgroup, -o ruser, -o nice specifiers"
//config: default y
//config: depends on (PS || MINIPS) && DESKTOP
// APPLET_NOEXEC:name main location suid_type help
//applet:IF_PS( APPLET_NOEXEC(ps, ps, BB_DIR_BIN, BB_SUID_DROP, ps))
//applet:IF_MINIPS(APPLET_NOEXEC(minips, ps, BB_DIR_BIN, BB_SUID_DROP, ps))
//kbuild:lib-$(CONFIG_PS) += ps.o
//kbuild:lib-$(CONFIG_MINIPS) += ps.o
//usage:#if ENABLE_DESKTOP
//usage:
//usage:#define ps_trivial_usage
//usage: "[-o COL1,COL2=HEADER]" IF_FEATURE_SHOW_THREADS(" [-T]")
//usage:#define ps_full_usage "\n\n"
//usage: "Show list of processes\n"
//usage: "\n -o COL1,COL2=HEADER Select columns for display"
//usage: IF_FEATURE_SHOW_THREADS(
//usage: "\n -T Show threads"
//usage: )
//usage:
//usage:#else /* !ENABLE_DESKTOP */
//usage:
//usage:#if !ENABLE_SELINUX && !ENABLE_FEATURE_PS_WIDE
//usage:#define USAGE_PS "\nThis version of ps accepts no options"
//usage:#else
//usage:#define USAGE_PS ""
//usage:#endif
//usage:
//usage:#define ps_trivial_usage
//usage: ""
//usage:#define ps_full_usage "\n\n"
//usage: "Show list of processes\n"
//usage: USAGE_PS
//usage: IF_SELINUX(
//usage: "\n -Z Show selinux context"
//usage: )
//usage: IF_FEATURE_PS_WIDE(
//usage: "\n w Wide output"
//usage: )
//usage: IF_FEATURE_PS_LONG(
//usage: "\n l Long output"
//usage: )
//usage: IF_FEATURE_SHOW_THREADS(
//usage: "\n T Show threads"
//usage: )
//usage:
//usage:#endif /* ENABLE_DESKTOP */
//usage:
//usage:#define ps_example_usage
//usage: "$ ps\n"
//usage: " PID Uid Gid State Command\n"
//usage: " 1 root root S init\n"
//usage: " 2 root root S [kflushd]\n"
//usage: " 3 root root S [kupdate]\n"
//usage: " 4 root root S [kpiod]\n"
//usage: " 5 root root S [kswapd]\n"
//usage: " 742 andersen andersen S [bash]\n"
//usage: " 743 andersen andersen S -bash\n"
//usage: " 745 root root S [getty]\n"
//usage: " 2990 andersen andersen R ps\n"
#include "libbb.h"
#include "common_bufsiz.h"
#ifdef __linux__
# include <sys/sysinfo.h>
#endif
/* Absolute maximum on output line length */
enum { MAX_WIDTH = 2*1024 };
#if ENABLE_FEATURE_PS_TIME || ENABLE_FEATURE_PS_LONG
static unsigned long get_uptime(void)
{
#ifdef __linux__
struct sysinfo info;
if (sysinfo(&info) < 0)
return 0;
return info.uptime;
#elif 1
unsigned long uptime;
char buf[sizeof(uptime)*3 + 2];
/* /proc/uptime is "UPTIME_SEC.NN IDLE_SEC.NN\n"
* (where IDLE is cumulative over all CPUs)
*/
if (open_read_close("/proc/uptime", buf, sizeof(buf)) <= 0)
bb_perror_msg_and_die("can't read '%s'", "/proc/uptime");
buf[sizeof(buf)-1] = '\0';
sscanf(buf, "%lu", &uptime);
return uptime;
#else
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0)
return 0;
return ts.tv_sec;
#endif
}
#endif
#if ENABLE_DESKTOP
/* TODO:
* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html
* specifies (for XSI-conformant systems) following default columns
* (l and f mark columns shown with -l and -f respectively):
* F l Flags (octal and additive) associated with the process (??)
* S l The state of the process
* UID f,l The user ID; the login name is printed with -f
* PID The process ID
* PPID f,l The parent process
* C f,l Processor utilization
* PRI l The priority of the process; higher numbers mean lower priority
* NI l Nice value
* ADDR l The address of the process
* SZ l The size in blocks of the core image of the process
* WCHAN l The event for which the process is waiting or sleeping
* STIME f Starting time of the process
* TTY The controlling terminal for the process
* TIME The cumulative execution time for the process
* CMD The command name; the full command line is shown with -f
*/
typedef struct {
uint16_t width;
char name6[6];
const char *header;
void (*f)(char *buf, int size, const procps_status_t *ps);
int ps_flags;
} ps_out_t;
struct globals {
ps_out_t* out;
int out_cnt;
int print_header;
int need_flags;
char *buffer;
unsigned terminal_width;
#if ENABLE_FEATURE_PS_TIME
# if ENABLE_FEATURE_PS_UNUSUAL_SYSTEMS || !defined(__linux__)
unsigned kernel_HZ;
# endif
unsigned long seconds_since_boot;
#endif
} FIX_ALIASING;
#define G (*(struct globals*)bb_common_bufsiz1)
#define out (G.out )
#define out_cnt (G.out_cnt )
#define print_header (G.print_header )
#define need_flags (G.need_flags )
#define buffer (G.buffer )
#define terminal_width (G.terminal_width )
#define INIT_G() do { setup_common_bufsiz(); } while (0)
#if ENABLE_FEATURE_PS_TIME
# if ENABLE_FEATURE_PS_UNUSUAL_SYSTEMS || !defined(__linux__)
# define get_kernel_HZ() (G.kernel_HZ)
# else
/* non-ancient Linux standardized on 100 for "times" freq */
# define get_kernel_HZ() ((unsigned)100)
# endif
#endif
/* Print value to buf, max size+1 chars (including trailing '\0') */
static void func_user(char *buf, int size, const procps_status_t *ps)
{
2008-02-02 22:13:51 +05:30
#if 1
safe_strncpy(buf, get_cached_username(ps->uid), size+1);
2008-02-02 22:13:51 +05:30
#else
/* "compatible" version, but it's larger */
/* procps 2.18 shows numeric UID if name overflows the field */
/* TODO: get_cached_username() returns numeric string if
* user has no passwd record, we will display it
* left-justified here; too long usernames are shown
* as _right-justified_ IDs. Is it worth fixing? */
const char *user = get_cached_username(ps->uid);
if (strlen(user) <= size)
2008-02-04 03:34:19 +05:30
safe_strncpy(buf, user, size+1);
2008-02-02 22:13:51 +05:30
else
sprintf(buf, "%*u", size, (unsigned)ps->uid);
#endif
}
static void func_group(char *buf, int size, const procps_status_t *ps)
{
safe_strncpy(buf, get_cached_groupname(ps->gid), size+1);
}
static void func_comm(char *buf, int size, const procps_status_t *ps)
{
safe_strncpy(buf, ps->comm, size+1);
}
static void func_state(char *buf, int size, const procps_status_t *ps)
{
safe_strncpy(buf, ps->state, size+1);
}
static void func_args(char *buf, int size, const procps_status_t *ps)
{
read_cmdline(buf, size+1, ps->pid, ps->comm);
}
static void func_pid(char *buf, int size, const procps_status_t *ps)
{
sprintf(buf, "%*u", size, ps->pid);
}
static void func_ppid(char *buf, int size, const procps_status_t *ps)
{
sprintf(buf, "%*u", size, ps->ppid);
}
static void func_pgid(char *buf, int size, const procps_status_t *ps)
{
sprintf(buf, "%*u", size, ps->pgid);
}
static void func_sid(char *buf, int size, const procps_status_t *ps)
{
sprintf(buf, "%*u", size, ps->sid);
}
static void put_lu(char *buf, int size, unsigned long u)
{
char buf4[5];
/* see http://en.wikipedia.org/wiki/Tera */
smart_ulltoa4(u, buf4, " mgtpezy")[0] = '\0';
sprintf(buf, "%.*s", size, buf4);
}
static void func_vsz(char *buf, int size, const procps_status_t *ps)
{
put_lu(buf, size, ps->vsz);
}
static void func_rss(char *buf, int size, const procps_status_t *ps)
{
put_lu(buf, size, ps->rss);
}
static void func_tty(char *buf, int size, const procps_status_t *ps)
{
buf[0] = '?';
buf[1] = '\0';
if (ps->tty_major) /* tty field of "0" means "no tty" */
snprintf(buf, size+1, "%u,%u", ps->tty_major, ps->tty_minor);
}
#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS
static void func_rgroup(char *buf, int size, const procps_status_t *ps)
{
safe_strncpy(buf, get_cached_groupname(ps->rgid), size+1);
}
static void func_ruser(char *buf, int size, const procps_status_t *ps)
{
safe_strncpy(buf, get_cached_username(ps->ruid), size+1);
}
static void func_nice(char *buf, int size, const procps_status_t *ps)
{
sprintf(buf, "%*d", size, ps->niceness);
}
#endif
#if ENABLE_FEATURE_PS_TIME
static void format_time(char *buf, int size, unsigned long tt)
{
unsigned ff;
/* Used to show "14453:50" if tt is large. Ugly.
* procps-ng 3.3.10 uses "[[dd-]hh:]mm:ss" format.
* TODO: switch to that?
*/
/* Formatting for 5-char TIME column.
* NB: "size" is not always 5: ELAPSED is wider (7),
* not taking advantage of that (yet?).
*/
ff = tt % 60;
tt /= 60;
if (tt < 60) {
snprintf(buf, size+1, "%2u:%02u", (unsigned)tt, ff);
return;
}
ff = tt % 60;
tt /= 60;
if (tt < 24) {
snprintf(buf, size+1, "%2uh%02u", (unsigned)tt, ff);
return;
}
ff = tt % 24;
tt /= 24;
if (tt < 100) {
snprintf(buf, size+1, "%2ud%02u", (unsigned)tt, ff);
return;
}
snprintf(buf, size+1, "%4lud", tt);
}
static void func_etime(char *buf, int size, const procps_status_t *ps)
{
/* elapsed time [[dd-]hh:]mm:ss; here only mm:ss */
unsigned long mm;
mm = ps->start_time / get_kernel_HZ();
mm = G.seconds_since_boot - mm;
format_time(buf, size, mm);
}
static void func_time(char *buf, int size, const procps_status_t *ps)
{
/* cumulative time [[dd-]hh:]mm:ss; here only mm:ss */
unsigned long mm;
mm = (ps->utime + ps->stime) / get_kernel_HZ();
format_time(buf, size, mm);
}
#endif
#if ENABLE_SELINUX
static void func_label(char *buf, int size, const procps_status_t *ps)
{
safe_strncpy(buf, ps->context ? ps->context : "unknown", size+1);
}
#endif
/*
static void func_pcpu(char *buf, int size, const procps_status_t *ps)
{
}
*/
static const ps_out_t out_spec[] ALIGN_PTR = {
/* Mandated by http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html: */
{ 8 , "user" ,"USER" ,func_user ,PSSCAN_UIDGID },
{ 8 , "group" ,"GROUP" ,func_group ,PSSCAN_UIDGID },
{ 16 , "comm" ,"COMMAND",func_comm ,PSSCAN_COMM },
{ MAX_WIDTH , "args" ,"COMMAND",func_args ,PSSCAN_COMM },
{ 5 , "pid" ,"PID" ,func_pid ,PSSCAN_PID },
{ 5 , "ppid" ,"PPID" ,func_ppid ,PSSCAN_PPID },
{ 5 , "pgid" ,"PGID" ,func_pgid ,PSSCAN_PGID },
#if ENABLE_FEATURE_PS_TIME
{ sizeof("ELAPSED")-1, "etime" ,"ELAPSED",func_etime ,PSSCAN_START_TIME },
#endif
#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS
{ 5 , "nice" ,"NI" ,func_nice ,PSSCAN_NICE },
{ 8 , "rgroup","RGROUP" ,func_rgroup,PSSCAN_RUIDGID },
{ 8 , "ruser" ,"RUSER" ,func_ruser ,PSSCAN_RUIDGID },
// { 5 , "pcpu" ,"%CPU" ,func_pcpu ,PSSCAN_ },
#endif
#if ENABLE_FEATURE_PS_TIME
{ 5 , "time" ,"TIME" ,func_time ,PSSCAN_STIME | PSSCAN_UTIME },
#endif
{ 6 , "tty" ,"TT" ,func_tty ,PSSCAN_TTY },
{ 4 , "vsz" ,"VSZ" ,func_vsz ,PSSCAN_VSZ },
/* Not mandated, but useful: */
{ 5 , "sid" ,"SID" ,func_sid ,PSSCAN_SID },
{ 4 , "stat" ,"STAT" ,func_state ,PSSCAN_STATE },
{ 4 , "rss" ,"RSS" ,func_rss ,PSSCAN_RSS },
#if ENABLE_SELINUX
{ 35 , "label" ,"LABEL" ,func_label ,PSSCAN_CONTEXT },
#endif
};
static ps_out_t* new_out_t(void)
{
out = xrealloc_vector(out, 2, out_cnt);
return &out[out_cnt++];
}
static const ps_out_t* find_out_spec(const char *name)
{
unsigned i;
char buf[ARRAY_SIZE(out_spec)*7 + 1];
char *p = buf;
for (i = 0; i < ARRAY_SIZE(out_spec); i++) {
if (strncmp(name, out_spec[i].name6, 6) == 0)
return &out_spec[i];
p += sprintf(p, "%.6s,", out_spec[i].name6);
}
p[-1] = '\0';
bb_error_msg_and_die("bad -o argument '%s', supported arguments: %s", name, buf);
}
static void parse_o(char* opt)
{
ps_out_t* new;
// POSIX: "-o is blank- or comma-separated list" (FIXME)
char *comma, *equal;
while (1) {
comma = strchr(opt, ',');
equal = strchr(opt, '=');
if (comma && (!equal || equal > comma)) {
*comma = '\0';
*new_out_t() = *find_out_spec(opt);
*comma = ',';
opt = comma + 1;
continue;
}
// opt points to last spec in comma separated list.
// This one can have =HEADER part.
new = new_out_t();
if (equal)
*equal = '\0';
*new = *find_out_spec(opt);
if (!equal)
break;
*equal++ = '=';
new->header = equal;
comma = strchr(equal, ',');
if (comma)
*comma = '\0';
// POSIX: the field widths shall be ... at least as wide as
// the header text (default or overridden value).
// If the header text is null, such as -o user=,
// the field width shall be at least as wide as the
// default header text
if (new->header[0]) {
new->width = strlen(new->header);
}
if (!comma)
break;
//*comma = ','; /* no, new->header should stay NUL-terminated */
opt = comma + 1;
}
}
static void alloc_line_buffer(void)
{
int i;
int width = 0;
for (i = 0; i < out_cnt; i++) {
need_flags |= out[i].ps_flags;
if (out[i].header[0]) {
print_header = 1;
}
width += out[i].width + 1; /* "FIELD " */
if ((int)(width - terminal_width) > 0) {
/* The rest does not fit on the screen */
//out[i].width -= (width - terminal_width - 1);
out_cnt = i + 1;
break;
}
}
#if ENABLE_SELINUX
if (!is_selinux_enabled())
need_flags &= ~PSSCAN_CONTEXT;
#endif
buffer = xmalloc(width + 1); /* for trailing \0 */
}
static void format_header(void)
{
int i;
ps_out_t* op;
char *p;
if (!print_header)
return;
p = buffer;
i = 0;
if (out_cnt) {
while (1) {
op = &out[i];
if (++i == out_cnt) /* do not pad last field */
break;
p += sprintf(p, "%-*s ", op->width, op->header);
}
strcpy(p, op->header);
}
printf("%.*s\n", terminal_width, buffer);
}
static void format_process(const procps_status_t *ps)
{
int i, len;
char *p = buffer;
i = 0;
if (out_cnt) while (1) {
out[i].f(p, out[i].width, ps);
// POSIX: Any field need not be meaningful in all
// implementations. In such a case a hyphen ( '-' )
// should be output in place of the field value.
2006-12-18 19:50:01 +05:30
if (!p[0]) {
p[0] = '-';
p[1] = '\0';
}
len = strlen(p);
p += len;
len = out[i].width - len + 1;
if (++i == out_cnt) /* do not pad last field */
break;
p += sprintf(p, "%*s", len, " "); /* " ", not "", to ensure separation of fields */
}
printf("%.*s\n", terminal_width, buffer);
}
#if ENABLE_SELINUX
# define SELINUX_O_PREFIX "label,"
# define DEFAULT_O_STR (SELINUX_O_PREFIX "pid,user" IF_FEATURE_PS_TIME(",time") ",args")
#else
# define DEFAULT_O_STR ("pid,user" IF_FEATURE_PS_TIME(",time") ",args")
#endif
int ps_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
2008-07-05 14:48:54 +05:30
int ps_main(int argc UNUSED_PARAM, char **argv)
{
procps_status_t *p;
llist_t* opt_o = NULL;
char default_o[sizeof(DEFAULT_O_STR)];
#if ENABLE_SELINUX || ENABLE_FEATURE_SHOW_THREADS
int opt;
#endif
enum {
OPT_Z = (1 << 0),
OPT_o = (1 << 1),
OPT_a = (1 << 2),
OPT_A = (1 << 3),
OPT_d = (1 << 4),
OPT_e = (1 << 5),
OPT_f = (1 << 6),
OPT_l = (1 << 7),
OPT_T = (1 << 8) * ENABLE_FEATURE_SHOW_THREADS,
};
INIT_G();
#if ENABLE_FEATURE_PS_TIME
G.seconds_since_boot = get_uptime();
# if ENABLE_FEATURE_PS_UNUSUAL_SYSTEMS || !defined(__linux__)
G.kernel_HZ = bb_clk_tck(); /* this is sysconf(_SC_CLK_TCK) */
# endif
#endif
// POSIX:
// -a Write information for all processes associated with terminals
// Implementations may omit session leaders from this list
// -A Write information for all processes
// -d Write information for all processes, except session leaders
// -e Write information for all processes (equivalent to -A)
// -f Generate a full listing
// -l Generate a long listing
// -o col1,col2,col3=header
// Select which columns to display
/* We allow (and ignore) most of the above. FIXME.
* -T is picked for threads (POSIX hasn't standardized it).
* procps v3.2.7 supports -T and shows tids as SPID column,
* it also supports -L where it shows tids as LWP column.
*/
#if ENABLE_SELINUX || ENABLE_FEATURE_SHOW_THREADS
opt =
#endif
getopt32(argv, "Zo:*aAdefl"IF_FEATURE_SHOW_THREADS("T"), &opt_o);
if (opt_o) {
do {
parse_o(llist_pop(&opt_o));
} while (opt_o);
} else {
/* Below: parse_o() needs char*, NOT const char*,
* can't pass it constant string. Need to make a copy first.
*/
#if ENABLE_SELINUX
if (!(opt & OPT_Z) || !is_selinux_enabled()) {
/* no -Z or no SELinux: do not show LABEL */
2008-07-17 02:41:09 +05:30
strcpy(default_o, DEFAULT_O_STR + sizeof(SELINUX_O_PREFIX)-1);
} else
#endif
{
strcpy(default_o, DEFAULT_O_STR);
}
parse_o(default_o);
}
#if ENABLE_FEATURE_SHOW_THREADS
if (opt & OPT_T)
need_flags |= PSSCAN_TASKS;
#endif
/* Was INT_MAX, but some libc's go belly up with printf("%.*s")
* and such large widths */
terminal_width = MAX_WIDTH;
if (isatty(1)) {
terminal_width = get_terminal_width(0);
if (--terminal_width > MAX_WIDTH)
terminal_width = MAX_WIDTH;
}
alloc_line_buffer();
format_header();
p = NULL;
while ((p = procps_scan(p, need_flags)) != NULL) {
format_process(p);
}
return EXIT_SUCCESS;
}
#else /* !ENABLE_DESKTOP */
int ps_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
2008-07-05 14:48:54 +05:30
int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
1999-10-20 13:35:35 +05:30
{
procps_status_t *p;
int psscan_flags = PSSCAN_PID | PSSCAN_UIDGID
| PSSCAN_STATE | PSSCAN_VSZ | PSSCAN_COMM;
unsigned terminal_width IF_NOT_FEATURE_PS_WIDE(= 79);
enum {
OPT_Z = (1 << 0) * ENABLE_SELINUX,
OPT_T = (1 << ENABLE_SELINUX) * ENABLE_FEATURE_SHOW_THREADS,
OPT_l = (1 << ENABLE_SELINUX) * (1 << ENABLE_FEATURE_SHOW_THREADS) * ENABLE_FEATURE_PS_LONG,
};
#if ENABLE_FEATURE_PS_LONG
time_t now = now; /* for compiler */
unsigned long uptime = uptime;
#endif
/* If we support any options, parse argv */
#if ENABLE_SELINUX || ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_PS_WIDE || ENABLE_FEATURE_PS_LONG
int opts = 0;
# if ENABLE_FEATURE_PS_WIDE
/* -w is a bit complicated */
int w_count = 0;
make_all_argv_opts(argv);
getopt32: remove opt_complementary function old new delta vgetopt32 1318 1392 +74 runsvdir_main 703 713 +10 bb_make_directory 423 425 +2 collect_cpu 546 545 -1 opt_chars 3 - -3 opt_complementary 4 - -4 tftpd_main 567 562 -5 ntp_init 476 471 -5 zcip_main 1266 1256 -10 xxd_main 428 418 -10 whois_main 140 130 -10 who_main 463 453 -10 which_main 212 202 -10 wget_main 2535 2525 -10 watchdog_main 291 281 -10 watch_main 222 212 -10 vlock_main 399 389 -10 uuencode_main 332 322 -10 uudecode_main 316 306 -10 unlink_main 45 35 -10 udhcpd_main 1482 1472 -10 udhcpc_main 2762 2752 -10 tune2fs_main 290 280 -10 tunctl_main 366 356 -10 truncate_main 218 208 -10 tr_main 518 508 -10 time_main 1134 1124 -10 tftp_main 286 276 -10 telnetd_main 1873 1863 -10 tcpudpsvd_main 1785 1775 -10 taskset_main 521 511 -10 tar_main 1009 999 -10 tail_main 1644 1634 -10 syslogd_main 1967 1957 -10 switch_root_main 368 358 -10 svlogd_main 1454 1444 -10 sv 1296 1286 -10 stat_main 104 94 -10 start_stop_daemon_main 1028 1018 -10 split_main 542 532 -10 sort_main 796 786 -10 slattach_main 624 614 -10 shuf_main 504 494 -10 setsid_main 96 86 -10 setserial_main 1132 1122 -10 setfont_main 388 378 -10 setconsole_main 78 68 -10 sendmail_main 1209 1199 -10 sed_main 677 667 -10 script_main 1077 1067 -10 run_parts_main 325 315 -10 rtcwake_main 454 444 -10 rm_main 175 165 -10 reformime_main 119 109 -10 readlink_main 123 113 -10 rdate_main 246 236 -10 pwdx_main 189 179 -10 pstree_main 317 307 -10 pscan_main 663 653 -10 popmaildir_main 818 808 -10 pmap_main 80 70 -10 nc_main 1042 1032 -10 mv_main 558 548 -10 mountpoint_main 477 467 -10 mount_main 1264 1254 -10 modprobe_main 768 758 -10 modinfo_main 333 323 -10 mktemp_main 200 190 -10 mkswap_main 324 314 -10 mkfs_vfat_main 1489 1479 -10 microcom_main 715 705 -10 md5_sha1_sum_main 521 511 -10 man_main 867 857 -10 makedevs_main 1052 1042 -10 ls_main 563 553 -10 losetup_main 432 422 -10 loadfont_main 89 79 -10 ln_main 524 514 -10 link_main 75 65 -10 ipcalc_main 544 534 -10 iostat_main 2397 2387 -10 install_main 768 758 -10 id_main 480 470 -10 i2cset_main 1239 1229 -10 i2cget_main 380 370 -10 i2cdump_main 1482 1472 -10 i2cdetect_main 682 672 -10 hwclock_main 406 396 -10 httpd_main 741 731 -10 grep_main 837 827 -10 getty_main 1559 1549 -10 fuser_main 297 287 -10 ftpgetput_main 345 335 -10 ftpd_main 2232 2222 -10 fstrim_main 251 241 -10 fsfreeze_main 77 67 -10 fsck_minix_main 2921 2911 -10 flock_main 314 304 -10 flashcp_main 740 730 -10 flash_eraseall_main 833 823 -10 fdformat_main 532 522 -10 expand_main 680 670 -10 eject_main 335 325 -10 dumpleases_main 630 620 -10 du_main 314 304 -10 dos2unix_main 441 431 -10 diff_main 1350 1340 -10 df_main 1064 1054 -10 date_main 1095 1085 -10 cut_main 961 951 -10 cryptpw_main 228 218 -10 crontab_main 575 565 -10 crond_main 1149 1139 -10 cp_main 370 360 -10 common_traceroute_main 3834 3824 -10 common_ping_main 1767 1757 -10 comm_main 239 229 -10 cmp_main 655 645 -10 chrt_main 379 369 -10 chpst_main 704 694 -10 chpasswd_main 308 298 -10 chown_main 171 161 -10 chmod_main 158 148 -10 cat_main 428 418 -10 bzip2_main 120 110 -10 blkdiscard_main 264 254 -10 base64_main 221 211 -10 arping_main 1665 1655 -10 ar_main 556 546 -10 adjtimex_main 406 396 -10 adduser_main 882 872 -10 addgroup_main 411 401 -10 acpid_main 1198 1188 -10 optstring 11 - -11 opt_string 18 - -18 OPT_STR 25 - -25 ubi_tools_main 1288 1258 -30 ls_options 31 - -31 ------------------------------------------------------------------------------ (add/remove: 0/6 grow/shrink: 3/129 up/down: 86/-1383) Total: -1297 bytes text data bss dec hex filename 915428 485 6876 922789 e14a5 busybox_old 914629 485 6872 921986 e1182 busybox_unstripped Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2017-08-09 01:25:02 +05:30
opts = getopt32(argv, "^"
IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l")"w"
"\0" "ww",
&w_count
);
/* if w is given once, GNU ps sets the width to 132,
* if w is given more than once, it is "unlimited"
*/
if (w_count) {
terminal_width = (w_count == 1) ? 132 : MAX_WIDTH;
} else {
terminal_width = get_terminal_width(0);
/* Go one less... */
if (--terminal_width > MAX_WIDTH)
terminal_width = MAX_WIDTH;
}
# else
/* -w is not supported, only -Z and/or -T */
make_all_argv_opts(argv);
opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l"));
# endif
# if ENABLE_SELINUX
if ((opts & OPT_Z) && is_selinux_enabled()) {
psscan_flags = PSSCAN_PID | PSSCAN_CONTEXT
| PSSCAN_STATE | PSSCAN_COMM;
puts(" PID CONTEXT STAT COMMAND");
} else
# endif
if (opts & OPT_l) {
psscan_flags = PSSCAN_STATE | PSSCAN_UIDGID | PSSCAN_PID | PSSCAN_PPID
| PSSCAN_TTY | PSSCAN_STIME | PSSCAN_UTIME | PSSCAN_COMM
| PSSCAN_VSZ | PSSCAN_RSS;
/* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html
* mandates for -l:
* -F Flags (?)
* S State
* UID,PID,PPID
* -C CPU usage
* -PRI The priority of the process; higher numbers mean lower priority
* -NI Nice value
* -ADDR The address of the process (?)
* SZ The size in blocks of the core image
* -WCHAN The event for which the process is waiting or sleeping
* TTY
* TIME The cumulative execution time
* CMD
* We don't show fields marked with '-'.
* We show VSZ and RSS instead of SZ.
* We also show STIME (standard says that -f shows it, -l doesn't).
*/
puts("S UID PID PPID VSZ RSS TTY STIME TIME CMD");
# if ENABLE_FEATURE_PS_LONG
now = time(NULL);
uptime = get_uptime();
# endif
}
else {
puts(" PID USER VSZ STAT COMMAND");
}
if (opts & OPT_T) {
psscan_flags |= PSSCAN_TASKS;
}
#endif
p = NULL;
while ((p = procps_scan(p, psscan_flags)) != NULL) {
int len;
#if ENABLE_SELINUX
if (psscan_flags & PSSCAN_CONTEXT) {
2008-01-07 22:11:41 +05:30
len = printf("%5u %-32.32s %s ",
p->pid,
p->context ? p->context : "unknown",
p->state);
2006-11-01 15:55:35 +05:30
} else
#endif
{
char buf6[6];
smart_ulltoa5(p->vsz, buf6, " mgtpezy")[0] = '\0';
#if ENABLE_FEATURE_PS_LONG
if (opts & OPT_l) {
char bufr[6], stime_str[6];
char tty[2 * sizeof(int)*3 + 2];
char *endp;
unsigned sut = (p->stime + p->utime) / 100;
unsigned elapsed = uptime - (p->start_time / 100);
time_t start = now - elapsed;
struct tm *tm = localtime(&start);
smart_ulltoa5(p->rss, bufr, " mgtpezy")[0] = '\0';
if (p->tty_major == 136)
/* It should be pts/N, not ptsN, but N > 9
* will overflow field width...
*/
endp = stpcpy(tty, "pts");
else
if (p->tty_major == 4) {
endp = stpcpy(tty, "tty");
if (p->tty_minor >= 64) {
p->tty_minor -= 64;
*endp++ = 'S';
}
}
else
endp = tty + sprintf(tty, "%d:", p->tty_major);
strcpy(endp, utoa(p->tty_minor));
strftime(stime_str, 6, (elapsed >= (24 * 60 * 60)) ? "%b%d" : "%H:%M", tm);
stime_str[5] = '\0';
// S UID PID PPID VSZ RSS TTY STIME TIME CMD
len = printf("%c %5u %5u %5u %5s %5s %-5s %s %02u:%02u:%02u ",
p->state[0], p->uid, p->pid, p->ppid, buf6, bufr, tty,
stime_str, sut / 3600, (sut % 3600) / 60, sut % 60);
} else
#endif
{
const char *user = get_cached_username(p->uid);
2008-01-07 22:11:41 +05:30
len = printf("%5u %-8.8s %s %s ",
p->pid, user, buf6, p->state);
}
}
{
int sz = terminal_width - len;
if (sz >= 0) {
char buf[sz + 1];
read_cmdline(buf, sz, p->pid, p->comm);
puts(buf);
}
}
1999-10-21 00:48:15 +05:30
}
if (ENABLE_FEATURE_CLEAN_UP)
clear_username_cache();
return EXIT_SUCCESS;
1999-10-20 13:35:35 +05:30
}
#endif /* !ENABLE_DESKTOP */