X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;ds=sidebyside;f=procps%2Fps.c;h=395cfcf565aa899ee8b1a38d20c611c3e58bf18a;hb=1432cb4bd9daf304111dd19e0011f8756c32e327;hp=68213594460fc2e94563406fb4a7f767b7359193;hpb=d537a95fdbc0b4a5f38edea8593b4c085fdd7fcb;p=oweals%2Fbusybox.git diff --git a/procps/ps.c b/procps/ps.c index 682135944..395cfcf56 100644 --- a/procps/ps.c +++ b/procps/ps.c @@ -2,299 +2,569 @@ /* * Mini ps implementation(s) for busybox * - * Copyright (C) 1999,2000 by Lineo, inc. Written by Erik Andersen - * , - * - * - * This contains _two_ implementations of ps for Linux. One uses the - * traditional /proc virtual filesystem, and the other use the devps kernel - * driver (written by Erik Andersen to avoid using /proc thereby saving 100k+). - * - * - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place, Suite 330, Boston, MA 02111-1307 USA + * Copyright (C) 1999-2004 by Erik Andersen + * Fix for SELinux Support:(c)2007 Hiroshi Shinji + * (c)2007 Yuichi Nakamura * + * Licensed under the GPL version 2, see the file LICENSE in this tarball. */ -#include "internal.h" -#include -#include -#include -#include -#include -#include -#include -#define BB_DECLARE_EXTERN -#define bb_need_help -#include "messages.c" +#include "libbb.h" -#define TERMINAL_WIDTH 79 /* not 80 in case terminal has linefold bug */ +/* Absolute maximum on output line length */ +enum { MAX_WIDTH = 2*1024 }; +#if ENABLE_DESKTOP +#include /* for times() */ +//#include /* for sysinfo() */ +#ifndef AT_CLKTCK +#define AT_CLKTCK 17 +#endif -#if ! defined BB_FEATURE_USE_DEVPS_PATCH -/* The following is the first ps implementation -- - * the one using the /proc virtual filesystem. - */ +#if ENABLE_SELINUX +#define SELINUX_O_PREFIX "label," +#define DEFAULT_O_STR (SELINUX_O_PREFIX "pid,user" USE_FEATURE_PS_TIME(",time") ",args") +#else +#define DEFAULT_O_STR ("pid,user" USE_FEATURE_PS_TIME(",time") ",args") +#endif -#if ! defined BB_FEATURE_USE_PROCFS -#error Sorry, I depend on the /proc filesystem right now. +typedef struct { + uint16_t width; + char name[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 + unsigned kernel_HZ; + unsigned long long seconds_since_boot; #endif + char default_o[sizeof(DEFAULT_O_STR)]; +}; +#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 kernel_HZ (G.kernel_HZ ) +#define seconds_since_boot (G.seconds_since_boot) +#define default_o (G.default_o ) + +#if ENABLE_FEATURE_PS_TIME +/* for ELF executables, notes are pushed before environment and args */ +static ptrdiff_t find_elf_note(ptrdiff_t findme) +{ + ptrdiff_t *ep = (ptrdiff_t *) environ; -typedef struct proc_s { - char - cmd[16]; /* basename of executable file in call to exec(2) */ - int - ruid, rgid, /* real only (sorry) */ - pid, /* process id */ - ppid; /* pid of parent process */ - char - state; /* single-char code for process state (S=sleeping) */ -} proc_t; + while (*ep++); + while (*ep) { + if (ep[0] == findme) { + return ep[1]; + } + ep += 2; + } + return -1; +} +#if ENABLE_FEATURE_PS_UNUSUAL_SYSTEMS +static unsigned get_HZ_by_waiting(void) +{ + struct timeval tv1, tv2; + unsigned t1, t2, r, hz; + unsigned cnt = cnt; /* for compiler */ + int diff; + + r = 0; + + /* Wait for times() to reach new tick */ + t1 = times(NULL); + do { + t2 = times(NULL); + } while (t2 == t1); + gettimeofday(&tv2, NULL); + + do { + t1 = t2; + tv1.tv_usec = tv2.tv_usec; + + /* Wait exactly one times() tick */ + do { + t2 = times(NULL); + } while (t2 == t1); + gettimeofday(&tv2, NULL); + + /* Calculate ticks per sec, rounding up to even */ + diff = tv2.tv_usec - tv1.tv_usec; + if (diff <= 0) diff += 1000000; + hz = 1000000u / (unsigned)diff; + hz = (hz+1) & ~1; + + /* Count how many same hz values we saw */ + if (r != hz) { + r = hz; + cnt = 0; + } + cnt++; + } while (cnt < 3); /* exit if saw 3 same values */ + return r; +} +#else +static inline unsigned get_HZ_by_waiting(void) +{ + /* Better method? */ + return 100; +} +#endif -static int file2str(char *filename, char *ret, int cap) +static unsigned get_kernel_HZ(void) { - int fd, num_read; - - if ((fd = open(filename, O_RDONLY, 0)) == -1) - return -1; - if ((num_read = read(fd, ret, cap - 1)) <= 0) - return -1; - ret[num_read] = 0; - close(fd); - return num_read; + //char buf[64]; + struct sysinfo info; + + if (kernel_HZ) + return kernel_HZ; + + /* Works for ELF only, Linux 2.4.0+ */ + kernel_HZ = find_elf_note(AT_CLKTCK); + if (kernel_HZ == (unsigned)-1) + kernel_HZ = get_HZ_by_waiting(); + + //if (open_read_close("/proc/uptime", buf, sizeof(buf) <= 0) + // bb_perror_msg_and_die("cannot read %s", "/proc/uptime"); + //buf[sizeof(buf)-1] = '\0'; + ///sscanf(buf, "%llu", &seconds_since_boot); + sysinfo(&info); + seconds_since_boot = info.uptime; + + return kernel_HZ; } +#endif +/* Print value to buf, max size+1 chars (including trailing '\0') */ -static void parse_proc_status(char *S, proc_t * P) +static void func_user(char *buf, int size, const procps_status_t *ps) { - char *tmp; - - memset(P->cmd, 0, sizeof P->cmd); - sscanf(S, "Name:\t%15c", P->cmd); - tmp = strchr(P->cmd, '\n'); - if (tmp) - *tmp = '\0'; - tmp = strstr(S, "State"); - sscanf(tmp, "State:\t%c", &P->state); - - tmp = strstr(S, "Pid:"); - if (tmp) - sscanf(tmp, "Pid:\t%d\n" "PPid:\t%d\n", &P->pid, &P->ppid); +#if 1 + safe_strncpy(buf, get_cached_username(ps->uid), size+1); +#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) + safe_strncpy(buf, user, size+1); else - errorMsg("Internal error!\n"); + sprintf(buf, "%*u", size, (unsigned)ps->uid); +#endif +} - /* For busybox, ignoring effective, saved, etc */ - tmp = strstr(S, "Uid:"); - if (tmp) - sscanf(tmp, "Uid:\t%d", &P->ruid); - else - errorMsg("Internal error!\n"); +static void func_comm(char *buf, int size, const procps_status_t *ps) +{ + safe_strncpy(buf, ps->comm, size+1); +} - tmp = strstr(S, "Gid:"); - if (tmp) - sscanf(tmp, "Gid:\t%d", &P->rgid); - else - errorMsg("Internal error!\n"); +static void func_args(char *buf, int size, const procps_status_t *ps) +{ + read_cmdline(buf, size, 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); +} -extern int ps_main(int argc, char **argv) +static void func_pgid(char *buf, int size, const procps_status_t *ps) { - proc_t p; - DIR *dir; - FILE *file; - struct dirent *entry; - char path[32], sbuf[512]; - char uidName[10] = ""; - char groupName[10] = ""; - int len, i, c; -#ifdef BB_FEATURE_AUTOWIDTH - struct winsize win = { 0, 0 }; - int terminal_width = TERMINAL_WIDTH; -#else -#define terminal_width TERMINAL_WIDTH -#endif + sprintf(buf, "%*u", size, ps->pgid); +} + +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"); + buf4[4] = '\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_TIME +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; + unsigned ss; + + mm = ps->start_time / get_kernel_HZ(); + /* must be after get_kernel_HZ()! */ + mm = seconds_since_boot - mm; + ss = mm % 60; + mm /= 60; + snprintf(buf, size+1, "%3lu:%02u", mm, ss); +} +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; + unsigned ss; + + mm = (ps->utime + ps->stime) / get_kernel_HZ(); + ss = mm % 60; + mm /= 60; + snprintf(buf, size+1, "%3lu:%02u", mm, ss); +} +#endif - if (argc > 1 && strcmp(argv[1], dash_dash_help) == 0) { - usage ("ps\n" -#ifndef BB_FEATURE_TRIVIAL_HELP - "\nReport process status\n" - "\nThis version of ps accepts no options.\n" +#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 - ); - } - dir = opendir("/proc"); - if (!dir) - fatalError("Can't open /proc\n"); +/* +static void func_nice(char *buf, int size, const procps_status_t *ps) +{ + ps->??? +} -#ifdef BB_FEATURE_AUTOWIDTH - ioctl(fileno(stdout), TIOCGWINSZ, &win); - if (win.ws_col > 0) - terminal_width = win.ws_col - 1; +static void func_pcpu(char *buf, int size, const procps_status_t *ps) +{ +} +*/ + +static const ps_out_t out_spec[] = { +// Mandated by POSIX: + { 8 , "user" ,"USER" ,func_user ,PSSCAN_UIDGID }, + { 16 , "comm" ,"COMMAND",func_comm ,PSSCAN_COMM }, + { 256 , "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 +// { sizeof("GROUP" )-1, "group" ,"GROUP" ,func_group ,PSSCAN_UIDGID }, +// { sizeof("NI" )-1, "nice" ,"NI" ,func_nice ,PSSCAN_ }, +// { sizeof("%CPU" )-1, "pcpu" ,"%CPU" ,func_pcpu ,PSSCAN_ }, +// { sizeof("RGROUP" )-1, "rgroup","RGROUP" ,func_rgroup,PSSCAN_UIDGID }, +// { sizeof("RUSER" )-1, "ruser" ,"RUSER" ,func_ruser ,PSSCAN_UIDGID }, +#if ENABLE_FEATURE_PS_TIME + { 6 , "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 by POSIX, but useful: + { 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++]; +} - fprintf(stdout, "%5s %-8s %-3s %5s %s\n", "PID", "Uid", "Gid", - "State", "Command"); - while ((entry = readdir(dir)) != NULL) { - uidName[0] = '\0'; - groupName[0] = '\0'; +static const ps_out_t* find_out_spec(const char *name) +{ + unsigned i; + for (i = 0; i < ARRAY_SIZE(out_spec); i++) { + if (!strcmp(name, out_spec[i].name)) + return &out_spec[i]; + } + bb_error_msg_and_die("bad -o argument '%s'", name); +} - if (!isdigit(*entry->d_name)) +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; - sprintf(path, "/proc/%s/status", entry->d_name); - if ((file2str(path, sbuf, sizeof sbuf)) != -1) { - parse_proc_status(sbuf, &p); } + break; + } + // 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) { + *equal = '='; + new->header = equal + 1; + // 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); + print_header = 1; + } + } else + print_header = 1; +} - /* Make some adjustments as needed */ - my_getpwuid(uidName, p.ruid); - if (*uidName == '\0') - sprintf(uidName, "%d", p.ruid); - my_getgrgid(groupName, p.rgid); - if (*groupName == '\0') - sprintf(groupName, "%d", p.rgid); - - sprintf(path, "/proc/%s/cmdline", entry->d_name); - file = fopen(path, "r"); - if (file == NULL) - continue; - i = 0; - len = fprintf(stdout, "%5d %-8s %-8s %c ", p.pid, uidName, groupName, - p.state); - while (((c = getc(file)) != EOF) && (i < (terminal_width-len))) { - i++; - if (c == '\0') - c = ' '; - putc(c, stdout); +static void post_process(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; } - if (i == 0) - fprintf(stdout, "[%s]", p.cmd); - fprintf(stdout, "\n"); + width += out[i].width + 1; /* "FIELD " */ } - closedir(dir); - return(TRUE); +#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); +} -#else /* BB_FEATURE_USE_DEVPS_PATCH */ +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. + 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, ""); + } + printf("%.*s\n", terminal_width, buffer); +} +int ps_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int ps_main(int argc UNUSED_PARAM, char **argv) +{ + procps_status_t *p; + llist_t* opt_o = NULL; + USE_SELINUX(int opt;) + + // 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 */ + opt_complementary = "o::"; + USE_SELINUX(opt =) getopt32(argv, "Zo:aAdefl", &opt_o); + if (opt_o) { + do { + parse_o(llist_pop(&opt_o)); + } while (opt_o); + } else { + /* Below: parse_o() needs char*, NOT const char*... */ +#if ENABLE_SELINUX + if (!(opt & 1) || !is_selinux_enabled()) { + /* no -Z or no SELinux: do not show LABEL */ + strcpy(default_o, DEFAULT_O_STR + sizeof(SELINUX_O_PREFIX)-1); + } else +#endif + { + strcpy(default_o, DEFAULT_O_STR); + } + parse_o(default_o); + } + post_process(); + + /* Was INT_MAX, but some libc's go belly up with printf("%.*s") + * and such large widths */ + terminal_width = MAX_WIDTH; + if (isatty(1)) { + get_terminal_width_height(0, &terminal_width, NULL); + if (--terminal_width > MAX_WIDTH) + terminal_width = MAX_WIDTH; + } + format_header(); + + p = NULL; + while ((p = procps_scan(p, need_flags))) { + format_process(p); + } + + return EXIT_SUCCESS; +} -/* The following is the second ps implementation -- - * this one uses the nifty new devps kernel device. - */ -#include /* For Erik's nifty devps device driver */ +#else /* !ENABLE_DESKTOP */ -extern int ps_main(int argc, char **argv) +int ps_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) { - char device[] = "/dev/ps"; - int i, j, len, fd; - pid_t num_pids; - pid_t* pid_array = NULL; - struct pid_info info; - char uidName[10] = ""; - char groupName[10] = ""; -#ifdef BB_FEATURE_AUTOWIDTH - struct winsize win = { 0, 0 }; - int terminal_width = TERMINAL_WIDTH; + procps_status_t *p = NULL; + int len; + SKIP_SELINUX(const) int use_selinux = 0; + USE_SELINUX(int i;) +#if !ENABLE_FEATURE_PS_WIDE + enum { terminal_width = 79 }; #else -#define terminal_width TERMINAL_WIDTH + unsigned terminal_width; + int w_count = 0; #endif - if (argc > 1 && **(argv + 1) == '-') - usage("ps-devps\n\nReport process status\n\nThis version of ps accepts no options.\n\n"); - - /* open device */ - fd = open(device, O_RDONLY); - if (fd < 0) - fatalError( "open failed for `%s': %s\n", device, strerror (errno)); - - /* Find out how many processes there are */ - if (ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids)<0) - fatalError( "\nDEVPS_GET_PID_LIST: %s\n", strerror (errno)); - - /* Allocate some memory -- grab a few extras just in case - * some new processes start up while we wait. The kernel will - * just ignore any extras if we give it too many, and will trunc. - * the list if we give it too few. */ - pid_array = (pid_t*) calloc( num_pids+10, sizeof(pid_t)); - pid_array[0] = num_pids+10; - - /* Now grab the pid list */ - if (ioctl (fd, DEVPS_GET_PID_LIST, pid_array)<0) - fatalError("\nDEVPS_GET_PID_LIST: %s\n", strerror (errno)); - -#ifdef BB_FEATURE_AUTOWIDTH - ioctl(fileno(stdout), TIOCGWINSZ, &win); - if (win.ws_col > 0) - terminal_width = win.ws_col - 1; +#if ENABLE_FEATURE_PS_WIDE || ENABLE_SELINUX +#if ENABLE_FEATURE_PS_WIDE + opt_complementary = "-:ww"; + USE_SELINUX(i =) getopt32(argv, USE_SELINUX("Z") "w", &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 { + get_terminal_width_height(0, &terminal_width, NULL); + /* Go one less... */ + if (--terminal_width > MAX_WIDTH) + terminal_width = MAX_WIDTH; + } +#else /* only ENABLE_SELINUX */ + i = getopt32(argv, "Z"); +#endif +#if ENABLE_SELINUX + if ((i & 1) && is_selinux_enabled()) + use_selinux = PSSCAN_CONTEXT; #endif +#endif /* ENABLE_FEATURE_PS_WIDE || ENABLE_SELINUX */ - /* Print up a ps listing */ - fprintf(stdout, "%5s %-8s %-3s %5s %s\n", "PID", "Uid", "Gid", - "State", "Command"); - - for (i=1; i 1) { - for( j=0; j<(sizeof(info.command_line)-1) && j < (terminal_width-len); j++) { - if (*(info.command_line+j) == '\0' && *(info.command_line+j+1) != '\0') { - *(info.command_line+j) = ' '; - } + if (use_selinux) + puts(" PID CONTEXT STAT COMMAND"); + else + puts(" PID USER VSZ STAT COMMAND"); + + while ((p = procps_scan(p, 0 + | PSSCAN_PID + | PSSCAN_UIDGID + | PSSCAN_STATE + | PSSCAN_VSZ + | PSSCAN_COMM + | use_selinux + ))) { +#if ENABLE_SELINUX + if (use_selinux) { + len = printf("%5u %-32.32s %s ", + p->pid, + p->context ? p->context : "unknown", + p->state); + } else +#endif + { + const char *user = get_cached_username(p->uid); + //if (p->vsz == 0) + // len = printf("%5u %-8.8s %s ", + // p->pid, user, p->state); + //else + { + char buf6[6]; + smart_ulltoa5(p->vsz, buf6, " mgtpezy"); + buf6[5] = '\0'; + len = printf("%5u %-8.8s %s %s ", + p->pid, user, buf6, p->state); } - *(info.command_line+j) = '\0'; - fprintf(stdout, "%s\n", info.command_line); - } else { - fprintf(stdout, "[%s]\n", info.name); } - } - - /* Free memory */ - free( pid_array); - /* close device */ - if (close (fd) != 0) - fatalError("close failed for `%s': %s\n", device, strerror (errno)); - - exit (0); + { + int sz = terminal_width - len; + char buf[sz + 1]; + read_cmdline(buf, sz, p->pid, p->comm); + puts(buf); + } + } + if (ENABLE_FEATURE_CLEAN_UP) + clear_username_cache(); + return EXIT_SUCCESS; } -#endif /* BB_FEATURE_USE_DEVPS_PATCH */ - +#endif /* ENABLE_DESKTOP */