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