Home | History | Annotate | Download | only in posix
      1 /* ps.c - show process list
      2  *
      3  * Copyright 2015 Rob Landley <rob (at) landley.net>
      4  *
      5  * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html
      6  * And http://kernel.org/doc/Documentation/filesystems/proc.txt Table 1-4
      7  * And linux kernel source fs/proc/array.c function do_task_stat()
      8  *
      9  * Deviations from posix: no -n because /proc/self/wchan exists; we use -n to
     10  * mean "show numeric users and groups" instead.
     11  * Posix says default output should have field named "TTY" but if you "-o tty"
     12  * the same field should be called "TT" which is _INSANE_ and I'm not doing it.
     13  * Similarly -f outputs USER but calls it UID (we call it USER).
     14  * It also says that -o "args" and "comm" should behave differently but use
     15  * the same title, which is not the same title as the default output. (No.)
     16  * Select by session id is -s not -g. Posix doesn't say truncated fields
     17  * should end with "+" but it's pretty common behavior.
     18  *
     19  * Posix defines -o ADDR as "The address of the process" but the process
     20  * start address is a constant on any elf system with mmu. The procps ADDR
     21  * field always prints "-" with an alignment of 1, which is why it has 11
     22  * characters left for "cmd" in in 80 column "ps -l" mode. On x86-64 you
     23  * need 12 chars, leaving nothing for cmd: I.E. posix 2008 ps -l mode can't
     24  * be sanely implemented on 64 bit Linux systems. In procps there's ps -y
     25  * which changes -l by removing the "F" column and swapping RSS for ADDR,
     26  * leaving 9 chars for cmd, so we're using that as our -l output.
     27  *
     28  * Added a bunch of new -o fields posix doesn't mention, and we don't
     29  * label "ps -o command,args,comm" as "COMMAND COMMAND COMMAND". We don't
     30  * output argv[0] unmodified for -o comm or -o args (but procps violates
     31  * posix for -o comm anyway, it's stat[2] not argv[0]).
     32  *
     33  * Note: iotop is STAYROOT so it can read other process's /proc/$PID/io
     34  *       files (why they're not globally readable when the rest of proc
     35  *       data is...?) and get a global I/O picture. Normal top is NOT,
     36  *       even though you can -o AIO there, to give sysadmins the option
     37  *       to reduce security exposure.)
     38  *
     39  * TODO: ps aux (att & bsd style "ps -ax" vs "ps ax" behavior difference)
     40  * TODO: switch -fl to -y
     41  * TODO: thread support /proc/$d/task/%d/stat (and -o stat has "l")
     42  * TODO: iotop: Window size change: respond immediately. Why not padding
     43  *       at right edge? (Not adjusting to screen size at all? Header wraps?)
     44  * TODO: top: thread support and SMP
     45  * TODO: pgrep -f only searches the amount of cmdline that fits in toybuf.
     46 
     47 USE_PS(NEWTOY(ps, "k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*Tu*U*g*G*wZ[!ol][+Ae][!oO]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
     48 // stayroot because iotop needs root to read other process' proc/$$/io
     49 USE_TOP(NEWTOY(top, ">0m" "O*Hk*o*p*u*s#<1d#=3<1n#<1bq[!oO]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
     50 USE_IOTOP(NEWTOY(iotop, ">0AaKO" "k*o*p*u*s#<1=7d#=3<1n#<1bq", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT|TOYFLAG_LOCALE))
     51 USE_PGREP(NEWTOY(pgrep, "?cld:u*U*t*s*P*g*G*fnovxL:[-no]", TOYFLAG_USR|TOYFLAG_BIN))
     52 USE_PKILL(NEWTOY(pkill,    "?Vu*U*t*s*P*g*G*fnovxl:[-no]", TOYFLAG_USR|TOYFLAG_BIN))
     53 
     54 config PS
     55   bool "ps"
     56   default y
     57   help
     58     usage: ps [-AadefLlnwZ] [-gG GROUP,] [-k FIELD,] [-o FIELD,] [-p PID,] [-t TTY,] [-uU USER,]
     59 
     60     List processes.
     61 
     62     Which processes to show (selections may be comma separated lists):
     63 
     64     -A	All processes
     65     -a	Processes with terminals that aren't session leaders
     66     -d	All processes that aren't session leaders
     67     -e	Same as -A
     68     -g	Belonging to GROUPs
     69     -G	Belonging to real GROUPs (before sgid)
     70     -p	PIDs (--pid)
     71     -P	Parent PIDs (--ppid)
     72     -s	In session IDs
     73     -t	Attached to selected TTYs
     74     -T	Show threads
     75     -u	Owned by USERs
     76     -U	Owned by real USERs (before suid)
     77 
     78     Output modifiers:
     79 
     80     -k	Sort FIELDs in +increasing or -decreasting order (--sort)
     81     -M	Measure field widths (expanding as necessary)
     82     -n	Show numeric USER and GROUP
     83     -w	Wide output (don't truncate fields)
     84 
     85     Which FIELDs to show. (Default = -o PID,TTY,TIME,CMD)
     86 
     87     -f	Full listing (-o USER:12=UID,PID,PPID,C,STIME,TTY,TIME,ARGS=CMD)
     88     -l	Long listing (-o F,S,UID,PID,PPID,C,PRI,NI,ADDR,SZ,WCHAN,TTY,TIME,CMD)
     89     -o	Output FIELDs instead of defaults, each with optional :size and =title
     90     -O	Add FIELDS to defaults
     91     -Z	Include LABEL
     92 
     93     Command line -o fields:
     94 
     95       ARGS     CMDLINE minus initial path     CMD  Command (thread) name (stat[2])
     96       CMDLINE  Command line (argv[])          COMM Command filename (/proc/$PID/exe)
     97       COMMAND  Command file (/proc/$PID/exe)  NAME Process name (argv[0] of $PID)
     98 
     99     Process attribute -o FIELDs:
    100 
    101       ADDR  Instruction pointer               BIT   Is this process 32 or 64 bits
    102       CPU   Which processor running on        ETIME   Elapsed time since PID start
    103       F     Flags (1=FORKNOEXEC 4=SUPERPRIV)  GID     Group id
    104       GROUP Group name                        LABEL   Security label
    105       MAJFL Major page faults                 MINFL   Minor page faults
    106       NI    Niceness (lower is faster)
    107       PCPU  Percentage of CPU time used       PCY     Android scheduling policy
    108       PGID  Process Group ID
    109       PID   Process ID                        PPID    Parent Process ID
    110       PRI   Priority (higher is faster)       PSR     Processor last executed on
    111       RGID  Real (before sgid) group ID       RGROUP  Real (before sgid) group name
    112       RSS   Resident Set Size (pages in use)  RTPRIO  Realtime priority
    113       RUID  Real (before suid) user ID        RUSER   Real (before suid) user name
    114       S     Process state:
    115             R (running) S (sleeping) D (device I/O) T (stopped)  t (traced)
    116             Z (zombie)  X (deader)   x (dead)       K (wakekill) W (waking)
    117       SCHED Scheduling policy (0=other, 1=fifo, 2=rr, 3=batch, 4=iso, 5=idle)
    118       STAT  Process state (S) plus:
    119             < high priority          N low priority L locked memory
    120             s session leader         + foreground   l multithreaded
    121       STIME Start time of process in hh:mm (size :19 shows yyyy-mm-dd hh:mm:ss)
    122       SZ    Memory Size (4k pages needed to completely swap out process)
    123       TCNT  Thread count                      TID     Thread ID
    124       TIME  CPU time consumed                 TTY     Controlling terminal
    125       UID   User id                           USER    User name
    126       VSZ   Virtual memory size (1k units)    %VSZ    VSZ as % of physical memory
    127       WCHAN What are we waiting in kernel for
    128 
    129 config TOP
    130   bool "top"
    131   depends on TOP_COMMON
    132   default y
    133   help
    134     usage: top [-H] [-k FIELD,] [-o FIELD,] [-s SORT]
    135 
    136     Show process activity in real time.
    137 
    138     -H	Show threads
    139     -k	Fallback sort FIELDS (default -S,-%CPU,-ETIME,-PID)
    140     -o	Show FIELDS (def PID,USER,PR,NI,VIRT,RES,SHR,S,%CPU,%MEM,TIME+,CMDLINE)
    141     -O	Add FIELDS (replacing PR,NI,VIRT,RES,SHR,S from default)
    142     -s	Sort by field number (1-X, default 9)
    143 
    144 # Requires CONFIG_IRQ_TIME_ACCOUNTING in the kernel for /proc/$$/io
    145 config IOTOP
    146   bool "iotop"
    147   depends on TOP_COMMON
    148   default y
    149   help
    150     usage: iotop [-AaKO]
    151 
    152     Rank processes by I/O.
    153 
    154     -A	All I/O, not just disk
    155     -a	Accumulated I/O (not percentage)
    156     -K	Kilobytes
    157     -k	Fallback sort FIELDS (default -[D]IO,-ETIME,-PID)
    158     -O	Only show processes doing I/O
    159     -o	Show FIELDS (default PID,PR,USER,[D]READ,[D]WRITE,SWAP,[D]IO,COMM)
    160     -s	Sort by field number (0-X, default 6)
    161 
    162 config TOP_COMMON
    163   bool
    164   default y
    165   help
    166     usage: * [-bq] [-n NUMBER] [-d SECONDS] [-p PID,] [-u USER,]
    167 
    168     -b	Batch mode (no tty)
    169     -d	Delay SECONDS between each cycle (default 3)
    170     -n	Exit after NUMBER iterations
    171     -p	Show these PIDs
    172     -u	Show these USERs
    173     -q	Quiet (no header lines)
    174 
    175     Cursor LEFT/RIGHT to change sort, UP/DOWN move list, space to force
    176     update, R to reverse sort, Q to exit.
    177 
    178 config PGREP
    179   bool "pgrep"
    180   default y
    181   depends on PGKILL_COMMON
    182   help
    183     usage: pgrep [-cl] [-d DELIM] [-L SIGNAL] [PATTERN]
    184 
    185     Search for process(es). PATTERN is an extended regular expression checked
    186     against command names.
    187 
    188     -c	Show only count of matches
    189     -d	Use DELIM instead of newline
    190     -L	Send SIGNAL instead of printing name
    191     -l	Show command name
    192 
    193 config PKILL
    194   bool "pkill"
    195   default y
    196   depends on PGKILL_COMMON
    197   help
    198     usage: pkill [-SIGNAL|-l SIGNAL] [PATTERN]
    199 
    200     -l	Send SIGNAL (default SIGTERM)
    201     -V	verbose
    202 
    203 config PGKILL_COMMON
    204   bool
    205   default y
    206   help
    207     usage: * [-fnovx] [-G GID,] [-g PGRP,] [-P PPID,] [-s SID,] [-t TERM,] [-U UID,] [-u EUID,]
    208 
    209     -f	Check full command line for PATTERN
    210     -G	Match real Group ID(s)
    211     -g	Match Process Group(s) (0 is current user)
    212     -n	Newest match only
    213     -o	Oldest match only
    214     -P	Match Parent Process ID(s)
    215     -s	Match Session ID(s) (0 for current)
    216     -t	Match Terminal(s)
    217     -U	Match real User ID(s)
    218     -u	Match effective User ID(s)
    219     -v	Negate the match
    220     -x	Match whole command (not substring)
    221 */
    222 
    223 #define FOR_ps
    224 #include "toys.h"
    225 
    226 GLOBALS(
    227   union {
    228     struct {
    229       struct arg_list *G;
    230       struct arg_list *g;
    231       struct arg_list *U;
    232       struct arg_list *u;
    233       struct arg_list *t;
    234       struct arg_list *s;
    235       struct arg_list *p;
    236       struct arg_list *O;
    237       struct arg_list *o;
    238       struct arg_list *P;
    239       struct arg_list *k;
    240     } ps;
    241     struct {
    242       long n;
    243       long d;
    244       long s;
    245       struct arg_list *u;
    246       struct arg_list *p;
    247       struct arg_list *o;
    248       struct arg_list *k;
    249       struct arg_list *O;
    250     } top;
    251     struct {
    252       char *L;
    253       struct arg_list *G;
    254       struct arg_list *g;
    255       struct arg_list *P;
    256       struct arg_list *s;
    257       struct arg_list *t;
    258       struct arg_list *U;
    259       struct arg_list *u;
    260       char *d;
    261 
    262       void *regexes, *snapshot;
    263       int signal;
    264       pid_t self, match;
    265     } pgrep;
    266   };
    267 
    268   struct sysinfo si;
    269   struct ptr_len gg, GG, pp, PP, ss, tt, uu, UU;
    270   struct dirtree *threadparent;
    271   unsigned width, height;
    272   dev_t tty;
    273   void *fields, *kfields;
    274   long long ticks, bits, time;
    275   int kcount, forcek, sortpos;
    276   int (*match_process)(long long *slot);
    277   void (*show_process)(void *tb);
    278 )
    279 
    280 struct strawberry {
    281   struct strawberry *next, *prev;
    282   short which, len, reverse;
    283   char *title;
    284   char forever[];
    285 };
    286 
    287 /* The slot[] array is mostly populated from /proc/$PID/stat (kernel proc.txt
    288  * table 1-4) but we shift and repurpose fields, with the result being: */
    289 
    290 enum {
    291  SLOT_pid,      /*process id*/            SLOT_ppid,      // parent process id
    292  SLOT_pgrp,     /*process group*/         SLOT_sid,       // session id
    293  SLOT_ttynr,    /*tty the process uses*/  SLOT_ttypgrp,   // pgrp of the tty
    294  SLOT_flags,    /*task flags*/            SLOT_minflt,    // minor faults
    295  SLOT_cminflt,  /*minor faults+child*/    SLOT_majflt,    // major faults
    296  SLOT_cmajflt,  /*major faults+child*/    SLOT_utime,     // user+kernel jiffies
    297  SLOT_stime,    /*kernel mode jiffies*/   SLOT_cutime,    // utime+child
    298  SLOT_cstime,   /*stime+child*/           SLOT_priority,  // priority level
    299  SLOT_nice,     /*nice level*/            SLOT_numthreads,// thread count
    300  SLOT_vmlck,    /*locked memory*/         SLOT_starttime, // jiffies after boot
    301  SLOT_vsize,    /*virtual memory size*/   SLOT_rss,       // resident set size
    302  SLOT_rsslim,   /*limit in bytes on rss*/ SLOT_startcode, // code segment addr
    303  SLOT_endcode,  /*code segment address*/  SLOT_startstack,// stack address
    304  SLOT_esp,      /*task stack pointer*/    SLOT_eip,       // instruction pointer
    305  SLOT_iobytes,  /*All I/O bytes*/         SLOT_diobytes,  // disk I/O bytes
    306  SLOT_utime2,   /*relative utime (top)*/  SLOT_uid,       // user id
    307  SLOT_ruid,     /*real user id*/          SLOT_gid,       // group id
    308  SLOT_rgid,     /*real group id*/         SLOT_exitsig,   // sent to parent
    309  SLOT_taskcpu,  /*CPU running on*/        SLOT_rtprio,    // realtime priority
    310  SLOT_policy,   /*man sched_setscheduler*/SLOT_blkioticks,// IO wait time
    311  SLOT_gtime,    /*guest jiffies of task*/ SLOT_cgtime,    // gtime+child
    312  SLOT_startbss, /*data/bss address*/      SLOT_endbss,    // end addr data+bss
    313  SLOT_upticks,  /*46-19 (divisor for %)*/ SLOT_argv0len,  // argv[0] length
    314  SLOT_uptime,   /*si.uptime @read time*/  SLOT_vsz,       // Virtual mem Size
    315  SLOT_rss2,     /*Resident Set Size*/     SLOT_shr,       // Shared memory
    316  SLOT_rchar,    /*All bytes read*/        SLOT_wchar,     // All bytes written
    317  SLOT_rbytes,   /*Disk bytes read*/       SLOT_wbytes,    // Disk bytes written
    318  SLOT_swap,     /*Swap pages used*/       SLOT_bits,      // 32 or 64
    319  SLOT_tid,      /*Thread ID*/             SLOT_tcount,    // Thread count
    320  SLOT_pcy,      /*Android sched policy*/
    321 
    322  SLOT_count
    323 };
    324 
    325 // Data layout in toybuf
    326 struct carveup {
    327   long long slot[SLOT_count]; // data (see enum above)
    328   unsigned short offset[6];   // offset of fields in str[] (skip name, always 0)
    329   char state;
    330   char str[];                 // name, tty, command, wchan, attr, cmdline
    331 };
    332 
    333 // TODO: Android uses -30 for LABEL, but ideally it would auto-size.
    334 // 64|slot means compare as string when sorting
    335 struct typography {
    336   char *name;
    337   signed char width, slot;
    338 } static const typos[] = TAGGED_ARRAY(PS,
    339   // Numbers
    340   {"PID", 5, SLOT_pid}, {"PPID", 5, SLOT_ppid}, {"PRI", 3, SLOT_priority},
    341   {"NI", 3, SLOT_nice}, {"ADDR", 4+sizeof(long), SLOT_eip},
    342   {"SZ", 5, SLOT_vsize}, {"RSS", 6, SLOT_rss}, {"PGID", 5, SLOT_pgrp},
    343   {"VSZ", 7, SLOT_vsize}, {"MAJFL", 6, SLOT_majflt}, {"MINFL", 6, SLOT_minflt},
    344   {"PR", 2, SLOT_priority}, {"PSR", 3, SLOT_taskcpu},
    345   {"RTPRIO", 6, SLOT_rtprio}, {"SCH", 3, SLOT_policy}, {"CPU", 3, SLOT_taskcpu},
    346   {"TID", 5, SLOT_tid}, {"TCNT", 4, SLOT_tcount}, {"BIT", 3, SLOT_bits},
    347 
    348   // String fields
    349   {"TTY", -8, -2}, {"WCHAN", -6, -3}, {"LABEL", -30, -4}, {"COMM", -27, -5},
    350   {"NAME", -27, -7}, {"COMMAND", -27, -5}, {"CMDLINE", -27, -6},
    351   {"ARGS", -27, -6}, {"CMD", -15, -1},
    352 
    353   // user/group
    354   {"UID", 5, SLOT_uid}, {"USER", -12, 64|SLOT_uid}, {"RUID", 4, SLOT_ruid},
    355   {"RUSER", -8, 64|SLOT_ruid}, {"GID", 8, SLOT_gid}, {"GROUP", -8, 64|SLOT_gid},
    356   {"RGID", 4, SLOT_rgid}, {"RGROUP", -8, 64|SLOT_rgid},
    357 
    358   // clock displays
    359   {"TIME", 8, SLOT_utime}, {"ELAPSED", 11, SLOT_starttime},
    360   {"TIME+", 9, SLOT_utime},
    361 
    362   // Percentage displays
    363   {"C", 1, SLOT_utime2}, {"%VSZ", 5, SLOT_vsize}, {"%MEM", 5, SLOT_rss},
    364   {"%CPU", 4, SLOT_utime2},
    365 
    366   // human_readable
    367   {"VIRT", 4, SLOT_vsz}, {"RES", 4, SLOT_rss2},
    368   {"SHR", 4, SLOT_shr}, {"READ", 6, SLOT_rchar}, {"WRITE", 6, SLOT_wchar},
    369   {"IO", 6, SLOT_iobytes}, {"DREAD", 6, SLOT_rbytes},
    370   {"DWRITE", 6, SLOT_wbytes}, {"SWAP", 6, SLOT_swap}, {"DIO", 6, SLOT_diobytes},
    371 
    372   // Misc
    373   {"STIME", 5, SLOT_starttime}, {"F", 1, 64|SLOT_flags}, {"S", -1, 64},
    374   {"STAT", -5, 64}, {"PCY", 3, 64|SLOT_pcy},
    375 );
    376 
    377 // Return 0 to discard, nonzero to keep
    378 static int shared_match_process(long long *slot)
    379 {
    380   struct ptr_len match[] = {
    381     {&TT.gg, SLOT_gid}, {&TT.GG, SLOT_rgid}, {&TT.pp, SLOT_pid},
    382     {&TT.PP, SLOT_ppid}, {&TT.ss, SLOT_sid}, {&TT.tt, SLOT_ttynr},
    383     {&TT.uu, SLOT_uid}, {&TT.UU, SLOT_ruid}
    384   };
    385   int i, j;
    386   long *ll = 0;
    387 
    388   // Do we have -g -G -p -P -s -t -u -U options selecting processes?
    389   for (i = 0; i < ARRAY_LEN(match); i++) {
    390     struct ptr_len *mm = match[i].ptr;
    391 
    392     if (mm->len) {
    393       ll = mm->ptr;
    394       for (j = 0; j<mm->len; j++) if (ll[j] == slot[match[i].len]) return 1;
    395     }
    396   }
    397 
    398   return ll ? 0 : -1;
    399 }
    400 
    401 
    402 // Return 0 to discard, nonzero to keep
    403 static int ps_match_process(long long *slot)
    404 {
    405   int i = shared_match_process(slot);
    406 
    407   if (i>0) return 1;
    408   // If we had selections and didn't match them, don't display
    409   if (!i) return 0;
    410 
    411   // Filter implicit categories for other display types
    412   if ((toys.optflags&(FLAG_a|FLAG_d)) && slot[SLOT_sid]==*slot) return 0;
    413   if ((toys.optflags&FLAG_a) && !slot[SLOT_ttynr]) return 0;
    414   if (!(toys.optflags&(FLAG_a|FLAG_d|FLAG_A|FLAG_e))
    415       && TT.tty!=slot[SLOT_ttynr]) return 0;
    416 
    417   return 1;
    418 }
    419 
    420 // Convert field to string representation
    421 static char *string_field(struct carveup *tb, struct strawberry *field)
    422 {
    423   char *buf = toybuf+sizeof(toybuf)-260, *out = buf, *s;
    424   int which = field->which, sl = typos[which].slot;
    425   long long *slot = tb->slot, ll = (sl >= 0) ? slot[sl&63] : 0;
    426 
    427   // numbers, mostly from /proc/$PID/stat
    428   if (which <= PS_BIT) {
    429     char *fmt = "%lld";
    430 
    431     if (which==PS_PRI) ll = 39-ll;
    432     if (which==PS_ADDR) fmt = "%llx";
    433     else if (which==PS_SZ) ll >>= 12;
    434     else if (which==PS_RSS) ll <<= 2;
    435     else if (which==PS_VSZ) ll >>= 10;
    436     else if (which==PS_PR && ll<-9) fmt="RT";
    437     else if ((which==PS_RTPRIO || which==PS_BIT) && ll == 0) fmt="-";
    438     sprintf(out, fmt, ll);
    439 
    440   // String fields
    441   } else if (sl < 0) {
    442     out = tb->str;
    443     sl *= -1;
    444     // First string slot has offset 0, others are offset[-slot-2]
    445     if (--sl) out += tb->offset[--sl];
    446     if (which==PS_ARGS || which==PS_COMM) {
    447       int i;
    448 
    449       s = out;
    450       for (i = 0; (which==PS_ARGS) ? i < slot[SLOT_argv0len] : out[i]; i++)
    451         if (out[i] == '/') s = out+i+1;
    452       out = s;
    453     }
    454     if (which>=PS_COMM && !*out) sprintf(out = buf, "[%s]", tb->str);
    455 
    456   // user/group
    457   } else if (which <= PS_RGROUP) {
    458     sprintf(out, "%lld", ll);
    459     if (sl&64) {
    460       if (which > PS_RUSER) {
    461         struct group *gr = bufgetgrgid(ll);
    462 
    463         if (gr) out = gr->gr_name;
    464       } else {
    465         struct passwd *pw = bufgetpwuid(ll);
    466 
    467         if (pw) out = pw->pw_name;
    468       }
    469     }
    470 
    471   // Clock displays
    472   } else if (which <= PS_TIME_) {
    473     int unit = 60, pad = 2, j = TT.ticks;
    474     time_t seconds;
    475 
    476     if (which!=PS_TIME_) unit *= 60*24;
    477     else pad = 0;
    478     // top adjusts slot[SLOT_upticks], we want original meaning.
    479     if (which==PS_ELAPSED) ll = (slot[SLOT_uptime]*j)-slot[SLOT_starttime];
    480     seconds = ll/j;
    481 
    482     // Output days-hours:mins:secs, skipping non-required fields with zero
    483     // TIME has 3 required fields, ETIME has 2. (Posix!) TIME+ is from top
    484     for (s = 0, j = 2*(which==PS_TIME_); j<4; j++) {
    485       if (!s && (seconds>unit || j == 1+(which!=PS_TIME))) s = out;
    486       if (s) {
    487         s += sprintf(s, j ? "%0*ld": "%*ld", pad, (long)(seconds/unit));
    488         pad = 2;
    489         if ((*s = "-::"[j])) s++;
    490       }
    491       seconds %= unit;
    492       unit /= j ? 60 : 24;
    493     }
    494     if (which==PS_TIME_ && s-out<8)
    495       sprintf(s, ".%02lld", (100*(ll%TT.ticks))/TT.ticks);
    496 
    497   // Percentage displays
    498   } else if (which <= PS__CPU) {
    499     ll = slot[sl&63]*1000;
    500     if (which==PS__VSZ || which==PS__MEM)
    501       ll /= TT.si.totalram/((which==PS__VSZ) ? 1024 : 4096);
    502     else if (slot[SLOT_upticks]) ll /= slot[SLOT_upticks];
    503     sl = ll;
    504     if (which==PS_C) sl += 5;
    505     sprintf(out, "%d", sl/10);
    506     if (which!=PS_C && sl<1000) sprintf(out+strlen(out), ".%d", sl%10);
    507 
    508   // Human readable
    509   } else if (which <= PS_DIO) {
    510     ll = slot[typos[which].slot];
    511     if (which <= PS_SHR) ll *= sysconf(_SC_PAGESIZE);
    512     if (TT.forcek) sprintf(out, "%lldk", ll/1024);
    513     else human_readable(out, ll, 0);
    514 
    515   // Posix doesn't specify what flags should say. Man page says
    516   // 1 for PF_FORKNOEXEC and 4 for PF_SUPERPRIV from linux/sched.h
    517   } else if (which==PS_F) sprintf(out, "%llo", (slot[SLOT_flags]>>6)&5);
    518   else if (which==PS_S || which==PS_STAT) {
    519     s = out;
    520     *s++ = tb->state;
    521     if (which==PS_STAT) {
    522       // TODO l = multithreaded
    523       if (slot[SLOT_nice]<0) *s++ = '<';
    524       else if (slot[SLOT_nice]>0) *s++ = 'N';
    525       if (slot[SLOT_sid]==*slot) *s++ = 's';
    526       if (slot[SLOT_vmlck]) *s++ = 'L';
    527       if (slot[SLOT_ttypgrp]==*slot) *s++ = '+';
    528     }
    529     *s = 0;
    530   } else if (which==PS_STIME) {
    531     time_t t = time(0)-slot[SLOT_uptime]+slot[SLOT_starttime]/TT.ticks;
    532 
    533     // Padding behavior's a bit odd: default field size is just hh:mm.
    534     // Increasing stime:size reveals more data at left until full,
    535     // so move start address so yyyy-mm-dd hh:mm revealed on left at :16,
    536     // then add :ss on right for :19.
    537     strftime(out, 260, "%F %T", localtime(&t));
    538     out = out+strlen(out)-3-abs(field->len);
    539     if (out<buf) out = buf;
    540 
    541   } else if (which==PS_PCY) sprintf(out, "%.2s", get_sched_policy_name(ll));
    542   else if (CFG_TOYBOX_DEBUG) error_exit("bad which %d", which);
    543 
    544   return out;
    545 }
    546 
    547 // Display process data that get_ps() read from /proc, formatting with TT.fields
    548 static void show_ps(void *p)
    549 {
    550   struct carveup *tb = p;
    551   struct strawberry *field;
    552   int pad, len, width = TT.width, abslen, sign, olen, extra = 0;
    553 
    554   // Loop through fields to display
    555   for (field = TT.fields; field; field = field->next) {
    556     char *out = string_field(tb, field);
    557 
    558     // Output the field, appropriately padded
    559 
    560     // Minimum one space between each field
    561     if (field != TT.fields) {
    562       putchar(' ');
    563       width--;
    564     }
    565 
    566     // Don't truncate number fields, but try to reclaim extra offset from later
    567     // fields that can naturally be shorter
    568     abslen = abs(field->len);
    569     sign = field->len<0 ? -1 : 1;
    570     olen = (TT.tty) ? utf8len(out) : strlen(out);
    571     if ((field->which<=PS_BIT || (toys.optflags&FLAG_w)) && olen>abslen) {
    572       // overflow but remember by how much
    573       extra += olen-abslen;
    574       abslen = olen;
    575     } else if (extra && olen<abslen) {
    576       int unused = abslen-olen;
    577 
    578       // If later fields have slack space, take back overflow
    579       if (unused>extra) unused = extra;
    580       abslen -= unused;
    581       extra -= unused;
    582     }
    583     if (abslen>width) abslen = width;
    584     len = pad = abslen;
    585     pad *= sign;
    586 
    587     // If last field is left justified, no trailing spaces.
    588     if (!field->next && sign<0) {
    589       pad = -1;
    590       len = width;
    591     }
    592 
    593     // If we truncated a left-justified field, show + instead of last char
    594     if (olen>len && len>1 && sign<0) {
    595       width--;
    596       len--;
    597       if (field->next) pad++;
    598       abslen = 0;
    599     }
    600 
    601     if (TT.tty) width -= draw_trim(out, pad, len);
    602     else width -= printf("%*.*s", pad, len, out);
    603     if (!abslen) putchar('+');
    604     if (!width) break;
    605   }
    606   xputc(TT.time ? '\r' : '\n');
    607 }
    608 
    609 // dirtree callback: read data about process to display, store, or discard it.
    610 // Fills toybuf with struct carveup and either DIRTREE_SAVEs a copy to ->extra
    611 // (in -k mode) or calls show_ps on toybuf (no malloc/copy/free there).
    612 static int get_ps(struct dirtree *new)
    613 {
    614   struct {
    615     char *name;     // Path under /proc/$PID directory
    616     long long bits; // Only fetch extra data if an -o field is displaying it
    617   } fetch[] = {
    618     // sources for carveup->offset[] data
    619     {"fd/", _PS_TTY}, {"wchan", _PS_WCHAN}, {"attr/current", _PS_LABEL},
    620     {"exe", _PS_COMMAND|_PS_COMM}, {"cmdline", _PS_CMDLINE|_PS_ARGS|_PS_NAME},
    621     {"", _PS_NAME}
    622   };
    623   struct carveup *tb = (void *)toybuf;
    624   long long *slot = tb->slot;
    625   char *name, *s, *buf = tb->str, *end = 0;
    626   int i, j, fd;
    627   off_t len;
    628 
    629   // Recurse one level into /proc children, skip non-numeric entries
    630   if (!new->parent)
    631     return DIRTREE_RECURSE|DIRTREE_SHUTUP|DIRTREE_PROC
    632       |(DIRTREE_SAVE*(TT.threadparent||!TT.show_process));
    633 
    634   memset(slot, 0, sizeof(tb->slot));
    635   tb->slot[SLOT_tid] = *slot = atol(new->name);
    636   if (TT.threadparent && TT.threadparent->extra)
    637     if (*slot == *(((struct carveup *)TT.threadparent->extra)->slot)) return 0;
    638   fd = dirtree_parentfd(new);
    639 
    640   len = 2048;
    641   sprintf(buf, "%lld/stat", *slot);
    642   if (!readfileat(fd, buf, buf, &len)) return 0;
    643 
    644   // parse oddball fields (name and state). Name can have embedded ')' so match
    645   // _last_ ')' in stat (although VFS limits filenames to 255 bytes max).
    646   // All remaining fields should be numeric.
    647   if (!(name = strchr(buf, '('))) return 0;
    648   for (s = ++name; *s; s++) if (*s == ')') end = s;
    649   if (!end || end-name>255) return 0;
    650 
    651   // Parse numeric fields (starting at 4th field in slot[SLOT_ppid])
    652   if (1>sscanf(s = end, ") %c%n", &tb->state, &i)) return 0;
    653   for (j = 1; j<SLOT_count; j++)
    654     if (1>sscanf(s += i, " %lld%n", slot+j, &i)) break;
    655 
    656   // Now we've read the data, move status and name right after slot[] array,
    657   // and convert low chars to ? for non-tty display while we're at it.
    658   for (i = 0; i<end-name; i++)
    659     if ((tb->str[i] = name[i]) < ' ')
    660       if (!TT.tty) tb->str[i] = '?';
    661   buf = tb->str+i;
    662   *buf++ = 0;
    663   len = sizeof(toybuf)-(buf-toybuf);
    664 
    665   // save uid, ruid, gid, gid, and rgid int slots 31-34 (we don't use sigcatch
    666   // or numeric wchan, and the remaining two are always zero), and vmlck into
    667   // 18 (which is "obsolete, always 0" from stat)
    668   slot[SLOT_uid] = new->st.st_uid;
    669   slot[SLOT_gid] = new->st.st_gid;
    670 
    671   // TIME and TIME+ use combined value, ksort needs 'em added.
    672   slot[SLOT_utime] += slot[SLOT_stime];
    673   slot[SLOT_utime2] = slot[SLOT_utime];
    674 
    675   // If RGROUP RUSER STAT RUID RGID SWAP happening, or -G or -U, parse "status"
    676   // and save ruid, rgid, and vmlck.
    677   if ((TT.bits&(_PS_RGROUP|_PS_RUSER|_PS_STAT|_PS_RUID|_PS_RGID|_PS_SWAP
    678                |_PS_IO|_PS_DIO)) || TT.GG.len || TT.UU.len)
    679   {
    680     off_t temp = len;
    681 
    682     sprintf(buf, "%lld/status", *slot);
    683     if (!readfileat(fd, buf, buf, &temp)) *buf = 0;
    684     s = strafter(buf, "\nUid:");
    685     slot[SLOT_ruid] = s ? atol(s) : new->st.st_uid;
    686     s = strafter(buf, "\nGid:");
    687     slot[SLOT_rgid] = s ? atol(s) : new->st.st_gid;
    688     if ((s = strafter(buf, "\nVmLck:"))) slot[SLOT_vmlck] = atoll(s);
    689     if ((s = strafter(buf, "\nVmSwap:"))) slot[SLOT_swap] = atoll(s);
    690   }
    691 
    692   // Do we need to read "io"?
    693   if (TT.bits&(_PS_READ|_PS_WRITE|_PS_DREAD|_PS_DWRITE|_PS_IO|_PS_DIO)) {
    694     off_t temp = len;
    695 
    696     sprintf(buf, "%lld/io", *slot);
    697     if (!readfileat(fd, buf, buf, &temp)) *buf = 0;
    698     if ((s = strafter(buf, "rchar:"))) slot[SLOT_rchar] = atoll(s);
    699     if ((s = strafter(buf, "wchar:"))) slot[SLOT_wchar] = atoll(s);
    700     if ((s = strafter(buf, "read_bytes:"))) slot[SLOT_rbytes] = atoll(s);
    701     if ((s = strafter(buf, "write_bytes:"))) slot[SLOT_wbytes] = atoll(s);
    702     slot[SLOT_iobytes] = slot[SLOT_rchar]+slot[SLOT_wchar]+slot[SLOT_swap];
    703     slot[SLOT_diobytes] = slot[SLOT_rbytes]+slot[SLOT_wbytes]+slot[SLOT_swap];
    704   }
    705 
    706   // We now know enough to skip processes we don't care about.
    707   if (TT.match_process && !TT.match_process(slot)) return 0;
    708 
    709   // /proc data is generated as it's read, so for maximum accuracy on slow
    710   // systems (or ps | more) we re-fetch uptime as we fetch each /proc line.
    711   sysinfo(&TT.si);
    712   slot[SLOT_uptime] = TT.si.uptime;
    713   slot[SLOT_upticks] = slot[SLOT_uptime]*TT.ticks - slot[SLOT_starttime];
    714 
    715   // Do we need to read "statm"?
    716   if (TT.bits&(_PS_VIRT|_PS_RES|_PS_SHR)) {
    717     off_t temp = len;
    718 
    719     sprintf(buf, "%lld/statm", *slot);
    720     if (!readfileat(fd, buf, buf, &temp)) *buf = 0;
    721 
    722     for (s = buf, i=0; i<3; i++)
    723       if (!sscanf(s, " %lld%n", slot+SLOT_vsz+i, &j)) slot[SLOT_vsz+i] = 0;
    724       else s += j;
    725   }
    726 
    727   // Do we need to read "exe"?
    728   if (TT.bits&_PS_BIT) {
    729     off_t temp = 6;
    730 
    731     sprintf(buf, "%lld/exe", *slot);
    732     if (readfileat(fd, buf, buf, &temp) && !memcmp(buf, "\177ELF", 4)) {
    733       if (buf[4] == 1) slot[SLOT_bits] = 32;
    734       else if (buf[4] == 2) slot[SLOT_bits] = 64;
    735     }
    736   }
    737 
    738   // Do we need Android scheduling policy?
    739   if (TT.bits&_PS_PCY) get_sched_policy(*slot, (void *)&slot[SLOT_pcy]);
    740 
    741   // Fetch string data while parentfd still available, appending to buf.
    742   // (There's well over 3k of toybuf left. We could dynamically malloc, but
    743   // it'd almost never get used, querying length of a proc file is awkward,
    744   // fixed buffer is nommu friendly... Wait for somebody to complain. :)
    745   slot[SLOT_argv0len] = 0;
    746   for (j = 0; j<ARRAY_LEN(fetch); j++) {
    747     tb->offset[j] = buf-(tb->str);
    748     if (!(TT.bits&fetch[j].bits)) {
    749       *buf++ = 0;
    750       continue;
    751     }
    752 
    753     // Determine remaining space, reserving minimum of 256 bytes/field and
    754     // 260 bytes scratch space at the end (for output conversion later).
    755     len = sizeof(toybuf)-(buf-toybuf)-260-256*(ARRAY_LEN(fetch)-j);
    756     sprintf(buf, "%lld/%s", *slot, fetch[j].name);
    757 
    758     // For exe we readlink instead of read contents
    759     if (j==3 || j==5) {
    760       struct carveup *ptb = 0;
    761       int k;
    762 
    763       // Thread doesn't have exe or argv[0], so use parent's
    764       if (TT.threadparent && TT.threadparent->extra)
    765         ptb = (void *)TT.threadparent->extra;
    766 
    767       if (j==3 && !ptb) len = readlinkat0(fd, buf, buf, len);
    768       else {
    769         if (j==3) i = strlen(s = ptb->str+ptb->offset[3]);
    770         else {
    771           if (!ptb || tb->slot[SLOT_argv0len]) ptb = tb;
    772           i = ptb->slot[SLOT_argv0len];
    773           s = ptb->str+ptb->offset[4];
    774           while (-1!=(k = stridx(s, '/')) && k<i) {
    775             s += k+1;
    776             i -= k+1;
    777           }
    778         }
    779         if (i<len) len = i;
    780         memcpy(buf, s, len);
    781         buf[len] = 0;
    782       }
    783 
    784     // If it's not the TTY field, data we want is in a file.
    785     // Last length saved in slot[] is command line (which has embedded NULs)
    786     } else if (!j) {
    787       int rdev = slot[SLOT_ttynr];
    788       struct stat st;
    789 
    790       // Call no tty "?" rather than "0:0".
    791       strcpy(buf, "?");
    792       if (rdev) {
    793         // Can we readlink() our way to a name?
    794         for (i = 0; i<3; i++) {
    795           sprintf(buf, "%lld/fd/%i", *slot, i);
    796           if (!fstatat(fd, buf, &st, 0) && S_ISCHR(st.st_mode)
    797             && st.st_rdev == rdev && (len = readlinkat0(fd, buf, buf, len)))
    798               break;
    799         }
    800 
    801         // Couldn't find it, try all the tty drivers.
    802         if (i == 3) {
    803           FILE *fp = fopen("/proc/tty/drivers", "r");
    804           int tty_major = 0, maj = dev_major(rdev), min = dev_minor(rdev);
    805 
    806           if (fp) {
    807             while (fscanf(fp, "%*s %256s %d %*s %*s", buf, &tty_major) == 2) {
    808               // TODO: we could parse the minor range too.
    809               if (tty_major == maj) {
    810                 len = strlen(buf);
    811                 len += sprintf(buf+len, "%d", min);
    812                 if (!stat(buf, &st) && S_ISCHR(st.st_mode) && st.st_rdev==rdev)
    813                   break;
    814               }
    815               tty_major = 0;
    816             }
    817             fclose(fp);
    818           }
    819 
    820           // Really couldn't find it, so just show major:minor.
    821           if (!tty_major) len = sprintf(buf, "%d:%d", maj, min);
    822         }
    823 
    824         s = buf;
    825         if (strstart(&s, "/dev/")) memmove(buf, s, len -= 4);
    826       }
    827 
    828     // Data we want is in a file.
    829     // Last length saved in slot[] is command line (which has embedded NULs)
    830     } else {
    831       int temp = 0;
    832 
    833       // When command has no arguments, don't space over the NUL
    834       if (readfileat(fd, buf, buf, &len) && len>0) {
    835 
    836         // Trim trailing whitespace and NUL bytes
    837         while (len)
    838           if (!buf[len-1] || isspace(buf[len-1])) buf[--len] = 0;
    839           else break;
    840 
    841         // Turn NUL to space, other low ascii to ? (in non-tty mode)
    842         // cmdline has a trailing NUL that we don't want to turn to space.
    843         for (i=0; i<len-1; i++) {
    844           char c = buf[i];
    845 
    846           if (!c) {
    847             if (!temp) temp = i;
    848             c = ' ';
    849           } else if (!TT.tty && c<' ') c = '?';
    850           buf[i] = c;
    851         }
    852       } else *buf = len = 0;
    853 
    854       // Store end of argv[0] so ARGS and CMDLINE can differ.
    855       // We do it for each file string slot but last is cmdline, which sticks.
    856       slot[SLOT_argv0len] = temp ? temp : len;  // Position of _first_ NUL
    857     }
    858 
    859     // Above calculated/retained len, so we don't need to re-strlen.
    860     buf += len+1;
    861   }
    862 
    863   TT.kcount++;
    864   if (TT.show_process && !TT.threadparent) {
    865     TT.show_process(tb);
    866 
    867     return 0;
    868   }
    869 
    870   // If we need to sort the output, add it to the list and return.
    871   s = xmalloc(buf-toybuf);
    872   new->extra = (long)s;
    873   memcpy(s, toybuf, buf-toybuf);
    874 
    875   return DIRTREE_SAVE;
    876 }
    877 
    878 static int get_threads(struct dirtree *new)
    879 {
    880   struct dirtree *dt;
    881   struct carveup *tb;
    882   unsigned pid, kcount;
    883 
    884   if (!new->parent) return get_ps(new);
    885   pid = atol(new->name);
    886 
    887   TT.threadparent = new;
    888   if (!get_ps(new)) {
    889     TT.threadparent = 0;
    890 
    891     return 0;
    892   }
    893 
    894   // Recurse down into tasks, retaining thread groups.
    895   // Disable show_process at least until we can calculate tcount
    896   kcount = TT.kcount;
    897   sprintf(toybuf, "/proc/%u/task", pid);
    898   new->child = dirtree_flagread(toybuf, DIRTREE_SHUTUP|DIRTREE_PROC, get_ps);
    899   if (new->child == DIRTREE_ABORTVAL) new->child = 0;
    900   TT.threadparent = 0;
    901   kcount = TT.kcount-kcount+1;
    902   tb = (void *)new->extra;
    903   tb->slot[SLOT_tcount] = kcount;
    904 
    905   // Fill out tid and thread count for each entry in group
    906   if (new->child) for (dt = new->child->child; dt; dt = dt->next) {
    907     tb = (void *)dt->extra;
    908     tb->slot[SLOT_pid] = pid;
    909     tb->slot[SLOT_tcount] = kcount;
    910   }
    911 
    912   // Save or display
    913   if (!TT.show_process) return DIRTREE_SAVE;
    914   TT.show_process((void *)new->extra);
    915   dt = new->child;
    916   new->child = 0;
    917   while (dt->child) {
    918     new = dt->child->next;
    919     TT.show_process((void *)dt->child->extra);
    920     free(dt->child);
    921     dt->child = new;
    922   }
    923   free(dt);
    924 
    925   return 0;
    926 }
    927 
    928 static char *parse_ko(void *data, char *type, int length)
    929 {
    930   struct strawberry *field;
    931   char *width, *title, *end, *s;
    932   int i, j, k;
    933 
    934   // Get title, length of title, type, end of type, and display width
    935 
    936   // Chip off =name to display
    937   if ((end = strchr(type, '=')) && length>(end-type)) {
    938     title = end+1;
    939     length -= (end-type)+1;
    940   } else {
    941     end = type+length;
    942     title = 0;
    943   }
    944 
    945   // Chip off :width to display
    946   if ((width = strchr(type, ':')) && width<end) {
    947     if (!title) length = width-type;
    948   } else width = 0;
    949 
    950   // Allocate structure, copy title
    951   field = xzalloc(sizeof(struct strawberry)+(length+1)*!!title);
    952   if (title) {
    953     memcpy(field->title = field->forever, title, length);
    954     field->title[field->len = length] = 0;
    955   }
    956 
    957   if (width) {
    958     field->len = strtol(++width, &title, 10);
    959     if (!isdigit(*width) || title != end) return title;
    960     end = --width;
    961   }
    962 
    963   // Find type
    964   field->reverse = 1;
    965   if (*type == '-') field->reverse = -1;
    966   else if (*type != '+') type--;
    967   type++;
    968   for (i = 0; i<ARRAY_LEN(typos); i++) {
    969     field->which = i;
    970     for (j = 0; j<2; j++) {
    971       if (!j) s = typos[i].name;
    972       // posix requires alternate names for some fields
    973       else if (-1==(k = stridx((char []){PS_NI, PS_SCH, PS_ELAPSED, PS__CPU,
    974         PS_VSZ, PS_USER, 0}, i))) continue;
    975       else
    976         s = ((char *[]){"NICE", "SCHED", "ETIME", "PCPU", "VSIZE", "UNAME"})[k];
    977 
    978       if (!strncasecmp(type, s, end-type) && strlen(s)==end-type) break;
    979     }
    980     if (j!=2) break;
    981   }
    982   if (i==ARRAY_LEN(typos)) return type;
    983   if (!field->title) field->title = typos[field->which].name;
    984   if (!field->len) field->len = typos[field->which].width;
    985   else if (typos[field->which].width<0) field->len *= -1;
    986   dlist_add_nomalloc(data, (void *)field);
    987 
    988   return 0;
    989 }
    990 
    991 static long long get_headers(struct strawberry *fields, char *buf, int blen)
    992 {
    993   long long bits = 0;
    994   int len = 0;
    995 
    996   for (; fields; fields = fields->next) {
    997     len += snprintf(buf+len, blen-len, " %*s"+!bits, fields->len,
    998       fields->title);
    999     bits |= 1LL<<fields->which;
   1000   }
   1001 
   1002   return bits;
   1003 }
   1004 
   1005 // Parse -p -s -t -u -U -g -G
   1006 static char *parse_rest(void *data, char *str, int len)
   1007 {
   1008   struct ptr_len *pl = (struct ptr_len *)data;
   1009   long *ll = pl->ptr;
   1010   char *end;
   1011   int num = 0;
   1012 
   1013   // Allocate next chunk of data
   1014   if (!(15&pl->len))
   1015     ll = pl->ptr = xrealloc(pl->ptr, sizeof(long)*(pl->len+16));
   1016 
   1017   // Parse numerical input
   1018   if (isdigit(*str)) {
   1019     ll[pl->len] = xstrtol(str, &end, 10);
   1020     if (end==(len+str)) num++;
   1021     // For pkill, -s 0 represents pkill's session id.
   1022     if (pl==&TT.ss && ll[pl->len]==0) ll[pl->len] = getsid(0);
   1023   }
   1024 
   1025   if (pl==&TT.pp || pl==&TT.ss) {
   1026     if (num && ll[pl->len]>0) {
   1027       pl->len++;
   1028 
   1029       return 0;
   1030     }
   1031   } else if (pl==&TT.tt) {
   1032     // -t pts = 12,pts/12 tty = /dev/tty2,tty2,S0
   1033     if (!num) {
   1034       if (strstart(&str, strcpy(toybuf, "/dev/"))) len -= 5;
   1035       if (strstart(&str, "pts/")) {
   1036         len -= 4;
   1037         num++;
   1038       } else if (strstart(&str, "tty")) len -= 3;
   1039     }
   1040     if (len<256 && (!(end = strchr(str, '/')) || end-str>len)) {
   1041       struct stat st;
   1042 
   1043       end = toybuf + sprintf(toybuf, "/dev/%s", num ? "pts/" : "tty");
   1044       memcpy(end, str, len);
   1045       end[len] = 0;
   1046       xstat(toybuf, &st);
   1047       ll[pl->len++] = st.st_rdev;
   1048 
   1049       return 0;
   1050     }
   1051   } else if (len<255) {
   1052     char name[256];
   1053 
   1054     if (num) {
   1055       pl->len++;
   1056 
   1057       return 0;
   1058     }
   1059 
   1060     memcpy(name, str, len);
   1061     name[len] = 0;
   1062     if (pl==&TT.gg || pl==&TT.GG) {
   1063       struct group *gr = getgrnam(name);
   1064       if (gr) {
   1065         ll[pl->len++] = gr->gr_gid;
   1066 
   1067         return 0;
   1068       }
   1069     } else if (pl==&TT.uu || pl==&TT.UU) {
   1070       struct passwd *pw = getpwnam(name);
   1071       if (pw) {
   1072         ll[pl->len++] = pw->pw_uid;
   1073 
   1074         return 0;
   1075       }
   1076     }
   1077   }
   1078 
   1079   // Return error
   1080   return str;
   1081 }
   1082 
   1083 // sort for -k
   1084 static int ksort(void *aa, void *bb)
   1085 {
   1086   struct strawberry *field;
   1087   struct carveup *ta = *(struct carveup **)aa, *tb = *(struct carveup **)bb;
   1088   int ret = 0, slot;
   1089 
   1090   for (field = TT.kfields; field && !ret; field = field->next) {
   1091     slot = typos[field->which].slot;
   1092 
   1093     // Can we do numeric sort?
   1094     if (!(slot&64)) {
   1095       if (ta->slot[slot]<tb->slot[slot]) ret = -1;
   1096       if (ta->slot[slot]>tb->slot[slot]) ret = 1;
   1097     }
   1098 
   1099     // fallback to string sort
   1100     if (!ret) {
   1101       memccpy(toybuf, string_field(ta, field), 0, 2048);
   1102       toybuf[2048] = 0;
   1103       ret = strcmp(toybuf, string_field(tb, field));
   1104     }
   1105     ret *= field->reverse;
   1106   }
   1107 
   1108   return ret;
   1109 }
   1110 
   1111 static struct carveup **collate_leaves(struct carveup **tb, struct dirtree *dt)
   1112 {
   1113   while (dt) {
   1114     struct dirtree *next = dt->next;
   1115 
   1116     if (dt->extra) *(tb++) = (void *)dt->extra;
   1117     if (dt->child) tb = collate_leaves(tb, dt->child);
   1118     free(dt);
   1119     dt = next;
   1120   }
   1121 
   1122   return tb;
   1123 }
   1124 
   1125 static struct carveup **collate(int count, struct dirtree *dt)
   1126 {
   1127   struct carveup **tbsort = xmalloc(count*sizeof(struct carveup *));
   1128 
   1129   collate_leaves(tbsort, dt);
   1130 
   1131   return tbsort;
   1132 }
   1133 
   1134 static void default_ko(char *s, void *fields, char *err, struct arg_list *arg)
   1135 {
   1136   struct arg_list def;
   1137 
   1138   memset(&def, 0, sizeof(struct arg_list));
   1139   def.arg = s;
   1140   comma_args(arg ? arg : &def, fields, err, parse_ko);
   1141 }
   1142 
   1143 static void shared_main(void)
   1144 {
   1145   int i;
   1146 
   1147   TT.ticks = sysconf(_SC_CLK_TCK);
   1148   if (!TT.width) {
   1149     TT.width = 80;
   1150     TT.height = 25;
   1151     // If ps can't query terminal size pad to 80 but do -w
   1152     if (toys.which->name[1] == 's') {
   1153       if (!isatty(1) || !terminal_size(&TT.width, &TT.height))
   1154         toys.optflags |= FLAG_w;
   1155     }
   1156   }
   1157 
   1158   // find controlling tty, falling back to /dev/tty if none
   1159   for (i = 0; !TT.tty && i<4; i++) {
   1160     struct stat st;
   1161     int fd = i;
   1162 
   1163     if (i==3 && -1==(fd = open("/dev/tty", O_RDONLY))) break;
   1164 
   1165     if (isatty(fd) && !fstat(fd, &st)) TT.tty = st.st_rdev;
   1166     if (i==3) close(fd);
   1167   }
   1168 }
   1169 
   1170 void ps_main(void)
   1171 {
   1172   char **arg;
   1173   struct dirtree *dt;
   1174   char *not_o;
   1175   int i;
   1176 
   1177   shared_main();
   1178   if (toys.optflags&FLAG_w) TT.width = 99999;
   1179 
   1180   // parse command line options other than -o
   1181   comma_args(TT.ps.P, &TT.PP, "bad -P", parse_rest);
   1182   comma_args(TT.ps.p, &TT.pp, "bad -p", parse_rest);
   1183   comma_args(TT.ps.t, &TT.tt, "bad -t", parse_rest);
   1184   comma_args(TT.ps.s, &TT.ss, "bad -s", parse_rest);
   1185   comma_args(TT.ps.u, &TT.uu, "bad -u", parse_rest);
   1186   comma_args(TT.ps.U, &TT.UU, "bad -U", parse_rest);
   1187   comma_args(TT.ps.g, &TT.gg, "bad -g", parse_rest);
   1188   comma_args(TT.ps.G, &TT.GG, "bad -G", parse_rest);
   1189   comma_args(TT.ps.k, &TT.kfields, "bad -k", parse_ko);
   1190   dlist_terminate(TT.kfields);
   1191 
   1192   // It's undocumented, but traditionally extra arguments are extra -p args
   1193   for (arg = toys.optargs; *arg; arg++)
   1194     if (parse_rest(&TT.pp, *arg, strlen(*arg))) error_exit_raw(*arg);
   1195 
   1196   // Figure out which fields to display
   1197   not_o = "%sTTY,TIME,CMD";
   1198   if (toys.optflags&FLAG_f)
   1199     sprintf(not_o = toybuf+128,
   1200       "USER:12=UID,%%sPPID,%s,STIME,TTY,TIME,ARGS=CMD",
   1201       (toys.optflags&FLAG_T) ? "TCNT" : "C");
   1202   else if (toys.optflags&FLAG_l)
   1203     not_o = "F,S,UID,%sPPID,C,PRI,NI,BIT,SZ,WCHAN,TTY,TIME,CMD";
   1204   else if (CFG_TOYBOX_ON_ANDROID)
   1205     sprintf(not_o = toybuf+128,
   1206             "USER,%%sPPID,VSIZE,RSS,WCHAN:10,ADDR:10,S,%s",
   1207             (toys.optflags&FLAG_T) ? "CMD" : "NAME");
   1208   sprintf(toybuf, not_o, (toys.optflags & FLAG_T) ? "PID,TID," : "PID,");
   1209 
   1210   // Init TT.fields. This only uses toybuf if TT.ps.o is NULL
   1211   if (toys.optflags&FLAG_Z) default_ko("LABEL", &TT.fields, 0, 0);
   1212   default_ko(toybuf, &TT.fields, "bad -o", TT.ps.o);
   1213 
   1214   if (TT.ps.O) {
   1215     if (TT.fields) TT.fields = ((struct strawberry *)TT.fields)->prev;
   1216     comma_args(TT.ps.O, &TT.fields, "bad -O", parse_ko);
   1217     if (TT.fields) TT.fields = ((struct strawberry *)TT.fields)->next;
   1218   }
   1219   dlist_terminate(TT.fields);
   1220 
   1221   // -f and -n change the meaning of some fields
   1222   if (toys.optflags&(FLAG_f|FLAG_n)) {
   1223     struct strawberry *ever;
   1224 
   1225     for (ever = TT.fields; ever; ever = ever->next) {
   1226       if ((toys.optflags&FLAG_n) && ever->which>=PS_UID
   1227         && ever->which<=PS_RGROUP && (typos[ever->which].slot&64))
   1228           ever->which--;
   1229     }
   1230   }
   1231 
   1232   // Calculate seen fields bit array, and if we aren't deferring printing
   1233   // print headers now (for low memory/nommu systems).
   1234   TT.bits = get_headers(TT.fields, toybuf, sizeof(toybuf));
   1235   if (!(toys.optflags&FLAG_M)) printf("%.*s\n", TT.width, toybuf);
   1236   if (!(toys.optflags&(FLAG_k|FLAG_M))) TT.show_process = show_ps;
   1237   TT.match_process = ps_match_process;
   1238   dt = dirtree_flagread("/proc", DIRTREE_SHUTUP|DIRTREE_PROC,
   1239     ((toys.optflags&FLAG_T) || (TT.bits&(_PS_TID|_PS_TCNT)))
   1240       ? get_threads : get_ps);
   1241 
   1242   if ((dt != DIRTREE_ABORTVAL) && toys.optflags&(FLAG_k|FLAG_M)) {
   1243     struct carveup **tbsort = collate(TT.kcount, dt);
   1244 
   1245     if (toys.optflags&FLAG_M) {
   1246       for (i = 0; i<TT.kcount; i++) {
   1247         struct strawberry *field;
   1248 
   1249         for (field = TT.fields; field; field = field->next) {
   1250           int len = strlen(string_field(tbsort[i], field));
   1251 
   1252           if (abs(field->len)<len) field->len = (field->len<0) ? -len : len;
   1253         }
   1254       }
   1255 
   1256       // Now that we've recalculated field widths, re-pad headers again
   1257       get_headers(TT.fields, toybuf, sizeof(toybuf));
   1258       printf("%.*s\n", TT.width, toybuf);
   1259     }
   1260 
   1261     if (toys.optflags&FLAG_k)
   1262       qsort(tbsort, TT.kcount, sizeof(struct carveup *), (void *)ksort);
   1263     for (i = 0; i<TT.kcount; i++) {
   1264       show_ps(tbsort[i]);
   1265       free(tbsort[i]);
   1266     }
   1267     if (CFG_TOYBOX_FREE) free(tbsort);
   1268   }
   1269 
   1270   if (CFG_TOYBOX_FREE) {
   1271     free(TT.gg.ptr);
   1272     free(TT.GG.ptr);
   1273     free(TT.pp.ptr);
   1274     free(TT.PP.ptr);
   1275     free(TT.ss.ptr);
   1276     free(TT.tt.ptr);
   1277     free(TT.uu.ptr);
   1278     free(TT.UU.ptr);
   1279     llist_traverse(TT.fields, free);
   1280   }
   1281 }
   1282 
   1283 #define CLEANUP_ps
   1284 #define FOR_top
   1285 #include "generated/flags.h"
   1286 
   1287 // select which of the -o fields to sort by
   1288 static void setsort(int pos)
   1289 {
   1290   struct strawberry *field, *going2;
   1291   int i = 0;
   1292 
   1293   if (pos<0) pos = 0;
   1294 
   1295   for (field = TT.fields; field; field = field->next) {
   1296     if ((TT.sortpos = i++)<pos && field->next) continue;
   1297     going2 = TT.kfields;
   1298     going2->which = field->which;
   1299     going2->len = field->len;
   1300     break;
   1301   }
   1302 }
   1303 
   1304 // If we have both, adjust slot[deltas[]] to be relative to previous
   1305 // measurement rather than process start. Stomping old.data is fine
   1306 // because we free it after displaying.
   1307 static int merge_deltas(long long *oslot, long long *nslot, int milis)
   1308 {
   1309   char deltas[] = {SLOT_utime2, SLOT_iobytes, SLOT_diobytes, SLOT_rchar,
   1310                    SLOT_wchar, SLOT_rbytes, SLOT_wbytes, SLOT_swap};
   1311   int i;
   1312 
   1313   for (i = 0; i<ARRAY_LEN(deltas); i++)
   1314     oslot[deltas[i]] = nslot[deltas[i]] - oslot[deltas[i]];
   1315   oslot[SLOT_upticks] = (milis*TT.ticks)/1000;
   1316 
   1317   return 1;
   1318 }
   1319 
   1320 static int header_line(int line, int rev)
   1321 {
   1322   if (!line) return 0;
   1323 
   1324   if (toys.optflags&FLAG_b) rev = 0;
   1325 
   1326   printf("%s%*.*s%s\r\n", rev ? "\033[7m" : "",
   1327     (toys.optflags&FLAG_b) ? 0 : -TT.width, TT.width, toybuf,
   1328     rev ? "\033[0m" : "");
   1329 
   1330   return line-1;
   1331 }
   1332 
   1333 static long long millitime(void)
   1334 {
   1335   struct timespec ts;
   1336 
   1337   clock_gettime(CLOCK_MONOTONIC, &ts);
   1338   return ts.tv_sec*1000+ts.tv_nsec/1000000;
   1339 }
   1340 
   1341 static void top_common(
   1342   int (*filter)(long long *oslot, long long *nslot, int milis))
   1343 {
   1344   long long timeout = 0, now, stats[16];
   1345   struct proclist {
   1346     struct carveup **tb;
   1347     int count;
   1348     long long whence;
   1349   } plist[2], *plold, *plnew, old, new, mix;
   1350   char scratch[16], *pos, *cpufields[] = {"user", "nice", "sys", "idle",
   1351     "iow", "irq", "sirq", "host"};
   1352 
   1353   unsigned tock = 0;
   1354   int i, lines, topoff = 0, done = 0;
   1355 
   1356   toys.signal = SIGWINCH;
   1357   TT.bits = get_headers(TT.fields, toybuf, sizeof(toybuf));
   1358   *scratch = 0;
   1359   memset(plist, 0, sizeof(plist));
   1360   memset(stats, 0, sizeof(stats));
   1361   do {
   1362     struct dirtree *dt;
   1363     int recalc = 1;
   1364 
   1365     plold = plist+(tock++&1);
   1366     plnew = plist+(tock&1);
   1367     plnew->whence = millitime();
   1368     dt = dirtree_flagread("/proc", DIRTREE_SHUTUP|DIRTREE_PROC,
   1369       ((toys.optflags&FLAG_H) || (TT.bits&(_PS_TID|_PS_TCNT)))
   1370         ? get_threads : get_ps);
   1371     if (dt == DIRTREE_ABORTVAL) error_exit("no /proc");
   1372     plnew->tb = collate(plnew->count = TT.kcount, dt);
   1373     TT.kcount = 0;
   1374 
   1375     if (readfile("/proc/stat", pos = toybuf, sizeof(toybuf))) {
   1376       long long *st = stats+8*(tock&1);
   1377 
   1378       // user nice system idle iowait irq softirq host
   1379       sscanf(pos, "cpu %lld %lld %lld %lld %lld %lld %lld %lld",
   1380         st, st+1, st+2, st+3, st+4, st+5, st+6, st+7);
   1381     }
   1382 
   1383     // First time, wait a quarter of a second to collect a little delta data.
   1384     if (!plold->tb) {
   1385       msleep(250);
   1386       continue;
   1387     }
   1388 
   1389     // Collate old and new into "mix", depends on /proc read in pid sort order
   1390     old = *plold;
   1391     new = *plnew;
   1392     mix.tb = xmalloc((old.count+new.count)*sizeof(struct carveup));
   1393     mix.count = 0;
   1394 
   1395     while (old.count || new.count) {
   1396       struct carveup *otb = *old.tb, *ntb = *new.tb;
   1397 
   1398       // If we just have old for this process, it exited. Discard it.
   1399       if (old.count && (!new.count || *otb->slot < *ntb->slot)) {
   1400         old.tb++;
   1401         old.count--;
   1402 
   1403         continue;
   1404       }
   1405 
   1406       // If we just have new, use it verbatim
   1407       if (!old.count || *otb->slot > *ntb->slot) mix.tb[mix.count] = ntb;
   1408       else {
   1409         // Keep or discard
   1410         if (filter(otb->slot, ntb->slot, new.whence-old.whence)) {
   1411           mix.tb[mix.count] = otb;
   1412           mix.count++;
   1413         }
   1414         old.tb++;
   1415         old.count--;
   1416       }
   1417       new.tb++;
   1418       new.count--;
   1419     }
   1420 
   1421     // Don't re-fetch data if it's not time yet, just re-display existing data.
   1422     for (;;) {
   1423       char was, is;
   1424 
   1425       if (recalc) {
   1426         qsort(mix.tb, mix.count, sizeof(struct carveup *), (void *)ksort);
   1427         if (!(toys.optflags&FLAG_b)) {
   1428           printf("\033[H\033[J");
   1429           if (toys.signal) {
   1430             toys.signal = 0;
   1431             terminal_probesize(&TT.width, &TT.height);
   1432           }
   1433         }
   1434         lines = TT.height;
   1435       }
   1436       if (recalc && !(toys.optflags&FLAG_q)) {
   1437         // Display "top" header.
   1438         if (*toys.which->name == 't') {
   1439           struct strawberry alluc;
   1440           long long ll, up = 0;
   1441           long run[6];
   1442           int j;
   1443 
   1444           // Count running, sleeping, stopped, zombie processes.
   1445           alluc.which = PS_S;
   1446           memset(run, 0, sizeof(run));
   1447           for (i = 0; i<mix.count; i++)
   1448             run[1+stridx("RSTZ", *string_field(mix.tb[i], &alluc))]++;
   1449           sprintf(toybuf,
   1450             "Tasks: %d total,%4ld running,%4ld sleeping,%4ld stopped,"
   1451             "%4ld zombie", mix.count, run[1], run[2], run[3], run[4]);
   1452           lines = header_line(lines, 0);
   1453 
   1454           if (readfile("/proc/meminfo", toybuf, sizeof(toybuf))) {
   1455             for (i=0; i<6; i++) {
   1456               pos = strafter(toybuf, (char *[]){"MemTotal:","\nMemFree:",
   1457                     "\nBuffers:","\nCached:","\nSwapTotal:","\nSwapFree:"}[i]);
   1458               run[i] = pos ? atol(pos) : 0;
   1459             }
   1460             sprintf(toybuf,
   1461              "Mem:%10ldk total,%9ldk used,%9ldk free,%9ldk buffers",
   1462               run[0], run[0]-run[1], run[1], run[2]);
   1463             lines = header_line(lines, 0);
   1464             sprintf(toybuf,
   1465               "Swap:%9ldk total,%9ldk used,%9ldk free,%9ldk cached",
   1466               run[4], run[4]-run[5], run[5], run[3]);
   1467             lines = header_line(lines, 0);
   1468           }
   1469 
   1470           pos = toybuf;
   1471           i = sysconf(_SC_NPROCESSORS_CONF);
   1472           pos += sprintf(pos, "%d%%cpu", i*100);
   1473           j = 4+(i>10);
   1474 
   1475           // If a processor goes idle it's powered down and its idle ticks don't
   1476           // advance, so calculate idle time as potential time - used.
   1477           if (mix.count) up = mix.tb[0]->slot[SLOT_upticks];
   1478           if (!up) up = 1;
   1479           now = up*i;
   1480           ll = stats[3] = stats[11] = 0;
   1481           for (i = 0; i<8; i++) ll += stats[i]-stats[i+8];
   1482           stats[3] = now - llabs(ll);
   1483 
   1484           for (i = 0; i<8; i++) {
   1485             ll = (llabs(stats[i]-stats[i+8])*1000)/up;
   1486             pos += sprintf(pos, "% *lld%%%s", j, (ll+5)/10, cpufields[i]);
   1487           }
   1488           lines = header_line(lines, 0);
   1489         } else {
   1490           struct strawberry *fields;
   1491           struct carveup tb;
   1492 
   1493           memset(&tb, 0, sizeof(struct carveup));
   1494           pos = stpcpy(toybuf, "Totals:");
   1495           for (fields = TT.fields; fields; fields = fields->next) {
   1496             long long ll, bits = 0;
   1497             int slot = typos[fields->which].slot&63;
   1498 
   1499             if (fields->which<PS_C || fields->which>PS_DIO) continue;
   1500             ll = 1LL<<fields->which;
   1501             if (bits&ll) continue;
   1502             bits |= ll;
   1503             for (i=0; i<mix.count; i++)
   1504               tb.slot[slot] += mix.tb[i]->slot[slot];
   1505             pos += snprintf(pos, sizeof(toybuf)/2-(pos-toybuf),
   1506               " %s: %*s,", typos[fields->which].name,
   1507               fields->len, string_field(&tb, fields));
   1508           }
   1509           *--pos = 0;
   1510           lines = header_line(lines, 0);
   1511         }
   1512 
   1513         get_headers(TT.fields, pos = toybuf, sizeof(toybuf));
   1514         for (i = 0, is = ' '; *pos; pos++) {
   1515           was = is;
   1516           is = *pos;
   1517           if (isspace(was) && !isspace(is) && i++==TT.sortpos && pos!=toybuf)
   1518             pos[-1] = '[';
   1519           if (!isspace(was) && isspace(is) && i==TT.sortpos+1) *pos = ']';
   1520         }
   1521         *pos = 0;
   1522         lines = header_line(lines, 1);
   1523       }
   1524       if (!recalc && !(toys.optflags&FLAG_b))
   1525         printf("\033[%dH\033[J", 1+TT.height-lines);
   1526       recalc = 1;
   1527 
   1528       for (i = 0; i<lines && i+topoff<mix.count; i++) {
   1529         if (!(toys.optflags&FLAG_b) && i) xputc('\n');
   1530         show_ps(mix.tb[i+topoff]);
   1531       }
   1532 
   1533       if (TT.top.n && !--TT.top.n) {
   1534         done++;
   1535         break;
   1536       }
   1537 
   1538       now = millitime();
   1539       if (timeout<=now) timeout = new.whence+TT.top.d;
   1540       if (timeout<=now || timeout>now+TT.top.d) timeout = now+TT.top.d;
   1541 
   1542       // In batch mode, we ignore the keyboard.
   1543       if (toys.optflags&FLAG_b) {
   1544         msleep(timeout-now);
   1545         // Make an obvious gap between datasets.
   1546         xputs("\n\n");
   1547         continue;
   1548       }
   1549 
   1550       i = scan_key_getsize(scratch, timeout-now, &TT.width, &TT.height);
   1551       if (i==-1 || i==3 || toupper(i)=='Q') {
   1552         done++;
   1553         break;
   1554       }
   1555       if (i==-2) break;
   1556       if (i==-3) continue;
   1557 
   1558       // Flush unknown escape sequences.
   1559       if (i==27) while (0<scan_key_getsize(scratch, 0, &TT.width, &TT.height));
   1560       else if (i==' ') {
   1561         timeout = 0;
   1562         break;
   1563       } else if (toupper(i)=='R')
   1564         ((struct strawberry *)TT.kfields)->reverse *= -1;
   1565       else {
   1566         i -= 256;
   1567         if (i == KEY_LEFT) setsort(TT.sortpos-1);
   1568         else if (i == KEY_RIGHT) setsort(TT.sortpos+1);
   1569         // KEY_UP is 0, so at end of strchr
   1570         else if (strchr((char []){KEY_DOWN,KEY_PGUP,KEY_PGDN,KEY_UP}, i)) {
   1571           recalc = 0;
   1572 
   1573           if (i == KEY_UP) topoff--;
   1574           else if (i == KEY_DOWN) topoff++;
   1575           else if (i == KEY_PGDN) topoff += lines;
   1576           else if (i == KEY_PGUP) topoff -= lines;
   1577           if (topoff<0) topoff = 0;
   1578           if (topoff>mix.count) topoff = mix.count;
   1579         }
   1580       }
   1581       continue;
   1582     }
   1583 
   1584     free(mix.tb);
   1585     for (i=0; i<plold->count; i++) free(plold->tb[i]);
   1586     free(plold->tb);
   1587   } while (!done);
   1588 
   1589   if (!(toys.optflags&FLAG_b)) tty_reset();
   1590 }
   1591 
   1592 static void top_setup(char *defo, char *defk)
   1593 {
   1594   TT.top.d *= 1000;
   1595   if (toys.optflags&FLAG_b) TT.width = TT.height = 99999;
   1596   else {
   1597     TT.time = millitime();
   1598     set_terminal(0, 1, 0);
   1599     sigatexit(tty_sigreset);
   1600     xsignal(SIGWINCH, generic_signal);
   1601     printf("\033[?25l\033[0m");
   1602   }
   1603   shared_main();
   1604 
   1605   comma_args(TT.top.u, &TT.uu, "bad -u", parse_rest);
   1606   comma_args(TT.top.p, &TT.pp, "bad -p", parse_rest);
   1607   TT.match_process = shared_match_process;
   1608 
   1609   default_ko(defo, &TT.fields, "bad -o", TT.top.o);
   1610   dlist_terminate(TT.fields);
   1611 
   1612   // First (dummy) sort field is overwritten by setsort()
   1613   default_ko("-S", &TT.kfields, 0, 0);
   1614   default_ko(defk, &TT.kfields, "bad -k", TT.top.k);
   1615   dlist_terminate(TT.kfields);
   1616   setsort(TT.top.s-1);
   1617 }
   1618 
   1619 void top_main(void)
   1620 {
   1621   sprintf(toybuf, "PID,USER,%s%%CPU,%%MEM,TIME+,%s",
   1622     TT.top.O ? "" : "PR,NI,VIRT,RES,SHR,S,",
   1623     toys.optflags&FLAG_H ? "CMD:15=THREAD,NAME=PROCESS" : "ARGS");
   1624   if (!TT.top.s) TT.top.s = TT.top.O ? 3 : 9;
   1625   top_setup(toybuf, "-%CPU,-ETIME,-PID");
   1626   if (TT.top.O) {
   1627     struct strawberry *fields = TT.fields;
   1628 
   1629     fields = fields->next->next;
   1630     comma_args(TT.top.O, &fields, "bad -O", parse_ko);
   1631   }
   1632 
   1633   top_common(merge_deltas);
   1634 }
   1635 
   1636 #define CLEANUP_top
   1637 #define FOR_iotop
   1638 #include "generated/flags.h"
   1639 
   1640 static int iotop_filter(long long *oslot, long long *nslot, int milis)
   1641 {
   1642   if (!(toys.optflags&FLAG_a)) merge_deltas(oslot, nslot, milis);
   1643   else oslot[SLOT_upticks] = ((millitime()-TT.time)*TT.ticks)/1000;
   1644 
   1645   return !(toys.optflags&FLAG_o)||oslot[SLOT_iobytes+!(toys.optflags&FLAG_A)];
   1646 }
   1647 
   1648 void iotop_main(void)
   1649 {
   1650   char *s1 = 0, *s2 = 0, *d = "D"+!!(toys.optflags&FLAG_A);
   1651 
   1652   if (toys.optflags&FLAG_K) TT.forcek++;
   1653 
   1654   top_setup(s1 = xmprintf("PID,PR,USER,%sREAD,%sWRITE,SWAP,%sIO,COMM",d,d,d),
   1655     s2 = xmprintf("-%sIO,-ETIME,-PID",d));
   1656   free(s1);
   1657   free(s2);
   1658   top_common(iotop_filter);
   1659 }
   1660 
   1661 // pkill's plumbing wraps pgrep's and thus mostly takes place in pgrep's flag
   1662 // context, so force pgrep's flags on even when building pkill standalone.
   1663 // (All the pgrep/pkill functions drop out when building ps standalone.)
   1664 #define FORCE_FLAGS
   1665 #define CLEANUP_iotop
   1666 #define FOR_pgrep
   1667 #include "generated/flags.h"
   1668 
   1669 struct regex_list {
   1670   struct regex_list *next;
   1671   regex_t reg;
   1672 };
   1673 
   1674 static void do_pgk(struct carveup *tb)
   1675 {
   1676   if (TT.pgrep.signal) {
   1677     if (kill(*tb->slot, TT.pgrep.signal)) {
   1678       char *s = num_to_sig(TT.pgrep.signal);
   1679 
   1680       if (!s) sprintf(s = toybuf, "%d", TT.pgrep.signal);
   1681       perror_msg("%s->%lld", s, *tb->slot);
   1682     }
   1683   }
   1684   if (!(toys.optflags&FLAG_c) && (!TT.pgrep.signal || TT.tty)) {
   1685     printf("%lld", *tb->slot);
   1686     if (toys.optflags&FLAG_l)
   1687       printf(" %s", tb->str+tb->offset[4]*!!(toys.optflags&FLAG_f));
   1688 
   1689     printf("%s", TT.pgrep.d ? TT.pgrep.d : "\n");
   1690   }
   1691 }
   1692 
   1693 static void match_pgrep(void *p)
   1694 {
   1695   struct carveup *tb = p;
   1696   regmatch_t match;
   1697   struct regex_list *reg;
   1698   char *name = tb->str+tb->offset[4]*!!(toys.optflags&FLAG_f);;
   1699 
   1700   // Never match ourselves.
   1701   if (TT.pgrep.self == *tb->slot) return;
   1702 
   1703   if (TT.pgrep.regexes) {
   1704     for (reg = TT.pgrep.regexes; reg; reg = reg->next) {
   1705       if (regexec(&reg->reg, name, 1, &match, 0)) continue;
   1706       if (toys.optflags&FLAG_x)
   1707         if (match.rm_so || match.rm_eo!=strlen(name)) continue;
   1708       break;
   1709     }
   1710     if ((toys.optflags&FLAG_v) ? !!reg : !reg) return;
   1711   }
   1712 
   1713   // pgrep should return success if there's a match.
   1714   toys.exitval = 0;
   1715 
   1716   // Repurpose a field for -c count.
   1717   TT.sortpos++;
   1718   if (toys.optflags&(FLAG_n|FLAG_o)) {
   1719     long long ll = tb->slot[SLOT_starttime];
   1720 
   1721     if (toys.optflags&FLAG_o) ll *= -1;
   1722     if (TT.time && TT.time>ll) return;
   1723     TT.time = ll;
   1724     free(TT.pgrep.snapshot);
   1725     TT.pgrep.snapshot = xmemdup(toybuf, (name+strlen(name)+1)-toybuf);
   1726   } else do_pgk(tb);
   1727 }
   1728 
   1729 static int pgrep_match_process(long long *slot)
   1730 {
   1731   int match = shared_match_process(slot);
   1732 
   1733   return (toys.optflags&FLAG_v) ? !match : match;
   1734 }
   1735 
   1736 void pgrep_main(void)
   1737 {
   1738   char **arg;
   1739   struct regex_list *reg;
   1740 
   1741   TT.pgrep.self = getpid();
   1742 
   1743   // No signal names start with "L", so no need for "L: " parsing.
   1744   if (TT.pgrep.L && 1>(TT.pgrep.signal = sig_to_num(TT.pgrep.L)))
   1745     error_exit("bad -L '%s'", TT.pgrep.L);
   1746 
   1747   comma_args(TT.pgrep.G, &TT.GG, "bad -G", parse_rest);
   1748   comma_args(TT.pgrep.g, &TT.gg, "bad -g", parse_rest);
   1749   comma_args(TT.pgrep.P, &TT.PP, "bad -P", parse_rest);
   1750   comma_args(TT.pgrep.s, &TT.ss, "bad -s", parse_rest);
   1751   comma_args(TT.pgrep.t, &TT.tt, "bad -t", parse_rest);
   1752   comma_args(TT.pgrep.U, &TT.UU, "bad -U", parse_rest);
   1753   comma_args(TT.pgrep.u, &TT.uu, "bad -u", parse_rest);
   1754 
   1755   if ((toys.optflags&(FLAG_x|FLAG_f)) ||
   1756       !(toys.optflags&(FLAG_G|FLAG_g|FLAG_P|FLAG_s|FLAG_t|FLAG_U|FLAG_u)))
   1757     if (!toys.optc) help_exit("No PATTERN");
   1758 
   1759   if (toys.optflags&FLAG_f) TT.bits |= _PS_CMDLINE;
   1760   for (arg = toys.optargs; *arg; arg++) {
   1761     reg = xmalloc(sizeof(struct regex_list));
   1762     xregcomp(&reg->reg, *arg, REG_EXTENDED);
   1763     reg->next = TT.pgrep.regexes;
   1764     TT.pgrep.regexes = reg;
   1765   }
   1766   TT.match_process = pgrep_match_process;
   1767   TT.show_process = match_pgrep;
   1768 
   1769   // pgrep should return failure if there are no matches.
   1770   toys.exitval = 1;
   1771 
   1772   dirtree_flagread("/proc", DIRTREE_SHUTUP|DIRTREE_PROC, get_ps);
   1773   if (toys.optflags&FLAG_c) printf("%d\n", TT.sortpos);
   1774   if (TT.pgrep.snapshot) {
   1775     do_pgk(TT.pgrep.snapshot);
   1776     if (CFG_TOYBOX_FREE) free(TT.pgrep.snapshot);
   1777   }
   1778   if (TT.pgrep.d) xputc('\n');
   1779 }
   1780 
   1781 #define CLEANUP_pgrep
   1782 #define FOR_pkill
   1783 #include "generated/flags.h"
   1784 
   1785 void pkill_main(void)
   1786 {
   1787   char **args = toys.optargs;
   1788 
   1789   if (!(toys.optflags&FLAG_l) && *args && **args=='-') TT.pgrep.L = *(args++)+1;
   1790   if (!TT.pgrep.L) TT.pgrep.signal = SIGTERM;
   1791   if (toys.optflags & FLAG_V) TT.tty = 1;
   1792   pgrep_main();
   1793 }
   1794