OSDN Git Service

7741dcd33a5d8caf13a046c248e5025c85734425
[android-x86/external-toybox.git] / toys / posix / ps.c
1 /* ps.c - show process list
2  *
3  * Copyright 2015 Rob Landley <rob@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 fields selected for display, in order, with :len and =title */
290
291 struct strawberry {
292   struct strawberry *next, *prev;
293   short which, len, reverse;
294   char *title;
295   char forever[];
296 };
297
298 /* The function get_ps() reads all the data about one process, saving it in
299  * toybox as a struct carveup. Simple ps calls then pass toybuf directly to
300  * show_ps(), but features like sorting instead append a copy to a linked list
301  * for further processing once all processes have been read.
302  *
303  * struct carveup contains a slot[] array of 64 bit values, with the following
304  * data at each position in the array. Most is read from /proc/$PID/stat (see
305  * https://kernel.org/doc/Documentation/filesystems/proc.txt table 1-4) but
306  * we we replace several fields with don't use with other data. */
307
308 enum {
309  SLOT_pid,      /*process id*/            SLOT_ppid,      // parent process id
310  SLOT_pgrp,     /*process group*/         SLOT_sid,       // session id
311  SLOT_ttynr,    /*tty the process uses*/  SLOT_ttypgrp,   // pgrp of the tty
312  SLOT_flags,    /*task flags*/            SLOT_minflt,    // minor faults
313  SLOT_cminflt,  /*minor faults+child*/    SLOT_majflt,    // major faults
314  SLOT_cmajflt,  /*major faults+child*/    SLOT_utime,     // user+kernel jiffies
315  SLOT_stime,    /*kernel mode jiffies*/   SLOT_cutime,    // utime+child utime
316  SLOT_cstime,   /*stime+child*/           SLOT_priority,  // priority level
317  SLOT_nice,     /*nice level*/            SLOT_numthreads,// thread count
318  SLOT_vmlck,    /*locked memory*/         SLOT_starttime, // jiffies after boot
319  SLOT_vsize,    /*virtual memory size*/   SLOT_rss,       // resident set size
320  SLOT_rsslim,   /*limit in bytes on rss*/ SLOT_startcode, // code segment addr
321  SLOT_endcode,  /*code segment address*/  SLOT_startstack,// stack address
322  SLOT_esp,      /*task stack pointer*/    SLOT_eip,       // instruction pointer
323  SLOT_iobytes,  /*All I/O bytes*/         SLOT_diobytes,  // disk I/O bytes
324  SLOT_utime2,   /*relative utime (top)*/  SLOT_uid,       // user id
325  SLOT_ruid,     /*real user id*/          SLOT_gid,       // group id
326  SLOT_rgid,     /*real group id*/         SLOT_exitsig,   // sent to parent
327  SLOT_taskcpu,  /*CPU running on*/        SLOT_rtprio,    // realtime priority
328  SLOT_policy,   /*man sched_setscheduler*/SLOT_blkioticks,// IO wait time
329  SLOT_gtime,    /*guest jiffies of task*/ SLOT_cgtime,    // gtime+child
330  SLOT_startbss, /*data/bss address*/      SLOT_endbss,    // end addr data+bss
331  SLOT_upticks,  /*uptime-starttime*/      SLOT_argv0len,  // argv[0] length
332  SLOT_uptime,   /*si.uptime @read time*/  SLOT_vsz,       // Virtual mem Size
333  SLOT_rss2,     /*Resident Set Size*/     SLOT_shr,       // Shared memory
334  SLOT_rchar,    /*All bytes read*/        SLOT_wchar,     // All bytes written
335  SLOT_rbytes,   /*Disk bytes read*/       SLOT_wbytes,    // Disk bytes written
336  SLOT_swap,     /*Swap pages used*/       SLOT_bits,      // 32 or 64
337  SLOT_tid,      /*Thread ID*/             SLOT_tcount,    // Thread count
338  SLOT_pcy,      /*Android sched policy*/
339
340  SLOT_count /* Size of array */
341 };
342
343 /* In addition to slot[], carevup contains 6 string fields to display
344    command name, tty device, selinux label... They're stored one after the
345    other in str[] (separated by null terminators), and offset[] contains the
346    starting position of each string after the first (which is always 0). */
347
348 // Data layout in toybuf
349 struct carveup {
350   long long slot[SLOT_count]; // data (see enum above)
351   unsigned short offset[6];   // offset of fields in str[] (skip CMD, always 0)
352   char state;
353   char str[];                 // CMD, TTY, WCHAN, LABEL, COMM, ARGS, NAME
354 };
355
356 /* The typos[] array lists all the types understood by "ps -o", I.E all the
357  * columns ps and top know how to display. Each entry has:
358  *
359  * name: the column name, displayed at top and used to select column with -o
360  *
361  * width: the display width. Fields are padded to this width when displaying
362  *        to a terminal (negative means right justified). Strings are truncated
363  *        to fit, numerical fields are padded but not truncated (although
364  *        the display code reclaims unused padding from later fields to try to
365  *        get the overflow back).
366  *
367  * slot: which slot[] out of carveup. Negative means it's a string field.
368  *       Setting bit |64 requests extra display/sort processing.
369  *
370  * The TAGGED_ARRAY plumbing produces an enum of indexes, the "tag" is the
371  * first string argument and the prefix is the first argument to TAGGED_ARRAY
372  * so in this case "NAME" becomes PS_NAME which is the offset into typos[]
373  * for that entry, and also _PS_NAME (the bit position, 1<<PS_NAME).
374  * We record active columns in TT.bits, ala:
375  *
376  *   if (TT.bits & _PS_NAME) printf("-o included PS_NAME");
377  */
378
379 // TODO: Android uses -30 for LABEL, but ideally it would auto-size.
380 // 64|slot means compare as string when sorting
381 struct typography {
382   char *name;
383   signed char width, slot;
384 } static const typos[] = TAGGED_ARRAY(PS,
385   // Numbers. (What's in slot[] is what's displayed, sorted numerically.)
386   {"PID", 5, SLOT_pid}, {"PPID", 5, SLOT_ppid}, {"PRI", 3, SLOT_priority},
387   {"NI", 3, SLOT_nice}, {"ADDR", 4+sizeof(long), SLOT_eip},
388   {"SZ", 5, SLOT_vsize}, {"RSS", 6, SLOT_rss}, {"PGID", 5, SLOT_pgrp},
389   {"VSZ", 7, SLOT_vsize}, {"MAJFL", 6, SLOT_majflt}, {"MINFL", 6, SLOT_minflt},
390   {"PR", 2, SLOT_priority}, {"PSR", 3, SLOT_taskcpu},
391   {"RTPRIO", 6, SLOT_rtprio}, {"SCH", 3, SLOT_policy}, {"CPU", 3, SLOT_taskcpu},
392   {"TID", 5, SLOT_tid}, {"TCNT", 4, SLOT_tcount}, {"BIT", 3, SLOT_bits},
393
394   // String fields (-1 is carveup->str, rest are str+offset[1-slot])
395   {"TTY", -8, -2}, {"WCHAN", -6, -3}, {"LABEL", -30, -4}, {"COMM", -27, -5},
396   {"NAME", -27, -7}, {"COMMAND", -27, -5}, {"CMDLINE", -27, -6},
397   {"ARGS", -27, -6}, {"CMD", -15, -1},
398
399   // user/group (may call getpwuid() or similar)
400   {"UID", 5, SLOT_uid}, {"USER", -12, 64|SLOT_uid}, {"RUID", 4, SLOT_ruid},
401   {"RUSER", -8, 64|SLOT_ruid}, {"GID", 8, SLOT_gid}, {"GROUP", -8, 64|SLOT_gid},
402   {"RGID", 4, SLOT_rgid}, {"RGROUP", -8, 64|SLOT_rgid},
403
404   // clock displays (00:00:00)
405   {"TIME", 8, SLOT_utime}, {"ELAPSED", 11, SLOT_starttime},
406   {"TIME+", 9, SLOT_utime},
407
408   // Percentage displays (fixed point, one decimal digit. 123 -> 12.3)
409   {"C", 1, SLOT_utime2}, {"%VSZ", 5, SLOT_vsize}, {"%MEM", 5, SLOT_rss},
410   {"%CPU", 4, SLOT_utime2},
411
412   // human_readable (function human_readable() in lib, 1.23M, 1.4G, etc)
413   {"VIRT", 4, SLOT_vsz}, {"RES", 4, SLOT_rss2},
414   {"SHR", 4, SLOT_shr}, {"READ", 6, SLOT_rchar}, {"WRITE", 6, SLOT_wchar},
415   {"IO", 6, SLOT_iobytes}, {"DREAD", 6, SLOT_rbytes},
416   {"DWRITE", 6, SLOT_wbytes}, {"SWAP", 6, SLOT_swap}, {"DIO", 6, SLOT_diobytes},
417
418   // Misc (special cases)
419   {"STIME", 5, SLOT_starttime}, {"F", 1, 64|SLOT_flags}, {"S", -1, 64},
420   {"STAT", -5, 64}, {"PCY", 3, 64|SLOT_pcy},
421 );
422
423 // Return 0 to discard, nonzero to keep
424 static int shared_match_process(long long *slot)
425 {
426   struct ptr_len match[] = {
427     {&TT.gg, SLOT_gid}, {&TT.GG, SLOT_rgid}, {&TT.pp, SLOT_pid},
428     {&TT.PP, SLOT_ppid}, {&TT.ss, SLOT_sid}, {&TT.tt, SLOT_ttynr},
429     {&TT.uu, SLOT_uid}, {&TT.UU, SLOT_ruid}
430   };
431   int i, j;
432   long *ll = 0;
433
434   // Do we have -g -G -p -P -s -t -u -U options selecting processes?
435   for (i = 0; i < ARRAY_LEN(match); i++) {
436     struct ptr_len *mm = match[i].ptr;
437
438     if (mm->len) {
439       ll = mm->ptr;
440       for (j = 0; j<mm->len; j++) if (ll[j] == slot[match[i].len]) return 1;
441     }
442   }
443
444   return ll ? 0 : -1;
445 }
446
447
448 // Return 0 to discard, nonzero to keep
449 static int ps_match_process(long long *slot)
450 {
451   int i = shared_match_process(slot);
452
453   if (i>0) return 1;
454   // If we had selections and didn't match them, don't display
455   if (!i) return 0;
456
457   // Filter implicit categories for other display types
458   if ((toys.optflags&(FLAG_a|FLAG_d)) && slot[SLOT_sid]==*slot) return 0;
459   if ((toys.optflags&FLAG_a) && !slot[SLOT_ttynr]) return 0;
460   if (!(toys.optflags&(FLAG_a|FLAG_d|FLAG_A|FLAG_e))
461       && TT.tty!=slot[SLOT_ttynr]) return 0;
462
463   return 1;
464 }
465
466 // Convert field to string representation
467 static char *string_field(struct carveup *tb, struct strawberry *field)
468 {
469   char *buf = toybuf+sizeof(toybuf)-260, *out = buf, *s;
470   int which = field->which, sl = typos[which].slot;
471   long long *slot = tb->slot, ll = (sl >= 0) ? slot[sl&63] : 0;
472
473   // numbers, mostly from /proc/$PID/stat
474   if (which <= PS_BIT) {
475     char *fmt = "%lld";
476
477     if (which==PS_PRI) ll = 39-ll;
478     if (which==PS_ADDR) fmt = "%llx";
479     else if (which==PS_SZ) ll >>= 12;
480     else if (which==PS_RSS) ll <<= 2;
481     else if (which==PS_VSZ) ll >>= 10;
482     else if (which==PS_PR && ll<-9) fmt="RT";
483     else if ((which==PS_RTPRIO || which==PS_BIT) && ll == 0) fmt="-";
484     sprintf(out, fmt, ll);
485
486   // String fields
487   } else if (sl < 0) {
488     out = tb->str;
489     sl *= -1;
490     // First string slot has offset 0, others are offset[-slot-2]
491     if (--sl) out += tb->offset[--sl];
492     if (which==PS_ARGS || which==PS_COMM) {
493       int i;
494
495       s = out;
496       for (i = 0; (which==PS_ARGS) ? i < slot[SLOT_argv0len] : out[i]; i++)
497         if (out[i] == '/') s = out+i+1;
498       out = s;
499     }
500     if (which>=PS_COMM && !*out) sprintf(out = buf, "[%s]", tb->str);
501
502   // user/group
503   } else if (which <= PS_RGROUP) {
504     sprintf(out, "%lld", ll);
505     if (sl&64) {
506       if (which > PS_RUSER) {
507         struct group *gr = bufgetgrgid(ll);
508
509         if (gr) out = gr->gr_name;
510       } else {
511         struct passwd *pw = bufgetpwuid(ll);
512
513         if (pw) out = pw->pw_name;
514       }
515     }
516
517   // Clock displays
518   } else if (which <= PS_TIME_) {
519     int unit = 60, pad = 2, j = TT.ticks; 
520     time_t seconds;
521
522     if (which!=PS_TIME_) unit *= 60*24;
523     else pad = 0;
524     // top adjusts slot[SLOT_upticks], we want original meaning.
525     if (which==PS_ELAPSED) ll = (slot[SLOT_uptime]*j)-slot[SLOT_starttime];
526     seconds = ll/j;
527
528     // Output days-hours:mins:secs, skipping non-required fields with zero
529     // TIME has 3 required fields, ETIME has 2. (Posix!) TIME+ is from top
530     for (s = 0, j = 2*(which==PS_TIME_); j<4; j++) {
531       if (!s && (seconds>unit || j == 1+(which!=PS_TIME))) s = out;
532       if (s) {
533         s += sprintf(s, j ? "%0*ld": "%*ld", pad, (long)(seconds/unit));
534         pad = 2;
535         if ((*s = "-::"[j])) s++;
536       }
537       seconds %= unit;
538       unit /= j ? 60 : 24;
539     }
540     if (which==PS_TIME_ && s-out<8)
541       sprintf(s, ".%02lld", (100*(ll%TT.ticks))/TT.ticks);
542
543   // Percentage displays
544   } else if (which <= PS__CPU) {
545     ll = slot[sl&63]*1000;
546     if (which==PS__VSZ || which==PS__MEM)
547       ll /= TT.si.totalram/((which==PS__VSZ) ? 1024 : 4096);
548     else if (slot[SLOT_upticks]) ll /= slot[SLOT_upticks];
549     sl = ll;
550     if (which==PS_C) sl += 5;
551     sprintf(out, "%d", sl/10);
552     if (which!=PS_C && sl<1000) sprintf(out+strlen(out), ".%d", sl%10);
553
554   // Human readable
555   } else if (which <= PS_DIO) {
556     ll = slot[typos[which].slot];
557     if (which <= PS_SHR) ll *= sysconf(_SC_PAGESIZE);
558     if (TT.forcek) sprintf(out, "%lldk", ll/1024);
559     else human_readable(out, ll, 0);
560
561   // Posix doesn't specify what flags should say. Man page says
562   // 1 for PF_FORKNOEXEC and 4 for PF_SUPERPRIV from linux/sched.h
563   } else if (which==PS_F) sprintf(out, "%llo", (slot[SLOT_flags]>>6)&5);
564   else if (which==PS_S || which==PS_STAT) {
565     s = out;
566     *s++ = tb->state;
567     if (which==PS_STAT) {
568       // TODO l = multithreaded
569       if (slot[SLOT_nice]<0) *s++ = '<';
570       else if (slot[SLOT_nice]>0) *s++ = 'N';
571       if (slot[SLOT_sid]==*slot) *s++ = 's';
572       if (slot[SLOT_vmlck]) *s++ = 'L';
573       if (slot[SLOT_ttypgrp]==*slot) *s++ = '+';
574     } 
575     *s = 0;
576   } else if (which==PS_STIME) {
577     time_t t = time(0)-slot[SLOT_uptime]+slot[SLOT_starttime]/TT.ticks;
578
579     // Padding behavior's a bit odd: default field size is just hh:mm.
580     // Increasing stime:size reveals more data at left until full,
581     // so move start address so yyyy-mm-dd hh:mm revealed on left at :16,
582     // then add :ss on right for :19.
583     strftime(out, 260, "%F %T", localtime(&t));
584     out = out+strlen(out)-3-abs(field->len);
585     if (out<buf) out = buf;
586
587   } else if (which==PS_PCY) sprintf(out, "%.2s", get_sched_policy_name(ll));
588   else if (CFG_TOYBOX_DEBUG) error_exit("bad which %d", which);
589
590   return out;
591 }
592
593 // Display process data that get_ps() read from /proc, formatting with TT.fields
594 static void show_ps(void *p)
595 {
596   struct carveup *tb = p;
597   struct strawberry *field;
598   int pad, len, width = TT.width, abslen, sign, olen, extra = 0;
599
600   // Loop through fields to display
601   for (field = TT.fields; field; field = field->next) {
602     char *out = string_field(tb, field);
603
604     // Output the field, appropriately padded
605
606     // Minimum one space between each field
607     if (width<2) break;
608     if (field != TT.fields) {
609       putchar(' ');
610       width--;
611     }
612
613     // Don't truncate number fields, but try to reclaim extra offset from later
614     // fields that can naturally be shorter
615     abslen = abs(field->len);
616     sign = field->len<0 ? -1 : 1;
617     olen = (TT.tty) ? utf8len(out) : strlen(out);
618     if ((field->which<=PS_BIT || (toys.optflags&FLAG_w)) && olen>abslen) {
619       // overflow but remember by how much
620       extra += olen-abslen;
621       abslen = olen;
622     } else if (extra && olen<abslen) {
623       int unused = abslen-olen;
624
625       // If later fields have slack space, take back overflow
626       if (unused>extra) unused = extra;
627       abslen -= unused;
628       extra -= unused;
629     }
630     if (abslen>width) abslen = width;
631     len = pad = abslen;
632     pad *= sign;
633
634     // If last field is left justified, no trailing spaces.
635     if (!field->next && sign<0) {
636       pad = -1;
637       len = width;
638     }
639
640     // If we truncated a left-justified field, show + instead of last char
641     if (olen>len && len>1 && sign<0) {
642       width--;
643       len--;
644       if (field->next) pad++;
645       abslen = 0;
646     }
647
648     if (TT.tty) width -= draw_trim(out, pad, len);
649     else width -= printf("%*.*s", pad, len, out);
650     if (!abslen) putchar('+');
651     if (!width) break;
652   }
653   xputc(TT.time ? '\r' : '\n');
654 }
655
656 // dirtree callback: read data about process to display, store, or discard it.
657 // Fills toybuf with struct carveup and either DIRTREE_SAVEs a copy to ->extra
658 // (in -k mode) or calls show_ps on toybuf (no malloc/copy/free there).
659 static int get_ps(struct dirtree *new)
660 {
661   struct {
662     char *name;     // Path under /proc/$PID directory
663     long long bits; // Only fetch extra data if an -o field is displaying it
664   } fetch[] = {
665     // sources for carveup->offset[] data
666     {"fd/", _PS_TTY}, {"wchan", _PS_WCHAN}, {"attr/current", _PS_LABEL},
667     {"exe", _PS_COMMAND|_PS_COMM}, {"cmdline", _PS_CMDLINE|_PS_ARGS|_PS_NAME},
668     {"", _PS_NAME}
669   };
670   struct carveup *tb = (void *)toybuf;
671   long long *slot = tb->slot;
672   char *name, *s, *buf = tb->str, *end = 0;
673   int i, j, fd;
674   off_t len;
675
676   // Recurse one level into /proc children, skip non-numeric entries
677   if (!new->parent)
678     return DIRTREE_RECURSE|DIRTREE_SHUTUP|DIRTREE_PROC
679       |(DIRTREE_SAVE*(TT.threadparent||!TT.show_process));
680
681   memset(slot, 0, sizeof(tb->slot));
682   tb->slot[SLOT_tid] = *slot = atol(new->name);
683   if (TT.threadparent && TT.threadparent->extra) {
684     *slot = *(((struct carveup *)TT.threadparent->extra)->slot);
685     // Parent also shows up as a thread, discard duplicate
686     if (*slot == tb->slot[SLOT_tid]) return 0;
687   }
688   fd = dirtree_parentfd(new);
689
690   len = 2048;
691   sprintf(buf, "%lld/stat", *slot);
692   if (!readfileat(fd, buf, buf, &len)) return 0;
693
694   // parse oddball fields (name and state). Name can have embedded ')' so match
695   // _last_ ')' in stat (although VFS limits filenames to 255 bytes max).
696   // All remaining fields should be numeric.
697   if (!(name = strchr(buf, '('))) return 0;
698   for (s = ++name; *s; s++) if (*s == ')') end = s;
699   if (!end || end-name>255) return 0;
700
701   // Parse numeric fields (starting at 4th field in slot[SLOT_ppid])
702   if (1>sscanf(s = end, ") %c%n", &tb->state, &i)) return 0;
703   for (j = 1; j<SLOT_count; j++)
704     if (1>sscanf(s += i, " %lld%n", slot+j, &i)) break;
705
706   // Now we've read the data, move status and name right after slot[] array,
707   // and convert low chars to ? for non-tty display while we're at it.
708   for (i = 0; i<end-name; i++)
709     if ((tb->str[i] = name[i]) < ' ')
710       if (!TT.tty) tb->str[i] = '?';
711   buf = tb->str+i;
712   *buf++ = 0;
713   len = sizeof(toybuf)-(buf-toybuf);
714
715   // save uid, ruid, gid, gid, and rgid int slots 31-34 (we don't use sigcatch
716   // or numeric wchan, and the remaining two are always zero), and vmlck into
717   // 18 (which is "obsolete, always 0" from stat)
718   slot[SLOT_uid] = new->st.st_uid;
719   slot[SLOT_gid] = new->st.st_gid;
720
721   // TIME and TIME+ use combined value, ksort needs 'em added.
722   slot[SLOT_utime] += slot[SLOT_stime];
723   slot[SLOT_utime2] = slot[SLOT_utime];
724
725   // If RGROUP RUSER STAT RUID RGID SWAP happening, or -G or -U, parse "status"
726   // and save ruid, rgid, and vmlck.
727   if ((TT.bits&(_PS_RGROUP|_PS_RUSER|_PS_STAT|_PS_RUID|_PS_RGID|_PS_SWAP
728                |_PS_IO|_PS_DIO)) || TT.GG.len || TT.UU.len)
729   {
730     off_t temp = len;
731
732     sprintf(buf, "%lld/status", *slot);
733     if (!readfileat(fd, buf, buf, &temp)) *buf = 0;
734     s = strafter(buf, "\nUid:");
735     slot[SLOT_ruid] = s ? atol(s) : new->st.st_uid;
736     s = strafter(buf, "\nGid:");
737     slot[SLOT_rgid] = s ? atol(s) : new->st.st_gid;
738     if ((s = strafter(buf, "\nVmLck:"))) slot[SLOT_vmlck] = atoll(s);
739     if ((s = strafter(buf, "\nVmSwap:"))) slot[SLOT_swap] = atoll(s);
740   }
741
742   // Do we need to read "io"?
743   if (TT.bits&(_PS_READ|_PS_WRITE|_PS_DREAD|_PS_DWRITE|_PS_IO|_PS_DIO)) {
744     off_t temp = len;
745
746     sprintf(buf, "%lld/io", *slot);
747     if (!readfileat(fd, buf, buf, &temp)) *buf = 0;
748     if ((s = strafter(buf, "rchar:"))) slot[SLOT_rchar] = atoll(s);
749     if ((s = strafter(buf, "wchar:"))) slot[SLOT_wchar] = atoll(s);
750     if ((s = strafter(buf, "read_bytes:"))) slot[SLOT_rbytes] = atoll(s);
751     if ((s = strafter(buf, "write_bytes:"))) slot[SLOT_wbytes] = atoll(s);
752     slot[SLOT_iobytes] = slot[SLOT_rchar]+slot[SLOT_wchar]+slot[SLOT_swap];
753     slot[SLOT_diobytes] = slot[SLOT_rbytes]+slot[SLOT_wbytes]+slot[SLOT_swap];
754   }
755
756   // We now know enough to skip processes we don't care about.
757   if (TT.match_process && !TT.match_process(slot)) return 0;
758
759   // /proc data is generated as it's read, so for maximum accuracy on slow
760   // systems (or ps | more) we re-fetch uptime as we fetch each /proc line.
761   sysinfo(&TT.si);
762   slot[SLOT_uptime] = TT.si.uptime;
763   slot[SLOT_upticks] = slot[SLOT_uptime]*TT.ticks - slot[SLOT_starttime];
764
765   // Do we need to read "statm"?
766   if (TT.bits&(_PS_VIRT|_PS_RES|_PS_SHR)) {
767     off_t temp = len;
768
769     sprintf(buf, "%lld/statm", *slot);
770     if (!readfileat(fd, buf, buf, &temp)) *buf = 0;
771     
772     for (s = buf, i=0; i<3; i++)
773       if (!sscanf(s, " %lld%n", slot+SLOT_vsz+i, &j)) slot[SLOT_vsz+i] = 0;
774       else s += j;
775   }
776
777   // Do we need to read "exe"?
778   if (TT.bits&_PS_BIT) {
779     off_t temp = 6;
780
781     sprintf(buf, "%lld/exe", *slot);
782     if (readfileat(fd, buf, buf, &temp) && !memcmp(buf, "\177ELF", 4)) {
783       if (buf[4] == 1) slot[SLOT_bits] = 32;
784       else if (buf[4] == 2) slot[SLOT_bits] = 64;
785     }
786   }
787
788   // Do we need Android scheduling policy?
789   if (TT.bits&_PS_PCY) get_sched_policy(*slot, (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, fetch[j].name);
807
808     // For exe we readlink instead of read contents
809     if (j==3 || j==5) {
810       struct carveup *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 || tb->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, 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 carveup *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 strawberry *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, copy title
1002   field = xzalloc(sizeof(struct strawberry)+(length+1)*!!title);
1003   if (title) {
1004     memcpy(field->title = field->forever, title, length);
1005     field->title[field->len = length] = 0;
1006   }
1007
1008   if (width) {
1009     field->len = strtol(++width, &title, 10);
1010     if (!isdigit(*width) || title != end) return title;
1011     end = --width;
1012   }
1013
1014   // Find type
1015   field->reverse = 1;
1016   if (*type == '-') field->reverse = -1;
1017   else if (*type != '+') type--;
1018   type++;
1019   for (i = 0; i<ARRAY_LEN(typos); i++) {
1020     field->which = i;
1021     for (j = 0; j<2; j++) {
1022       if (!j) s = typos[i].name;
1023       // posix requires alternate names for some fields
1024       else if (-1==(k = stridx((char []){PS_NI, PS_SCH, PS_ELAPSED, PS__CPU,
1025         PS_VSZ, PS_USER, 0}, i))) continue;
1026       else
1027         s = ((char *[]){"NICE", "SCHED", "ETIME", "PCPU", "VSIZE", "UNAME"})[k];
1028
1029       if (!strncasecmp(type, s, end-type) && strlen(s)==end-type) break;
1030     }
1031     if (j!=2) break;
1032   }
1033   if (i==ARRAY_LEN(typos)) return type;
1034   if (!field->title) field->title = typos[field->which].name;
1035   if (!field->len) field->len = typos[field->which].width;
1036   else if (typos[field->which].width<0) field->len *= -1;
1037   dlist_add_nomalloc(data, (void *)field);
1038
1039   return 0;
1040 }
1041
1042 static long long get_headers(struct strawberry *fields, char *buf, int blen)
1043 {
1044   long long bits = 0;
1045   int len = 0;
1046
1047   for (; fields; fields = fields->next) {
1048     len += snprintf(buf+len, blen-len, " %*s"+!bits, fields->len,
1049       fields->title);
1050     bits |= 1LL<<fields->which;
1051   }
1052
1053   return bits;
1054 }
1055
1056 // Parse -p -s -t -u -U -g -G
1057 static char *parse_rest(void *data, char *str, int len)
1058 {
1059   struct ptr_len *pl = (struct ptr_len *)data;
1060   long *ll = pl->ptr;
1061   char *end;
1062   int num = 0;
1063
1064   // Allocate next chunk of data
1065   if (!(15&pl->len))
1066     ll = pl->ptr = xrealloc(pl->ptr, sizeof(long)*(pl->len+16));
1067
1068   // Parse numerical input
1069   if (isdigit(*str)) {
1070     ll[pl->len] = xstrtol(str, &end, 10);
1071     if (end==(len+str)) num++;
1072     // For pkill, -s 0 represents pkill's session id.
1073     if (pl==&TT.ss && ll[pl->len]==0) ll[pl->len] = getsid(0);
1074   }
1075
1076   if (pl==&TT.pp || pl==&TT.ss) {
1077     if (num && ll[pl->len]>0) {
1078       pl->len++;
1079
1080       return 0;
1081     }
1082   } else if (pl==&TT.tt) {
1083     // -t pts = 12,pts/12 tty = /dev/tty2,tty2,S0
1084     if (!num) {
1085       if (strstart(&str, strcpy(toybuf, "/dev/"))) len -= 5;
1086       if (strstart(&str, "pts/")) {
1087         len -= 4;
1088         num++;
1089       } else if (strstart(&str, "tty")) len -= 3;
1090     }
1091     if (len<256 && (!(end = strchr(str, '/')) || end-str>len)) {
1092       struct stat st;
1093
1094       end = toybuf + sprintf(toybuf, "/dev/%s", num ? "pts/" : "tty");
1095       memcpy(end, str, len);
1096       end[len] = 0;
1097       xstat(toybuf, &st);
1098       ll[pl->len++] = st.st_rdev;
1099
1100       return 0;
1101     }
1102   } else if (len<255) {
1103     char name[256];
1104
1105     if (num) {
1106       pl->len++;
1107
1108       return 0;
1109     }
1110
1111     memcpy(name, str, len);
1112     name[len] = 0;
1113     if (pl==&TT.gg || pl==&TT.GG) {
1114       struct group *gr = getgrnam(name);
1115       if (gr) {
1116         ll[pl->len++] = gr->gr_gid;
1117
1118         return 0;
1119       }
1120     } else if (pl==&TT.uu || pl==&TT.UU) {
1121       struct passwd *pw = getpwnam(name);
1122       if (pw) {
1123         ll[pl->len++] = pw->pw_uid;
1124
1125         return 0;
1126       }
1127     }
1128   }
1129
1130   // Return error
1131   return str;
1132 }
1133
1134 // sort for -k
1135 static int ksort(void *aa, void *bb)
1136 {
1137   struct strawberry *field;
1138   struct carveup *ta = *(struct carveup **)aa, *tb = *(struct carveup **)bb;
1139   int ret = 0, slot;
1140
1141   for (field = TT.kfields; field && !ret; field = field->next) {
1142     slot = typos[field->which].slot;
1143
1144     // Can we do numeric sort?
1145     if (!(slot&64)) {
1146       if (ta->slot[slot]<tb->slot[slot]) ret = -1;
1147       if (ta->slot[slot]>tb->slot[slot]) ret = 1;
1148     }
1149
1150     // fallback to string sort
1151     if (!ret) {
1152       memccpy(toybuf, string_field(ta, field), 0, 2048);
1153       toybuf[2048] = 0;
1154       ret = strcmp(toybuf, string_field(tb, field));
1155     }
1156     ret *= field->reverse;
1157   }
1158
1159   return ret;
1160 }
1161
1162 static struct carveup **collate_leaves(struct carveup **tb, struct dirtree *dt) 
1163 {
1164   while (dt) {
1165     struct dirtree *next = dt->next;
1166
1167     if (dt->extra) *(tb++) = (void *)dt->extra;
1168     if (dt->child) tb = collate_leaves(tb, dt->child);
1169     free(dt);
1170     dt = next;
1171   }
1172
1173   return tb;
1174 }
1175
1176 static struct carveup **collate(int count, struct dirtree *dt)
1177 {
1178   struct carveup **tbsort = xmalloc(count*sizeof(struct carveup *));
1179
1180   collate_leaves(tbsort, dt);
1181
1182   return tbsort;
1183
1184
1185 static void default_ko(char *s, void *fields, char *err, struct arg_list *arg)
1186 {
1187   struct arg_list def;
1188
1189   memset(&def, 0, sizeof(struct arg_list));
1190   def.arg = s;
1191   comma_args(arg ? arg : &def, fields, err, parse_ko);
1192 }
1193
1194 void ps_main(void)
1195 {
1196   char **arg;
1197   struct dirtree *dt;
1198   char *not_o;
1199   int i;
1200
1201   TT.ticks = sysconf(_SC_CLK_TCK); // units for starttime/uptime
1202
1203   if (-1 != (i = tty_fd())) {
1204     struct stat st;
1205
1206     if (!fstat(i, &st)) TT.tty = st.st_rdev;
1207   }
1208
1209   // If we can't query terminal size pad to 80 but do -w
1210   TT.width = 80;
1211   if (!isatty(1) || !terminal_size(&TT.width, 0))
1212     toys.optflags |= FLAG_w;
1213   if (toys.optflags&FLAG_w) TT.width = 99999;
1214
1215   // parse command line options other than -o
1216   comma_args(TT.ps.P, &TT.PP, "bad -P", parse_rest);
1217   comma_args(TT.ps.p, &TT.pp, "bad -p", parse_rest);
1218   comma_args(TT.ps.t, &TT.tt, "bad -t", parse_rest);
1219   comma_args(TT.ps.s, &TT.ss, "bad -s", parse_rest);
1220   comma_args(TT.ps.u, &TT.uu, "bad -u", parse_rest);
1221   comma_args(TT.ps.U, &TT.UU, "bad -U", parse_rest);
1222   comma_args(TT.ps.g, &TT.gg, "bad -g", parse_rest);
1223   comma_args(TT.ps.G, &TT.GG, "bad -G", parse_rest);
1224   comma_args(TT.ps.k, &TT.kfields, "bad -k", parse_ko);
1225   dlist_terminate(TT.kfields);
1226
1227   // It's undocumented, but traditionally extra arguments are extra -p args
1228   for (arg = toys.optargs; *arg; arg++)
1229     if (parse_rest(&TT.pp, *arg, strlen(*arg))) error_exit_raw(*arg);
1230
1231   // Figure out which fields to display
1232   not_o = "%sTTY,TIME,CMD";
1233   if (toys.optflags&FLAG_f)
1234     sprintf(not_o = toybuf+128,
1235       "USER:12=UID,%%sPPID,%s,STIME,TTY,TIME,ARGS=CMD",
1236       (toys.optflags&FLAG_T) ? "TCNT" : "C");
1237   else if (toys.optflags&FLAG_l)
1238     not_o = "F,S,UID,%sPPID,C,PRI,NI,BIT,SZ,WCHAN,TTY,TIME,CMD";
1239   else if (CFG_TOYBOX_ON_ANDROID)
1240     sprintf(not_o = toybuf+128,
1241             "USER,%%sPPID,VSIZE,RSS,WCHAN:10,ADDR:10,S,%s",
1242             (toys.optflags&FLAG_T) ? "CMD" : "NAME");
1243   sprintf(toybuf, not_o, (toys.optflags & FLAG_T) ? "PID,TID," : "PID,");
1244
1245   // Init TT.fields. This only uses toybuf if TT.ps.o is NULL
1246   if (toys.optflags&FLAG_Z) default_ko("LABEL", &TT.fields, 0, 0);
1247   default_ko(toybuf, &TT.fields, "bad -o", TT.ps.o);
1248
1249   if (TT.ps.O) {
1250     if (TT.fields) TT.fields = ((struct strawberry *)TT.fields)->prev;
1251     comma_args(TT.ps.O, &TT.fields, "bad -O", parse_ko);
1252     if (TT.fields) TT.fields = ((struct strawberry *)TT.fields)->next;
1253   }
1254   dlist_terminate(TT.fields);
1255
1256   // -f and -n change the meaning of some fields
1257   if (toys.optflags&(FLAG_f|FLAG_n)) {
1258     struct strawberry *ever;
1259
1260     for (ever = TT.fields; ever; ever = ever->next) {
1261       if ((toys.optflags&FLAG_n) && ever->which>=PS_UID
1262         && ever->which<=PS_RGROUP && (typos[ever->which].slot&64))
1263           ever->which--;
1264     }
1265   }
1266
1267   // Calculate seen fields bit array, and if we aren't deferring printing
1268   // print headers now (for low memory/nommu systems).
1269   TT.bits = get_headers(TT.fields, toybuf, sizeof(toybuf));
1270   if (!(toys.optflags&FLAG_M)) printf("%.*s\n", TT.width, toybuf);
1271   if (!(toys.optflags&(FLAG_k|FLAG_M))) TT.show_process = show_ps;
1272   TT.match_process = ps_match_process;
1273   dt = dirtree_flagread("/proc", DIRTREE_SHUTUP|DIRTREE_PROC,
1274     ((toys.optflags&FLAG_T) || (TT.bits&(_PS_TID|_PS_TCNT)))
1275       ? get_threads : get_ps);
1276
1277   if ((dt != DIRTREE_ABORTVAL) && toys.optflags&(FLAG_k|FLAG_M)) {
1278     struct carveup **tbsort = collate(TT.kcount, dt);
1279
1280     if (toys.optflags&FLAG_M) {
1281       for (i = 0; i<TT.kcount; i++) {
1282         struct strawberry *field;
1283
1284         for (field = TT.fields; field; field = field->next) {
1285           int len = strlen(string_field(tbsort[i], field));
1286
1287           if (abs(field->len)<len) field->len = (field->len<0) ? -len : len;
1288         }
1289       }
1290
1291       // Now that we've recalculated field widths, re-pad headers again
1292       get_headers(TT.fields, toybuf, sizeof(toybuf));
1293       printf("%.*s\n", TT.width, toybuf);
1294     }
1295
1296     if (toys.optflags&FLAG_k)
1297       qsort(tbsort, TT.kcount, sizeof(struct carveup *), (void *)ksort);
1298     for (i = 0; i<TT.kcount; i++) {
1299       show_ps(tbsort[i]);
1300       free(tbsort[i]);
1301     }
1302     if (CFG_TOYBOX_FREE) free(tbsort);
1303   }
1304
1305   if (CFG_TOYBOX_FREE) {
1306     free(TT.gg.ptr);
1307     free(TT.GG.ptr);
1308     free(TT.pp.ptr);
1309     free(TT.PP.ptr);
1310     free(TT.ss.ptr);
1311     free(TT.tt.ptr);
1312     free(TT.uu.ptr);
1313     free(TT.UU.ptr);
1314     llist_traverse(TT.fields, free);
1315   }
1316 }
1317
1318 #define CLEANUP_ps
1319 #define FOR_top
1320 #include "generated/flags.h"
1321
1322 // select which of the -o fields to sort by
1323 static void setsort(int pos)
1324 {
1325   struct strawberry *field, *going2;
1326   int i = 0;
1327
1328   if (pos<0) pos = 0;
1329
1330   for (field = TT.fields; field; field = field->next) {
1331     if ((TT.sortpos = i++)<pos && field->next) continue;
1332     going2 = TT.kfields;
1333     going2->which = field->which;
1334     going2->len = field->len;
1335     break;
1336   }
1337 }
1338
1339 // If we have both, adjust slot[deltas[]] to be relative to previous
1340 // measurement rather than process start. Stomping old.data is fine
1341 // because we free it after displaying.
1342 static int merge_deltas(long long *oslot, long long *nslot, int milis)
1343 {
1344   char deltas[] = {SLOT_utime2, SLOT_iobytes, SLOT_diobytes, SLOT_rchar,
1345                    SLOT_wchar, SLOT_rbytes, SLOT_wbytes, SLOT_swap};
1346   int i;
1347
1348   for (i = 0; i<ARRAY_LEN(deltas); i++)
1349     oslot[deltas[i]] = nslot[deltas[i]] - oslot[deltas[i]];
1350   oslot[SLOT_upticks] = (milis*TT.ticks)/1000;
1351
1352   return 1;
1353 }
1354
1355 static int header_line(int line, int rev)
1356 {
1357   if (!line) return 0;
1358
1359   if (toys.optflags&FLAG_b) rev = 0;
1360
1361   printf("%s%*.*s%s\r\n", rev ? "\033[7m" : "",
1362     (toys.optflags&FLAG_b) ? 0 : -TT.width, TT.width, toybuf,
1363     rev ? "\033[0m" : "");
1364
1365   return line-1;
1366 }
1367
1368 static void top_common(
1369   int (*filter)(long long *oslot, long long *nslot, int milis))
1370 {
1371   long long timeout = 0, now, stats[16];
1372   struct proclist {
1373     struct carveup **tb;
1374     int count;
1375     long long whence;
1376   } plist[2], *plold, *plnew, old, new, mix;
1377   char scratch[16], *pos, *cpufields[] = {"user", "nice", "sys", "idle",
1378     "iow", "irq", "sirq", "host"};
1379  
1380   unsigned tock = 0;
1381   int i, lines, topoff = 0, done = 0;
1382
1383   toys.signal = SIGWINCH;
1384   TT.bits = get_headers(TT.fields, toybuf, sizeof(toybuf));
1385   *scratch = 0;
1386   memset(plist, 0, sizeof(plist));
1387   memset(stats, 0, sizeof(stats));
1388   do {
1389     struct dirtree *dt;
1390     int recalc = 1;
1391
1392     plold = plist+(tock++&1);
1393     plnew = plist+(tock&1);
1394     plnew->whence = millitime();
1395     dt = dirtree_flagread("/proc", DIRTREE_SHUTUP|DIRTREE_PROC,
1396       ((toys.optflags&FLAG_H) || (TT.bits&(_PS_TID|_PS_TCNT)))
1397         ? get_threads : get_ps);
1398     if (dt == DIRTREE_ABORTVAL) error_exit("no /proc");
1399     plnew->tb = collate(plnew->count = TT.kcount, dt);
1400     TT.kcount = 0;
1401
1402     if (readfile("/proc/stat", pos = toybuf, sizeof(toybuf))) {
1403       long long *st = stats+8*(tock&1);
1404
1405       // user nice system idle iowait irq softirq host
1406       sscanf(pos, "cpu %lld %lld %lld %lld %lld %lld %lld %lld",
1407         st, st+1, st+2, st+3, st+4, st+5, st+6, st+7);
1408     }
1409
1410     // First time, wait a quarter of a second to collect a little delta data.
1411     if (!plold->tb) {
1412       msleep(250);
1413       continue;
1414     }
1415
1416     // Collate old and new into "mix", depends on /proc read in pid sort order
1417     old = *plold;
1418     new = *plnew;
1419     mix.tb = xmalloc((old.count+new.count)*sizeof(struct carveup));
1420     mix.count = 0;
1421
1422     while (old.count || new.count) {
1423       struct carveup *otb = *old.tb, *ntb = *new.tb;
1424
1425       // If we just have old for this process, it exited. Discard it.
1426       if (old.count && (!new.count || *otb->slot < *ntb->slot)) {
1427         old.tb++;
1428         old.count--;
1429
1430         continue;
1431       }
1432
1433       // If we just have new, use it verbatim
1434       if (!old.count || *otb->slot > *ntb->slot) mix.tb[mix.count] = ntb;
1435       else {
1436         // Keep or discard
1437         if (filter(otb->slot, ntb->slot, new.whence-old.whence)) {
1438           mix.tb[mix.count] = otb;
1439           mix.count++;
1440         }
1441         old.tb++;
1442         old.count--;
1443       }
1444       new.tb++;
1445       new.count--;
1446     }
1447
1448     // Don't re-fetch data if it's not time yet, just re-display existing data.
1449     for (;;) {
1450       char was, is;
1451
1452       if (recalc) {
1453         qsort(mix.tb, mix.count, sizeof(struct carveup *), (void *)ksort);
1454         if (!(toys.optflags&FLAG_b)) {
1455           printf("\033[H\033[J");
1456           if (toys.signal) {
1457             toys.signal = 0;
1458             terminal_probesize(&TT.width, &TT.height);
1459           }
1460         }
1461         if (TT.top.m) TT.height = TT.top.m+5;
1462         lines = TT.height;
1463       }
1464       if (recalc && !(toys.optflags&FLAG_q)) {
1465         // Display "top" header.
1466         if (*toys.which->name == 't') {
1467           struct strawberry alluc;
1468           long long ll, up = 0;
1469           long run[6];
1470           int j;
1471
1472           // Count running, sleeping, stopped, zombie processes.
1473           alluc.which = PS_S;
1474           memset(run, 0, sizeof(run));
1475           for (i = 0; i<mix.count; i++)
1476             run[1+stridx("RSTZ", *string_field(mix.tb[i], &alluc))]++;
1477           sprintf(toybuf,
1478             "Tasks: %d total,%4ld running,%4ld sleeping,%4ld stopped,"
1479             "%4ld zombie", mix.count, run[1], run[2], run[3], run[4]);
1480           lines = header_line(lines, 0);
1481
1482           if (readfile("/proc/meminfo", toybuf, sizeof(toybuf))) {
1483             for (i=0; i<6; i++) {
1484               pos = strafter(toybuf, (char *[]){"MemTotal:","\nMemFree:",
1485                     "\nBuffers:","\nCached:","\nSwapTotal:","\nSwapFree:"}[i]);
1486               run[i] = pos ? atol(pos) : 0;
1487             }
1488             sprintf(toybuf,
1489              "Mem:%10ldk total,%9ldk used,%9ldk free,%9ldk buffers",
1490               run[0], run[0]-run[1], run[1], run[2]);
1491             lines = header_line(lines, 0);
1492             sprintf(toybuf,
1493               "Swap:%9ldk total,%9ldk used,%9ldk free,%9ldk cached",
1494               run[4], run[4]-run[5], run[5], run[3]);
1495             lines = header_line(lines, 0);
1496           }
1497
1498           pos = toybuf;
1499           i = sysconf(_SC_NPROCESSORS_CONF);
1500           pos += sprintf(pos, "%d%%cpu", i*100);
1501           j = 4+(i>10);
1502
1503           // If a processor goes idle it's powered down and its idle ticks don't
1504           // advance, so calculate idle time as potential time - used.
1505           if (mix.count) up = mix.tb[0]->slot[SLOT_upticks];
1506           if (!up) up = 1;
1507           now = up*i;
1508           ll = stats[3] = stats[11] = 0;
1509           for (i = 0; i<8; i++) ll += stats[i]-stats[i+8];
1510           stats[3] = now - llabs(ll);
1511
1512           for (i = 0; i<8; i++) {
1513             ll = (llabs(stats[i]-stats[i+8])*1000)/up;
1514             pos += sprintf(pos, "% *lld%%%s", j, (ll+5)/10, cpufields[i]);
1515           }
1516           lines = header_line(lines, 0);
1517         } else {
1518           struct strawberry *fields;
1519           struct carveup tb;
1520
1521           memset(&tb, 0, sizeof(struct carveup));
1522           pos = stpcpy(toybuf, "Totals:");
1523           for (fields = TT.fields; fields; fields = fields->next) {
1524             long long ll, bits = 0;
1525             int slot = typos[fields->which].slot&63;
1526
1527             if (fields->which<PS_C || fields->which>PS_DIO) continue;
1528             ll = 1LL<<fields->which;
1529             if (bits&ll) continue;
1530             bits |= ll;
1531             for (i=0; i<mix.count; i++)
1532               tb.slot[slot] += mix.tb[i]->slot[slot];
1533             pos += snprintf(pos, sizeof(toybuf)/2-(pos-toybuf),
1534               " %s: %*s,", typos[fields->which].name,
1535               fields->len, string_field(&tb, fields));
1536           }
1537           *--pos = 0;
1538           lines = header_line(lines, 0);
1539         }
1540
1541         get_headers(TT.fields, pos = toybuf, sizeof(toybuf));
1542         for (i = 0, is = ' '; *pos; pos++) {
1543           was = is;
1544           is = *pos;
1545           if (isspace(was) && !isspace(is) && i++==TT.sortpos && pos!=toybuf)
1546             pos[-1] = '[';
1547           if (!isspace(was) && isspace(is) && i==TT.sortpos+1) *pos = ']';
1548         }
1549         *pos = 0;
1550         lines = header_line(lines, 1);
1551       }
1552       if (!recalc && !(toys.optflags&FLAG_b))
1553         printf("\033[%dH\033[J", 1+TT.height-lines);
1554       recalc = 1;
1555
1556       for (i = 0; i<lines && i+topoff<mix.count; i++) {
1557         if (!(toys.optflags&FLAG_b) && i) xputc('\n');
1558         show_ps(mix.tb[i+topoff]);
1559       }
1560
1561       if (TT.top.n && !--TT.top.n) {
1562         done++;
1563         break;
1564       }
1565
1566       now = millitime();
1567       if (timeout<=now) timeout = new.whence+TT.top.d;
1568       if (timeout<=now || timeout>now+TT.top.d) timeout = now+TT.top.d;
1569
1570       // In batch mode, we ignore the keyboard.
1571       if (toys.optflags&FLAG_b) {
1572         msleep(timeout-now);
1573         // Make an obvious gap between datasets.
1574         xputs("\n\n");
1575         continue;
1576       }
1577
1578       i = scan_key_getsize(scratch, timeout-now, &TT.width, &TT.height);
1579       if (i==-1 || i==3 || toupper(i)=='Q') {
1580         done++;
1581         break;
1582       }
1583       if (i==-2) break;
1584       if (i==-3) continue;
1585
1586       // Flush unknown escape sequences.
1587       if (i==27) while (0<scan_key_getsize(scratch, 0, &TT.width, &TT.height));
1588       else if (i==' ') {
1589         timeout = 0;
1590         break;
1591       } else if (toupper(i)=='R')
1592         ((struct strawberry *)TT.kfields)->reverse *= -1;
1593       else {
1594         i -= 256;
1595         if (i == KEY_LEFT) setsort(TT.sortpos-1);
1596         else if (i == KEY_RIGHT) setsort(TT.sortpos+1);
1597         // KEY_UP is 0, so at end of strchr
1598         else if (strchr((char []){KEY_DOWN,KEY_PGUP,KEY_PGDN,KEY_UP}, i)) {
1599           recalc = 0;
1600
1601           if (i == KEY_UP) topoff--;
1602           else if (i == KEY_DOWN) topoff++;
1603           else if (i == KEY_PGDN) topoff += lines;
1604           else if (i == KEY_PGUP) topoff -= lines;
1605           if (topoff<0) topoff = 0; 
1606           if (topoff>mix.count) topoff = mix.count;
1607         }
1608       }
1609       continue;
1610     }
1611
1612     free(mix.tb);
1613     for (i=0; i<plold->count; i++) free(plold->tb[i]);
1614     free(plold->tb);
1615   } while (!done);
1616
1617   if (!(toys.optflags&FLAG_b)) tty_reset();
1618 }
1619
1620 static void top_setup(char *defo, char *defk)
1621 {
1622   TT.top.d *= 1000;
1623
1624   TT.ticks = sysconf(_SC_CLK_TCK); // units for starttime/uptime
1625   TT.tty = tty_fd() != -1;
1626
1627   // Are we doing "batch" output or interactive?
1628   if (toys.optflags&FLAG_b) TT.width = TT.height = 99999;
1629   else {
1630     // Grab starting time, make terminal raw, switch off cursor,
1631     // set signal handler to put terminal/cursor back to normal at exit.
1632     TT.time = millitime();
1633     set_terminal(0, 1, 0);
1634     sigatexit(tty_sigreset);
1635     xsignal(SIGWINCH, generic_signal);
1636     printf("\033[?25l\033[0m");
1637     TT.width = 80;
1638     TT.height = 25;
1639   }
1640
1641   comma_args(TT.top.u, &TT.uu, "bad -u", parse_rest);
1642   comma_args(TT.top.p, &TT.pp, "bad -p", parse_rest);
1643   TT.match_process = shared_match_process;
1644
1645   default_ko(defo, &TT.fields, "bad -o", TT.top.o);
1646   dlist_terminate(TT.fields);
1647
1648   // First (dummy) sort field is overwritten by setsort()
1649   default_ko("-S", &TT.kfields, 0, 0);
1650   default_ko(defk, &TT.kfields, "bad -k", TT.top.k);
1651   dlist_terminate(TT.kfields);
1652   setsort(TT.top.s-1);
1653 }
1654
1655 void top_main(void)
1656 {
1657   sprintf(toybuf, "PID,USER,%s%%CPU,%%MEM,TIME+,%s",
1658     TT.top.O ? "" : "PR,NI,VIRT,RES,SHR,S,",
1659     toys.optflags&FLAG_H ? "CMD:15=THREAD,NAME=PROCESS" : "ARGS");
1660   if (!TT.top.s) TT.top.s = TT.top.O ? 3 : 9;
1661   top_setup(toybuf, "-%CPU,-ETIME,-PID");
1662   if (TT.top.O) {
1663     struct strawberry *fields = TT.fields;
1664
1665     fields = fields->next->next;
1666     comma_args(TT.top.O, &fields, "bad -O", parse_ko);
1667   }
1668
1669   top_common(merge_deltas);
1670 }
1671
1672 #define CLEANUP_top
1673 #define FOR_iotop
1674 #include "generated/flags.h"
1675
1676 static int iotop_filter(long long *oslot, long long *nslot, int milis)
1677 {
1678   if (!(toys.optflags&FLAG_a)) merge_deltas(oslot, nslot, milis);
1679   else oslot[SLOT_upticks] = ((millitime()-TT.time)*TT.ticks)/1000;
1680
1681   return !(toys.optflags&FLAG_o)||oslot[SLOT_iobytes+!(toys.optflags&FLAG_A)];
1682 }
1683
1684 void iotop_main(void)
1685 {
1686   char *s1 = 0, *s2 = 0, *d = "D"+!!(toys.optflags&FLAG_A);
1687
1688   if (toys.optflags&FLAG_K) TT.forcek++;
1689
1690   top_setup(s1 = xmprintf("PID,PR,USER,%sREAD,%sWRITE,SWAP,%sIO,COMM",d,d,d),
1691     s2 = xmprintf("-%sIO,-ETIME,-PID",d));
1692   free(s1);
1693   free(s2);
1694   top_common(iotop_filter);
1695 }
1696
1697 // pkill's plumbing wraps pgrep's and thus mostly takes place in pgrep's flag
1698 // context, so force pgrep's flags on even when building pkill standalone.
1699 // (All the pgrep/pkill functions drop out when building ps standalone.)
1700 #define FORCE_FLAGS
1701 #define CLEANUP_iotop
1702 #define FOR_pgrep
1703 #include "generated/flags.h"
1704
1705 struct regex_list {
1706   struct regex_list *next;
1707   regex_t reg;
1708 };
1709
1710 static void do_pgk(struct carveup *tb)
1711 {
1712   if (TT.pgrep.signal) {
1713     if (kill(*tb->slot, TT.pgrep.signal)) {
1714       char *s = num_to_sig(TT.pgrep.signal);
1715
1716       if (!s) sprintf(s = toybuf, "%d", TT.pgrep.signal);
1717       perror_msg("%s->%lld", s, *tb->slot);
1718     }
1719   }
1720   if (!(toys.optflags&FLAG_c) && (!TT.pgrep.signal || TT.tty)) {
1721     printf("%lld", *tb->slot);
1722     if (toys.optflags&FLAG_l)
1723       printf(" %s", tb->str+tb->offset[4]*!!(toys.optflags&FLAG_f));
1724     
1725     printf("%s", TT.pgrep.d ? TT.pgrep.d : "\n");
1726   }
1727 }
1728
1729 static void match_pgrep(void *p)
1730 {
1731   struct carveup *tb = p;
1732   regmatch_t match;
1733   struct regex_list *reg;
1734   char *name = tb->str+tb->offset[4]*!!(toys.optflags&FLAG_f);;
1735
1736   // Never match ourselves.
1737   if (TT.pgrep.self == *tb->slot) return;
1738
1739   if (TT.pgrep.regexes) {
1740     for (reg = TT.pgrep.regexes; reg; reg = reg->next) {
1741       if (regexec(&reg->reg, name, 1, &match, 0)) continue;
1742       if (toys.optflags&FLAG_x)
1743         if (match.rm_so || match.rm_eo!=strlen(name)) continue;
1744       break;
1745     }
1746     if ((toys.optflags&FLAG_v) ? !!reg : !reg) return;
1747   }
1748
1749   // pgrep should return success if there's a match.
1750   toys.exitval = 0;
1751
1752   // Repurpose a field for -c count.
1753   TT.sortpos++;
1754   if (toys.optflags&(FLAG_n|FLAG_o)) {
1755     long long ll = tb->slot[SLOT_starttime];
1756
1757     if (toys.optflags&FLAG_o) ll *= -1;
1758     if (TT.time && TT.time>ll) return;
1759     TT.time = ll;
1760     free(TT.pgrep.snapshot);
1761     TT.pgrep.snapshot = xmemdup(toybuf, (name+strlen(name)+1)-toybuf);
1762   } else do_pgk(tb);
1763 }
1764
1765 static int pgrep_match_process(long long *slot)
1766 {
1767   int match = shared_match_process(slot);
1768
1769   return (toys.optflags&FLAG_v) ? !match : match;
1770 }
1771
1772 void pgrep_main(void)
1773 {
1774   char **arg;
1775   struct regex_list *reg;
1776
1777   TT.pgrep.self = getpid();
1778
1779   // No signal names start with "L", so no need for "L: " in optstr.
1780   if (TT.pgrep.L && 1>(TT.pgrep.signal = sig_to_num(TT.pgrep.L)))
1781     error_exit("bad -L '%s'", TT.pgrep.L);
1782
1783   comma_args(TT.pgrep.G, &TT.GG, "bad -G", parse_rest);
1784   comma_args(TT.pgrep.g, &TT.gg, "bad -g", parse_rest);
1785   comma_args(TT.pgrep.P, &TT.PP, "bad -P", parse_rest);
1786   comma_args(TT.pgrep.s, &TT.ss, "bad -s", parse_rest);
1787   comma_args(TT.pgrep.t, &TT.tt, "bad -t", parse_rest);
1788   comma_args(TT.pgrep.U, &TT.UU, "bad -U", parse_rest);
1789   comma_args(TT.pgrep.u, &TT.uu, "bad -u", parse_rest);
1790
1791   if ((toys.optflags&(FLAG_x|FLAG_f)) ||
1792       !(toys.optflags&(FLAG_G|FLAG_g|FLAG_P|FLAG_s|FLAG_t|FLAG_U|FLAG_u)))
1793     if (!toys.optc) help_exit("No PATTERN");
1794
1795   if (toys.optflags&FLAG_f) TT.bits |= _PS_CMDLINE;
1796   for (arg = toys.optargs; *arg; arg++) {
1797     reg = xmalloc(sizeof(struct regex_list));
1798     xregcomp(&reg->reg, *arg, REG_EXTENDED);
1799     reg->next = TT.pgrep.regexes;
1800     TT.pgrep.regexes = reg;
1801   }
1802   TT.match_process = pgrep_match_process;
1803   TT.show_process = match_pgrep;
1804
1805   // pgrep should return failure if there are no matches.
1806   toys.exitval = 1;
1807
1808   dirtree_flagread("/proc", DIRTREE_SHUTUP|DIRTREE_PROC, get_ps);
1809   if (toys.optflags&FLAG_c) printf("%d\n", TT.sortpos);
1810   if (TT.pgrep.snapshot) {
1811     do_pgk(TT.pgrep.snapshot);
1812     if (CFG_TOYBOX_FREE) free(TT.pgrep.snapshot);
1813   }
1814   if (TT.pgrep.d) xputc('\n');
1815 }
1816
1817 #define CLEANUP_pgrep
1818 #define FOR_pkill
1819 #include "generated/flags.h"
1820
1821 void pkill_main(void)
1822 {
1823   char **args = toys.optargs;
1824
1825   if (!(toys.optflags&FLAG_l) && *args && **args=='-') TT.pgrep.L = *(args++)+1;
1826   if (!TT.pgrep.L) TT.pgrep.signal = SIGTERM;
1827   if (toys.optflags & FLAG_V) TT.tty = 1;
1828   pgrep_main();
1829 }