OSDN Git Service

Replace slot[] constants with SLOT_blah, fix some that weren't displaying right.
[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  * TODO: ps aux (att & bsd style "ps -ax" vs "ps ax" behavior difference)
33  * TODO: switch -fl to -y
34  * TODO: thread support /proc/$d/task/%d/stat (and -o stat has "l")
35  * TODO: iotop: Window size change: respond immediately. Why not padding
36  *       at right edge? (Not adjusting to screen size at all? Header wraps?)
37
38 USE_PS(NEWTOY(ps, "k(sort)*P(ppid)*aAdeflno*p(pid)*s*t*u*U*g*G*wZ[!ol][+Ae]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
39 // stayroot because iotop needs root to read other process' proc/$$/io
40 USE_TOP(NEWTOY(top, ">0m" "p*u*d#=3<1n#<1bq", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT|TOYFLAG_LOCALE))
41 USE_IOTOP(NEWTOY(iotop, ">0Aako"  "p*u*d#=3<1n#<1bq", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT|TOYFLAG_LOCALE))
42 USE_PGREP(NEWTOY(pgrep, "?cld:u*U*t*s*P*g*G*fnovxL:", TOYFLAG_USR|TOYFLAG_BIN))
43 USE_PKILL(NEWTOY(pkill,     "Vu*U*t*s*P*g*G*fnovxl:", TOYFLAG_USR|TOYFLAG_BIN))
44
45 config PS
46   bool "ps"
47   default y
48   help
49     usage: ps [-AadeflnwZ] [-gG GROUP,] [-k FIELD,] [-o FIELD,] [-p PID,] [-t TTY,] [-uU USER,]
50
51     List processes.
52
53     Which processes to show (selections may be comma separated lists):
54
55     -A  All processes
56     -a  Processes with terminals that aren't session leaders
57     -d  All processes that aren't session leaders
58     -e  Same as -A
59     -g  Belonging to GROUPs
60     -G  Belonging to real GROUPs (before sgid)
61     -p  PIDs (--pid)
62     -P  Parent PIDs (--ppid)
63     -s  In session IDs
64     -t  Attached to selected TTYs
65     -u  Owned by USERs
66     -U  Owned by real USERs (before suid)
67
68     Output modifiers:
69
70     -k  Sort FIELDs in +increasing or -decreasting order (--sort)
71     -n  Show numeric USER and GROUP
72     -w  Wide output (don't truncate at terminal width)
73
74     Which FIELDs to show. (Default = -o PID,TTY,TIME,CMD)
75
76     -f  Full listing (-o USER:8=UID,PID,PPID,C,STIME,TTY,TIME,CMD)
77     -l  Long listing (-o F,S,UID,PID,PPID,C,PRI,NI,ADDR,SZ,WCHAN,TTY,TIME,CMD)
78     -o  Output the listed FIELDs, each with optional :size and/or =title
79     -Z  Include LABEL
80
81     Available -o FIELDs:
82
83       ADDR  Instruction pointer               ARGS    Command line (argv[] -path)
84       CMD   COMM without -f, ARGS with -f     CMDLINE Command line (argv[])
85       COMM  Original command name             COMMAND Original command path
86       CPU   Which processor running on        ETIME   Elapsed time since PID start
87       F     Flags (1=FORKNOEXEC 4=SUPERPRIV)  GID     Group id
88       GROUP Group name                        LABEL   Security label
89       MAJFL Major page faults                 MINFL   Minor page faults
90       NAME  Command name (argv[0])            NI      Niceness (lower is faster)
91       PCPU  Percentage of CPU time used       PGID    Process Group ID
92       PID   Process ID                        PPID    Parent Process ID
93       PRI   Priority (higher is faster)       PSR     Processor last executed on
94       RGID  Real (before sgid) group ID       RGROUP  Real (before sgid) group name
95       RSS   Resident Set Size (pages in use)  RTPRIO  Realtime priority
96       RUID  Real (before suid) user ID        RUSER   Real (before suid) user name
97       S     Process state:
98             R (running) S (sleeping) D (device I/O) T (stopped)  t (traced)
99             Z (zombie)  X (deader)   x (dead)       K (wakekill) W (waking)
100       SCHED Scheduling policy (0=other, 1=fifo, 2=rr, 3=batch, 4=iso, 5=idle)
101       STAT  Process state (S) plus:
102             < high priority          N low priority L locked memory
103             s session leader         + foreground   l multithreaded
104       STIME Start time of process in hh:mm (size :19 shows yyyy-mm-dd hh:mm:ss)
105       SZ    Memory Size (4k pages needed to completely swap out process)
106       TIME  CPU time consumed                 TTY     Controlling terminal
107       UID   User id                           USER    User name
108       VSZ   Virtual memory size (1k units)    %VSZ    VSZ as % of physical memory
109       WCHAN Waiting in kernel for
110
111 config TOP
112   bool "top"
113   default y
114   help
115     usage: top [-m] [ -d seconds ] [ -n iterations ]
116
117     Provide a view of process activity in real time.
118     Keys
119        N/M/P/T show CPU usage, sort by pid/mem/cpu/time
120        S       show memory
121        R       reverse sort
122        H       toggle threads
123        C,1     toggle SMP
124        Q,^C    exit
125
126     Options
127        -n Iterations before exiting
128        -d Delay between updates
129        -m Same as 's' key
130
131 # Requires CONFIG_IRQ_TIME_ACCOUNTING in the kernel for /proc/$$/io
132 config IOTOP
133   bool "iotop"
134   default y
135   help
136     usage: iotop [-Aako]
137
138     Rank processes by I/O.
139
140     -A  All I/O, not just disk
141     -a  Accumulated I/O (not percentage)
142     -k  Kilobytes
143     -o  Only show processes doing I/O
144
145     Cursor left/right to change sort, space to update, Q to exit.
146
147 config TOP_COMMON
148   bool
149   default y
150   help
151     usage: COMMON [-bq] [-n NUMBER] [-d SECONDS] [-p PID,] [-u USER,]
152     -b  Batch mode (no tty)
153     -d  Delay SECONDS between each cycle (default 3)
154     -n  Exit after NUMBER iterations
155     -p  Show these PIDs
156     -u  Show these USERs
157     -q  Quiet (no header lines)
158
159 config PGREP
160   bool "pgrep"
161   default y
162   depends on PGKILL_COMMON
163   help
164     usage: pgrep [-cL] [-d DELIM] [-L SIGNAL] [PATTERN]
165
166     Search for process(es). PATTERN is an extended regular expression checked
167     against command names.
168
169     -c  Show only count of matches
170     -d  Use DELIM instead of newline
171     -L  Send SIGNAL instead of printing name
172     -l  Show command name
173
174 config PGKILL_COMMON
175   bool
176   default y
177   help
178     usage: pgrep [-fnovx] [-G GID,] [-g PGRP,] [-P PPID,] [-s SID,] [-t TERM,] [-U UID,] [-u EUID,]
179
180     -f  Check full command line for PATTERN
181     -G  Match real Group ID(s)
182     -g  Match Process Group(s) (0 is current user)
183     -n  Newest match only
184     -o  Oldest match only
185     -P  Match Parent Process ID(s)
186     -s  Match Session ID(s) (0 for current)
187     -t  Match Terminal(s)
188     -U  Match real User ID(s)
189     -u  Match effective User ID(s)
190     -v  Negate the match
191     -x  Match whole command (not substring)
192
193 config PKILL
194   bool "pkill"
195   default y
196   help
197     usage: pkill [-l SIGNAL] [PATTERN]
198
199     -l  SIGNAL to send
200     -V  verbose
201 */
202
203 #define FOR_ps
204 #include "toys.h"
205
206 GLOBALS(
207   union {
208     struct {
209       struct arg_list *G;
210       struct arg_list *g;
211       struct arg_list *U;
212       struct arg_list *u;
213       struct arg_list *t;
214       struct arg_list *s;
215       struct arg_list *p;
216       struct arg_list *o;
217       struct arg_list *P;
218       struct arg_list *k;
219     } ps;
220     struct {
221       long n;
222       long d;
223       struct arg_list *u;
224       struct arg_list *p;
225     } top;
226     struct{
227       char *L;
228       struct arg_list *G;
229       struct arg_list *g;
230       struct arg_list *P;
231       struct arg_list *s;
232       struct arg_list *t;
233       struct arg_list *U;
234       struct arg_list *u;
235       char *d;
236
237       void *regexes;
238       int signal;
239       pid_t self;
240     } pgrep;
241   };
242
243   struct sysinfo si;
244   struct ptr_len gg, GG, pp, PP, ss, tt, uu, UU;
245   unsigned width, height;
246   dev_t tty;
247   void *fields, *kfields;
248   long long ticks, bits, ioread, iowrite, aioread, aiowrite;
249   size_t header_len;
250   int kcount, forcek, sortpos;
251   int (*match_process)(long long *slot);
252   void (*show_process)(void *tb);
253 )
254
255 struct strawberry {
256   struct strawberry *next, *prev;
257   short which, len, reverse;
258   char *title;
259   char forever[];
260 };
261
262 /* The slot[] array is mostly populated from /proc/$PID/stat (kernel proc.txt
263  * table 1-4) but we shift and repurpose fields, with the result being: */
264
265 enum {
266  SLOT_pid,      /*process id*/            SLOT_ppid,      // parent process id
267  SLOT_pgrp,     /*process group*/         SLOT_sid,       // session id
268  SLOT_ttynr,    /*tty the process uses*/  SLOT_ttypgrp,   // pgrp of the tty
269  SLOT_flags,    /*task flags*/            SLOT_minflt,    // minor faults
270  SLOT_cminflt,  /*minor faults+child*/    SLOT_majflt,    // major faults
271  SLOT_cmajflt,  /*major faults+child*/    SLOT_utime,     // user+kernel jiffies
272  SLOT_stime,    /*kernel mode jiffies*/   SLOT_cutime,    // utime+child
273  SLOT_cstime,   /*stime+child*/           SLOT_priority,  // priority level
274  SLOT_nice,     /*nice level*/            SLOT_numthreads,// thread count
275  SLOT_vmlck,    /*locked memory*/         SLOT_starttime, // jiffies after boot
276  SLOT_vsize,    /*virtual memory size*/   SLOT_rss,       // resident set size
277  SLOT_rsslim,   /*limit in bytes on rss*/ SLOT_startcode, // code segment addr
278  SLOT_endcode,  /*code segment address*/  SLOT_startstack,// stack address
279  SLOT_esp,      /*task stack pointer*/    SLOT_eip,       // instruction pointer
280  SLOT_iobytes,  /*All I/O bytes*/         SLOT_diobytes,  // disk I/O bytes
281  SLOT_utime2,   /*relative utime (top)*/  SLOT_uid,       // user id
282  SLOT_ruid,     /*real user id*/          SLOT_gid,       // group id
283  SLOT_rgid,     /*real group id*/         SLOT_exitsig,   // sent to parent
284  SLOT_taskcpu,  /*CPU running on*/        SLOT_rtprio,    // realtime priority
285  SLOT_policy,   /*man sched_setscheduler*/SLOT_blkioticks,// IO wait time
286  SLOT_gtime,    /*guest jiffies of task*/ SLOT_cgtime,    // gtime+child
287  SLOT_startbss, /*data/bss address*/      SLOT_endbss,    // end addr data+bss
288  SLOT_upticks,  /*46-19 (divisor for %)*/ SLOT_argv0len,  // argv[0] length
289  SLOT_uptime,   /*si.uptime @read time*/  SLOT_vsz,       // Virtual mem Size
290  SLOT_rss2,     /*Resident Set Size*/     SLOT_shr,       // Shared memory
291  SLOT_rchar,    /*All bytes read*/        SLOT_wchar,     // All bytes written
292  SLOT_rbytes,   /*Disk bytes read*/       SLOT_wbytes,    // Disk bytes written
293  SLOT_swap,     /*Swap pages used*/
294 };
295
296 // Data layout in toybuf
297 struct carveup {
298   long long slot[55];       // data from /proc
299   unsigned short offset[5]; // offset of fields in str[] (skip name, always 0)
300   char state;
301   char str[];               // name, tty, command, wchan, attr, cmdline
302 };
303
304 // TODO: Android uses -30 for LABEL, but ideally it would auto-size.
305 // 64|slot means compare as string when sorting
306 struct typography {
307   char *name;
308   signed char width, slot;
309 } static const typos[] = TAGGED_ARRAY(PS,
310   // Numbers
311   {"PID", 5, SLOT_pid}, {"PPID", 5, SLOT_ppid}, {"PRI", 3, SLOT_priority},
312   {"NI", 3, SLOT_nice}, {"ADDR", 4+sizeof(long), SLOT_eip},
313   {"SZ", 5, SLOT_vsize}, {"RSS", 5, SLOT_rss}, {"PGID", 5, SLOT_pgrp},
314   {"VSZ", 6, SLOT_vsize}, {"MAJFL", 6, SLOT_majflt}, {"MINFL", 6, SLOT_minflt},
315   {"PR", 2, SLOT_priority}, {"PSR", 3, SLOT_taskcpu},
316   {"RTPRIO", 6, SLOT_rtprio}, {"SCH", 3, SLOT_policy}, {"CPU", 3, SLOT_taskcpu},
317
318   // String fields
319   {"COMM", -15, -1}, {"TTY", -8, -2}, {"WCHAN", -6, -3}, {"LABEL", -30, -4},
320   {"COMMAND", -27, -5}, {"CMDLINE", -27, -6}, {"ARGS", -27, -6},
321   {"NAME", -15, -6}, {"CMD", -27, -1},
322
323   // user/group
324   {"UID", 5, SLOT_uid}, {"USER", -8, 64|SLOT_uid}, {"RUID", 4, SLOT_ruid},
325   {"RUSER", -8, 64|SLOT_ruid}, {"GID", 8, SLOT_gid}, {"GROUP", -8, 64|SLOT_gid},
326   {"RGID", 4, SLOT_rgid}, {"RGROUP", -8, 64|SLOT_rgid},
327
328   // clock displays
329   {"TIME", 8, SLOT_utime}, {"ELAPSED", 11, SLOT_starttime},
330   {"TIME+", 9, SLOT_utime},
331
332   // Percentage displays
333   {"C", 1, SLOT_utime2}, {"%VSZ", 5, SLOT_vsize}, {"%MEM", 5, SLOT_rss},
334   {"%CPU", 4, SLOT_utime2},
335
336   // human_readable
337   {"VIRT", 4, SLOT_vsz}, {"RES", 4, SLOT_rss2},
338   {"SHR", 4, SLOT_shr}, {"READ", 6, SLOT_rchar}, {"WRITE", 6, SLOT_wchar},
339   {"IO", 6, SLOT_iobytes}, {"DREAD", 6, SLOT_rbytes},
340   {"DWRITE", 6, SLOT_wbytes}, {"SWAP", 6, SLOT_swap}, {"DIO", 6, SLOT_diobytes},
341
342   // Misc
343   {"STIME", 5, SLOT_starttime}, {"F", 1, 64|SLOT_flags}, {"S", -1, 64},
344   {"STAT", -5, 64},
345
346
347 );
348
349 // Return 0 to discard, nonzero to keep
350 static int shared_match_process(long long *slot)
351 {
352   struct ptr_len match[] = {
353     {&TT.gg, SLOT_gid}, {&TT.GG, SLOT_rgid}, {&TT.pp, SLOT_pid},
354     {&TT.PP, SLOT_ppid}, {&TT.ss, SLOT_sid}, {&TT.tt, SLOT_ttynr},
355     {&TT.uu, SLOT_uid}, {&TT.UU, SLOT_ruid}
356   };
357   int i, j;
358   long *ll = 0;
359
360   // Do we have -g -G -p -P -s -t -u -U options selecting processes?
361   for (i = 0; i < ARRAY_LEN(match); i++) {
362     struct ptr_len *mm = match[i].ptr;
363     if (mm->len) {
364       ll = mm->ptr;
365       for (j = 0; j<mm->len; j++) if (ll[j] == slot[match[i].len]) return 1;
366     }
367   }
368
369   return ll ? 0 : -1;
370 }
371
372
373 // Return 0 to discard, nonzero to keep
374 static int ps_match_process(long long *slot)
375 {
376   int i = shared_match_process(slot);
377
378   if (i>0) return 1;
379   // If we had selections and didn't match them, don't display
380   if (!i) return 0;
381
382   // Filter implicit categories for other display types
383   if ((toys.optflags&(FLAG_a|FLAG_d)) && slot[SLOT_sid]==*slot) return 0;
384   if ((toys.optflags&FLAG_a) && !slot[SLOT_ttynr]) return 0;
385   if (!(toys.optflags&(FLAG_a|FLAG_d|FLAG_A|FLAG_e))
386       && TT.tty!=slot[SLOT_ttynr]) return 0;
387
388   return 1;
389 }
390
391 // Convert field to string representation
392 static char *string_field(struct carveup *tb, struct strawberry *field)
393 {
394   char *buf = toybuf+sizeof(toybuf)-260, *out = buf, *s;
395   int which = field->which, sl = typos[which].slot;
396   long long *slot = tb->slot, ll = (sl >= 0) ? slot[sl&63] : 0;
397
398   // numbers, mostly from /proc/$PID/stat
399   if (which <= PS_CPU) {
400     char *fmt = "%lld";
401
402     if (which==PS_PRI) ll = 39-ll;
403     if (which==PS_ADDR) fmt = "%llx";
404     else if (which==PS_SZ) ll >>= 12;
405     else if (which==PS_RSS) ll <<= 2;
406     else if (which==PS_VSZ) ll >>= 10;
407     else if (which==PS_PR && ll<-9) fmt="RT";
408     else if (which==PS_RTPRIO && ll == 0) fmt="-";
409     sprintf(out, fmt, ll);
410
411   // String fields
412   } else if (sl < 0) {
413     if (slot[SLOT_argv0len])
414       tb->str[tb->offset[4]+slot[SLOT_argv0len]] = (which==PS_NAME) ? 0 : ' ';
415     out = tb->str;
416     sl *= -1;
417     if (--sl) out += tb->offset[--sl];
418     if (which==PS_ARGS)
419       for (s = out; *s && *s != ' '; s++) if (*s == '/') out = s+1;
420     if (which>=PS_COMMAND && !*out) sprintf(out = buf, "[%s]", tb->str);
421
422   // user/group
423   } else if (which <= PS_RGROUP) {
424     sprintf(out, "%lld", ll);
425     if (sl&64) {
426       if (which > PS_RUSER) {
427         struct group *gr = getgrgid(ll);
428
429         if (gr) out = gr->gr_name;
430       } else {
431         struct passwd *pw = getpwuid(ll);
432
433         if (pw) out = pw->pw_name;
434       }
435     }
436
437   // Clock displays
438   } else if (which <= PS_TIME_) {
439     int unit = 60, pad = 2, j = TT.ticks; 
440     time_t seconds;
441
442     if (which!=PS_TIME_) unit *= 60*24;
443     else pad = 0;
444     // top adjusts slot[SLOT_upticks], we want original meaning.
445     if (which==PS_ELAPSED) ll = (slot[SLOT_uptime]*j)-slot[SLOT_starttime];
446     seconds = ll/j;
447
448     // Output days-hours:mins:secs, skipping non-required fields with zero
449     // TIME has 3 required fields, ETIME has 2. (Posix!) TIME+ is from top
450     for (s = 0, j = 2*(which==PS_TIME_); j<4; j++) {
451       if (!s && (seconds>unit || j == 1+(which!=PS_TIME))) s = out;
452       if (s) {
453         s += sprintf(s, j ? "%0*ld": "%*ld", pad, (long)(seconds/unit));
454         pad = 2;
455         if ((*s = "-::"[j])) s++;
456       }
457       seconds %= unit;
458       unit /= j ? 60 : 24;
459     }
460     if (which==PS_TIME_ && s-out<8)
461       sprintf(s, ".%02lld", (100*(ll%TT.ticks))/TT.ticks);
462
463   // Percentage displays
464   } else if (which <= PS__CPU) {
465     ll = slot[sl&63]*1000;
466     if (which==PS__VSZ || which==PS__MEM)
467       ll /= TT.si.totalram/((which==PS__VSZ) ? 1024 : 4096);
468     else if (slot[SLOT_upticks]) ll /= slot[SLOT_upticks];
469     sl = ll;
470     if (which==PS_C) sl += 5;
471     sprintf(out, "%d", sl/10);
472     if (which!=PS_C && sl<1000) sprintf(out+strlen(out), ".%d", sl%10);
473
474   // Human readable
475   } else if (which <= PS_DIO) {
476     ll = slot[typos[which].slot];
477     if (which <= PS_SHR) ll *= sysconf(_SC_PAGESIZE);
478     if (TT.forcek) sprintf(out, "%lldk", ll/1024);
479     else human_readable(out, ll, 0);
480
481   // Posix doesn't specify what flags should say. Man page says
482   // 1 for PF_FORKNOEXEC and 4 for PF_SUPERPRIV from linux/sched.h
483   } else if (which==PS_F) sprintf(out, "%llo", (slot[SLOT_flags]>>6)&5);
484   else if (which==PS_S || which==PS_STAT) {
485     s = out;
486     *s++ = tb->state;
487     if (which==PS_STAT) {
488       // TODO l = multithreaded
489       if (slot[SLOT_nice]<0) *s++ = '<';
490       else if (slot[SLOT_nice]>0) *s++ = 'N';
491       if (slot[SLOT_sid]==*slot) *s++ = 's';
492       if (slot[SLOT_vmlck]) *s++ = 'L';
493       if (slot[SLOT_ttypgrp]==*slot) *s++ = '+';
494     } 
495     *s = 0;
496   } else if (which==PS_STIME) {
497     time_t t = time(0)-slot[SLOT_uptime]+slot[SLOT_starttime]/TT.ticks;
498
499     // Padding behavior's a bit odd: default field size is just hh:mm.
500     // Increasing stime:size reveals more data at left until full,
501     // so move start address so yyyy-mm-dd hh:mm revealed on left at :16,
502     // then add :ss on right for :19.
503     strftime(out, 260, "%F %T", localtime(&t));
504     out = out+strlen(out)-3-abs(field->len);
505     if (out<buf) out = buf;
506
507   } else if (CFG_TOYBOX_DEBUG) error_exit("bad which %d", which);
508
509   return out;
510 }
511
512 // Display process data that get_ps() read from /proc, formatting with TT.fields
513 static void show_ps(struct carveup *tb)
514 {
515   struct strawberry *field;
516   int pad, len, width = TT.width;
517
518   // Loop through fields to display
519   for (field = TT.fields; field; field = field->next) {
520     char *out = string_field(tb, field);
521
522     // Output the field, appropriately padded
523     if (field != TT.fields) {
524       putchar(' ');
525       width--;
526     }
527     len = width;
528     pad = 0;
529     if (field->next || field->len>0)
530       len = abs(pad = width<abs(field->len) ? width : field->len);
531
532     if (TT.tty) width -= draw_trim(out, pad, len);
533     else width -= printf("%*.*s", pad, len, out);
534     if (!width) break;
535   }
536   xputc('\n');
537 }
538
539 // dirtree callback: read data about process to display, store, or discard it.
540 // Fills toybuf with struct carveup and either DIRTREE_SAVEs a copy to ->extra
541 // (in -k mode) or calls show_ps on toybuf (no malloc/copy/free there).
542 static int get_ps(struct dirtree *new)
543 {
544   struct {
545     char *name;
546     long long bits;
547   } fetch[] = {
548     {"fd/", _PS_TTY}, {"wchan", _PS_WCHAN}, {"attr/current", _PS_LABEL},
549     {"exe", _PS_COMMAND}, {"cmdline", _PS_CMDLINE|_PS_ARGS|_PS_NAME}
550   };
551   struct carveup *tb = (void *)toybuf;
552   long long *slot = tb->slot;
553   char *name, *s, *buf = tb->str, *end = 0;
554   int i, j, fd;
555   off_t len;
556
557   // Recurse one level into /proc children, skip non-numeric entries
558   if (!new->parent)
559     return DIRTREE_RECURSE|DIRTREE_SHUTUP|(DIRTREE_SAVE*!TT.show_process);
560
561   memset(slot, 0, sizeof(tb->slot));
562   if (!(*slot = atol(new->name))) return 0;
563   fd = dirtree_parentfd(new);
564
565   len = 2048;
566   sprintf(buf, "%lld/stat", *slot);
567   if (!readfileat(fd, buf, buf, &len)) return 0;
568
569   // parse oddball fields (name and state). Name can have embedded ')' so match
570   // _last_ ')' in stat (although VFS limits filenames to 255 bytes max).
571   // All remaining fields should be numeric.
572   if (!(name = strchr(buf, '('))) return 0;
573   for (s = ++name; *s; s++) if (*s == ')') end = s;
574   if (!end || end-name>255) return 0;
575
576   // Parse numeric fields (starting at 4th field in slot[SLOT_ppid])
577   if (1>sscanf(s = end, ") %c%n", &tb->state, &i)) return 0;
578   for (j = 1; j<50; j++) if (1>sscanf(s += i, " %lld%n", slot+j, &i)) break;
579
580   // Now we've read the data, move status and name right after slot[] array,
581   // and convert low chars to ? for non-tty display while we're at it.
582   for (i = 0; i<end-name; i++)
583     if ((tb->str[i] = name[i]) < ' ')
584       if (!TT.tty) tb->str[i] = '?';
585   buf = tb->str+i;
586   *buf++ = 0;
587   len = sizeof(toybuf)-(buf-toybuf);
588
589   // save uid, ruid, gid, gid, and rgid int slots 31-34 (we don't use sigcatch
590   // or numeric wchan, and the remaining two are always zero), and vmlck into
591   // 18 (which is "obsolete, always 0" from stat)
592   slot[SLOT_uid] = new->st.st_uid;
593   slot[SLOT_gid] = new->st.st_gid;
594
595   // TIME and TIME+ use combined value, ksort needs 'em added.
596   slot[SLOT_utime] += slot[SLOT_stime];
597   slot[SLOT_utime2] = slot[SLOT_utime];
598
599   // If RGROUP RUSER STAT RUID RGID SWAP happening, or -G or -U, parse "status"
600   // and save ruid, rgid, and vmlck.
601   if ((TT.bits&(_PS_RGROUP|_PS_RUSER|_PS_STAT|_PS_RUID|_PS_RGID|_PS_SWAP
602                |_PS_IO|_PS_DIO)) || TT.GG.len || TT.UU.len)
603   {
604     off_t temp = len;
605
606     sprintf(buf, "%lld/status", *slot);
607     if (!readfileat(fd, buf, buf, &temp)) *buf = 0;
608     s = strafter(buf, "\nUid:");
609     slot[SLOT_ruid] = s ? atol(s) : new->st.st_uid;
610     s = strafter(buf, "\nGid:");
611     slot[SLOT_rgid] = s ? atol(s) : new->st.st_gid;
612     if ((s = strafter(buf, "\nVmLck:"))) slot[SLOT_vmlck] = atoll(s);
613     if ((s = strafter(buf, "\nVmSwap:"))) slot[SLOT_swap] = atoll(s);
614   }
615
616   // Do we need to read "io"?
617   if (TT.bits&(_PS_READ|_PS_WRITE|_PS_DREAD|_PS_DWRITE|_PS_IO|_PS_DIO)) {
618     off_t temp = len;
619
620     sprintf(buf, "%lld/io", *slot);
621     if (!readfileat(fd, buf, buf, &temp)) *buf = 0;
622     if ((s = strafter(buf, "rchar:"))) slot[SLOT_rchar] = atoll(s);
623     if ((s = strafter(buf, "wchar:"))) slot[SLOT_wchar] = atoll(s);
624     if ((s = strafter(buf, "read_bytes:"))) slot[SLOT_rbytes] = atoll(s);
625     if ((s = strafter(buf, "write_bytes:"))) slot[SLOT_wbytes] = atoll(s);
626     slot[SLOT_iobytes] = slot[SLOT_rchar]+slot[SLOT_wchar]+slot[SLOT_swap];
627     slot[SLOT_diobytes] = slot[SLOT_rbytes]+slot[SLOT_wbytes]+slot[SLOT_swap];
628   }
629
630   // We now know enough to skip processes we don't care about.
631   if (TT.match_process && !TT.match_process(slot)) return 0;
632
633   // /proc data is generated as it's read, so for maximum accuracy on slow
634   // systems (or ps | more) we re-fetch uptime as we fetch each /proc line.
635   sysinfo(&TT.si);
636   slot[SLOT_uptime] = TT.si.uptime;
637   slot[SLOT_upticks] = slot[SLOT_uptime]*TT.ticks - slot[SLOT_rss];
638
639   // Do we need to read "statm"?
640   if (TT.bits&(_PS_VIRT|_PS_RES|_PS_SHR)) {
641     off_t temp = len;
642
643     sprintf(buf, "%lld/statm", *slot);
644     if (!readfileat(fd, buf, buf, &temp)) *buf = 0;
645     
646     for (s = buf, i=0; i<3; i++)
647       if (!sscanf(s, " %lld%n", slot+SLOT_vsz+i, &j)) slot[SLOT_vsz+i] = 0;
648       else s += j;
649   }
650
651   // Fetch string data while parentfd still available, appending to buf.
652   // (There's well over 3k of toybuf left. We could dynamically malloc, but
653   // it'd almost never get used, querying length of a proc file is awkward,
654   // fixed buffer is nommu friendly... Wait for somebody to complain. :)
655   slot[SLOT_argv0len] = 0;
656   for (j = 0; j<ARRAY_LEN(fetch); j++) { 
657     tb->offset[j] = buf-(tb->str);
658     if (!(TT.bits&fetch[j].bits)) {
659       *buf++ = 0;
660       continue;
661     }
662
663     // Determine remaining space, reserving minimum of 256 bytes/field and
664     // 260 bytes scratch space at the end (for output conversion later).
665     len = sizeof(toybuf)-(buf-toybuf)-260-256*(ARRAY_LEN(fetch)-j);
666     sprintf(buf, "%lld/%s", *slot, fetch[j].name);
667
668     // For cmdline we readlink instead of read contents
669     if (j==3) {
670       if ((len = readlinkat(fd, buf, buf, len))>0) buf[len] = 0;
671       else *buf = 0;
672
673     // If it's not the TTY field, data we want is in a file.
674     // Last length saved in slot[] is command line (which has embedded NULs)
675     } else if (!j) {
676       int rdev = slot[SLOT_ttynr];
677       struct stat st;
678
679       // Call no tty "?" rather than "0:0".
680       strcpy(buf, "?");
681       if (rdev) {
682         // Can we readlink() our way to a name?
683         for (i = 0; i<3; i++) {
684           sprintf(buf, "%lld/fd/%i", *slot, i);
685           if (!fstatat(fd, buf, &st, 0) && S_ISCHR(st.st_mode)
686             && st.st_rdev == rdev && 0<(len = readlinkat(fd, buf, buf, len)))
687           {
688             buf[len] = 0;
689             break;
690           }
691         }
692
693         // Couldn't find it, try all the tty drivers.
694         if (i == 3) {
695           FILE *fp = fopen("/proc/tty/drivers", "r");
696           int tty_major = 0, maj = major(rdev), min = minor(rdev);
697
698           if (fp) {
699             while (fscanf(fp, "%*s %256s %d %*s %*s", buf, &tty_major) == 2) {
700               // TODO: we could parse the minor range too.
701               if (tty_major == maj) {
702                 sprintf(buf+strlen(buf), "%d", min);
703                 if (!stat(buf, &st) && S_ISCHR(st.st_mode) && st.st_rdev==rdev)
704                   break;
705               }
706               tty_major = 0;
707             }
708             fclose(fp);
709           }
710
711           // Really couldn't find it, so just show major:minor.
712           if (!tty_major) sprintf(buf, "%d:%d", maj, min);
713         }
714
715         s = buf;
716         if (strstart(&s, "/dev/")) memmove(buf, s, strlen(s)+1);
717       }
718
719     // Data we want is in a file.
720     // Last length saved in slot[] is command line (which has embedded NULs)
721     } else {
722
723       // When command has no arguments, don't space over the NUL
724       if (readfileat(fd, buf, buf, &len) && len>0) {
725         int temp = 0;
726
727         if (buf[len-1]=='\n') buf[--len] = 0;
728
729         // Turn NUL to space, other low ascii to ? (in non-tty mode)
730         for (i=0; i<len; i++) {
731           char c = buf[i];
732
733           if (!c) {
734             if (!temp) temp = i;
735             c = ' ';
736           } else if (!TT.tty && c<' ') c = '?';
737           buf[i] = c;
738         }
739         len = temp; // position of _first_ NUL
740       } else *buf = len = 0;
741       // Store end of argv[0] so NAME and CMDLINE can differ.
742       slot[SLOT_argv0len] = len;
743     }
744
745     buf += strlen(buf)+1;
746   }
747
748   if (TT.show_process) {
749     TT.show_process(tb);
750
751     return 0;
752   }
753
754   // If we need to sort the output, add it to the list and return.
755   s = xmalloc(buf-toybuf);
756   new->extra = (long)s;
757   memcpy(s, toybuf, buf-toybuf);
758   TT.kcount++;
759
760   return DIRTREE_SAVE;
761 }
762
763 static char *parse_ko(void *data, char *type, int length)
764 {
765   struct strawberry *field;
766   char *width, *title, *end, *s;
767   int i, j, k;
768
769   // Get title, length of title, type, end of type, and display width
770
771   // Chip off =name to display
772   if ((end = strchr(type, '=')) && length>(end-type)) {
773     title = end+1;
774     length -= (end-type)+1;
775   } else {
776     end = type+length;
777     title = 0;
778   }
779
780   // Chip off :width to display
781   if ((width = strchr(type, ':')) && width<end) {
782     if (!title) length = width-type;
783   } else width = 0;
784
785   // Allocate structure, copy title
786   field = xzalloc(sizeof(struct strawberry)+(length+1)*!!title);
787   if (title) {
788     memcpy(field->title = field->forever, title, length);
789     field->title[field->len = length] = 0;
790   }
791
792   if (width) {
793     field->len = strtol(++width, &title, 10);
794     if (!isdigit(*width) || title != end) return title;
795     end = --width;
796   }
797
798   // Find type
799   if (*(struct strawberry **)data == TT.kfields) {
800     field->reverse = 1;
801     if (*type == '-') field->reverse = -1;
802     else if (*type != '+') type--;
803     type++;
804   }
805   for (i = 0; i<ARRAY_LEN(typos); i++) {
806     field->which = i;
807     for (j = 0; j<2; j++) {
808       if (!j) s = typos[i].name;
809       // posix requires alternate names for some fields
810       else if (-1==(k = stridx((char []){PS_NI, PS_SCH, PS_ELAPSED, PS__CPU,
811         PS_VSZ, PS_USER, 0}, i))) continue;
812       else
813         s = ((char *[]){"NICE", "SCHED", "ETIME", "PCPU", "VSIZE", "UNAME"})[k];
814
815       if (!strncasecmp(type, s, end-type) && strlen(s)==end-type) break;
816     }
817     if (j!=2) break;
818   }
819   if (i==ARRAY_LEN(typos)) return type;
820   if (!field->title) field->title = typos[field->which].name;
821   if (!field->len) field->len = typos[field->which].width;
822   else if (typos[field->which].width<0) field->len *= -1;
823   dlist_add_nomalloc(data, (void *)field);
824
825   // Print padded header for -o.
826   if (*(struct strawberry **)data == TT.fields) {
827     TT.header_len +=
828       snprintf(toybuf + TT.header_len, sizeof(toybuf) - TT.header_len,
829                " %*s" + (field == TT.fields), field->len, field->title);
830     TT.bits |= 1LL<<field->which;
831   }
832
833   return 0;
834 }
835
836 // Parse -p -s -t -u -U -g -G
837 static char *parse_rest(void *data, char *str, int len)
838 {
839   struct ptr_len *pl = (struct ptr_len *)data;
840   long *ll = pl->ptr;
841   char *end;
842   int num = 0;
843
844   // Allocate next chunk of data
845   if (!(15&pl->len))
846     ll = pl->ptr = xrealloc(pl->ptr, sizeof(long)*(pl->len+16));
847
848   // Parse numerical input
849   if (isdigit(*str)) {
850     ll[pl->len] = xstrtol(str, &end, 10);
851     if (end==(len+str)) num++;
852   }
853
854   if (pl==&TT.pp || pl==&TT.ss) {
855     if (num && ll[pl->len]>0) {
856       pl->len++;
857
858       return 0;
859     }
860   } else if (pl==&TT.tt) {
861     // -t pts = 12,pts/12 tty = /dev/tty2,tty2,S0
862     if (!num) {
863       if (strstart(&str, strcpy(toybuf, "/dev/"))) len -= 5;
864       if (strstart(&str, "pts/")) {
865         len -= 4;
866         num++;
867       } else if (strstart(&str, "tty")) len -= 3;
868     }
869     if (len<256 && (!(end = strchr(str, '/')) || end-str>len)) {
870       struct stat st;
871
872       end = toybuf + sprintf(toybuf, "/dev/%s", num ? "pts/" : "tty");
873       memcpy(end, str, len);
874       end[len] = 0;
875       xstat(toybuf, &st);
876       ll[pl->len++] = st.st_rdev;
877
878       return 0;
879     }
880   } else if (len<255) {
881     char name[256];
882
883     if (num) {
884       pl->len++;
885
886       return 0;
887     }
888
889     memcpy(name, str, len);
890     name[len] = 0;
891     if (pl==&TT.gg || pl==&TT.GG) {
892       struct group *gr = getgrnam(name);
893       if (gr) {
894         ll[pl->len++] = gr->gr_gid;
895
896         return 0;
897       }
898     } else if (pl==&TT.uu || pl==&TT.UU) {
899       struct passwd *pw = getpwnam(name);
900       if (pw) {
901         ll[pl->len++] = pw->pw_uid;
902
903         return 0;
904       }
905     }
906   }
907
908   // Return error
909   return str;
910 }
911
912 // sort for -k
913 static int ksort(void *aa, void *bb)
914 {
915   struct strawberry *field;
916   struct carveup *ta = *(struct carveup **)aa, *tb = *(struct carveup **)bb;
917   int ret = 0, slot;
918
919   for (field = TT.kfields; field && !ret; field = field->next) {
920     slot = typos[field->which].slot;
921
922     // Can we do numeric sort?
923     if (!(slot&64)) {
924       if (ta->slot[slot]<tb->slot[slot]) ret = -1;
925       if (ta->slot[slot]>tb->slot[slot]) ret = 1;
926     }
927
928     // fallback to string sort
929     if (!ret) {
930       memccpy(toybuf, string_field(ta, field), 0, 2048);
931       toybuf[2048] = 0;
932       ret = strcmp(toybuf, string_field(tb, field));
933     }
934     ret *= field->reverse;
935   }
936
937   return ret;
938 }
939
940 static struct carveup **collate(int count, struct dirtree *dt,
941   int (*sort)(void *a, void *b))
942 {
943   struct dirtree *temp;
944   struct carveup **tbsort = xmalloc(count*sizeof(struct carveup *));
945   int i;
946
947   // descend into child list
948   *tbsort = (void *)dt;
949   dt = dt->child;
950   free(*tbsort);
951
952   // populate array
953   for (i = 0; i < count; i++) {
954     temp = dt->next;
955     tbsort[i] = (void *)dt->extra;
956     free(dt);
957     dt = temp;
958   }
959
960   return tbsort;
961
962
963 static void shared_main(void)
964 {
965   int i;
966
967   TT.ticks = sysconf(_SC_CLK_TCK);
968   if (!TT.width) {
969     TT.width = 80;
970     TT.height = 25;
971     terminal_size(&TT.width, &TT.height);
972   }
973
974   // find controlling tty, falling back to /dev/tty if none
975   for (i = 0; !TT.tty && i<4; i++) {
976     struct stat st;
977     int fd = i;
978
979     if (i==3 && -1==(fd = open("/dev/tty", O_RDONLY))) break;
980
981     if (isatty(fd) && !fstat(fd, &st)) TT.tty = st.st_rdev;
982     if (i==3) close(fd);
983   }
984 }
985
986 void ps_main(void)
987 {
988   struct dirtree *dt;
989   int i;
990
991   if (toys.optflags&FLAG_w) TT.width = 99999;
992   shared_main();
993
994   // parse command line options other than -o
995   comma_args(TT.ps.P, &TT.PP, "bad -P", parse_rest);
996   comma_args(TT.ps.p, &TT.pp, "bad -p", parse_rest);
997   comma_args(TT.ps.t, &TT.tt, "bad -t", parse_rest);
998   comma_args(TT.ps.s, &TT.ss, "bad -s", parse_rest);
999   comma_args(TT.ps.u, &TT.uu, "bad -u", parse_rest);
1000   comma_args(TT.ps.U, &TT.UU, "bad -U", parse_rest);
1001   comma_args(TT.ps.g, &TT.gg, "bad -g", parse_rest);
1002   comma_args(TT.ps.G, &TT.GG, "bad -G", parse_rest);
1003   comma_args(TT.ps.k, &TT.kfields, "bad -k", parse_ko);
1004   dlist_terminate(TT.kfields);
1005
1006   // Parse manual field selection, or default/-f/-l, plus -Z,
1007   // constructing the header line in toybuf as we go.
1008   if (toys.optflags&FLAG_Z) {
1009     struct arg_list Z = { 0, "LABEL" };
1010
1011     comma_args(&Z, &TT.fields, "-Z", parse_ko);
1012   }
1013   if (TT.ps.o) comma_args(TT.ps.o, &TT.fields, "bad -o field", parse_ko);
1014   else {
1015     struct arg_list al;
1016
1017     al.next = 0;
1018     if (toys.optflags&FLAG_f)
1019       al.arg = "USER:8=UID,PID,PPID,C,STIME,TTY,TIME,CMD";
1020     else if (toys.optflags&FLAG_l)
1021       al.arg = "F,S,UID,PID,PPID,C,PRI,NI,ADDR,SZ,WCHAN,TTY,TIME,CMD";
1022     else if (CFG_TOYBOX_ON_ANDROID)
1023       al.arg = "USER,PID,PPID,VSIZE,RSS,WCHAN:10,ADDR:10=PC,S,CMDLINE";
1024     else al.arg = "PID,TTY,TIME,CMD";
1025
1026     comma_args(&al, &TT.fields, 0, parse_ko);
1027   }
1028   dlist_terminate(TT.fields);
1029   printf("%s\n", toybuf);
1030
1031   // misunderstand fields the flags say to
1032   if (toys.optflags&(FLAG_f|FLAG_n)) {
1033     struct strawberry *ever;
1034
1035     for (ever = TT.fields; ever; ever = ever->next) {
1036       int alluc = ever->which;
1037
1038       if ((toys.optflags&FLAG_f) && alluc==PS_CMD) alluc = PS_ARGS;
1039       if ((toys.optflags&FLAG_n) && alluc>=PS_UID && alluc<=PS_RGROUP
1040           && (typos[alluc].slot&64)) alluc--;
1041       if (alluc != ever->which) {
1042         TT.bits &= 1LL<<ever->which;
1043         TT.bits |= 1LL<<(ever->which = alluc);
1044       }
1045     }
1046   }
1047
1048   if (!(toys.optflags&FLAG_k)) TT.show_process = (void *)show_ps;
1049   TT.match_process = ps_match_process;
1050   dt = dirtree_read("/proc", get_ps);
1051
1052   if (toys.optflags&FLAG_k) {
1053     struct carveup **tbsort = collate(TT.kcount, dt, ksort);
1054
1055     qsort(tbsort, TT.kcount, sizeof(struct carveup *), (void *)ksort);
1056     for (i = 0; i<TT.kcount; i++) {
1057       show_ps(tbsort[i]);
1058       free(tbsort[i]);
1059     }
1060     if (CFG_TOYBOX_FREE) free(tbsort);
1061   }
1062
1063   if (CFG_TOYBOX_FREE) {
1064     free(TT.gg.ptr);
1065     free(TT.GG.ptr);
1066     free(TT.pp.ptr);
1067     free(TT.PP.ptr);
1068     free(TT.ss.ptr);
1069     free(TT.tt.ptr);
1070     free(TT.uu.ptr);
1071     free(TT.UU.ptr);
1072     llist_traverse(TT.fields, free);
1073   }
1074 }
1075
1076 #define CLEANUP_ps
1077 #define FOR_top
1078 #include "generated/flags.h"
1079
1080 // select which of the -o fields to sort by
1081 static void setsort(int pos)
1082 {
1083   struct strawberry *field, *going2;
1084   int i = 0;
1085
1086   if (pos<0) pos = 0;
1087
1088   for (field = TT.fields; field; field = field->next) {
1089     if ((TT.sortpos = i++)<pos) continue;
1090     going2 = TT.kfields;
1091     going2->which = field->which;
1092     going2->len = field->len;
1093     break;
1094   }
1095 }
1096
1097 // If we have both, adjust slot[deltas[]] to be relative to previous
1098 // measurement rather than process start. Stomping old.data is fine
1099 // because we free it after displaying.
1100 static int merge_deltas(long long *oslot, long long *nslot)
1101 {
1102   char deltas[] = {SLOT_utime2, SLOT_iobytes, SLOT_diobytes, SLOT_upticks,
1103                    SLOT_rchar, SLOT_wchar, SLOT_rbytes, SLOT_wbytes, SLOT_swap};
1104   int i;
1105
1106   for (i = 0; i<ARRAY_LEN(deltas); i++)
1107     oslot[deltas[i]] = nslot[deltas[i]] - oslot[deltas[i]];
1108
1109   return 1;
1110 }
1111
1112 static void top_common(char *header,
1113   int (*filter)(long long *oslot, long long *nslot))
1114 {
1115   struct timespec ts;
1116   long long timeout = 0, now;
1117   struct proclist {
1118     struct carveup **tb;
1119     int count;
1120   } plist[2], *plold, *plnew, old, new, mix;
1121   char scratch[16];
1122   unsigned tock = 0;
1123   int i, lines, done = 0;
1124
1125   *scratch = 0;
1126   TT.top.d *= 1000;
1127   if (toys.optflags&FLAG_b) TT.width = TT.height = 99999;
1128   else {
1129     xset_terminal(0, 1, 0);
1130     sigatexit(tty_sigreset);
1131   }
1132   shared_main();
1133
1134   comma_args(TT.top.u, &TT.uu, "bad -u", parse_rest);
1135   comma_args(TT.top.p, &TT.pp, "bad -p", parse_rest);
1136
1137   TT.match_process = shared_match_process;
1138   memset(plist, 0, sizeof(plist));
1139   do {
1140     struct dirtree *dt = dirtree_read("/proc", get_ps);
1141
1142     plold = plist+(tock++&1);
1143     plnew = plist+(tock&1);
1144     plnew->tb = collate(plnew->count = TT.kcount, dt, ksort);
1145     TT.kcount = 0;
1146
1147     // First time, wait a quarter of a second to collect a little delta data.
1148     if (!plold->tb) {
1149       msleep(250);
1150       continue;
1151     }
1152
1153     // Collate old and new into "mix", depends on /proc read in pid sort order
1154     old = *plold;
1155     new = *plnew;
1156     mix.tb = xmalloc((old.count+new.count)*sizeof(struct carveup));
1157     mix.count = 0;
1158
1159     while (old.count || new.count) {
1160       struct carveup *otb = *old.tb, *ntb = *new.tb;
1161
1162       // If we just have old, discard it.
1163       if (old.count && (!new.count || *otb->slot < *ntb->slot)) {
1164         old.tb++;
1165         old.count--;
1166
1167         continue;
1168       }
1169
1170       // If we just have new, use it verbatim
1171       if (!old.count || *otb->slot > *ntb->slot) mix.tb[mix.count] = ntb;
1172       else {
1173         // Keep or discard
1174         if (filter(otb->slot, ntb->slot)) {
1175           mix.tb[mix.count] = otb;
1176           mix.count++;
1177         }
1178         old.tb++;
1179         old.count--;
1180       }
1181       new.tb++;
1182       new.count--;
1183     }
1184
1185     // Will will re-fetch no data before its time. - Mork calling Orson Welles
1186     for (;;) {
1187       char was, is, *pos;
1188
1189       qsort(mix.tb, mix.count, sizeof(struct carveup *), (void *)ksort);
1190 printf("cheese\n");
1191       if (!(toys.optflags&FLAG_b)) printf("\033[H\033[J");
1192       if (!(toys.optflags&FLAG_q)) {
1193         i = 0;
1194         strcpy(pos = toybuf, header);
1195
1196         for (i=0, is = *pos; *pos; pos++) {
1197           was = is;
1198           is = *pos;
1199           if (isspace(was) && !isspace(is) && i++==TT.sortpos) pos[-1] = '[';
1200           if (!isspace(was) && isspace(is) && i==TT.sortpos+1) *pos = ']';
1201         }
1202         *pos = 0;
1203         printf("\033[7m%*.*s\033[0m\n\r",
1204           (toys.optflags&FLAG_b) ? 0 : -TT.width, TT.width, toybuf);
1205
1206         if (!(toys.optflags&FLAG_b))
1207           terminal_probesize(&TT.width, &TT.height);
1208       }
1209       lines = TT.height-2;
1210
1211       for (i=0; i<lines && i<mix.count; i++) {
1212         show_ps(mix.tb[i]);
1213         xputc('\r');
1214       }
1215
1216       if (TT.top.n && !--TT.top.n) {
1217         done++;
1218         break;
1219       }
1220
1221       // Get current time in miliseconds
1222       clock_gettime(CLOCK_MONOTONIC, &ts);
1223       now = ts.tv_sec*1000+ts.tv_nsec/1000000;
1224       if (timeout<=now) timeout += TT.top.d;
1225       if (timeout<=now) timeout = now+TT.top.d;
1226
1227       i = scan_key_getsize(scratch, timeout-now, &TT.width, &TT.height);
1228       if (i==-1 || i==3 || toupper(i)=='Q') {
1229         done++;
1230         break;
1231       }
1232       if (i==-2) break;
1233
1234       // Flush unknown escape sequences.
1235       if (i==27) while (0<scan_key_getsize(scratch, 0, &TT.width, &TT.height));
1236       else if (i==' ') {
1237         timeout = now;
1238         break;
1239       } else {
1240         i -= 256;
1241         if (i == KEY_LEFT) setsort(TT.sortpos-1);
1242         else if (i == KEY_RIGHT) setsort(TT.sortpos+1);
1243       }
1244       continue;
1245     }
1246
1247     free(mix.tb);
1248     for (i=0; i<plold->count; i++) free(plold->tb[i]);
1249     free(plold->tb);
1250   } while (!done);
1251   if (!(toys.optflags&FLAG_b)) tty_reset();
1252 }
1253
1254 void top_main(void)
1255 {
1256   struct arg_list al;
1257   char *header;
1258
1259   // Display fields
1260   al.next = 0;
1261   al.arg = xstrdup("PID,USER,PR,NI,VIRT,RES,SHR,S,%CPU,%MEM,TIME+,CMDLINE");
1262   comma_args(&al, &TT.fields, 0, parse_ko);
1263   free(al.arg);
1264   dlist_terminate(TT.fields);
1265   header=xstrdup(toybuf);
1266
1267   // Fallback sorts
1268   al.arg = xstrdup("-S,-%CPU,-ETIME,-PID");
1269   comma_args(&al, &TT.kfields, "bang", parse_ko);
1270   dlist_terminate(TT.kfields);
1271   setsort(8);
1272
1273   top_common(header, merge_deltas);
1274 }
1275
1276 #define CLEANUP_top
1277 #define FOR_iotop
1278 #include "generated/flags.h"
1279
1280 static int iotop_filter(long long *oslot, long long *nslot)
1281 {
1282   if (!(toys.optflags&FLAG_a)) merge_deltas(oslot, nslot);
1283
1284   return !(toys.optflags&FLAG_o) || oslot[SLOT_iobytes+!(toys.optflags&FLAG_A)];
1285 }
1286
1287 void iotop_main(void)
1288 {
1289   struct arg_list al;
1290   char *header, *d = "D"+!!(toys.optflags&FLAG_A);
1291
1292   if (toys.optflags&FLAG_k) TT.forcek++;
1293
1294   al.next = 0;
1295   al.arg = xmprintf("PID,PR,USER,%sREAD,%sWRITE,SWAP,%sIO,COMM", d, d, d);
1296   comma_args(&al, &TT.fields, 0, parse_ko);
1297   free(al.arg);
1298   dlist_terminate(TT.fields);
1299   header = strdup(toybuf);
1300
1301   // Fallback sorts. First (dummy) field gets overwritten by setsort()
1302   al.arg = xmprintf("-S,-%sIO,-ETIME,-PID",d);
1303   comma_args(&al, &TT.kfields, 0, parse_ko);
1304   free(al.arg);
1305   dlist_terminate(TT.kfields);
1306   setsort(6);
1307
1308   top_common(header, iotop_filter);
1309 }
1310
1311 // pkill's plumbing wrap's pgrep's and thus mostly takes place in pgrep's flag
1312 // context, so force pgrep's flags on even when building pkill standalone.
1313 // (All the pgrep/pkill functions drop out when building ps standalone.)
1314 #define FORCE_FLAGS
1315 #define CLEANUP_iotop
1316 #define FOR_pgrep
1317 #include "generated/flags.h"
1318
1319 struct regex_list {
1320   struct regex_list *next;
1321   regex_t reg;
1322 };
1323
1324 static void show_pgrep(struct carveup *tb)
1325 {
1326   regmatch_t match;
1327   struct regex_list *reg;
1328   char *name = tb->str;
1329
1330   // Never match ourselves.
1331   if (TT.pgrep.self == *tb->slot) return;
1332
1333   if (toys.optflags&FLAG_f) name += tb->offset[4];
1334
1335   if (TT.pgrep.regexes) {
1336     for (reg = TT.pgrep.regexes; reg; reg = reg->next) {
1337       if (regexec(&reg->reg, name, 1, &match, 0)) continue;
1338       if (toys.optflags&FLAG_x)
1339         if (match.rm_so || match.rm_eo!=strlen(name)) continue;
1340       break;
1341     }
1342     if ((toys.optflags&FLAG_v) ? !!reg : !reg) return;
1343   }
1344
1345   // Repurpose a field for -c count
1346   TT.sortpos++;
1347   if (TT.pgrep.signal) {
1348     if (kill(*tb->slot, TT.pgrep.signal)) {
1349       char *s = num_to_sig(TT.pgrep.signal);
1350
1351       if (!s) sprintf(s = toybuf, "%d", TT.pgrep.signal);
1352       perror_msg("%s->%lld", s, *tb->slot);
1353     }
1354   }
1355   if (!(toys.optflags&FLAG_c) && (!TT.pgrep.signal || TT.tty)) {
1356     printf("%lld", *tb->slot);
1357     if (toys.optflags&FLAG_l) printf(" %s", name);
1358     
1359     printf("%s", TT.pgrep.d ? TT.pgrep.d : "\n");
1360   }
1361 }
1362
1363 static int pgrep_match_process(long long *slot)
1364 {
1365   int match = shared_match_process(slot);
1366
1367   return (toys.optflags&FLAG_v) ? !match : match;
1368 }
1369
1370 void pgrep_main(void)
1371 {
1372   char **arg;
1373   struct regex_list *reg;
1374
1375   TT.pgrep.self = getpid();
1376
1377   // No signal names start with "L", so no need for "L: " parsing.
1378   if (TT.pgrep.L && 1>(TT.pgrep.signal = sig_to_num(TT.pgrep.L)))
1379     error_exit("bad -L '%s'", TT.pgrep.L);
1380
1381   comma_args(TT.pgrep.G, &TT.GG, "bad -G", parse_rest);
1382   comma_args(TT.pgrep.g, &TT.gg, "bad -g", parse_rest);
1383   comma_args(TT.pgrep.P, &TT.PP, "bad -P", parse_rest);
1384   comma_args(TT.pgrep.s, &TT.ss, "bad -s", parse_rest);
1385   comma_args(TT.pgrep.t, &TT.tt, "bad -t", parse_rest);
1386   comma_args(TT.pgrep.U, &TT.UU, "bad -U", parse_rest);
1387   comma_args(TT.pgrep.u, &TT.uu, "bad -u", parse_rest);
1388
1389   if ((toys.optflags&(FLAG_x|FLAG_f)) ||
1390       !(toys.optflags&(FLAG_G|FLAG_g|FLAG_P|FLAG_s|FLAG_t|FLAG_U|FLAG_u)))
1391     if (!toys.optc) help_exit("No PATTERN");
1392
1393   if (toys.optflags&FLAG_f) TT.bits |= _PS_CMDLINE;
1394   for (arg = toys.optargs; *arg; arg++) {
1395     reg = xmalloc(sizeof(struct regex_list));
1396     xregcomp(&reg->reg, *arg, REG_EXTENDED);
1397     reg->next = TT.pgrep.regexes;
1398     TT.pgrep.regexes = reg;
1399   }
1400   TT.match_process = pgrep_match_process;
1401   TT.show_process = (void *)show_pgrep;
1402
1403   dirtree_read("/proc", get_ps);
1404   if (toys.optflags&FLAG_c) printf("%d\n", TT.sortpos);
1405   if (TT.pgrep.d) xputc('\n');
1406 }
1407
1408 #define CLEANUP_pgrep
1409 #define FOR_pkill
1410 #include "generated/flags.h"
1411
1412 void pkill_main(void)
1413 {
1414   if (!TT.pgrep.L) TT.pgrep.signal = SIGTERM;
1415   if (toys.optflags & FLAG_V) TT.tty = 1;
1416   pgrep_main();
1417 }