OSDN Git Service

Fix ps bug, last field wasn't expanding to width.
[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) {
597       pad = 0;
598       len = width;
599     }
600
601     if (TT.tty) width -= draw_trim(out, pad, len);
602     else width -= printf("%*.*s", pad, len, out);
603     if (!width) break;
604   }
605   xputc(TT.time ? '\r' : '\n');
606 }
607
608 // dirtree callback: read data about process to display, store, or discard it.
609 // Fills toybuf with struct carveup and either DIRTREE_SAVEs a copy to ->extra
610 // (in -k mode) or calls show_ps on toybuf (no malloc/copy/free there).
611 static int get_ps(struct dirtree *new)
612 {
613   struct {
614     char *name;     // Path under /proc/$PID directory
615     long long bits; // Only fetch extra data if an -o field is displaying it
616   } fetch[] = {
617     // sources for carveup->offset[] data
618     {"fd/", _PS_TTY}, {"wchan", _PS_WCHAN}, {"attr/current", _PS_LABEL},
619     {"exe", _PS_COMMAND|_PS_NAME}, {"cmdline", _PS_CMDLINE|_PS_ARGS|_PS_TNAME},
620     {"", _PS_TNAME}
621   };
622   struct carveup *tb = (void *)toybuf;
623   long long *slot = tb->slot;
624   char *name, *s, *buf = tb->str, *end = 0;
625   int i, j, fd;
626   off_t len;
627
628   // Recurse one level into /proc children, skip non-numeric entries
629   if (!new->parent)
630     return DIRTREE_RECURSE|DIRTREE_SHUTUP
631       |(DIRTREE_SAVE*(TT.threadparent||!TT.show_process));
632
633   memset(slot, 0, sizeof(tb->slot));
634   if (!(tb->slot[SLOT_tid] = *slot = atol(new->name))) return 0;
635   if (TT.threadparent && TT.threadparent->extra)
636     if (*slot == *(((struct carveup *)TT.threadparent->extra)->slot)) return 0;
637   fd = dirtree_parentfd(new);
638
639   len = 2048;
640   sprintf(buf, "%lld/stat", *slot);
641   if (!readfileat(fd, buf, buf, &len)) return 0;
642
643   // parse oddball fields (name and state). Name can have embedded ')' so match
644   // _last_ ')' in stat (although VFS limits filenames to 255 bytes max).
645   // All remaining fields should be numeric.
646   if (!(name = strchr(buf, '('))) return 0;
647   for (s = ++name; *s; s++) if (*s == ')') end = s;
648   if (!end || end-name>255) return 0;
649
650   // Parse numeric fields (starting at 4th field in slot[SLOT_ppid])
651   if (1>sscanf(s = end, ") %c%n", &tb->state, &i)) return 0;
652   for (j = 1; j<SLOT_count; j++)
653     if (1>sscanf(s += i, " %lld%n", slot+j, &i)) break;
654
655   // Now we've read the data, move status and name right after slot[] array,
656   // and convert low chars to ? for non-tty display while we're at it.
657   for (i = 0; i<end-name; i++)
658     if ((tb->str[i] = name[i]) < ' ')
659       if (!TT.tty) tb->str[i] = '?';
660   buf = tb->str+i;
661   *buf++ = 0;
662   len = sizeof(toybuf)-(buf-toybuf);
663
664   // save uid, ruid, gid, gid, and rgid int slots 31-34 (we don't use sigcatch
665   // or numeric wchan, and the remaining two are always zero), and vmlck into
666   // 18 (which is "obsolete, always 0" from stat)
667   slot[SLOT_uid] = new->st.st_uid;
668   slot[SLOT_gid] = new->st.st_gid;
669
670   // TIME and TIME+ use combined value, ksort needs 'em added.
671   slot[SLOT_utime] += slot[SLOT_stime];
672   slot[SLOT_utime2] = slot[SLOT_utime];
673
674   // If RGROUP RUSER STAT RUID RGID SWAP happening, or -G or -U, parse "status"
675   // and save ruid, rgid, and vmlck.
676   if ((TT.bits&(_PS_RGROUP|_PS_RUSER|_PS_STAT|_PS_RUID|_PS_RGID|_PS_SWAP
677                |_PS_IO|_PS_DIO)) || TT.GG.len || TT.UU.len)
678   {
679     off_t temp = len;
680
681     sprintf(buf, "%lld/status", *slot);
682     if (!readfileat(fd, buf, buf, &temp)) *buf = 0;
683     s = strafter(buf, "\nUid:");
684     slot[SLOT_ruid] = s ? atol(s) : new->st.st_uid;
685     s = strafter(buf, "\nGid:");
686     slot[SLOT_rgid] = s ? atol(s) : new->st.st_gid;
687     if ((s = strafter(buf, "\nVmLck:"))) slot[SLOT_vmlck] = atoll(s);
688     if ((s = strafter(buf, "\nVmSwap:"))) slot[SLOT_swap] = atoll(s);
689   }
690
691   // Do we need to read "io"?
692   if (TT.bits&(_PS_READ|_PS_WRITE|_PS_DREAD|_PS_DWRITE|_PS_IO|_PS_DIO)) {
693     off_t temp = len;
694
695     sprintf(buf, "%lld/io", *slot);
696     if (!readfileat(fd, buf, buf, &temp)) *buf = 0;
697     if ((s = strafter(buf, "rchar:"))) slot[SLOT_rchar] = atoll(s);
698     if ((s = strafter(buf, "wchar:"))) slot[SLOT_wchar] = atoll(s);
699     if ((s = strafter(buf, "read_bytes:"))) slot[SLOT_rbytes] = atoll(s);
700     if ((s = strafter(buf, "write_bytes:"))) slot[SLOT_wbytes] = atoll(s);
701     slot[SLOT_iobytes] = slot[SLOT_rchar]+slot[SLOT_wchar]+slot[SLOT_swap];
702     slot[SLOT_diobytes] = slot[SLOT_rbytes]+slot[SLOT_wbytes]+slot[SLOT_swap];
703   }
704
705   // We now know enough to skip processes we don't care about.
706   if (TT.match_process && !TT.match_process(slot)) return 0;
707
708   // /proc data is generated as it's read, so for maximum accuracy on slow
709   // systems (or ps | more) we re-fetch uptime as we fetch each /proc line.
710   sysinfo(&TT.si);
711   slot[SLOT_uptime] = TT.si.uptime;
712   slot[SLOT_upticks] = slot[SLOT_uptime]*TT.ticks - slot[SLOT_starttime];
713
714   // Do we need to read "statm"?
715   if (TT.bits&(_PS_VIRT|_PS_RES|_PS_SHR)) {
716     off_t temp = len;
717
718     sprintf(buf, "%lld/statm", *slot);
719     if (!readfileat(fd, buf, buf, &temp)) *buf = 0;
720     
721     for (s = buf, i=0; i<3; i++)
722       if (!sscanf(s, " %lld%n", slot+SLOT_vsz+i, &j)) slot[SLOT_vsz+i] = 0;
723       else s += j;
724   }
725
726   // Do we need to read "exe"?
727   if (TT.bits&_PS_BIT) {
728     off_t temp = 6;
729
730     sprintf(buf, "%lld/exe", *slot);
731     if (readfileat(fd, buf, buf, &temp) && !memcmp(buf, "\177ELF", 4)) {
732       if (buf[4] == 1) slot[SLOT_bits] = 32;
733       else if (buf[4] == 2) slot[SLOT_bits] = 64;
734     }
735   }
736
737   // Do we need Android scheduling policy?
738   if (TT.bits&_PS_PCY) get_sched_policy(*slot, (void *)&slot[SLOT_pcy]);
739
740   // Fetch string data while parentfd still available, appending to buf.
741   // (There's well over 3k of toybuf left. We could dynamically malloc, but
742   // it'd almost never get used, querying length of a proc file is awkward,
743   // fixed buffer is nommu friendly... Wait for somebody to complain. :)
744   slot[SLOT_argv0len] = 0;
745   for (j = 0; j<ARRAY_LEN(fetch); j++) {
746     tb->offset[j] = buf-(tb->str);
747     if (!(TT.bits&fetch[j].bits)) {
748       *buf++ = 0;
749       continue;
750     }
751
752     // Determine remaining space, reserving minimum of 256 bytes/field and
753     // 260 bytes scratch space at the end (for output conversion later).
754     len = sizeof(toybuf)-(buf-toybuf)-260-256*(ARRAY_LEN(fetch)-j);
755     sprintf(buf, "%lld/%s", *slot, fetch[j].name);
756
757     // For exe we readlink instead of read contents
758     if (j==3 || j==5) {
759       struct carveup *ptb = 0;
760       int k;
761
762       // Thread doesn't have exe or argv[0], so use parent's
763       if (TT.threadparent && TT.threadparent->extra)
764         ptb = (void *)TT.threadparent->extra;
765
766       if (j==3 && !ptb) {
767         if ((len = readlinkat(fd, buf, buf, len))<1) len = 0;
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       }
782       buf[len] = 0;
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 && 0<(len = readlinkat(fd, buf, buf, len)))
798           {
799             buf[len] = 0;
800             break;
801           }
802         }
803
804         // Couldn't find it, try all the tty drivers.
805         if (i == 3) {
806           FILE *fp = fopen("/proc/tty/drivers", "r");
807           int tty_major = 0, maj = dev_major(rdev), min = dev_minor(rdev);
808
809           if (fp) {
810             while (fscanf(fp, "%*s %256s %d %*s %*s", buf, &tty_major) == 2) {
811               // TODO: we could parse the minor range too.
812               if (tty_major == maj) {
813                 len = strlen(buf);
814                 len += sprintf(buf+len, "%d", min);
815                 if (!stat(buf, &st) && S_ISCHR(st.st_mode) && st.st_rdev==rdev)
816                   break;
817               }
818               tty_major = 0;
819             }
820             fclose(fp);
821           }
822
823           // Really couldn't find it, so just show major:minor.
824           if (!tty_major) len = sprintf(buf, "%d:%d", maj, min);
825         }
826
827         s = buf;
828         if (strstart(&s, "/dev/")) memmove(buf, s, len -= 5);
829       }
830
831     // Data we want is in a file.
832     // Last length saved in slot[] is command line (which has embedded NULs)
833     } else {
834
835       // When command has no arguments, don't space over the NUL
836       if (readfileat(fd, buf, buf, &len) && len>0) {
837         int temp = 0;
838
839         // Trim trailing whitespace and NUL bytes
840         while (len)
841           if (!buf[len-1] || isspace(buf[len-1])) buf[--len] = 0;
842           else break;
843
844         // Turn NUL to space, other low ascii to ? (in non-tty mode)
845         // cmdline has a trailing NUL that we don't want to turn to space.
846         for (i=0; i<len-1; i++) {
847           char c = buf[i];
848
849           if (!c) {
850             if (!temp) temp = i;
851             c = ' ';
852           } else if (!TT.tty && c<' ') c = '?';
853           buf[i] = c;
854         }
855         // Store end of argv[0] so ARGS and CMDLINE can differ.
856         // We do it for each file string slot but last is cmdline, which sticks.
857         slot[SLOT_argv0len] = temp ? temp : len;  // Position of _first_ NUL
858       } else *buf = len = 0;
859     }
860
861     // Above calculated/retained len, so we don't need to re-strlen.
862     buf += len+1;
863   }
864
865   TT.kcount++;
866   if (TT.show_process && !TT.threadparent) {
867     TT.show_process(tb);
868
869     return 0;
870   }
871
872   // If we need to sort the output, add it to the list and return.
873   s = xmalloc(buf-toybuf);
874   new->extra = (long)s;
875   memcpy(s, toybuf, buf-toybuf);
876
877   return DIRTREE_SAVE;
878 }
879
880 static int get_threads(struct dirtree *new)
881 {
882   struct dirtree *dt;
883   struct carveup *tb;
884   unsigned pid, kcount;
885
886   if (!new->parent) return get_ps(new);
887
888   if (!(pid = atol(new->name))) return 0;
889
890   TT.threadparent = new;
891   if (!get_ps(new)) {
892     TT.threadparent = 0;
893
894     return 0;
895   }
896
897   // Recurse down into tasks, retaining thread groups.
898   // Disable show_process at least until we can calculate tcount
899   kcount = TT.kcount;
900   sprintf(toybuf, "/proc/%u/task", pid);
901   new->child = dirtree_flagread(toybuf, DIRTREE_SHUTUP, get_ps);
902   TT.threadparent = 0;
903   kcount = TT.kcount-kcount+1;
904   tb = (void *)new->extra;
905   tb->slot[SLOT_tcount] = kcount;
906
907   // Fill out tid and thread count for each entry in group
908   if (new->child) for (dt = new->child->child; dt; dt = dt->next) {
909     tb = (void *)dt->extra;
910     tb->slot[SLOT_pid] = pid;
911     tb->slot[SLOT_tcount] = kcount;
912   }
913
914   // Save or display
915   if (!TT.show_process) return DIRTREE_SAVE;
916   TT.show_process((void *)new->extra);
917   dt = new->child;
918   new->child = 0;
919   while (dt->child) {
920     new = dt->child->next;
921     TT.show_process((void *)dt->child->extra);
922     free(dt->child);
923     dt->child = new;
924   }
925   free(dt);
926
927   return 0;
928 }
929
930 static char *parse_ko(void *data, char *type, int length)
931 {
932   struct strawberry *field;
933   char *width, *title, *end, *s;
934   int i, j, k;
935
936   // Get title, length of title, type, end of type, and display width
937
938   // Chip off =name to display
939   if ((end = strchr(type, '=')) && length>(end-type)) {
940     title = end+1;
941     length -= (end-type)+1;
942   } else {
943     end = type+length;
944     title = 0;
945   }
946
947   // Chip off :width to display
948   if ((width = strchr(type, ':')) && width<end) {
949     if (!title) length = width-type;
950   } else width = 0;
951
952   // Allocate structure, copy title
953   field = xzalloc(sizeof(struct strawberry)+(length+1)*!!title);
954   if (title) {
955     memcpy(field->title = field->forever, title, length);
956     field->title[field->len = length] = 0;
957   }
958
959   if (width) {
960     field->len = strtol(++width, &title, 10);
961     if (!isdigit(*width) || title != end) return title;
962     end = --width;
963   }
964
965   // Find type
966   field->reverse = 1;
967   if (*type == '-') field->reverse = -1;
968   else if (*type != '+') type--;
969   type++;
970   for (i = 0; i<ARRAY_LEN(typos); i++) {
971     field->which = i;
972     for (j = 0; j<2; j++) {
973       if (!j) s = typos[i].name;
974       // posix requires alternate names for some fields
975       else if (-1==(k = stridx((char []){PS_NI, PS_SCH, PS_ELAPSED, PS__CPU,
976         PS_VSZ, PS_USER, 0}, i))) continue;
977       else
978         s = ((char *[]){"NICE", "SCHED", "ETIME", "PCPU", "VSIZE", "UNAME"})[k];
979
980       if (!strncasecmp(type, s, end-type) && strlen(s)==end-type) break;
981     }
982     if (j!=2) break;
983   }
984   if (i==ARRAY_LEN(typos)) return type;
985   if (!field->title) field->title = typos[field->which].name;
986   if (!field->len) field->len = typos[field->which].width;
987   else if (typos[field->which].width<0) field->len *= -1;
988   dlist_add_nomalloc(data, (void *)field);
989
990   return 0;
991 }
992
993 long long get_headers(struct strawberry *fields, char *buf, int blen)
994 {
995   long long bits = 0;
996   int len = 0;
997
998   for (; fields; fields = fields->next) {
999     len += snprintf(buf+len, blen-len, " %*s"+!bits, fields->len,
1000       fields->title);
1001     bits |= 1LL<<fields->which;
1002   }
1003
1004   return bits;
1005 }
1006
1007 // Parse -p -s -t -u -U -g -G
1008 static char *parse_rest(void *data, char *str, int len)
1009 {
1010   struct ptr_len *pl = (struct ptr_len *)data;
1011   long *ll = pl->ptr;
1012   char *end;
1013   int num = 0;
1014
1015   // Allocate next chunk of data
1016   if (!(15&pl->len))
1017     ll = pl->ptr = xrealloc(pl->ptr, sizeof(long)*(pl->len+16));
1018
1019   // Parse numerical input
1020   if (isdigit(*str)) {
1021     ll[pl->len] = xstrtol(str, &end, 10);
1022     if (end==(len+str)) num++;
1023     // For pkill, -s 0 represents pkill's session id.
1024     if (pl==&TT.ss && ll[pl->len]==0) ll[pl->len] = getsid(0);
1025   }
1026
1027   if (pl==&TT.pp || pl==&TT.ss) {
1028     if (num && ll[pl->len]>0) {
1029       pl->len++;
1030
1031       return 0;
1032     }
1033   } else if (pl==&TT.tt) {
1034     // -t pts = 12,pts/12 tty = /dev/tty2,tty2,S0
1035     if (!num) {
1036       if (strstart(&str, strcpy(toybuf, "/dev/"))) len -= 5;
1037       if (strstart(&str, "pts/")) {
1038         len -= 4;
1039         num++;
1040       } else if (strstart(&str, "tty")) len -= 3;
1041     }
1042     if (len<256 && (!(end = strchr(str, '/')) || end-str>len)) {
1043       struct stat st;
1044
1045       end = toybuf + sprintf(toybuf, "/dev/%s", num ? "pts/" : "tty");
1046       memcpy(end, str, len);
1047       end[len] = 0;
1048       xstat(toybuf, &st);
1049       ll[pl->len++] = st.st_rdev;
1050
1051       return 0;
1052     }
1053   } else if (len<255) {
1054     char name[256];
1055
1056     if (num) {
1057       pl->len++;
1058
1059       return 0;
1060     }
1061
1062     memcpy(name, str, len);
1063     name[len] = 0;
1064     if (pl==&TT.gg || pl==&TT.GG) {
1065       struct group *gr = getgrnam(name);
1066       if (gr) {
1067         ll[pl->len++] = gr->gr_gid;
1068
1069         return 0;
1070       }
1071     } else if (pl==&TT.uu || pl==&TT.UU) {
1072       struct passwd *pw = getpwnam(name);
1073       if (pw) {
1074         ll[pl->len++] = pw->pw_uid;
1075
1076         return 0;
1077       }
1078     }
1079   }
1080
1081   // Return error
1082   return str;
1083 }
1084
1085 // sort for -k
1086 static int ksort(void *aa, void *bb)
1087 {
1088   struct strawberry *field;
1089   struct carveup *ta = *(struct carveup **)aa, *tb = *(struct carveup **)bb;
1090   int ret = 0, slot;
1091
1092   for (field = TT.kfields; field && !ret; field = field->next) {
1093     slot = typos[field->which].slot;
1094
1095     // Can we do numeric sort?
1096     if (!(slot&64)) {
1097       if (ta->slot[slot]<tb->slot[slot]) ret = -1;
1098       if (ta->slot[slot]>tb->slot[slot]) ret = 1;
1099     }
1100
1101     // fallback to string sort
1102     if (!ret) {
1103       memccpy(toybuf, string_field(ta, field), 0, 2048);
1104       toybuf[2048] = 0;
1105       ret = strcmp(toybuf, string_field(tb, field));
1106     }
1107     ret *= field->reverse;
1108   }
1109
1110   return ret;
1111 }
1112
1113 static struct carveup **collate_leaves(struct carveup **tb, struct dirtree *dt) 
1114 {
1115   while (dt) {
1116     struct dirtree *next = dt->next;
1117
1118     if (dt->extra) *(tb++) = (void *)dt->extra;
1119     if (dt->child) tb = collate_leaves(tb, dt->child);
1120     free(dt);
1121     dt = next;
1122   }
1123
1124   return tb;
1125 }
1126
1127 static struct carveup **collate(int count, struct dirtree *dt)
1128 {
1129   struct carveup **tbsort = xmalloc(count*sizeof(struct carveup *));
1130
1131   collate_leaves(tbsort, dt);
1132
1133   return tbsort;
1134
1135
1136 static void default_ko(char *s, void *fields, char *err, struct arg_list *arg)
1137 {
1138   struct arg_list def;
1139
1140   memset(&def, 0, sizeof(struct arg_list));
1141   def.arg = s;
1142   comma_args(arg ? arg : &def, fields, err, parse_ko);
1143 }
1144
1145 static void shared_main(void)
1146 {
1147   int i;
1148
1149   TT.ticks = sysconf(_SC_CLK_TCK);
1150   if (!TT.width) {
1151     TT.width = (toys.which->name[1] == 's') ? 99999 : 80;
1152     TT.height = 25;
1153     terminal_size(&TT.width, &TT.height);
1154   }
1155
1156   // find controlling tty, falling back to /dev/tty if none
1157   for (i = 0; !TT.tty && i<4; i++) {
1158     struct stat st;
1159     int fd = i;
1160
1161     if (i==3 && -1==(fd = open("/dev/tty", O_RDONLY))) break;
1162
1163     if (isatty(fd) && !fstat(fd, &st)) TT.tty = st.st_rdev;
1164     if (i==3) close(fd);
1165   }
1166 }
1167
1168 void ps_main(void)
1169 {
1170   struct dirtree *dt;
1171   char *not_o;
1172   int i;
1173
1174   if (toys.optflags&FLAG_w) TT.width = 99999;
1175   shared_main();
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   // Figure out which fields to display
1190   not_o = "%sTTY,TIME,CMD";
1191   if (toys.optflags&FLAG_f)
1192     sprintf(not_o = toybuf+128, "USER:8=UID,%%sPPID,%s,STIME,TTY,TIME,CMD",
1193       (toys.optflags&FLAG_T) ? "TCNT" : "C");
1194   else if (toys.optflags&FLAG_l)
1195     not_o = "F,S,UID,%sPPID,C,PRI,NI,ADDR,SZ,WCHAN,TTY,TIME,CMD";
1196   else if (CFG_TOYBOX_ON_ANDROID)
1197     not_o = "USER,%sPPID,VSIZE,RSS,WCHAN:10,ADDR:10=PC,S,NAME";
1198   sprintf(toybuf, not_o, (toys.optflags & FLAG_T) ? "PID,TID," : "PID,");
1199
1200   // Init TT.fields. This only uses toybuf if TT.ps.o is NULL
1201   if (toys.optflags&FLAG_Z) default_ko("LABEL", &TT.fields, 0, 0);
1202   default_ko(toybuf, &TT.fields, "bad -o", TT.ps.o);
1203
1204   if (TT.ps.O) {
1205     if (TT.fields) TT.fields = ((struct strawberry *)TT.fields)->prev;
1206     comma_args(TT.ps.O, &TT.fields, "bad -O", parse_ko);
1207     if (TT.fields) TT.fields = ((struct strawberry *)TT.fields)->next;
1208   }
1209   dlist_terminate(TT.fields);
1210
1211   // -f and -n change the meaning of some fields
1212   if (toys.optflags&(FLAG_f|FLAG_n)) {
1213     struct strawberry *ever;
1214
1215     for (ever = TT.fields; ever; ever = ever->next) {
1216       if ((toys.optflags&FLAG_f) && ever->which==PS_CMD) ever->which = PS_ARGS;
1217       if ((toys.optflags&FLAG_n) && ever->which>=PS_UID
1218         && ever->which<=PS_RGROUP && (typos[ever->which].slot&64))
1219           ever->which--;
1220     }
1221   }
1222
1223   // Calculate seen fields bit array, and if we aren't deferring printing
1224   // print headers now (for low memory/nommu systems).
1225   TT.bits = get_headers(TT.fields, toybuf, sizeof(toybuf));
1226   if (!(toys.optflags&FLAG_M)) printf("%.*s\n", TT.width, toybuf);
1227   if (!(toys.optflags&(FLAG_k|FLAG_M))) TT.show_process = (void *)show_ps;
1228   TT.match_process = ps_match_process;
1229   dt = dirtree_read("/proc",
1230     ((toys.optflags&FLAG_T) || (TT.bits&(_PS_TID|_PS_TCNT|_PS_TNAME)))
1231       ? get_threads : get_ps);
1232
1233   if (toys.optflags&(FLAG_k|FLAG_M)) {
1234     struct carveup **tbsort = collate(TT.kcount, dt);
1235
1236     if (toys.optflags&FLAG_M) {
1237       for (i = 0; i<TT.kcount; i++) {
1238         struct strawberry *field;
1239
1240         for (field = TT.fields; field; field = field->next) {
1241           int len = strlen(string_field(tbsort[i], field));
1242
1243           if (abs(field->len)<len) field->len = (field->len<0) ? -len : len;
1244         }
1245       }
1246
1247       // Now that we've recalculated field widths, re-pad headers again
1248       get_headers(TT.fields, toybuf, sizeof(toybuf));
1249       printf("%.*s\n", TT.width, toybuf);
1250     }
1251
1252     if (toys.optflags&FLAG_k)
1253       qsort(tbsort, TT.kcount, sizeof(struct carveup *), (void *)ksort);
1254     for (i = 0; i<TT.kcount; i++) {
1255       show_ps(tbsort[i]);
1256       free(tbsort[i]);
1257     }
1258     if (CFG_TOYBOX_FREE) free(tbsort);
1259   }
1260
1261   if (CFG_TOYBOX_FREE) {
1262     free(TT.gg.ptr);
1263     free(TT.GG.ptr);
1264     free(TT.pp.ptr);
1265     free(TT.PP.ptr);
1266     free(TT.ss.ptr);
1267     free(TT.tt.ptr);
1268     free(TT.uu.ptr);
1269     free(TT.UU.ptr);
1270     llist_traverse(TT.fields, free);
1271   }
1272 }
1273
1274 #define CLEANUP_ps
1275 #define FOR_top
1276 #include "generated/flags.h"
1277
1278 // select which of the -o fields to sort by
1279 static void setsort(int pos)
1280 {
1281   struct strawberry *field, *going2;
1282   int i = 0;
1283
1284   if (pos<0) pos = 0;
1285
1286   for (field = TT.fields; field; field = field->next) {
1287     if ((TT.sortpos = i++)<pos && field->next) continue;
1288     going2 = TT.kfields;
1289     going2->which = field->which;
1290     going2->len = field->len;
1291     break;
1292   }
1293 }
1294
1295 // If we have both, adjust slot[deltas[]] to be relative to previous
1296 // measurement rather than process start. Stomping old.data is fine
1297 // because we free it after displaying.
1298 static int merge_deltas(long long *oslot, long long *nslot, int milis)
1299 {
1300   char deltas[] = {SLOT_utime2, SLOT_iobytes, SLOT_diobytes, SLOT_rchar,
1301                    SLOT_wchar, SLOT_rbytes, SLOT_wbytes, SLOT_swap};
1302   int i;
1303
1304   for (i = 0; i<ARRAY_LEN(deltas); i++)
1305     oslot[deltas[i]] = nslot[deltas[i]] - oslot[deltas[i]];
1306   oslot[SLOT_upticks] = (milis*TT.ticks)/1000;
1307
1308   return 1;
1309 }
1310
1311 static int header_line(int line, int rev)
1312 {
1313   if (!line) return 0;
1314
1315   if (toys.optflags&FLAG_b) rev = 0;
1316
1317   printf("%s%*.*s%s\r\n", rev ? "\033[7m" : "",
1318     (toys.optflags&FLAG_b) ? 0 : -TT.width, TT.width, toybuf,
1319     rev ? "\033[0m" : "");
1320
1321   return line-1;
1322 }
1323
1324 static long long millitime(void)
1325 {
1326   struct timespec ts;
1327
1328   clock_gettime(CLOCK_MONOTONIC, &ts);
1329   return ts.tv_sec*1000+ts.tv_nsec/1000000;
1330 }
1331
1332 static void top_common(
1333   int (*filter)(long long *oslot, long long *nslot, int milis))
1334 {
1335   long long timeout = 0, now, stats[16];
1336   struct proclist {
1337     struct carveup **tb;
1338     int count;
1339     long long whence;
1340   } plist[2], *plold, *plnew, old, new, mix;
1341   char scratch[16], *pos, *cpufields[] = {"user", "nice", "sys", "idle",
1342     "iow", "irq", "sirq", "host"};
1343  
1344   unsigned tock = 0;
1345   int i, lines, topoff = 0, done = 0;
1346
1347   toys.signal = SIGWINCH;
1348   TT.bits = get_headers(TT.fields, toybuf, sizeof(toybuf));
1349   *scratch = 0;
1350   memset(plist, 0, sizeof(plist));
1351   memset(stats, 0, sizeof(stats));
1352   do {
1353     struct dirtree *dt;
1354     int recalc = 1;
1355
1356     plold = plist+(tock++&1);
1357     plnew = plist+(tock&1);
1358     plnew->whence = millitime();
1359     dt = dirtree_read("/proc",
1360       ((toys.optflags&FLAG_H) || (TT.bits&(_PS_TID|_PS_TCNT)))
1361         ? get_threads : get_ps);
1362     plnew->tb = collate(plnew->count = TT.kcount, dt);
1363     TT.kcount = 0;
1364
1365     if (readfile("/proc/stat", pos = toybuf, sizeof(toybuf))) {
1366       long long *st = stats+8*(tock&1);
1367
1368       // user nice system idle iowait irq softirq host
1369       sscanf(pos, "cpu %lld %lld %lld %lld %lld %lld %lld %lld",
1370         st, st+1, st+2, st+3, st+4, st+5, st+6, st+7);
1371     }
1372
1373     // First time, wait a quarter of a second to collect a little delta data.
1374     if (!plold->tb) {
1375       msleep(250);
1376       continue;
1377     }
1378
1379     // Collate old and new into "mix", depends on /proc read in pid sort order
1380     old = *plold;
1381     new = *plnew;
1382     mix.tb = xmalloc((old.count+new.count)*sizeof(struct carveup));
1383     mix.count = 0;
1384
1385     while (old.count || new.count) {
1386       struct carveup *otb = *old.tb, *ntb = *new.tb;
1387
1388       // If we just have old for this process, it exited. Discard it.
1389       if (old.count && (!new.count || *otb->slot < *ntb->slot)) {
1390         old.tb++;
1391         old.count--;
1392
1393         continue;
1394       }
1395
1396       // If we just have new, use it verbatim
1397       if (!old.count || *otb->slot > *ntb->slot) mix.tb[mix.count] = ntb;
1398       else {
1399         // Keep or discard
1400         if (filter(otb->slot, ntb->slot, new.whence-old.whence)) {
1401           mix.tb[mix.count] = otb;
1402           mix.count++;
1403         }
1404         old.tb++;
1405         old.count--;
1406       }
1407       new.tb++;
1408       new.count--;
1409     }
1410
1411     // Don't re-fetch data if it's not time yet, just re-display existing data.
1412     for (;;) {
1413       char was, is;
1414
1415       if (recalc) {
1416         qsort(mix.tb, mix.count, sizeof(struct carveup *), (void *)ksort);
1417         if (!(toys.optflags&FLAG_b)) {
1418           printf("\033[H\033[J");
1419           if (toys.signal) {
1420             toys.signal = 0;
1421             terminal_probesize(&TT.width, &TT.height);
1422           }
1423         }
1424         lines = TT.height;
1425       }
1426       if (recalc && !(toys.optflags&FLAG_q)) {
1427         // Display "top" header.
1428         if (*toys.which->name == 't') {
1429           struct strawberry alluc;
1430           long long ll, up = 0;
1431           long run[6];
1432           int j;
1433
1434           // Count running, sleeping, stopped, zombie processes.
1435           alluc.which = PS_S;
1436           memset(run, 0, sizeof(run));
1437           for (i = 0; i<mix.count; i++)
1438             run[1+stridx("RSTZ", *string_field(mix.tb[i], &alluc))]++;
1439           sprintf(toybuf,
1440             "Tasks: %d total,%4ld running,%4ld sleeping,%4ld stopped,"
1441             "%4ld zombie", mix.count, run[1], run[2], run[3], run[4]);
1442           lines = header_line(lines, 0);
1443
1444           if (readfile("/proc/meminfo", toybuf, sizeof(toybuf))) {
1445             for (i=0; i<6; i++) {
1446               pos = strafter(toybuf, (char *[]){"MemTotal:","\nMemFree:",
1447                     "\nBuffers:","\nCached:","\nSwapTotal:","\nSwapFree:"}[i]);
1448               run[i] = pos ? atol(pos) : 0;
1449             }
1450             sprintf(toybuf,
1451              "Mem:%10ldk total,%9ldk used,%9ldk free,%9ldk buffers",
1452               run[0], run[0]-run[1], run[1], run[2]);
1453             lines = header_line(lines, 0);
1454             sprintf(toybuf,
1455               "Swap:%9ldk total,%9ldk used,%9ldk free,%9ldk cached",
1456               run[4], run[4]-run[5], run[5], run[3]);
1457             lines = header_line(lines, 0);
1458           }
1459
1460           pos = toybuf;
1461           i = sysconf(_SC_NPROCESSORS_CONF);
1462           pos += sprintf(pos, "%d%%cpu", i*100);
1463           j = 4+(i>10);
1464
1465           // If a processor goes idle it's powered down and its idle ticks don't
1466           // advance, so calculate idle time as potential time - used.
1467           if (mix.count) up = mix.tb[0]->slot[SLOT_upticks];
1468           if (!up) up = 1;
1469           now = up*i;
1470           ll = stats[3] = stats[11] = 0;
1471           for (i = 0; i<8; i++) ll += stats[i]-stats[i+8];
1472           stats[3] = now - llabs(ll);
1473
1474           for (i = 0; i<8; i++) {
1475             ll = (llabs(stats[i]-stats[i+8])*1000)/up;
1476             pos += sprintf(pos, "% *lld%%%s", j, (ll+5)/10, cpufields[i]);
1477           }
1478           lines = header_line(lines, 0);
1479         } else {
1480           struct strawberry *fields;
1481           struct carveup tb;
1482
1483           memset(&tb, 0, sizeof(struct carveup));
1484           pos = stpcpy(toybuf, "Totals:");
1485           for (fields = TT.fields; fields; fields = fields->next) {
1486             long long ll, bits = 0;
1487             int slot = typos[fields->which].slot&63;
1488
1489             if (fields->which<PS_C || fields->which>PS_DIO) continue;
1490             ll = 1LL<<fields->which;
1491             if (bits&ll) continue;
1492             bits |= ll;
1493             for (i=0; i<mix.count; i++)
1494               tb.slot[slot] += mix.tb[i]->slot[slot];
1495             pos += snprintf(pos, sizeof(toybuf)/2-(pos-toybuf),
1496               " %s: %*s,", typos[fields->which].name,
1497               fields->len, string_field(&tb, fields));
1498           }
1499           *--pos = 0;
1500           lines = header_line(lines, 0);
1501         }
1502
1503         get_headers(TT.fields, pos = toybuf, sizeof(toybuf));
1504         for (i = 0, is = ' '; *pos; pos++) {
1505           was = is;
1506           is = *pos;
1507           if (isspace(was) && !isspace(is) && i++==TT.sortpos && pos!=toybuf)
1508             pos[-1] = '[';
1509           if (!isspace(was) && isspace(is) && i==TT.sortpos+1) *pos = ']';
1510         }
1511         *pos = 0;
1512         lines = header_line(lines, 1);
1513       }
1514       if (!recalc && !(toys.optflags&FLAG_b))
1515         printf("\033[%dH\033[J", 1+TT.height-lines);
1516       recalc = 1;
1517
1518       for (i = 0; i<lines && i+topoff<mix.count; i++) {
1519         if (!(toys.optflags&FLAG_b) && i) xputc('\n');
1520         show_ps(mix.tb[i+topoff]);
1521       }
1522
1523       if (TT.top.n && !--TT.top.n) {
1524         done++;
1525         break;
1526       }
1527
1528       now = millitime();
1529       if (timeout<=now) timeout = new.whence+TT.top.d;
1530       if (timeout<=now || timeout>now+TT.top.d) timeout = now+TT.top.d;
1531
1532       // In batch mode, we ignore the keyboard.
1533       if (toys.optflags&FLAG_b) {
1534         msleep(timeout-now);
1535         // Make an obvious gap between datasets.
1536         xputs("\n\n");
1537         continue;
1538       }
1539
1540       i = scan_key_getsize(scratch, timeout-now, &TT.width, &TT.height);
1541       if (i==-1 || i==3 || toupper(i)=='Q') {
1542         done++;
1543         break;
1544       }
1545       if (i==-2) break;
1546
1547       // Flush unknown escape sequences.
1548       if (i==27) while (0<scan_key_getsize(scratch, 0, &TT.width, &TT.height));
1549       else if (i==' ') {
1550         timeout = 0;
1551         break;
1552       } else if (toupper(i)=='R')
1553         ((struct strawberry *)TT.kfields)->reverse *= -1;
1554       else {
1555         i -= 256;
1556         if (i == KEY_LEFT) setsort(TT.sortpos-1);
1557         else if (i == KEY_RIGHT) setsort(TT.sortpos+1);
1558         // KEY_UP is 0, so at end of strchr
1559         else if (strchr((char []){KEY_DOWN,KEY_PGUP,KEY_PGDN,KEY_UP}, i)) {
1560           recalc = 0;
1561
1562           if (i == KEY_UP) topoff--;
1563           else if (i == KEY_DOWN) topoff++;
1564           else if (i == KEY_PGDN) topoff += lines;
1565           else if (i == KEY_PGUP) topoff -= lines;
1566           if (topoff<0) topoff = 0; 
1567           if (topoff>mix.count) topoff = mix.count;
1568         }
1569       }
1570       continue;
1571     }
1572
1573     free(mix.tb);
1574     for (i=0; i<plold->count; i++) free(plold->tb[i]);
1575     free(plold->tb);
1576   } while (!done);
1577
1578   if (!(toys.optflags&FLAG_b)) tty_reset();
1579 }
1580
1581 static void top_setup(char *defo, char *defk)
1582 {
1583   TT.top.d *= 1000;
1584   if (toys.optflags&FLAG_b) TT.width = TT.height = 99999;
1585   else {
1586     TT.time = millitime();
1587     set_terminal(0, 1, 0);
1588     sigatexit(tty_sigreset);
1589     xsignal(SIGWINCH, generic_signal);
1590     printf("\033[?25l\033[0m");
1591   }
1592   shared_main();
1593
1594   comma_args(TT.top.u, &TT.uu, "bad -u", parse_rest);
1595   comma_args(TT.top.p, &TT.pp, "bad -p", parse_rest);
1596   TT.match_process = shared_match_process;
1597
1598   default_ko(defo, &TT.fields, "bad -o", TT.top.o);
1599   dlist_terminate(TT.fields);
1600
1601   // First (dummy) sort field is overwritten by setsort()
1602   default_ko("-S", &TT.kfields, 0, 0);
1603   default_ko(defk, &TT.kfields, "bad -k", TT.top.k);
1604   dlist_terminate(TT.kfields);
1605   setsort(TT.top.s-1);
1606 }
1607
1608 void top_main(void)
1609 {
1610   // usage: [-h HEADER] -o OUTPUT -k SORT
1611
1612   sprintf(toybuf, "PID,USER,%s%%CPU,%%MEM,TIME+,ARGS",
1613     TT.top.O ? "" : "PR,NI,VIRT,RES,SHR,S,");
1614   if (!TT.top.s) TT.top.s = TT.top.O ? 3 : 9;
1615   top_setup(toybuf, "-%CPU,-ETIME,-PID");
1616   if (TT.top.O) {
1617     struct strawberry *fields = TT.fields;
1618
1619     fields = fields->next->next;
1620     comma_args(TT.top.O, &fields, "bad -O", parse_ko);
1621   }
1622
1623   top_common(merge_deltas);
1624 }
1625
1626 #define CLEANUP_top
1627 #define FOR_iotop
1628 #include "generated/flags.h"
1629
1630 static int iotop_filter(long long *oslot, long long *nslot, int milis)
1631 {
1632   if (!(toys.optflags&FLAG_a)) merge_deltas(oslot, nslot, milis);
1633   else oslot[SLOT_upticks] = ((millitime()-TT.time)*TT.ticks)/1000;
1634
1635   return !(toys.optflags&FLAG_o)||oslot[SLOT_iobytes+!(toys.optflags&FLAG_A)];
1636 }
1637
1638 void iotop_main(void)
1639 {
1640   char *s1 = 0, *s2 = 0, *d = "D"+!!(toys.optflags&FLAG_A);
1641
1642   if (toys.optflags&FLAG_K) TT.forcek++;
1643
1644   top_setup(s1 = xmprintf("PID,PR,USER,%sREAD,%sWRITE,SWAP,%sIO,COMM",d,d,d),
1645     s2 = xmprintf("-%sIO,-ETIME,-PID",d));
1646   free(s1);
1647   free(s2);
1648   top_common(iotop_filter);
1649 }
1650
1651 // pkill's plumbing wraps pgrep's and thus mostly takes place in pgrep's flag
1652 // context, so force pgrep's flags on even when building pkill standalone.
1653 // (All the pgrep/pkill functions drop out when building ps standalone.)
1654 #define FORCE_FLAGS
1655 #define CLEANUP_iotop
1656 #define FOR_pgrep
1657 #include "generated/flags.h"
1658
1659 struct regex_list {
1660   struct regex_list *next;
1661   regex_t reg;
1662 };
1663
1664 static void do_pgk(struct carveup *tb)
1665 {
1666   if (TT.pgrep.signal) {
1667     if (kill(*tb->slot, TT.pgrep.signal)) {
1668       char *s = num_to_sig(TT.pgrep.signal);
1669
1670       if (!s) sprintf(s = toybuf, "%d", TT.pgrep.signal);
1671       perror_msg("%s->%lld", s, *tb->slot);
1672     }
1673   }
1674   if (!(toys.optflags&FLAG_c) && (!TT.pgrep.signal || TT.tty)) {
1675     printf("%lld", *tb->slot);
1676     if (toys.optflags&FLAG_l)
1677       printf(" %s", tb->str+tb->offset[4]*!!(toys.optflags&FLAG_f));
1678     
1679     printf("%s", TT.pgrep.d ? TT.pgrep.d : "\n");
1680   }
1681 }
1682
1683 static void match_pgrep(struct carveup *tb)
1684 {
1685   regmatch_t match;
1686   struct regex_list *reg;
1687   char *name = tb->str+tb->offset[4]*!!(toys.optflags&FLAG_f);;
1688
1689   // Never match ourselves.
1690   if (TT.pgrep.self == *tb->slot) return;
1691
1692   if (TT.pgrep.regexes) {
1693     for (reg = TT.pgrep.regexes; reg; reg = reg->next) {
1694       if (regexec(&reg->reg, name, 1, &match, 0)) continue;
1695       if (toys.optflags&FLAG_x)
1696         if (match.rm_so || match.rm_eo!=strlen(name)) continue;
1697       break;
1698     }
1699     if ((toys.optflags&FLAG_v) ? !!reg : !reg) return;
1700   }
1701
1702   // pgrep should return success if there's a match.
1703   toys.exitval = 0;
1704
1705   // Repurpose a field for -c count.
1706   TT.sortpos++;
1707   if (toys.optflags&(FLAG_n|FLAG_o)) {
1708     long long ll = tb->slot[SLOT_starttime];
1709
1710     if (toys.optflags&FLAG_o) ll *= -1;
1711     if (TT.time && TT.time>ll) return;
1712     TT.time = ll;
1713     free(TT.pgrep.snapshot);
1714     TT.pgrep.snapshot = xmemdup(toybuf, (name+strlen(name)+1)-toybuf);
1715   } else do_pgk(tb);
1716 }
1717
1718 static int pgrep_match_process(long long *slot)
1719 {
1720   int match = shared_match_process(slot);
1721
1722   return (toys.optflags&FLAG_v) ? !match : match;
1723 }
1724
1725 void pgrep_main(void)
1726 {
1727   char **arg;
1728   struct regex_list *reg;
1729
1730   TT.pgrep.self = getpid();
1731
1732   // No signal names start with "L", so no need for "L: " parsing.
1733   if (TT.pgrep.L && 1>(TT.pgrep.signal = sig_to_num(TT.pgrep.L)))
1734     error_exit("bad -L '%s'", TT.pgrep.L);
1735
1736   comma_args(TT.pgrep.G, &TT.GG, "bad -G", parse_rest);
1737   comma_args(TT.pgrep.g, &TT.gg, "bad -g", parse_rest);
1738   comma_args(TT.pgrep.P, &TT.PP, "bad -P", parse_rest);
1739   comma_args(TT.pgrep.s, &TT.ss, "bad -s", parse_rest);
1740   comma_args(TT.pgrep.t, &TT.tt, "bad -t", parse_rest);
1741   comma_args(TT.pgrep.U, &TT.UU, "bad -U", parse_rest);
1742   comma_args(TT.pgrep.u, &TT.uu, "bad -u", parse_rest);
1743
1744   if ((toys.optflags&(FLAG_x|FLAG_f)) ||
1745       !(toys.optflags&(FLAG_G|FLAG_g|FLAG_P|FLAG_s|FLAG_t|FLAG_U|FLAG_u)))
1746     if (!toys.optc) help_exit("No PATTERN");
1747
1748   if (toys.optflags&FLAG_f) TT.bits |= _PS_CMDLINE;
1749   for (arg = toys.optargs; *arg; arg++) {
1750     reg = xmalloc(sizeof(struct regex_list));
1751     xregcomp(&reg->reg, *arg, REG_EXTENDED);
1752     reg->next = TT.pgrep.regexes;
1753     TT.pgrep.regexes = reg;
1754   }
1755   TT.match_process = pgrep_match_process;
1756   TT.show_process = (void *)match_pgrep;
1757
1758   // pgrep should return failure if there are no matches.
1759   toys.exitval = 1;
1760
1761   dirtree_read("/proc", get_ps);
1762   if (toys.optflags&FLAG_c) printf("%d\n", TT.sortpos);
1763   if (TT.pgrep.snapshot) {
1764     do_pgk(TT.pgrep.snapshot);
1765     if (CFG_TOYBOX_FREE) free(TT.pgrep.snapshot);
1766   }
1767   if (TT.pgrep.d) xputc('\n');
1768 }
1769
1770 #define CLEANUP_pgrep
1771 #define FOR_pkill
1772 #include "generated/flags.h"
1773
1774 void pkill_main(void)
1775 {
1776   char **args = toys.optargs;
1777
1778   if (!(toys.optflags&FLAG_l) && *args && **args=='-') TT.pgrep.L = *(args++)+1;
1779   if (!TT.pgrep.L) TT.pgrep.signal = SIGTERM;
1780   if (toys.optflags & FLAG_V) TT.tty = 1;
1781   pgrep_main();
1782 }