OSDN Git Service

Change the TNAME behavior to "Show parent argv[0]. If that's blank, showour argv...
[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.
17  *
18  * Posix defines -o ADDR as "The address of the process" but the process
19  * start address is a constant on any elf system with mmu. The procps ADDR
20  * field always prints "-" with an alignment of 1, which is why it has 11
21  * characters left for "cmd" in in 80 column "ps -l" mode. On x86-64 you
22  * need 12 chars, leaving nothing for cmd: I.E. posix 2008 ps -l mode can't
23  * be sanely implemented on 64 bit Linux systems. In procps there's ps -y
24  * which changes -l by removing the "F" column and swapping RSS for ADDR,
25  * leaving 9 chars for cmd, so we're using that as our -l output.
26  *
27  * Added a bunch of new -o fields posix doesn't mention, and we don't
28  * label "ps -o command,args,comm" as "COMMAND COMMAND COMMAND". We don't
29  * output argv[0] unmodified for -o comm or -o args (but procps violates
30  * posix for -o comm anyway, it's stat[2] not argv[0]).
31  *
32  * Note: iotop is STAYROOT so it can read other process's /proc/$PID/io
33  *       files (why they're not globally readable when the rest of proc
34  *       data is...?) and get a global I/O picture. Normal top is NOT,
35  *       even though you can -o AIO there, to give sysadmins the option
36  *       to reduce security exposure.)
37  *
38  * TODO: ps aux (att & bsd style "ps -ax" vs "ps ax" behavior difference)
39  * TODO: switch -fl to -y
40  * TODO: thread support /proc/$d/task/%d/stat (and -o stat has "l")
41  * TODO: iotop: Window size change: respond immediately. Why not padding
42  *       at right edge? (Not adjusting to screen size at all? Header wraps?)
43  * TODO: top: thread support and SMP
44  * TODO: pgrep -f only searches the amount of cmdline that fits in toybuf.
45
46 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))
47 // stayroot because iotop needs root to read other process' proc/$$/io
48 USE_TOP(NEWTOY(top, ">0m" "O*Hk*o*p*u*s#<1d#=3<1n#<1bq[!oO]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
49 USE_IOTOP(NEWTOY(iotop, ">0AaKO" "k*o*p*u*s#<1=7d#=3<1n#<1bq", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT|TOYFLAG_LOCALE))
50 USE_PGREP(NEWTOY(pgrep, "?cld:u*U*t*s*P*g*G*fnovxL:[-no]", TOYFLAG_USR|TOYFLAG_BIN))
51 USE_PKILL(NEWTOY(pkill,    "?Vu*U*t*s*P*g*G*fnovxl:[-no]", TOYFLAG_USR|TOYFLAG_BIN))
52
53 config PS
54   bool "ps"
55   default y
56   help
57     usage: ps [-AadefLlnwZ] [-gG GROUP,] [-k FIELD,] [-o FIELD,] [-p PID,] [-t TTY,] [-uU USER,]
58
59     List processes.
60
61     Which processes to show (selections may be comma separated lists):
62
63     -A  All processes
64     -a  Processes with terminals that aren't session leaders
65     -d  All processes that aren't session leaders
66     -e  Same as -A
67     -g  Belonging to GROUPs
68     -G  Belonging to real GROUPs (before sgid)
69     -p  PIDs (--pid)
70     -P  Parent PIDs (--ppid)
71     -s  In session IDs
72     -t  Attached to selected TTYs
73     -T  Show threads
74     -u  Owned by USERs
75     -U  Owned by real USERs (before suid)
76
77     Output modifiers:
78
79     -k  Sort FIELDs in +increasing or -decreasting order (--sort)
80     -M  Measure field widths (expanding as necessary)
81     -n  Show numeric USER and GROUP
82     -w  Wide output (don't truncate at terminal width)
83
84     Which FIELDs to show. (Default = -o PID,TTY,TIME,CMD)
85
86     -f  Full listing (-o USER:8=UID,PID,PPID,C,STIME,TTY,TIME,CMD)
87     -l  Long listing (-o F,S,UID,PID,PPID,C,PRI,NI,ADDR,SZ,WCHAN,TTY,TIME,CMD)
88     -o  Output FIELDs instead of defaults, each with optional :size and =title
89     -O  Add FIELDS to defaults
90     -Z  Include LABEL
91
92     Command line -o fields:
93
94       ARGS     Command line (argv[] -path)    CMD    COMM, or ARGS with -f
95       CMDLINE  Command line (argv[])          COMM   Original command name (stat[2])
96       COMMAND  Command name (/proc/$PID/exe)  NAME   Command name (COMMAND -path)
97       TNAME    Thread 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", 5, SLOT_rss}, {"PGID", 5, SLOT_pgrp},
343   {"VSZ", 6, 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", -15, -1},
350   {"NAME", -15, -5}, {"TNAME", -27, -7}, {"COMMAND", -27, -5},
351   {"CMDLINE", -27, -6}, {"ARGS", -27, -6}, {"CMD", -27, -1},
352
353   // user/group
354   {"UID", 5, SLOT_uid}, {"USER", -8, 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 TNAME is blank, show ARGS instead
447     if (which==PS_ARGS && !*out)
448       out = tb->str+tb->offset[-2-typos[which = PS_ARGS].slot];
449     if (which==PS_ARGS || which==PS_NAME) {
450       int i, j;
451
452       s = out;
453       for (i = 0; (which==PS_ARGS) ? i < slot[SLOT_argv0len] : out[i]; i++)
454         if (out[i] == '/') s = out+i+1;
455       i = s - out;
456       out = s;
457       if (which != field->which) {
458         j = slot[SLOT_argv0len]-i;
459         if (j > 259) j = 259;
460         memcpy(buf, out+i, j);
461         buf[j] = 0;
462         out = buf;
463       }
464     }
465     if (which>=PS_COMM && !*out) sprintf(out = buf, "[%s]", tb->str);
466
467   // user/group
468   } else if (which <= PS_RGROUP) {
469     sprintf(out, "%lld", ll);
470     if (sl&64) {
471       if (which > PS_RUSER) {
472         struct group *gr = bufgetgrgid(ll);
473
474         if (gr) out = gr->gr_name;
475       } else {
476         struct passwd *pw = bufgetpwuid(ll);
477
478         if (pw) out = pw->pw_name;
479       }
480     }
481
482   // Clock displays
483   } else if (which <= PS_TIME_) {
484     int unit = 60, pad = 2, j = TT.ticks; 
485     time_t seconds;
486
487     if (which!=PS_TIME_) unit *= 60*24;
488     else pad = 0;
489     // top adjusts slot[SLOT_upticks], we want original meaning.
490     if (which==PS_ELAPSED) ll = (slot[SLOT_uptime]*j)-slot[SLOT_starttime];
491     seconds = ll/j;
492
493     // Output days-hours:mins:secs, skipping non-required fields with zero
494     // TIME has 3 required fields, ETIME has 2. (Posix!) TIME+ is from top
495     for (s = 0, j = 2*(which==PS_TIME_); j<4; j++) {
496       if (!s && (seconds>unit || j == 1+(which!=PS_TIME))) s = out;
497       if (s) {
498         s += sprintf(s, j ? "%0*ld": "%*ld", pad, (long)(seconds/unit));
499         pad = 2;
500         if ((*s = "-::"[j])) s++;
501       }
502       seconds %= unit;
503       unit /= j ? 60 : 24;
504     }
505     if (which==PS_TIME_ && s-out<8)
506       sprintf(s, ".%02lld", (100*(ll%TT.ticks))/TT.ticks);
507
508   // Percentage displays
509   } else if (which <= PS__CPU) {
510     ll = slot[sl&63]*1000;
511     if (which==PS__VSZ || which==PS__MEM)
512       ll /= TT.si.totalram/((which==PS__VSZ) ? 1024 : 4096);
513     else if (slot[SLOT_upticks]) ll /= slot[SLOT_upticks];
514     sl = ll;
515     if (which==PS_C) sl += 5;
516     sprintf(out, "%d", sl/10);
517     if (which!=PS_C && sl<1000) sprintf(out+strlen(out), ".%d", sl%10);
518
519   // Human readable
520   } else if (which <= PS_DIO) {
521     ll = slot[typos[which].slot];
522     if (which <= PS_SHR) ll *= sysconf(_SC_PAGESIZE);
523     if (TT.forcek) sprintf(out, "%lldk", ll/1024);
524     else human_readable(out, ll, 0);
525
526   // Posix doesn't specify what flags should say. Man page says
527   // 1 for PF_FORKNOEXEC and 4 for PF_SUPERPRIV from linux/sched.h
528   } else if (which==PS_F) sprintf(out, "%llo", (slot[SLOT_flags]>>6)&5);
529   else if (which==PS_S || which==PS_STAT) {
530     s = out;
531     *s++ = tb->state;
532     if (which==PS_STAT) {
533       // TODO l = multithreaded
534       if (slot[SLOT_nice]<0) *s++ = '<';
535       else if (slot[SLOT_nice]>0) *s++ = 'N';
536       if (slot[SLOT_sid]==*slot) *s++ = 's';
537       if (slot[SLOT_vmlck]) *s++ = 'L';
538       if (slot[SLOT_ttypgrp]==*slot) *s++ = '+';
539     } 
540     *s = 0;
541   } else if (which==PS_STIME) {
542     time_t t = time(0)-slot[SLOT_uptime]+slot[SLOT_starttime]/TT.ticks;
543
544     // Padding behavior's a bit odd: default field size is just hh:mm.
545     // Increasing stime:size reveals more data at left until full,
546     // so move start address so yyyy-mm-dd hh:mm revealed on left at :16,
547     // then add :ss on right for :19.
548     strftime(out, 260, "%F %T", localtime(&t));
549     out = out+strlen(out)-3-abs(field->len);
550     if (out<buf) out = buf;
551
552   } else if (which==PS_PCY) sprintf(out, "%.2s", get_sched_policy_name(ll));
553   else if (CFG_TOYBOX_DEBUG) error_exit("bad which %d", which);
554
555   return out;
556 }
557
558 // Display process data that get_ps() read from /proc, formatting with TT.fields
559 static void show_ps(struct carveup *tb)
560 {
561   struct strawberry *field;
562   int pad, len, width = TT.width, abslen, sign, olen, extra = 0;
563
564   // Loop through fields to display
565   for (field = TT.fields; field; field = field->next) {
566     char *out = string_field(tb, field);
567
568     // Output the field, appropriately padded
569
570     // Minimum one space between each field
571     if (field != TT.fields) {
572       putchar(' ');
573       width--;
574     }
575
576     // Don't truncate number fields, but try to reclaim extra offset from later
577     // fields that can naturally be shorter
578     abslen = abs(field->len);
579     sign = field->len<0 ? -1 : 1;
580     if (field->which<=PS_BIT || extra) olen = strlen(out);
581     if (field->which<=PS_BIT && olen>abslen) {
582       // overflow but remember by how much
583       extra += olen-abslen;
584       abslen = olen;
585     } else if (extra && olen<abslen) {
586       // If later fields have slack space, take back overflow
587       olen = abslen-olen;
588       if (olen>extra) olen = extra;
589       abslen -= olen;
590       extra -= olen;
591     }
592     if (abslen>width) abslen = width;
593     len = pad = abslen;
594     pad *= sign;
595     // If last field is left justified, no trailing spaces.
596     if (!field->next && sign<0) pad = 0;
597
598     if (TT.tty) width -= draw_trim(out, pad, len);
599     else width -= printf("%*.*s", pad, len, out);
600     if (!width) break;
601   }
602   xputc(TT.time ? '\r' : '\n');
603 }
604
605 // dirtree callback: read data about process to display, store, or discard it.
606 // Fills toybuf with struct carveup and either DIRTREE_SAVEs a copy to ->extra
607 // (in -k mode) or calls show_ps on toybuf (no malloc/copy/free there).
608 static int get_ps(struct dirtree *new)
609 {
610   struct {
611     char *name;     // Path under /proc/$PID directory
612     long long bits; // Only fetch extra data if an -o field is displaying it
613   } fetch[] = {
614     // sources for carveup->offset[] data
615     {"fd/", _PS_TTY}, {"wchan", _PS_WCHAN}, {"attr/current", _PS_LABEL},
616     {"exe", _PS_COMMAND|_PS_NAME}, {"cmdline", _PS_CMDLINE|_PS_ARGS|_PS_TNAME},
617     {"", _PS_TNAME}
618   };
619   struct carveup *tb = (void *)toybuf;
620   long long *slot = tb->slot;
621   char *name, *s, *buf = tb->str, *end = 0;
622   int i, j, fd;
623   off_t len;
624
625   // Recurse one level into /proc children, skip non-numeric entries
626   if (!new->parent)
627     return DIRTREE_RECURSE|DIRTREE_SHUTUP
628       |(DIRTREE_SAVE*(TT.threadparent||!TT.show_process));
629
630   memset(slot, 0, sizeof(tb->slot));
631   if (!(tb->slot[SLOT_tid] = *slot = atol(new->name))) return 0;
632   if (TT.threadparent && TT.threadparent->extra)
633     if (*slot == *(((struct carveup *)TT.threadparent->extra)->slot)) return 0;
634   fd = dirtree_parentfd(new);
635
636   len = 2048;
637   sprintf(buf, "%lld/stat", *slot);
638   if (!readfileat(fd, buf, buf, &len)) return 0;
639
640   // parse oddball fields (name and state). Name can have embedded ')' so match
641   // _last_ ')' in stat (although VFS limits filenames to 255 bytes max).
642   // All remaining fields should be numeric.
643   if (!(name = strchr(buf, '('))) return 0;
644   for (s = ++name; *s; s++) if (*s == ')') end = s;
645   if (!end || end-name>255) return 0;
646
647   // Parse numeric fields (starting at 4th field in slot[SLOT_ppid])
648   if (1>sscanf(s = end, ") %c%n", &tb->state, &i)) return 0;
649   for (j = 1; j<SLOT_count; j++)
650     if (1>sscanf(s += i, " %lld%n", slot+j, &i)) break;
651
652   // Now we've read the data, move status and name right after slot[] array,
653   // and convert low chars to ? for non-tty display while we're at it.
654   for (i = 0; i<end-name; i++)
655     if ((tb->str[i] = name[i]) < ' ')
656       if (!TT.tty) tb->str[i] = '?';
657   buf = tb->str+i;
658   *buf++ = 0;
659   len = sizeof(toybuf)-(buf-toybuf);
660
661   // save uid, ruid, gid, gid, and rgid int slots 31-34 (we don't use sigcatch
662   // or numeric wchan, and the remaining two are always zero), and vmlck into
663   // 18 (which is "obsolete, always 0" from stat)
664   slot[SLOT_uid] = new->st.st_uid;
665   slot[SLOT_gid] = new->st.st_gid;
666
667   // TIME and TIME+ use combined value, ksort needs 'em added.
668   slot[SLOT_utime] += slot[SLOT_stime];
669   slot[SLOT_utime2] = slot[SLOT_utime];
670
671   // If RGROUP RUSER STAT RUID RGID SWAP happening, or -G or -U, parse "status"
672   // and save ruid, rgid, and vmlck.
673   if ((TT.bits&(_PS_RGROUP|_PS_RUSER|_PS_STAT|_PS_RUID|_PS_RGID|_PS_SWAP
674                |_PS_IO|_PS_DIO)) || TT.GG.len || TT.UU.len)
675   {
676     off_t temp = len;
677
678     sprintf(buf, "%lld/status", *slot);
679     if (!readfileat(fd, buf, buf, &temp)) *buf = 0;
680     s = strafter(buf, "\nUid:");
681     slot[SLOT_ruid] = s ? atol(s) : new->st.st_uid;
682     s = strafter(buf, "\nGid:");
683     slot[SLOT_rgid] = s ? atol(s) : new->st.st_gid;
684     if ((s = strafter(buf, "\nVmLck:"))) slot[SLOT_vmlck] = atoll(s);
685     if ((s = strafter(buf, "\nVmSwap:"))) slot[SLOT_swap] = atoll(s);
686   }
687
688   // Do we need to read "io"?
689   if (TT.bits&(_PS_READ|_PS_WRITE|_PS_DREAD|_PS_DWRITE|_PS_IO|_PS_DIO)) {
690     off_t temp = len;
691
692     sprintf(buf, "%lld/io", *slot);
693     if (!readfileat(fd, buf, buf, &temp)) *buf = 0;
694     if ((s = strafter(buf, "rchar:"))) slot[SLOT_rchar] = atoll(s);
695     if ((s = strafter(buf, "wchar:"))) slot[SLOT_wchar] = atoll(s);
696     if ((s = strafter(buf, "read_bytes:"))) slot[SLOT_rbytes] = atoll(s);
697     if ((s = strafter(buf, "write_bytes:"))) slot[SLOT_wbytes] = atoll(s);
698     slot[SLOT_iobytes] = slot[SLOT_rchar]+slot[SLOT_wchar]+slot[SLOT_swap];
699     slot[SLOT_diobytes] = slot[SLOT_rbytes]+slot[SLOT_wbytes]+slot[SLOT_swap];
700   }
701
702   // We now know enough to skip processes we don't care about.
703   if (TT.match_process && !TT.match_process(slot)) return 0;
704
705   // /proc data is generated as it's read, so for maximum accuracy on slow
706   // systems (or ps | more) we re-fetch uptime as we fetch each /proc line.
707   sysinfo(&TT.si);
708   slot[SLOT_uptime] = TT.si.uptime;
709   slot[SLOT_upticks] = slot[SLOT_uptime]*TT.ticks - slot[SLOT_starttime];
710
711   // Do we need to read "statm"?
712   if (TT.bits&(_PS_VIRT|_PS_RES|_PS_SHR)) {
713     off_t temp = len;
714
715     sprintf(buf, "%lld/statm", *slot);
716     if (!readfileat(fd, buf, buf, &temp)) *buf = 0;
717     
718     for (s = buf, i=0; i<3; i++)
719       if (!sscanf(s, " %lld%n", slot+SLOT_vsz+i, &j)) slot[SLOT_vsz+i] = 0;
720       else s += j;
721   }
722
723   // Do we need to read "exe"?
724   if (TT.bits&_PS_BIT) {
725     off_t temp = 6;
726
727     sprintf(buf, "%lld/exe", *slot);
728     if (readfileat(fd, buf, buf, &temp) && !memcmp(buf, "\177ELF", 4)) {
729       if (buf[4] == 1) slot[SLOT_bits] = 32;
730       else if (buf[4] == 2) slot[SLOT_bits] = 64;
731     }
732   }
733
734   // Do we need Android scheduling policy?
735   if (TT.bits&_PS_PCY) get_sched_policy(*slot, (void *)&slot[SLOT_pcy]);
736
737   // Fetch string data while parentfd still available, appending to buf.
738   // (There's well over 3k of toybuf left. We could dynamically malloc, but
739   // it'd almost never get used, querying length of a proc file is awkward,
740   // fixed buffer is nommu friendly... Wait for somebody to complain. :)
741   slot[SLOT_argv0len] = 0;
742   for (j = 0; j<ARRAY_LEN(fetch); j++) {
743     tb->offset[j] = buf-(tb->str);
744     if (!(TT.bits&fetch[j].bits)) {
745       *buf++ = 0;
746       continue;
747     }
748
749     // Determine remaining space, reserving minimum of 256 bytes/field and
750     // 260 bytes scratch space at the end (for output conversion later).
751     len = sizeof(toybuf)-(buf-toybuf)-260-256*(ARRAY_LEN(fetch)-j);
752     sprintf(buf, "%lld/%s", *slot, fetch[j].name);
753
754     // For exe we readlink instead of read contents
755     if (j==3 || j==5) {
756       struct carveup *ptb = 0;
757       int k;
758
759       // Thread doesn't have exe or argv[0], so use parent's
760       if (TT.threadparent && TT.threadparent->extra)
761         ptb = (void *)TT.threadparent->extra;
762
763       if (j==3 && !ptb) {
764         if ((len = readlinkat(fd, buf, buf, len))<1) len = 0;
765       } else {
766         if (j==3) i = strlen(s = ptb->str+ptb->offset[3]);
767         else {
768           if (!ptb || tb->slot[SLOT_argv0len]) ptb = tb;
769           i = ptb->slot[SLOT_argv0len];
770           s = ptb->str+ptb->offset[4];
771           while (-1!=(k = stridx(s, '/')) && k<i) {
772             s += k+1;
773             i -= k+1;
774           }
775         }
776         if (i<len) len = i;
777         memcpy(buf, s, len);
778       }
779       buf[len] = 0;
780
781     // If it's not the TTY field, data we want is in a file.
782     // Last length saved in slot[] is command line (which has embedded NULs)
783     } else if (!j) {
784       int rdev = slot[SLOT_ttynr];
785       struct stat st;
786
787       // Call no tty "?" rather than "0:0".
788       strcpy(buf, "?");
789       if (rdev) {
790         // Can we readlink() our way to a name?
791         for (i = 0; i<3; i++) {
792           sprintf(buf, "%lld/fd/%i", *slot, i);
793           if (!fstatat(fd, buf, &st, 0) && S_ISCHR(st.st_mode)
794             && st.st_rdev == rdev && 0<(len = readlinkat(fd, buf, buf, len)))
795           {
796             buf[len] = 0;
797             break;
798           }
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 -= 5);
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
832       // When command has no arguments, don't space over the NUL
833       if (readfileat(fd, buf, buf, &len) && len>0) {
834         int temp = 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         // Store end of argv[0] so ARGS and CMDLINE can differ.
853         // We do it for each file string slot but last is cmdline, which sticks.
854         slot[SLOT_argv0len] = temp ? temp : len;  // Position of _first_ NUL
855       } else *buf = len = 0;
856     }
857
858     // Above calculated/retained len, so we don't need to re-strlen.
859     buf += len+1;
860   }
861
862   TT.kcount++;
863   if (TT.show_process && !TT.threadparent) {
864     TT.show_process(tb);
865
866     return 0;
867   }
868
869   // If we need to sort the output, add it to the list and return.
870   s = xmalloc(buf-toybuf);
871   new->extra = (long)s;
872   memcpy(s, toybuf, buf-toybuf);
873
874   return DIRTREE_SAVE;
875 }
876
877 static int get_threads(struct dirtree *new)
878 {
879   struct dirtree *dt;
880   struct carveup *tb;
881   unsigned pid, kcount;
882
883   if (!new->parent) return get_ps(new);
884
885   if (!(pid = atol(new->name))) return 0;
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, 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 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 = (toys.which->name[1] == 's') ? 99999 : 80;
1149     TT.height = 25;
1150     terminal_size(&TT.width, &TT.height);
1151   }
1152
1153   // find controlling tty, falling back to /dev/tty if none
1154   for (i = 0; !TT.tty && i<4; i++) {
1155     struct stat st;
1156     int fd = i;
1157
1158     if (i==3 && -1==(fd = open("/dev/tty", O_RDONLY))) break;
1159
1160     if (isatty(fd) && !fstat(fd, &st)) TT.tty = st.st_rdev;
1161     if (i==3) close(fd);
1162   }
1163 }
1164
1165 void ps_main(void)
1166 {
1167   struct dirtree *dt;
1168   char *not_o;
1169   int i;
1170
1171   if (toys.optflags&FLAG_w) TT.width = 99999;
1172   shared_main();
1173
1174   // parse command line options other than -o
1175   comma_args(TT.ps.P, &TT.PP, "bad -P", parse_rest);
1176   comma_args(TT.ps.p, &TT.pp, "bad -p", parse_rest);
1177   comma_args(TT.ps.t, &TT.tt, "bad -t", parse_rest);
1178   comma_args(TT.ps.s, &TT.ss, "bad -s", parse_rest);
1179   comma_args(TT.ps.u, &TT.uu, "bad -u", parse_rest);
1180   comma_args(TT.ps.U, &TT.UU, "bad -U", parse_rest);
1181   comma_args(TT.ps.g, &TT.gg, "bad -g", parse_rest);
1182   comma_args(TT.ps.G, &TT.GG, "bad -G", parse_rest);
1183   comma_args(TT.ps.k, &TT.kfields, "bad -k", parse_ko);
1184   dlist_terminate(TT.kfields);
1185
1186   // Figure out which fields to display
1187   not_o = "%sTTY,TIME,CMD";
1188   if (toys.optflags&FLAG_f)
1189     sprintf(not_o = toybuf+128, "USER:8=UID,%%sPPID,%s,STIME,TTY,TIME,CMD",
1190       (toys.optflags&FLAG_T) ? "TCNT" : "C");
1191   else if (toys.optflags&FLAG_l)
1192     not_o = "F,S,UID,%sPPID,C,PRI,NI,ADDR,SZ,WCHAN,TTY,TIME,CMD";
1193   else if (CFG_TOYBOX_ON_ANDROID)
1194     not_o = "USER,%sPPID,VSIZE,RSS,WCHAN:10,ADDR:10=PC,S,NAME";
1195   sprintf(toybuf, not_o, (toys.optflags & FLAG_T) ? "PID,TID," : "PID,");
1196
1197   // Init TT.fields. This only uses toybuf if TT.ps.o is NULL
1198   if (toys.optflags&FLAG_Z) default_ko("LABEL", &TT.fields, 0, 0);
1199   default_ko(toybuf, &TT.fields, "bad -o", TT.ps.o);
1200
1201   if (TT.ps.O) {
1202     if (TT.fields) TT.fields = ((struct strawberry *)TT.fields)->prev;
1203     comma_args(TT.ps.O, &TT.fields, "bad -O", parse_ko);
1204     if (TT.fields) TT.fields = ((struct strawberry *)TT.fields)->next;
1205   }
1206   dlist_terminate(TT.fields);
1207
1208   // -f and -n change the meaning of some fields
1209   if (toys.optflags&(FLAG_f|FLAG_n)) {
1210     struct strawberry *ever;
1211
1212     for (ever = TT.fields; ever; ever = ever->next) {
1213       if ((toys.optflags&FLAG_f) && ever->which==PS_CMD) ever->which = PS_ARGS;
1214       if ((toys.optflags&FLAG_n) && ever->which>=PS_UID
1215         && ever->which<=PS_RGROUP && (typos[ever->which].slot&64))
1216           ever->which--;
1217     }
1218   }
1219
1220   // Calculate seen fields bit array, and if we aren't deferring printing
1221   // print headers now (for low memory/nommu systems).
1222   TT.bits = get_headers(TT.fields, toybuf, sizeof(toybuf));
1223   if (!(toys.optflags&FLAG_M)) printf("%.*s\n", TT.width, toybuf);
1224   if (!(toys.optflags&(FLAG_k|FLAG_M))) TT.show_process = (void *)show_ps;
1225   TT.match_process = ps_match_process;
1226   dt = dirtree_read("/proc",
1227     ((toys.optflags&FLAG_T) || (TT.bits&(_PS_TID|_PS_TCNT|_PS_TNAME)))
1228       ? get_threads : get_ps);
1229
1230   if (toys.optflags&(FLAG_k|FLAG_M)) {
1231     struct carveup **tbsort = collate(TT.kcount, dt);
1232
1233     if (toys.optflags&FLAG_M) {
1234       for (i = 0; i<TT.kcount; i++) {
1235         struct strawberry *field;
1236
1237         for (field = TT.fields; field; field = field->next) {
1238           int len = strlen(string_field(tbsort[i], field));
1239
1240           if (abs(field->len)<len) field->len = (field->len<0) ? -len : len;
1241         }
1242       }
1243
1244       // Now that we've recalculated field widths, re-pad headers again
1245       get_headers(TT.fields, toybuf, sizeof(toybuf));
1246       printf("%.*s\n", TT.width, toybuf);
1247     }
1248
1249     if (toys.optflags&FLAG_k)
1250       qsort(tbsort, TT.kcount, sizeof(struct carveup *), (void *)ksort);
1251     for (i = 0; i<TT.kcount; i++) {
1252       show_ps(tbsort[i]);
1253       free(tbsort[i]);
1254     }
1255     if (CFG_TOYBOX_FREE) free(tbsort);
1256   }
1257
1258   if (CFG_TOYBOX_FREE) {
1259     free(TT.gg.ptr);
1260     free(TT.GG.ptr);
1261     free(TT.pp.ptr);
1262     free(TT.PP.ptr);
1263     free(TT.ss.ptr);
1264     free(TT.tt.ptr);
1265     free(TT.uu.ptr);
1266     free(TT.UU.ptr);
1267     llist_traverse(TT.fields, free);
1268   }
1269 }
1270
1271 #define CLEANUP_ps
1272 #define FOR_top
1273 #include "generated/flags.h"
1274
1275 // select which of the -o fields to sort by
1276 static void setsort(int pos)
1277 {
1278   struct strawberry *field, *going2;
1279   int i = 0;
1280
1281   if (pos<0) pos = 0;
1282
1283   for (field = TT.fields; field; field = field->next) {
1284     if ((TT.sortpos = i++)<pos && field->next) continue;
1285     going2 = TT.kfields;
1286     going2->which = field->which;
1287     going2->len = field->len;
1288     break;
1289   }
1290 }
1291
1292 // If we have both, adjust slot[deltas[]] to be relative to previous
1293 // measurement rather than process start. Stomping old.data is fine
1294 // because we free it after displaying.
1295 static int merge_deltas(long long *oslot, long long *nslot, int milis)
1296 {
1297   char deltas[] = {SLOT_utime2, SLOT_iobytes, SLOT_diobytes, SLOT_rchar,
1298                    SLOT_wchar, SLOT_rbytes, SLOT_wbytes, SLOT_swap};
1299   int i;
1300
1301   for (i = 0; i<ARRAY_LEN(deltas); i++)
1302     oslot[deltas[i]] = nslot[deltas[i]] - oslot[deltas[i]];
1303   oslot[SLOT_upticks] = (milis*TT.ticks)/1000;
1304
1305   return 1;
1306 }
1307
1308 static int header_line(int line, int rev)
1309 {
1310   if (!line) return 0;
1311
1312   if (toys.optflags&FLAG_b) rev = 0;
1313
1314   printf("%s%*.*s%s\r\n", rev ? "\033[7m" : "",
1315     (toys.optflags&FLAG_b) ? 0 : -TT.width, TT.width, toybuf,
1316     rev ? "\033[0m" : "");
1317
1318   return line-1;
1319 }
1320
1321 static long long millitime(void)
1322 {
1323   struct timespec ts;
1324
1325   clock_gettime(CLOCK_MONOTONIC, &ts);
1326   return ts.tv_sec*1000+ts.tv_nsec/1000000;
1327 }
1328
1329 static void top_common(
1330   int (*filter)(long long *oslot, long long *nslot, int milis))
1331 {
1332   long long timeout = 0, now, stats[16];
1333   struct proclist {
1334     struct carveup **tb;
1335     int count;
1336     long long whence;
1337   } plist[2], *plold, *plnew, old, new, mix;
1338   char scratch[16], *pos, *cpufields[] = {"user", "nice", "sys", "idle",
1339     "iow", "irq", "sirq", "host"};
1340  
1341   unsigned tock = 0;
1342   int i, lines, topoff = 0, done = 0;
1343
1344   toys.signal = SIGWINCH;
1345   TT.bits = get_headers(TT.fields, toybuf, sizeof(toybuf));
1346   *scratch = 0;
1347   memset(plist, 0, sizeof(plist));
1348   memset(stats, 0, sizeof(stats));
1349   do {
1350     struct dirtree *dt;
1351     int recalc = 1;
1352
1353     plold = plist+(tock++&1);
1354     plnew = plist+(tock&1);
1355     plnew->whence = millitime();
1356     dt = dirtree_read("/proc",
1357       ((toys.optflags&FLAG_H) || (TT.bits&(_PS_TID|_PS_TCNT)))
1358         ? get_threads : get_ps);
1359     plnew->tb = collate(plnew->count = TT.kcount, dt);
1360     TT.kcount = 0;
1361
1362     if (readfile("/proc/stat", pos = toybuf, sizeof(toybuf))) {
1363       long long *st = stats+8*(tock&1);
1364
1365       // user nice system idle iowait irq softirq host
1366       sscanf(pos, "cpu %lld %lld %lld %lld %lld %lld %lld %lld",
1367         st, st+1, st+2, st+3, st+4, st+5, st+6, st+7);
1368     }
1369
1370     // First time, wait a quarter of a second to collect a little delta data.
1371     if (!plold->tb) {
1372       msleep(250);
1373       continue;
1374     }
1375
1376     // Collate old and new into "mix", depends on /proc read in pid sort order
1377     old = *plold;
1378     new = *plnew;
1379     mix.tb = xmalloc((old.count+new.count)*sizeof(struct carveup));
1380     mix.count = 0;
1381
1382     while (old.count || new.count) {
1383       struct carveup *otb = *old.tb, *ntb = *new.tb;
1384
1385       // If we just have old for this process, it exited. Discard it.
1386       if (old.count && (!new.count || *otb->slot < *ntb->slot)) {
1387         old.tb++;
1388         old.count--;
1389
1390         continue;
1391       }
1392
1393       // If we just have new, use it verbatim
1394       if (!old.count || *otb->slot > *ntb->slot) mix.tb[mix.count] = ntb;
1395       else {
1396         // Keep or discard
1397         if (filter(otb->slot, ntb->slot, new.whence-old.whence)) {
1398           mix.tb[mix.count] = otb;
1399           mix.count++;
1400         }
1401         old.tb++;
1402         old.count--;
1403       }
1404       new.tb++;
1405       new.count--;
1406     }
1407
1408     // Don't re-fetch data if it's not time yet, just re-display existing data.
1409     for (;;) {
1410       char was, is;
1411
1412       if (recalc) {
1413         qsort(mix.tb, mix.count, sizeof(struct carveup *), (void *)ksort);
1414         if (!(toys.optflags&FLAG_b)) {
1415           printf("\033[H\033[J");
1416           if (toys.signal) {
1417             toys.signal = 0;
1418             terminal_probesize(&TT.width, &TT.height);
1419           }
1420         }
1421         lines = TT.height;
1422       }
1423       if (recalc && !(toys.optflags&FLAG_q)) {
1424         // Display "top" header.
1425         if (*toys.which->name == 't') {
1426           struct strawberry alluc;
1427           long long ll, up = 0;
1428           long run[6];
1429           int j;
1430
1431           // Count running, sleeping, stopped, zombie processes.
1432           alluc.which = PS_S;
1433           memset(run, 0, sizeof(run));
1434           for (i = 0; i<mix.count; i++)
1435             run[1+stridx("RSTZ", *string_field(mix.tb[i], &alluc))]++;
1436           sprintf(toybuf,
1437             "Tasks: %d total,%4ld running,%4ld sleeping,%4ld stopped,"
1438             "%4ld zombie", mix.count, run[1], run[2], run[3], run[4]);
1439           lines = header_line(lines, 0);
1440
1441           if (readfile("/proc/meminfo", toybuf, sizeof(toybuf))) {
1442             for (i=0; i<6; i++) {
1443               pos = strafter(toybuf, (char *[]){"MemTotal:","\nMemFree:",
1444                     "\nBuffers:","\nCached:","\nSwapTotal:","\nSwapFree:"}[i]);
1445               run[i] = pos ? atol(pos) : 0;
1446             }
1447             sprintf(toybuf,
1448              "Mem:%10ldk total,%9ldk used,%9ldk free,%9ldk buffers",
1449               run[0], run[0]-run[1], run[1], run[2]);
1450             lines = header_line(lines, 0);
1451             sprintf(toybuf,
1452               "Swap:%9ldk total,%9ldk used,%9ldk free,%9ldk cached",
1453               run[4], run[4]-run[5], run[5], run[3]);
1454             lines = header_line(lines, 0);
1455           }
1456
1457           pos = toybuf;
1458           i = sysconf(_SC_NPROCESSORS_CONF);
1459           pos += sprintf(pos, "%d%%cpu", i*100);
1460           j = 4+(i>10);
1461
1462           // If a processor goes idle it's powered down and its idle ticks don't
1463           // advance, so calculate idle time as potential time - used.
1464           if (mix.count) up = mix.tb[0]->slot[SLOT_upticks];
1465           if (!up) up = 1;
1466           now = up*i;
1467           ll = stats[3] = stats[11] = 0;
1468           for (i = 0; i<8; i++) ll += stats[i]-stats[i+8];
1469           stats[3] = now - llabs(ll);
1470
1471           for (i = 0; i<8; i++) {
1472             ll = (llabs(stats[i]-stats[i+8])*1000)/up;
1473             pos += sprintf(pos, "% *lld%%%s", j, (ll+5)/10, cpufields[i]);
1474           }
1475           lines = header_line(lines, 0);
1476         } else {
1477           struct strawberry *fields;
1478           struct carveup tb;
1479
1480           memset(&tb, 0, sizeof(struct carveup));
1481           pos = stpcpy(toybuf, "Totals:");
1482           for (fields = TT.fields; fields; fields = fields->next) {
1483             long long ll, bits = 0;
1484             int slot = typos[fields->which].slot&63;
1485
1486             if (fields->which<PS_C || fields->which>PS_DIO) continue;
1487             ll = 1LL<<fields->which;
1488             if (bits&ll) continue;
1489             bits |= ll;
1490             for (i=0; i<mix.count; i++)
1491               tb.slot[slot] += mix.tb[i]->slot[slot];
1492             pos += snprintf(pos, sizeof(toybuf)/2-(pos-toybuf),
1493               " %s: %*s,", typos[fields->which].name,
1494               fields->len, string_field(&tb, fields));
1495           }
1496           *--pos = 0;
1497           lines = header_line(lines, 0);
1498         }
1499
1500         get_headers(TT.fields, pos = toybuf, sizeof(toybuf));
1501         for (i = 0, is = ' '; *pos; pos++) {
1502           was = is;
1503           is = *pos;
1504           if (isspace(was) && !isspace(is) && i++==TT.sortpos && pos!=toybuf)
1505             pos[-1] = '[';
1506           if (!isspace(was) && isspace(is) && i==TT.sortpos+1) *pos = ']';
1507         }
1508         *pos = 0;
1509         lines = header_line(lines, 1);
1510       }
1511       if (!recalc && !(toys.optflags&FLAG_b))
1512         printf("\033[%dH\033[J", 1+TT.height-lines);
1513       recalc = 1;
1514
1515       for (i = 0; i<lines && i+topoff<mix.count; i++) {
1516         if (!(toys.optflags&FLAG_b) && i) xputc('\n');
1517         show_ps(mix.tb[i+topoff]);
1518       }
1519
1520       if (TT.top.n && !--TT.top.n) {
1521         done++;
1522         break;
1523       }
1524
1525       now = millitime();
1526       if (timeout<=now) timeout = new.whence+TT.top.d;
1527       if (timeout<=now || timeout>now+TT.top.d) timeout = now+TT.top.d;
1528
1529       // In batch mode, we ignore the keyboard.
1530       if (toys.optflags&FLAG_b) {
1531         msleep(timeout-now);
1532         // Make an obvious gap between datasets.
1533         xputs("\n\n");
1534         continue;
1535       }
1536
1537       i = scan_key_getsize(scratch, timeout-now, &TT.width, &TT.height);
1538       if (i==-1 || i==3 || toupper(i)=='Q') {
1539         done++;
1540         break;
1541       }
1542       if (i==-2) break;
1543
1544       // Flush unknown escape sequences.
1545       if (i==27) while (0<scan_key_getsize(scratch, 0, &TT.width, &TT.height));
1546       else if (i==' ') {
1547         timeout = 0;
1548         break;
1549       } else if (toupper(i)=='R')
1550         ((struct strawberry *)TT.kfields)->reverse *= -1;
1551       else {
1552         i -= 256;
1553         if (i == KEY_LEFT) setsort(TT.sortpos-1);
1554         else if (i == KEY_RIGHT) setsort(TT.sortpos+1);
1555         // KEY_UP is 0, so at end of strchr
1556         else if (strchr((char []){KEY_DOWN,KEY_PGUP,KEY_PGDN,KEY_UP}, i)) {
1557           recalc = 0;
1558
1559           if (i == KEY_UP) topoff--;
1560           else if (i == KEY_DOWN) topoff++;
1561           else if (i == KEY_PGDN) topoff += lines;
1562           else if (i == KEY_PGUP) topoff -= lines;
1563           if (topoff<0) topoff = 0; 
1564           if (topoff>mix.count) topoff = mix.count;
1565         }
1566       }
1567       continue;
1568     }
1569
1570     free(mix.tb);
1571     for (i=0; i<plold->count; i++) free(plold->tb[i]);
1572     free(plold->tb);
1573   } while (!done);
1574
1575   if (!(toys.optflags&FLAG_b)) tty_reset();
1576 }
1577
1578 static void top_setup(char *defo, char *defk)
1579 {
1580   TT.top.d *= 1000;
1581   if (toys.optflags&FLAG_b) TT.width = TT.height = 99999;
1582   else {
1583     TT.time = millitime();
1584     set_terminal(0, 1, 0);
1585     sigatexit(tty_sigreset);
1586     xsignal(SIGWINCH, generic_signal);
1587     printf("\033[?25l\033[0m");
1588   }
1589   shared_main();
1590
1591   comma_args(TT.top.u, &TT.uu, "bad -u", parse_rest);
1592   comma_args(TT.top.p, &TT.pp, "bad -p", parse_rest);
1593   TT.match_process = shared_match_process;
1594
1595   default_ko(defo, &TT.fields, "bad -o", TT.top.o);
1596   dlist_terminate(TT.fields);
1597
1598   // First (dummy) sort field is overwritten by setsort()
1599   default_ko("-S", &TT.kfields, 0, 0);
1600   default_ko(defk, &TT.kfields, "bad -k", TT.top.k);
1601   dlist_terminate(TT.kfields);
1602   setsort(TT.top.s-1);
1603 }
1604
1605 void top_main(void)
1606 {
1607   // usage: [-h HEADER] -o OUTPUT -k SORT
1608
1609   sprintf(toybuf, "PID,USER,%s%%CPU,%%MEM,TIME+,ARGS",
1610     TT.top.O ? "" : "PR,NI,VIRT,RES,SHR,S,");
1611   if (!TT.top.s) TT.top.s = TT.top.O ? 3 : 9;
1612   top_setup(toybuf, "-%CPU,-ETIME,-PID");
1613   if (TT.top.O) {
1614     struct strawberry *fields = TT.fields;
1615
1616     fields = fields->next->next;
1617     comma_args(TT.top.O, &fields, "bad -O", parse_ko);
1618   }
1619
1620   top_common(merge_deltas);
1621 }
1622
1623 #define CLEANUP_top
1624 #define FOR_iotop
1625 #include "generated/flags.h"
1626
1627 static int iotop_filter(long long *oslot, long long *nslot, int milis)
1628 {
1629   if (!(toys.optflags&FLAG_a)) merge_deltas(oslot, nslot, milis);
1630   else oslot[SLOT_upticks] = ((millitime()-TT.time)*TT.ticks)/1000;
1631
1632   return !(toys.optflags&FLAG_o)||oslot[SLOT_iobytes+!(toys.optflags&FLAG_A)];
1633 }
1634
1635 void iotop_main(void)
1636 {
1637   char *s1 = 0, *s2 = 0, *d = "D"+!!(toys.optflags&FLAG_A);
1638
1639   if (toys.optflags&FLAG_K) TT.forcek++;
1640
1641   top_setup(s1 = xmprintf("PID,PR,USER,%sREAD,%sWRITE,SWAP,%sIO,COMM",d,d,d),
1642     s2 = xmprintf("-%sIO,-ETIME,-PID",d));
1643   free(s1);
1644   free(s2);
1645   top_common(iotop_filter);
1646 }
1647
1648 // pkill's plumbing wraps pgrep's and thus mostly takes place in pgrep's flag
1649 // context, so force pgrep's flags on even when building pkill standalone.
1650 // (All the pgrep/pkill functions drop out when building ps standalone.)
1651 #define FORCE_FLAGS
1652 #define CLEANUP_iotop
1653 #define FOR_pgrep
1654 #include "generated/flags.h"
1655
1656 struct regex_list {
1657   struct regex_list *next;
1658   regex_t reg;
1659 };
1660
1661 static void do_pgk(struct carveup *tb)
1662 {
1663   if (TT.pgrep.signal) {
1664     if (kill(*tb->slot, TT.pgrep.signal)) {
1665       char *s = num_to_sig(TT.pgrep.signal);
1666
1667       if (!s) sprintf(s = toybuf, "%d", TT.pgrep.signal);
1668       perror_msg("%s->%lld", s, *tb->slot);
1669     }
1670   }
1671   if (!(toys.optflags&FLAG_c) && (!TT.pgrep.signal || TT.tty)) {
1672     printf("%lld", *tb->slot);
1673     if (toys.optflags&FLAG_l)
1674       printf(" %s", tb->str+tb->offset[4]*!!(toys.optflags&FLAG_f));
1675     
1676     printf("%s", TT.pgrep.d ? TT.pgrep.d : "\n");
1677   }
1678 }
1679
1680 static void match_pgrep(struct carveup *tb)
1681 {
1682   regmatch_t match;
1683   struct regex_list *reg;
1684   char *name = tb->str+tb->offset[4]*!!(toys.optflags&FLAG_f);;
1685
1686   // Never match ourselves.
1687   if (TT.pgrep.self == *tb->slot) return;
1688
1689   if (TT.pgrep.regexes) {
1690     for (reg = TT.pgrep.regexes; reg; reg = reg->next) {
1691       if (regexec(&reg->reg, name, 1, &match, 0)) continue;
1692       if (toys.optflags&FLAG_x)
1693         if (match.rm_so || match.rm_eo!=strlen(name)) continue;
1694       break;
1695     }
1696     if ((toys.optflags&FLAG_v) ? !!reg : !reg) return;
1697   }
1698
1699   // pgrep should return success if there's a match.
1700   toys.exitval = 0;
1701
1702   // Repurpose a field for -c count.
1703   TT.sortpos++;
1704   if (toys.optflags&(FLAG_n|FLAG_o)) {
1705     long long ll = tb->slot[SLOT_starttime];
1706
1707     if (toys.optflags&FLAG_o) ll *= -1;
1708     if (TT.time && TT.time>ll) return;
1709     TT.time = ll;
1710     free(TT.pgrep.snapshot);
1711     TT.pgrep.snapshot = xmemdup(toybuf, (name+strlen(name)+1)-toybuf);
1712   } else do_pgk(tb);
1713 }
1714
1715 static int pgrep_match_process(long long *slot)
1716 {
1717   int match = shared_match_process(slot);
1718
1719   return (toys.optflags&FLAG_v) ? !match : match;
1720 }
1721
1722 void pgrep_main(void)
1723 {
1724   char **arg;
1725   struct regex_list *reg;
1726
1727   TT.pgrep.self = getpid();
1728
1729   // No signal names start with "L", so no need for "L: " parsing.
1730   if (TT.pgrep.L && 1>(TT.pgrep.signal = sig_to_num(TT.pgrep.L)))
1731     error_exit("bad -L '%s'", TT.pgrep.L);
1732
1733   comma_args(TT.pgrep.G, &TT.GG, "bad -G", parse_rest);
1734   comma_args(TT.pgrep.g, &TT.gg, "bad -g", parse_rest);
1735   comma_args(TT.pgrep.P, &TT.PP, "bad -P", parse_rest);
1736   comma_args(TT.pgrep.s, &TT.ss, "bad -s", parse_rest);
1737   comma_args(TT.pgrep.t, &TT.tt, "bad -t", parse_rest);
1738   comma_args(TT.pgrep.U, &TT.UU, "bad -U", parse_rest);
1739   comma_args(TT.pgrep.u, &TT.uu, "bad -u", parse_rest);
1740
1741   if ((toys.optflags&(FLAG_x|FLAG_f)) ||
1742       !(toys.optflags&(FLAG_G|FLAG_g|FLAG_P|FLAG_s|FLAG_t|FLAG_U|FLAG_u)))
1743     if (!toys.optc) help_exit("No PATTERN");
1744
1745   if (toys.optflags&FLAG_f) TT.bits |= _PS_CMDLINE;
1746   for (arg = toys.optargs; *arg; arg++) {
1747     reg = xmalloc(sizeof(struct regex_list));
1748     xregcomp(&reg->reg, *arg, REG_EXTENDED);
1749     reg->next = TT.pgrep.regexes;
1750     TT.pgrep.regexes = reg;
1751   }
1752   TT.match_process = pgrep_match_process;
1753   TT.show_process = (void *)match_pgrep;
1754
1755   // pgrep should return failure if there are no matches.
1756   toys.exitval = 1;
1757
1758   dirtree_read("/proc", get_ps);
1759   if (toys.optflags&FLAG_c) printf("%d\n", TT.sortpos);
1760   if (TT.pgrep.snapshot) {
1761     do_pgk(TT.pgrep.snapshot);
1762     if (CFG_TOYBOX_FREE) free(TT.pgrep.snapshot);
1763   }
1764   if (TT.pgrep.d) xputc('\n');
1765 }
1766
1767 #define CLEANUP_pgrep
1768 #define FOR_pkill
1769 #include "generated/flags.h"
1770
1771 void pkill_main(void)
1772 {
1773   char **args = toys.optargs;
1774
1775   if (!(toys.optflags&FLAG_l) && *args && **args=='-') TT.pgrep.L = *(args++)+1;
1776   if (!TT.pgrep.L) TT.pgrep.signal = SIGTERM;
1777   if (toys.optflags & FLAG_V) TT.tty = 1;
1778   pgrep_main();
1779 }