OSDN Git Service

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