1*cf5a6c84SAndroid Build Coastguard Worker /* ps.c - show process list
2*cf5a6c84SAndroid Build Coastguard Worker *
3*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2015 Rob Landley <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker *
5*cf5a6c84SAndroid Build Coastguard Worker * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html
6*cf5a6c84SAndroid Build Coastguard Worker * And http://kernel.org/doc/Documentation/filesystems/proc.txt Table 1-4
7*cf5a6c84SAndroid Build Coastguard Worker * And linux kernel source fs/proc/array.c function do_task_stat()
8*cf5a6c84SAndroid Build Coastguard Worker *
9*cf5a6c84SAndroid Build Coastguard Worker * Deviations from posix: no -n because /proc/self/wchan exists; we use -n to
10*cf5a6c84SAndroid Build Coastguard Worker * mean "show numeric users and groups" instead.
11*cf5a6c84SAndroid Build Coastguard Worker * Posix says default output should have field named "TTY" but if you "-o tty"
12*cf5a6c84SAndroid Build Coastguard Worker * the same field should be called "TT" which is _INSANE_ and I'm not doing it.
13*cf5a6c84SAndroid Build Coastguard Worker * Similarly -f outputs USER but calls it UID (we call it USER).
14*cf5a6c84SAndroid Build Coastguard Worker * It also says that -o "args" and "comm" should behave differently but use
15*cf5a6c84SAndroid Build Coastguard Worker * the same title, which is not the same title as the default output. (No.)
16*cf5a6c84SAndroid Build Coastguard Worker * Select by session id is -s not -g. Posix doesn't say truncated fields
17*cf5a6c84SAndroid Build Coastguard Worker * should end with "+" but it's pretty common behavior.
18*cf5a6c84SAndroid Build Coastguard Worker *
19*cf5a6c84SAndroid Build Coastguard Worker * Posix defines -o ADDR as "The address of the process" but the process
20*cf5a6c84SAndroid Build Coastguard Worker * start address is a constant on any elf system with mmu. The procps ADDR
21*cf5a6c84SAndroid Build Coastguard Worker * field always prints "-" with an alignment of 1, which is why it has 11
22*cf5a6c84SAndroid Build Coastguard Worker * characters left for "cmd" in in 80 column "ps -l" mode. On x86-64 you
23*cf5a6c84SAndroid Build Coastguard Worker * need 12 chars, leaving nothing for cmd: I.E. posix 2008 ps -l mode can't
24*cf5a6c84SAndroid Build Coastguard Worker * be sanely implemented on 64 bit Linux systems. In procps there's ps -y
25*cf5a6c84SAndroid Build Coastguard Worker * which changes -l by removing the "F" column and swapping RSS for ADDR,
26*cf5a6c84SAndroid Build Coastguard Worker * leaving 9 chars for cmd, so we're using that as our -l output.
27*cf5a6c84SAndroid Build Coastguard Worker *
28*cf5a6c84SAndroid Build Coastguard Worker * Added a bunch of new -o fields posix doesn't mention, and we don't
29*cf5a6c84SAndroid Build Coastguard Worker * label "ps -o command,args,comm" as "COMMAND COMMAND COMMAND". We don't
30*cf5a6c84SAndroid Build Coastguard Worker * output argv[0] unmodified for -o comm or -o args (but procps violates
31*cf5a6c84SAndroid Build Coastguard Worker * posix for -o comm anyway, it's stat[2] not argv[0]).
32*cf5a6c84SAndroid Build Coastguard Worker *
33*cf5a6c84SAndroid Build Coastguard Worker * Note: iotop is STAYROOT so it can read other process's /proc/$PID/io
34*cf5a6c84SAndroid Build Coastguard Worker * files (why they're not globally readable when the rest of proc
35*cf5a6c84SAndroid Build Coastguard Worker * data is...?) and get a global I/O picture. Normal top is NOT,
36*cf5a6c84SAndroid Build Coastguard Worker * even though you can -o AIO there, to give sysadmins the option
37*cf5a6c84SAndroid Build Coastguard Worker * to reduce security exposure.)
38*cf5a6c84SAndroid Build Coastguard Worker *
39*cf5a6c84SAndroid Build Coastguard Worker * TODO: ps aux (att & bsd style "ps -ax" vs "ps ax" behavior difference)
40*cf5a6c84SAndroid Build Coastguard Worker * TODO: switch -fl to -y
41*cf5a6c84SAndroid Build Coastguard Worker * TODO: thread support /proc/$d/task/%d/stat (and -o stat has "l")
42*cf5a6c84SAndroid Build Coastguard Worker * TODO: iotop: Window size change: respond immediately. Why not padding
43*cf5a6c84SAndroid Build Coastguard Worker * at right edge? (Not adjusting to screen size at all? Header wraps?)
44*cf5a6c84SAndroid Build Coastguard Worker * TODO: top: thread support and SMP
45*cf5a6c84SAndroid Build Coastguard Worker * TODO: pgrep -f only searches the amount of cmdline that fits in toybuf.
46*cf5a6c84SAndroid Build Coastguard Worker * TODO: pgrep qemu-system-i386 never matches because one char too long
47*cf5a6c84SAndroid Build Coastguard Worker
48*cf5a6c84SAndroid Build Coastguard Worker USE_PS(NEWTOY(ps, "k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*Tu*U*g*G*wZ[!ol][+Ae][!oO]", TOYFLAG_BIN))
49*cf5a6c84SAndroid Build Coastguard Worker // stayroot because iotop needs root to read other process' proc/$$/io
50*cf5a6c84SAndroid Build Coastguard Worker // TOP and IOTOP have a large common option block used for common processing,
51*cf5a6c84SAndroid Build Coastguard Worker // the default values are different but the flags are in the same order.
52*cf5a6c84SAndroid Build Coastguard Worker USE_TOP(NEWTOY(top, ">0O*h" "Hk*o*p*u*s#<1d%<100=3000m#n#<1bq[!oO]", TOYFLAG_USR|TOYFLAG_BIN))
53*cf5a6c84SAndroid Build Coastguard Worker USE_IOTOP(NEWTOY(iotop, ">0AaKO" "Hk*o*p*u*s#<1=7d%<100=3000m#n#<1bq", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT))
54*cf5a6c84SAndroid Build Coastguard Worker USE_PGREP(NEWTOY(pgrep, "?cld:u*U*t*s*P*g*G*fnovxL:[-no]", TOYFLAG_USR|TOYFLAG_BIN))
55*cf5a6c84SAndroid Build Coastguard Worker USE_PKILL(NEWTOY(pkill, "?Vu*U*t*s*P*g*G*fnovxl:[-no]", TOYFLAG_USR|TOYFLAG_BIN))
56*cf5a6c84SAndroid Build Coastguard Worker
57*cf5a6c84SAndroid Build Coastguard Worker config PS
58*cf5a6c84SAndroid Build Coastguard Worker bool "ps"
59*cf5a6c84SAndroid Build Coastguard Worker default y
60*cf5a6c84SAndroid Build Coastguard Worker help
61*cf5a6c84SAndroid Build Coastguard Worker usage: ps [-AadefLlnwZ] [-gG GROUP,] [-k FIELD,] [-o FIELD,] [-p PID,] [-t TTY,] [-uU USER,]
62*cf5a6c84SAndroid Build Coastguard Worker
63*cf5a6c84SAndroid Build Coastguard Worker List processes.
64*cf5a6c84SAndroid Build Coastguard Worker
65*cf5a6c84SAndroid Build Coastguard Worker Which processes to show (-gGuUpPt selections may be comma separated lists):
66*cf5a6c84SAndroid Build Coastguard Worker
67*cf5a6c84SAndroid Build Coastguard Worker -A All -a Has terminal not session leader
68*cf5a6c84SAndroid Build Coastguard Worker -d All but session leaders -e Synonym for -A
69*cf5a6c84SAndroid Build Coastguard Worker -g In GROUPs -G In real GROUPs (before sgid)
70*cf5a6c84SAndroid Build Coastguard Worker -p PIDs (--pid) -P Parent PIDs (--ppid)
71*cf5a6c84SAndroid Build Coastguard Worker -s In session IDs -t Attached to selected TTYs
72*cf5a6c84SAndroid Build Coastguard Worker -T Show threads also -u Owned by selected USERs
73*cf5a6c84SAndroid Build Coastguard Worker -U Real USERs (before suid)
74*cf5a6c84SAndroid Build Coastguard Worker
75*cf5a6c84SAndroid Build Coastguard Worker Output modifiers:
76*cf5a6c84SAndroid Build Coastguard Worker
77*cf5a6c84SAndroid Build Coastguard Worker -k Sort FIELDs (-FIELD to reverse) -M Measure/pad future field widths
78*cf5a6c84SAndroid Build Coastguard Worker -n Show numeric USER and GROUP -w Wide output (don't truncate fields)
79*cf5a6c84SAndroid Build Coastguard Worker
80*cf5a6c84SAndroid Build Coastguard Worker Which FIELDs to show. (-o HELP for list, default = -o PID,TTY,TIME,CMD)
81*cf5a6c84SAndroid Build Coastguard Worker
82*cf5a6c84SAndroid Build Coastguard Worker -f Full listing (-o USER:12=UID,PID,PPID,C,STIME,TTY,TIME,ARGS=CMD)
83*cf5a6c84SAndroid Build Coastguard Worker -l Long listing (-o F,S,UID,PID,PPID,C,PRI,NI,ADDR,SZ,WCHAN,TTY,TIME,CMD)
84*cf5a6c84SAndroid Build Coastguard Worker -o Output FIELDs instead of defaults, each with optional :size and =title
85*cf5a6c84SAndroid Build Coastguard Worker -O Add FIELDS to defaults
86*cf5a6c84SAndroid Build Coastguard Worker -Z Include LABEL
87*cf5a6c84SAndroid Build Coastguard Worker
88*cf5a6c84SAndroid Build Coastguard Worker config TOP
89*cf5a6c84SAndroid Build Coastguard Worker bool "top"
90*cf5a6c84SAndroid Build Coastguard Worker default y
91*cf5a6c84SAndroid Build Coastguard Worker help
92*cf5a6c84SAndroid Build Coastguard Worker usage: top [-Hhbq] [-k FIELD,] [-o FIELD,] [-s SORT] [-n NUMBER] [-m LINES] [-d SECONDS] [-p PID,] [-u USER,]
93*cf5a6c84SAndroid Build Coastguard Worker
94*cf5a6c84SAndroid Build Coastguard Worker Show process activity in real time.
95*cf5a6c84SAndroid Build Coastguard Worker
96*cf5a6c84SAndroid Build Coastguard Worker -H Show threads
97*cf5a6c84SAndroid Build Coastguard Worker -h Usage graphs instead of text
98*cf5a6c84SAndroid Build Coastguard Worker -k Fallback sort FIELDS (default -S,-%CPU,-ETIME,-PID)
99*cf5a6c84SAndroid Build Coastguard Worker -o Show FIELDS (def PID,USER,PR,NI,VIRT,RES,SHR,S,%CPU,%MEM,TIME+,CMDLINE)
100*cf5a6c84SAndroid Build Coastguard Worker -O Add FIELDS (replacing PR,NI,VIRT,RES,SHR,S from default)
101*cf5a6c84SAndroid Build Coastguard Worker -s Sort by field number (1-X, default 9)
102*cf5a6c84SAndroid Build Coastguard Worker -b Batch mode (no tty)
103*cf5a6c84SAndroid Build Coastguard Worker -d Delay SECONDS between each cycle (default 3)
104*cf5a6c84SAndroid Build Coastguard Worker -m Maximum number of tasks to show
105*cf5a6c84SAndroid Build Coastguard Worker -n Exit after NUMBER iterations
106*cf5a6c84SAndroid Build Coastguard Worker -p Show these PIDs
107*cf5a6c84SAndroid Build Coastguard Worker -u Show these USERs
108*cf5a6c84SAndroid Build Coastguard Worker -q Quiet (no header lines)
109*cf5a6c84SAndroid Build Coastguard Worker
110*cf5a6c84SAndroid Build Coastguard Worker Cursor UP/DOWN or LEFT/RIGHT to move list, SHIFT LEFT/RIGHT to change sort,
111*cf5a6c84SAndroid Build Coastguard Worker space to force update, R to reverse sort, Q to exit.
112*cf5a6c84SAndroid Build Coastguard Worker
113*cf5a6c84SAndroid Build Coastguard Worker # Requires CONFIG_IRQ_TIME_ACCOUNTING in the kernel for /proc/$$/io
114*cf5a6c84SAndroid Build Coastguard Worker config IOTOP
115*cf5a6c84SAndroid Build Coastguard Worker bool "iotop"
116*cf5a6c84SAndroid Build Coastguard Worker default y
117*cf5a6c84SAndroid Build Coastguard Worker help
118*cf5a6c84SAndroid Build Coastguard Worker usage: iotop [-AaKObq] [-n NUMBER] [-d SECONDS] [-p PID,] [-u USER,]
119*cf5a6c84SAndroid Build Coastguard Worker
120*cf5a6c84SAndroid Build Coastguard Worker Rank processes by I/O.
121*cf5a6c84SAndroid Build Coastguard Worker
122*cf5a6c84SAndroid Build Coastguard Worker -A All I/O, not just disk
123*cf5a6c84SAndroid Build Coastguard Worker -a Accumulated I/O (not percentage)
124*cf5a6c84SAndroid Build Coastguard Worker -H Show threads
125*cf5a6c84SAndroid Build Coastguard Worker -K Kilobytes
126*cf5a6c84SAndroid Build Coastguard Worker -k Fallback sort FIELDS (default -[D]IO,-ETIME,-PID)
127*cf5a6c84SAndroid Build Coastguard Worker -m Maximum number of tasks to show
128*cf5a6c84SAndroid Build Coastguard Worker -O Only show processes doing I/O
129*cf5a6c84SAndroid Build Coastguard Worker -o Show FIELDS (default PID,PR,USER,[D]READ,[D]WRITE,SWAP,[D]IO,COMM)
130*cf5a6c84SAndroid Build Coastguard Worker -s Sort by field number (0-X, default 6)
131*cf5a6c84SAndroid Build Coastguard Worker -b Batch mode (no tty)
132*cf5a6c84SAndroid Build Coastguard Worker -d Delay SECONDS between each cycle (default 3)
133*cf5a6c84SAndroid Build Coastguard Worker -n Exit after NUMBER iterations
134*cf5a6c84SAndroid Build Coastguard Worker -p Show these PIDs
135*cf5a6c84SAndroid Build Coastguard Worker -u Show these USERs
136*cf5a6c84SAndroid Build Coastguard Worker -q Quiet (no header lines)
137*cf5a6c84SAndroid Build Coastguard Worker
138*cf5a6c84SAndroid Build Coastguard Worker Cursor LEFT/RIGHT to change sort, UP/DOWN move list, space to force
139*cf5a6c84SAndroid Build Coastguard Worker update, R to reverse sort, Q to exit.
140*cf5a6c84SAndroid Build Coastguard Worker
141*cf5a6c84SAndroid Build Coastguard Worker config PGREP
142*cf5a6c84SAndroid Build Coastguard Worker bool "pgrep"
143*cf5a6c84SAndroid Build Coastguard Worker default y
144*cf5a6c84SAndroid Build Coastguard Worker help
145*cf5a6c84SAndroid Build Coastguard Worker usage: pgrep [-clfnovx] [-d DELIM] [-L SIGNAL] [PATTERN] [-G GID,] [-g PGRP,] [-P PPID,] [-s SID,] [-t TERM,] [-U UID,] [-u EUID,]
146*cf5a6c84SAndroid Build Coastguard Worker
147*cf5a6c84SAndroid Build Coastguard Worker Search for process(es). PATTERN is an extended regular expression checked
148*cf5a6c84SAndroid Build Coastguard Worker against command names.
149*cf5a6c84SAndroid Build Coastguard Worker
150*cf5a6c84SAndroid Build Coastguard Worker -c Show only count of matches
151*cf5a6c84SAndroid Build Coastguard Worker -d Use DELIM instead of newline
152*cf5a6c84SAndroid Build Coastguard Worker -L Send SIGNAL instead of printing name
153*cf5a6c84SAndroid Build Coastguard Worker -l Show command name
154*cf5a6c84SAndroid Build Coastguard Worker -f Check full command line for PATTERN
155*cf5a6c84SAndroid Build Coastguard Worker -G Match real Group ID(s)
156*cf5a6c84SAndroid Build Coastguard Worker -g Match Process Group(s) (0 is current user)
157*cf5a6c84SAndroid Build Coastguard Worker -n Newest match only
158*cf5a6c84SAndroid Build Coastguard Worker -o Oldest match only
159*cf5a6c84SAndroid Build Coastguard Worker -P Match Parent Process ID(s)
160*cf5a6c84SAndroid Build Coastguard Worker -s Match Session ID(s) (0 for current)
161*cf5a6c84SAndroid Build Coastguard Worker -t Match Terminal(s)
162*cf5a6c84SAndroid Build Coastguard Worker -U Match real User ID(s)
163*cf5a6c84SAndroid Build Coastguard Worker -u Match effective User ID(s)
164*cf5a6c84SAndroid Build Coastguard Worker -v Negate the match
165*cf5a6c84SAndroid Build Coastguard Worker -x Match whole command (not substring)
166*cf5a6c84SAndroid Build Coastguard Worker
167*cf5a6c84SAndroid Build Coastguard Worker config PKILL
168*cf5a6c84SAndroid Build Coastguard Worker bool "pkill"
169*cf5a6c84SAndroid Build Coastguard Worker default y
170*cf5a6c84SAndroid Build Coastguard Worker help
171*cf5a6c84SAndroid Build Coastguard Worker usage: pkill [-fnovx] [-SIGNAL|-l SIGNAL] [PATTERN] [-G GID,] [-g PGRP,] [-P PPID,] [-s SID,] [-t TERM,] [-U UID,] [-u EUID,]
172*cf5a6c84SAndroid Build Coastguard Worker
173*cf5a6c84SAndroid Build Coastguard Worker -l Send SIGNAL (default SIGTERM)
174*cf5a6c84SAndroid Build Coastguard Worker -V Verbose
175*cf5a6c84SAndroid Build Coastguard Worker -f Check full command line for PATTERN
176*cf5a6c84SAndroid Build Coastguard Worker -G Match real Group ID(s)
177*cf5a6c84SAndroid Build Coastguard Worker -g Match Process Group(s) (0 is current user)
178*cf5a6c84SAndroid Build Coastguard Worker -n Newest match only
179*cf5a6c84SAndroid Build Coastguard Worker -o Oldest match only
180*cf5a6c84SAndroid Build Coastguard Worker -P Match Parent Process ID(s)
181*cf5a6c84SAndroid Build Coastguard Worker -s Match Session ID(s) (0 for current)
182*cf5a6c84SAndroid Build Coastguard Worker -t Match Terminal(s)
183*cf5a6c84SAndroid Build Coastguard Worker -U Match real User ID(s)
184*cf5a6c84SAndroid Build Coastguard Worker -u Match effective User ID(s)
185*cf5a6c84SAndroid Build Coastguard Worker -v Negate the match
186*cf5a6c84SAndroid Build Coastguard Worker -x Match whole command (not substring)
187*cf5a6c84SAndroid Build Coastguard Worker */
188*cf5a6c84SAndroid Build Coastguard Worker
189*cf5a6c84SAndroid Build Coastguard Worker #define FOR_ps
190*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
191*cf5a6c84SAndroid Build Coastguard Worker
192*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
193*cf5a6c84SAndroid Build Coastguard Worker union {
194*cf5a6c84SAndroid Build Coastguard Worker struct {
195*cf5a6c84SAndroid Build Coastguard Worker struct arg_list *G, *g, *U, *u, *t, *s, *p, *O, *o, *P, *k;
196*cf5a6c84SAndroid Build Coastguard Worker } ps;
197*cf5a6c84SAndroid Build Coastguard Worker struct {
198*cf5a6c84SAndroid Build Coastguard Worker long n, m, d, s;
199*cf5a6c84SAndroid Build Coastguard Worker struct arg_list *u, *p, *o, *k, *O;
200*cf5a6c84SAndroid Build Coastguard Worker } top;
201*cf5a6c84SAndroid Build Coastguard Worker struct {
202*cf5a6c84SAndroid Build Coastguard Worker char *L;
203*cf5a6c84SAndroid Build Coastguard Worker struct arg_list *G, *g, *P, *s, *t, *U, *u;
204*cf5a6c84SAndroid Build Coastguard Worker char *d;
205*cf5a6c84SAndroid Build Coastguard Worker
206*cf5a6c84SAndroid Build Coastguard Worker void *regexes, *snapshot;
207*cf5a6c84SAndroid Build Coastguard Worker int signal;
208*cf5a6c84SAndroid Build Coastguard Worker pid_t self, match;
209*cf5a6c84SAndroid Build Coastguard Worker } pgrep;
210*cf5a6c84SAndroid Build Coastguard Worker };
211*cf5a6c84SAndroid Build Coastguard Worker
212*cf5a6c84SAndroid Build Coastguard Worker struct ps_ptr_len {
213*cf5a6c84SAndroid Build Coastguard Worker void *ptr;
214*cf5a6c84SAndroid Build Coastguard Worker long len;
215*cf5a6c84SAndroid Build Coastguard Worker } gg, GG, pp, PP, ss, tt, uu, UU;
216*cf5a6c84SAndroid Build Coastguard Worker struct dirtree *threadparent;
217*cf5a6c84SAndroid Build Coastguard Worker unsigned width, height, scroll;
218*cf5a6c84SAndroid Build Coastguard Worker dev_t tty;
219*cf5a6c84SAndroid Build Coastguard Worker void *fields, *kfields;
220*cf5a6c84SAndroid Build Coastguard Worker long long ticks, bits, time;
221*cf5a6c84SAndroid Build Coastguard Worker int kcount, forcek, sortpos, pidlen;
222*cf5a6c84SAndroid Build Coastguard Worker int (*match_process)(long long *slot);
223*cf5a6c84SAndroid Build Coastguard Worker void (*show_process)(void *tb);
224*cf5a6c84SAndroid Build Coastguard Worker )
225*cf5a6c84SAndroid Build Coastguard Worker
226*cf5a6c84SAndroid Build Coastguard Worker // Linked list of -o fields selected for display, in order, with :len and =title
227*cf5a6c84SAndroid Build Coastguard Worker
228*cf5a6c84SAndroid Build Coastguard Worker struct ofields {
229*cf5a6c84SAndroid Build Coastguard Worker struct ofields *next, *prev;
230*cf5a6c84SAndroid Build Coastguard Worker short which, len, reverse;
231*cf5a6c84SAndroid Build Coastguard Worker char *title;
232*cf5a6c84SAndroid Build Coastguard Worker };
233*cf5a6c84SAndroid Build Coastguard Worker
234*cf5a6c84SAndroid Build Coastguard Worker /* The function get_ps() reads all the data about one process, saving it in
235*cf5a6c84SAndroid Build Coastguard Worker * toybox as a struct procpid. Simple ps calls then pass toybuf directly to
236*cf5a6c84SAndroid Build Coastguard Worker * show_ps(), but features like sorting append a copy to a linked list
237*cf5a6c84SAndroid Build Coastguard Worker * for further processing once all processes have been read.
238*cf5a6c84SAndroid Build Coastguard Worker *
239*cf5a6c84SAndroid Build Coastguard Worker * struct procpid contains a slot[] array of 64 bit values, with the following
240*cf5a6c84SAndroid Build Coastguard Worker * data at each position in the array. Most is read from /proc/$PID/stat (see
241*cf5a6c84SAndroid Build Coastguard Worker * https://kernel.org/doc/Documentation/filesystems/proc.txt table 1-4) but
242*cf5a6c84SAndroid Build Coastguard Worker * we replace several fields with don't use with other data. */
243*cf5a6c84SAndroid Build Coastguard Worker
244*cf5a6c84SAndroid Build Coastguard Worker enum {
245*cf5a6c84SAndroid Build Coastguard Worker SLOT_pid, /*process id*/ SLOT_ppid, // parent process id
246*cf5a6c84SAndroid Build Coastguard Worker SLOT_pgrp, /*process group*/ SLOT_sid, // session id
247*cf5a6c84SAndroid Build Coastguard Worker SLOT_ttynr, /*tty the process uses*/ SLOT_ttypgrp, // pgrp of the tty
248*cf5a6c84SAndroid Build Coastguard Worker SLOT_flags, /*task flags*/ SLOT_minflt, // minor faults
249*cf5a6c84SAndroid Build Coastguard Worker SLOT_cminflt, /*minor faults+child*/ SLOT_majflt, // major faults
250*cf5a6c84SAndroid Build Coastguard Worker SLOT_cmajflt, /*major faults+child*/ SLOT_utime, // user+kernel jiffies
251*cf5a6c84SAndroid Build Coastguard Worker SLOT_stime, /*kernel mode jiffies*/ SLOT_cutime, // utime+child utime
252*cf5a6c84SAndroid Build Coastguard Worker SLOT_cstime, /*stime+child*/ SLOT_priority, // priority level
253*cf5a6c84SAndroid Build Coastguard Worker SLOT_nice, /*nice level*/ SLOT_numthreads,// thread count
254*cf5a6c84SAndroid Build Coastguard Worker SLOT_vmlck, /*locked memory*/ SLOT_starttime, // jiffies after boot
255*cf5a6c84SAndroid Build Coastguard Worker SLOT_vsize, /*virtual memory size*/ SLOT_rss, // resident set size
256*cf5a6c84SAndroid Build Coastguard Worker SLOT_rsslim, /*limit in bytes on rss*/ SLOT_startcode, // code segment addr
257*cf5a6c84SAndroid Build Coastguard Worker SLOT_endcode, /*code segment address*/ SLOT_startstack,// stack address
258*cf5a6c84SAndroid Build Coastguard Worker SLOT_esp, /*task stack pointer*/ SLOT_eip, // instruction pointer
259*cf5a6c84SAndroid Build Coastguard Worker SLOT_iobytes, /*All I/O bytes*/ SLOT_diobytes, // disk I/O bytes
260*cf5a6c84SAndroid Build Coastguard Worker SLOT_utime2, /*relative utime (top)*/ SLOT_uid, // user id
261*cf5a6c84SAndroid Build Coastguard Worker SLOT_ruid, /*real user id*/ SLOT_gid, // group id
262*cf5a6c84SAndroid Build Coastguard Worker SLOT_rgid, /*real group id*/ SLOT_exitsig, // sent to parent
263*cf5a6c84SAndroid Build Coastguard Worker SLOT_taskcpu, /*CPU running on*/ SLOT_rtprio, // realtime priority
264*cf5a6c84SAndroid Build Coastguard Worker SLOT_policy, /*man sched_setscheduler*/SLOT_blkioticks,// IO wait time
265*cf5a6c84SAndroid Build Coastguard Worker SLOT_gtime, /*guest jiffies of task*/ SLOT_cgtime, // gtime+child
266*cf5a6c84SAndroid Build Coastguard Worker SLOT_startbss, /*data/bss address*/ SLOT_endbss, // end addr data+bss
267*cf5a6c84SAndroid Build Coastguard Worker // end of /proc/$PID/stat fields
268*cf5a6c84SAndroid Build Coastguard Worker SLOT_upticks, /*uptime-starttime*/ SLOT_argv0len, // argv[0] length
269*cf5a6c84SAndroid Build Coastguard Worker SLOT_uptime, /*sysinfo.uptime*/ SLOT_totalram, // sysinfo.totalram
270*cf5a6c84SAndroid Build Coastguard Worker SLOT_vsz, /*Virtual mem Size*/ SLOT_shr, // Shared memory
271*cf5a6c84SAndroid Build Coastguard Worker SLOT_pcy, /*Android sched pol*/ SLOT_rchar, // All bytes read
272*cf5a6c84SAndroid Build Coastguard Worker SLOT_wchar, /*All bytes written*/ SLOT_rbytes, // Disk bytes read
273*cf5a6c84SAndroid Build Coastguard Worker SLOT_wbytes, /*Disk bytes written*/ SLOT_swap, // Swap pages used
274*cf5a6c84SAndroid Build Coastguard Worker SLOT_bits, /*32 or 64*/ SLOT_tid, // Thread ID
275*cf5a6c84SAndroid Build Coastguard Worker SLOT_tcount, /*Thread count*/
276*cf5a6c84SAndroid Build Coastguard Worker
277*cf5a6c84SAndroid Build Coastguard Worker SLOT_count /* Size of array */
278*cf5a6c84SAndroid Build Coastguard Worker };
279*cf5a6c84SAndroid Build Coastguard Worker
280*cf5a6c84SAndroid Build Coastguard Worker /* In addition to slot[], carevup contains 6 string fields to display
281*cf5a6c84SAndroid Build Coastguard Worker command name, tty device, selinux label... They're stored one after the
282*cf5a6c84SAndroid Build Coastguard Worker other in str[] (separated by null terminators), and offset[] contains the
283*cf5a6c84SAndroid Build Coastguard Worker starting position of each string after the first (which is always 0). */
284*cf5a6c84SAndroid Build Coastguard Worker
285*cf5a6c84SAndroid Build Coastguard Worker // Data layout in toybuf
286*cf5a6c84SAndroid Build Coastguard Worker struct procpid {
287*cf5a6c84SAndroid Build Coastguard Worker long long slot[SLOT_count]; // data (see enum above)
288*cf5a6c84SAndroid Build Coastguard Worker unsigned short offset[6]; // offset of fields in str[] (skip CMD, always 0)
289*cf5a6c84SAndroid Build Coastguard Worker char state;
290*cf5a6c84SAndroid Build Coastguard Worker char pcy[3]; // Android scheduling policy
291*cf5a6c84SAndroid Build Coastguard Worker char str[]; // CMD, TTY, WCHAN, LABEL, COMM, ARGS, NAME
292*cf5a6c84SAndroid Build Coastguard Worker };
293*cf5a6c84SAndroid Build Coastguard Worker
294*cf5a6c84SAndroid Build Coastguard Worker /* The typos[] array lists all the types understood by "ps -o", I.E all the
295*cf5a6c84SAndroid Build Coastguard Worker * columns ps and top know how to display. Each entry has:
296*cf5a6c84SAndroid Build Coastguard Worker *
297*cf5a6c84SAndroid Build Coastguard Worker * name: the column name, displayed at top and used to select column with -o
298*cf5a6c84SAndroid Build Coastguard Worker *
299*cf5a6c84SAndroid Build Coastguard Worker * width: the display width. Fields are padded to this width when displaying
300*cf5a6c84SAndroid Build Coastguard Worker * to a terminal (negative means right justified). Strings are truncated
301*cf5a6c84SAndroid Build Coastguard Worker * to fit, numerical fields are padded but not truncated (although
302*cf5a6c84SAndroid Build Coastguard Worker * the display code reclaims unused padding from later fields to try to
303*cf5a6c84SAndroid Build Coastguard Worker * get the overflow back).
304*cf5a6c84SAndroid Build Coastguard Worker *
305*cf5a6c84SAndroid Build Coastguard Worker * slot: which slot[] out of procpid. Negative means it's a string field.
306*cf5a6c84SAndroid Build Coastguard Worker * value|XX requests extra display/sort processing.
307*cf5a6c84SAndroid Build Coastguard Worker *
308*cf5a6c84SAndroid Build Coastguard Worker * The TAGGED_ARRAY plumbing produces an enum of indexes, the "tag" is the
309*cf5a6c84SAndroid Build Coastguard Worker * first string argument and the prefix is the first argument to TAGGED_ARRAY
310*cf5a6c84SAndroid Build Coastguard Worker * so in this case "NAME" becomes PS_NAME which is the offset into typos[]
311*cf5a6c84SAndroid Build Coastguard Worker * for that entry, and also _PS_NAME (the bit position, 1<<PS_NAME).
312*cf5a6c84SAndroid Build Coastguard Worker * We record active columns in TT.bits, ala:
313*cf5a6c84SAndroid Build Coastguard Worker *
314*cf5a6c84SAndroid Build Coastguard Worker * if (TT.bits & _PS_NAME) printf("-o included PS_NAME");
315*cf5a6c84SAndroid Build Coastguard Worker */
316*cf5a6c84SAndroid Build Coastguard Worker
317*cf5a6c84SAndroid Build Coastguard Worker #define XX 64 // force string representation for sorting, etc
318*cf5a6c84SAndroid Build Coastguard Worker
319*cf5a6c84SAndroid Build Coastguard Worker // TODO: Android uses -30 for LABEL, but ideally it would auto-size.
320*cf5a6c84SAndroid Build Coastguard Worker struct typography {
321*cf5a6c84SAndroid Build Coastguard Worker char *name, *help;
322*cf5a6c84SAndroid Build Coastguard Worker signed char width, slot;
323*cf5a6c84SAndroid Build Coastguard Worker } static const typos[] = TAGGED_ARRAY(PS,
324*cf5a6c84SAndroid Build Coastguard Worker // Numbers. (What's in slot[] is what's displayed, sorted numerically.)
325*cf5a6c84SAndroid Build Coastguard Worker {"PID", "Process ID", 6, SLOT_pid},
326*cf5a6c84SAndroid Build Coastguard Worker {"PPID", "Parent Process ID", 6, SLOT_ppid},
327*cf5a6c84SAndroid Build Coastguard Worker {"PRI", "Priority (dynamic 0 to 139)", 3, SLOT_priority},
328*cf5a6c84SAndroid Build Coastguard Worker {"NI", "Niceness (static 19 to -20)", 3, SLOT_nice},
329*cf5a6c84SAndroid Build Coastguard Worker {"ADDR", "Instruction pointer", 4+sizeof(long), SLOT_eip},
330*cf5a6c84SAndroid Build Coastguard Worker {"SZ", "4k pages to swap out", 5, SLOT_vsize},
331*cf5a6c84SAndroid Build Coastguard Worker {"RSS", "Resident Set Size (DRAM pages)", 6, SLOT_rss},
332*cf5a6c84SAndroid Build Coastguard Worker {"PGID", "Process Group ID", 5, SLOT_pgrp},
333*cf5a6c84SAndroid Build Coastguard Worker {"VSZ", "Virtual memory size (1k units)", 7, SLOT_vsize},
334*cf5a6c84SAndroid Build Coastguard Worker {"MAJFL", "Major page faults", 6, SLOT_majflt},
335*cf5a6c84SAndroid Build Coastguard Worker {"MINFL", "Minor page faults", 6, SLOT_minflt},
336*cf5a6c84SAndroid Build Coastguard Worker {"PR", "Prio Reversed (dyn 39-0, RT)", 2, SLOT_priority},
337*cf5a6c84SAndroid Build Coastguard Worker {"PSR", "Processor last executed on", 3, SLOT_taskcpu},
338*cf5a6c84SAndroid Build Coastguard Worker {"RTPRIO", "Realtime priority", 6, SLOT_rtprio},
339*cf5a6c84SAndroid Build Coastguard Worker {"SCH", "Scheduling policy (0=other, 1=fifo, 2=rr, 3=batch, 4=iso, 5=idle)",
340*cf5a6c84SAndroid Build Coastguard Worker 3, SLOT_policy},
341*cf5a6c84SAndroid Build Coastguard Worker {"CPU", "Which processor running on", 3, SLOT_taskcpu},
342*cf5a6c84SAndroid Build Coastguard Worker {"TID", "Thread ID", 5, SLOT_tid},
343*cf5a6c84SAndroid Build Coastguard Worker {"TCNT", "Thread count", 4, SLOT_tcount},
344*cf5a6c84SAndroid Build Coastguard Worker {"BIT", "32 or 64", 3, SLOT_bits},
345*cf5a6c84SAndroid Build Coastguard Worker
346*cf5a6c84SAndroid Build Coastguard Worker // String fields (-1 is procpid->str, rest are str+offset[1-slot])
347*cf5a6c84SAndroid Build Coastguard Worker {"TTY", "Controlling terminal", -8, -2},
348*cf5a6c84SAndroid Build Coastguard Worker {"WCHAN", "Wait location in kernel", -6, -3},
349*cf5a6c84SAndroid Build Coastguard Worker {"LABEL", "Security label", -30, -4},
350*cf5a6c84SAndroid Build Coastguard Worker {"COMM", "EXE filename (/proc/PID/exe)", -27, -5},
351*cf5a6c84SAndroid Build Coastguard Worker {"NAME", "Process name (PID's argv[0])", -27, -7},
352*cf5a6c84SAndroid Build Coastguard Worker {"COMMAND", "EXE path (/proc/PID/exe)", -27, -5},
353*cf5a6c84SAndroid Build Coastguard Worker {"CMDLINE", "Command line (argv[])", -27, -6},
354*cf5a6c84SAndroid Build Coastguard Worker {"ARGS", "CMDLINE minus initial path", -27, -6},
355*cf5a6c84SAndroid Build Coastguard Worker {"CMD", "Thread name (/proc/TID/stat:2)", -15, -1},
356*cf5a6c84SAndroid Build Coastguard Worker
357*cf5a6c84SAndroid Build Coastguard Worker // user/group (may call getpwuid() or similar)
358*cf5a6c84SAndroid Build Coastguard Worker {"UID", "User id", 5, SLOT_uid},
359*cf5a6c84SAndroid Build Coastguard Worker {"USER", "User name", -12, XX|SLOT_uid},
360*cf5a6c84SAndroid Build Coastguard Worker {"RUID", "Real (before suid) user ID", 4, SLOT_ruid},
361*cf5a6c84SAndroid Build Coastguard Worker {"RUSER", "Real (before suid) user name", -8, XX|SLOT_ruid},
362*cf5a6c84SAndroid Build Coastguard Worker {"GID", "Group ID", 8, SLOT_gid},
363*cf5a6c84SAndroid Build Coastguard Worker {"GROUP", "Group name", -8, XX|SLOT_gid},
364*cf5a6c84SAndroid Build Coastguard Worker {"RGID", "Real (before sgid) Group ID", 4, SLOT_rgid},
365*cf5a6c84SAndroid Build Coastguard Worker {"RGROUP", "Real (before sgid) group name", -8, XX|SLOT_rgid},
366*cf5a6c84SAndroid Build Coastguard Worker
367*cf5a6c84SAndroid Build Coastguard Worker // clock displays (00:00:00)
368*cf5a6c84SAndroid Build Coastguard Worker {"TIME", "CPU time consumed", 8, SLOT_utime},
369*cf5a6c84SAndroid Build Coastguard Worker {"ELAPSED", "Elapsed time since PID start", 11, SLOT_starttime},
370*cf5a6c84SAndroid Build Coastguard Worker {"TIME+", "CPU time (high precision)", 9, SLOT_utime},
371*cf5a6c84SAndroid Build Coastguard Worker
372*cf5a6c84SAndroid Build Coastguard Worker // Percentage displays (fixed point, one decimal digit. 123 -> 12.3)
373*cf5a6c84SAndroid Build Coastguard Worker {"C", "Total %CPU used since start", 1, SLOT_utime2},
374*cf5a6c84SAndroid Build Coastguard Worker {"%VSZ", "VSZ as % of physical memory", 5, SLOT_vsize},
375*cf5a6c84SAndroid Build Coastguard Worker {"%MEM", "RSS as % of physical memory", 5, SLOT_rss},
376*cf5a6c84SAndroid Build Coastguard Worker {"%CPU", "Percentage of CPU time used", 4, SLOT_utime2},
377*cf5a6c84SAndroid Build Coastguard Worker
378*cf5a6c84SAndroid Build Coastguard Worker // human_readable (function human_readable() in lib, 1.23M, 1.4G, etc)
379*cf5a6c84SAndroid Build Coastguard Worker {"VIRT", "Virtual memory size", 4, SLOT_vsz},
380*cf5a6c84SAndroid Build Coastguard Worker {"RES", "Short RSS", 4, SLOT_rss},
381*cf5a6c84SAndroid Build Coastguard Worker {"SHR", "Shared memory", 4, SLOT_shr},
382*cf5a6c84SAndroid Build Coastguard Worker {"READ", "Data read", 6, SLOT_rchar},
383*cf5a6c84SAndroid Build Coastguard Worker {"WRITE", "Data written", 6, SLOT_wchar},
384*cf5a6c84SAndroid Build Coastguard Worker {"IO", "Data I/O", 6, SLOT_iobytes},
385*cf5a6c84SAndroid Build Coastguard Worker {"DREAD", "Data read from disk", 6, SLOT_rbytes},
386*cf5a6c84SAndroid Build Coastguard Worker {"DWRITE", "Data written to disk", 6, SLOT_wbytes},
387*cf5a6c84SAndroid Build Coastguard Worker {"SWAP", "Swap I/O", 6, SLOT_swap},
388*cf5a6c84SAndroid Build Coastguard Worker {"DIO", "Disk I/O", 6, SLOT_diobytes},
389*cf5a6c84SAndroid Build Coastguard Worker
390*cf5a6c84SAndroid Build Coastguard Worker // Misc (special cases)
391*cf5a6c84SAndroid Build Coastguard Worker {"STIME", "Start time (ISO 8601)", 5, SLOT_starttime},
392*cf5a6c84SAndroid Build Coastguard Worker {"F", "Flags 1=FORKNOEXEC 4=SUPERPRIV", 1, XX|SLOT_flags},
393*cf5a6c84SAndroid Build Coastguard Worker {"S", "Process state:\n"
394*cf5a6c84SAndroid Build Coastguard Worker "\t R (running) S (sleeping) D (device I/O) T (stopped) t (trace stop)\n"
395*cf5a6c84SAndroid Build Coastguard Worker "\t X (dead) Z (zombie) P (parked) I (idle)\n"
396*cf5a6c84SAndroid Build Coastguard Worker "\t Also between Linux 2.6.33 and 3.13:\n"
397*cf5a6c84SAndroid Build Coastguard Worker "\t x (dead) K (wakekill) W (waking)\n",
398*cf5a6c84SAndroid Build Coastguard Worker -1, XX},
399*cf5a6c84SAndroid Build Coastguard Worker {"STAT", "Process state (S) plus:\n"
400*cf5a6c84SAndroid Build Coastguard Worker "\t < high priority N low priority L locked memory\n"
401*cf5a6c84SAndroid Build Coastguard Worker "\t s session leader + foreground l multithreaded",
402*cf5a6c84SAndroid Build Coastguard Worker -5, XX},
403*cf5a6c84SAndroid Build Coastguard Worker {"PCY", "Android scheduling policy", 3, XX|SLOT_pcy},
404*cf5a6c84SAndroid Build Coastguard Worker );
405*cf5a6c84SAndroid Build Coastguard Worker
406*cf5a6c84SAndroid Build Coastguard Worker // Show sorted "-o help" text for fields listed in toybuf[len]
help_fields(int len,int multi)407*cf5a6c84SAndroid Build Coastguard Worker static void help_fields(int len, int multi)
408*cf5a6c84SAndroid Build Coastguard Worker {
409*cf5a6c84SAndroid Build Coastguard Worker int i, j, k, left = 0;
410*cf5a6c84SAndroid Build Coastguard Worker struct typography *t;
411*cf5a6c84SAndroid Build Coastguard Worker
412*cf5a6c84SAndroid Build Coastguard Worker // Quick and dirty sort of toybuf[] entries (see TODO below)
413*cf5a6c84SAndroid Build Coastguard Worker for (j = len; j--; ) {
414*cf5a6c84SAndroid Build Coastguard Worker k = -1;
415*cf5a6c84SAndroid Build Coastguard Worker
416*cf5a6c84SAndroid Build Coastguard Worker for (i=0; i<j; i++) {
417*cf5a6c84SAndroid Build Coastguard Worker if (strcmp(typos[toybuf[i]].name, typos[toybuf[i+1]].name)>0) {
418*cf5a6c84SAndroid Build Coastguard Worker k = toybuf[i];
419*cf5a6c84SAndroid Build Coastguard Worker toybuf[i] = toybuf[i+1];
420*cf5a6c84SAndroid Build Coastguard Worker toybuf[i+1] = k;
421*cf5a6c84SAndroid Build Coastguard Worker }
422*cf5a6c84SAndroid Build Coastguard Worker }
423*cf5a6c84SAndroid Build Coastguard Worker if (k == -1) break;
424*cf5a6c84SAndroid Build Coastguard Worker }
425*cf5a6c84SAndroid Build Coastguard Worker
426*cf5a6c84SAndroid Build Coastguard Worker // Display loop
427*cf5a6c84SAndroid Build Coastguard Worker for (i = j = 0; i<len; i++, j++) {
428*cf5a6c84SAndroid Build Coastguard Worker t = (void *)(typos+toybuf[i]);
429*cf5a6c84SAndroid Build Coastguard Worker if (strlen(t->help)>30) {
430*cf5a6c84SAndroid Build Coastguard Worker if (multi) printf(" %-8s%s\n", t->name, t->help);
431*cf5a6c84SAndroid Build Coastguard Worker else j--;
432*cf5a6c84SAndroid Build Coastguard Worker } else if (!multi) {
433*cf5a6c84SAndroid Build Coastguard Worker left = !(j&1);
434*cf5a6c84SAndroid Build Coastguard Worker printf(" %-8s%*s%c"+2*!left, t->name, -30*left, t->help, 10+22*left);
435*cf5a6c84SAndroid Build Coastguard Worker }
436*cf5a6c84SAndroid Build Coastguard Worker }
437*cf5a6c84SAndroid Build Coastguard Worker if (!multi && left) xputc('\n');
438*cf5a6c84SAndroid Build Coastguard Worker }
439*cf5a6c84SAndroid Build Coastguard Worker
440*cf5a6c84SAndroid Build Coastguard Worker // Print help text for each -o field, with categories.
help_help(void)441*cf5a6c84SAndroid Build Coastguard Worker static void help_help(void)
442*cf5a6c84SAndroid Build Coastguard Worker {
443*cf5a6c84SAndroid Build Coastguard Worker int i, jump = PS_CMD+1-PS_COMM;
444*cf5a6c84SAndroid Build Coastguard Worker
445*cf5a6c84SAndroid Build Coastguard Worker // TODO: sort the array of -o types so they're already alphabetical and
446*cf5a6c84SAndroid Build Coastguard Worker // don't need sorting here. A regex to find everything that currently cares
447*cf5a6c84SAndroid Build Coastguard Worker // about symbol order might be: "which *[><]=* *PS"
448*cf5a6c84SAndroid Build Coastguard Worker
449*cf5a6c84SAndroid Build Coastguard Worker // First show the half-dozen variants of command line display.
450*cf5a6c84SAndroid Build Coastguard Worker
451*cf5a6c84SAndroid Build Coastguard Worker printf("Command line field types:\n\n");
452*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i<jump; i++) toybuf[i] = PS_COMM+i;
453*cf5a6c84SAndroid Build Coastguard Worker help_fields(jump, 0);
454*cf5a6c84SAndroid Build Coastguard Worker
455*cf5a6c84SAndroid Build Coastguard Worker // Show the rest of the -o types, starting with the ones that don't columnize
456*cf5a6c84SAndroid Build Coastguard Worker
457*cf5a6c84SAndroid Build Coastguard Worker printf("\nProcess attribute field types:\n\n");
458*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i<ARRAY_LEN(typos)-jump; i++) toybuf[i] = i+(i>=PS_COMM)*jump;
459*cf5a6c84SAndroid Build Coastguard Worker help_fields(ARRAY_LEN(typos)-jump, 1);
460*cf5a6c84SAndroid Build Coastguard Worker help_fields(ARRAY_LEN(typos)-jump, 0);
461*cf5a6c84SAndroid Build Coastguard Worker
462*cf5a6c84SAndroid Build Coastguard Worker xexit();
463*cf5a6c84SAndroid Build Coastguard Worker }
464*cf5a6c84SAndroid Build Coastguard Worker
465*cf5a6c84SAndroid Build Coastguard Worker // process match filter for top/ps/pgrep: Return 0 to discard, nonzero to keep
shared_match_process(long long * slot)466*cf5a6c84SAndroid Build Coastguard Worker static int shared_match_process(long long *slot)
467*cf5a6c84SAndroid Build Coastguard Worker {
468*cf5a6c84SAndroid Build Coastguard Worker struct ps_ptr_len match[] = {
469*cf5a6c84SAndroid Build Coastguard Worker {&TT.gg, SLOT_gid}, {&TT.GG, SLOT_rgid}, {&TT.pp, SLOT_pid},
470*cf5a6c84SAndroid Build Coastguard Worker {&TT.PP, SLOT_ppid}, {&TT.ss, SLOT_sid}, {&TT.tt, SLOT_ttynr},
471*cf5a6c84SAndroid Build Coastguard Worker {&TT.uu, SLOT_uid}, {&TT.UU, SLOT_ruid}
472*cf5a6c84SAndroid Build Coastguard Worker };
473*cf5a6c84SAndroid Build Coastguard Worker int i, j;
474*cf5a6c84SAndroid Build Coastguard Worker long *ll = 0;
475*cf5a6c84SAndroid Build Coastguard Worker
476*cf5a6c84SAndroid Build Coastguard Worker // Do we have -g -G -p -P -s -t -u -U options selecting processes?
477*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i < ARRAY_LEN(match); i++) {
478*cf5a6c84SAndroid Build Coastguard Worker struct ps_ptr_len *mm = match[i].ptr;
479*cf5a6c84SAndroid Build Coastguard Worker
480*cf5a6c84SAndroid Build Coastguard Worker if (mm->len) {
481*cf5a6c84SAndroid Build Coastguard Worker ll = mm->ptr;
482*cf5a6c84SAndroid Build Coastguard Worker for (j = 0; j<mm->len; j++) if (ll[j] == slot[match[i].len]) return 1;
483*cf5a6c84SAndroid Build Coastguard Worker }
484*cf5a6c84SAndroid Build Coastguard Worker }
485*cf5a6c84SAndroid Build Coastguard Worker
486*cf5a6c84SAndroid Build Coastguard Worker return ll ? 0 : -1;
487*cf5a6c84SAndroid Build Coastguard Worker }
488*cf5a6c84SAndroid Build Coastguard Worker
489*cf5a6c84SAndroid Build Coastguard Worker // process match filter for ps: Return 0 to discard, nonzero to keep
ps_match_process(long long * slot)490*cf5a6c84SAndroid Build Coastguard Worker static int ps_match_process(long long *slot)
491*cf5a6c84SAndroid Build Coastguard Worker {
492*cf5a6c84SAndroid Build Coastguard Worker int i = shared_match_process(slot);
493*cf5a6c84SAndroid Build Coastguard Worker
494*cf5a6c84SAndroid Build Coastguard Worker if (i>0) return 1;
495*cf5a6c84SAndroid Build Coastguard Worker // If we had selections and didn't match them, don't display
496*cf5a6c84SAndroid Build Coastguard Worker if (!i) return 0;
497*cf5a6c84SAndroid Build Coastguard Worker
498*cf5a6c84SAndroid Build Coastguard Worker // Filter implicit categories for other display types
499*cf5a6c84SAndroid Build Coastguard Worker if ((FLAG(a)||FLAG(d)) && slot[SLOT_sid]==*slot) return 0;
500*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(a) && !slot[SLOT_ttynr]) return 0;
501*cf5a6c84SAndroid Build Coastguard Worker if (!(FLAG(a)||FLAG(d)||FLAG(A)||FLAG(e)) && TT.tty!=slot[SLOT_ttynr])
502*cf5a6c84SAndroid Build Coastguard Worker return 0;
503*cf5a6c84SAndroid Build Coastguard Worker
504*cf5a6c84SAndroid Build Coastguard Worker return 1;
505*cf5a6c84SAndroid Build Coastguard Worker }
506*cf5a6c84SAndroid Build Coastguard Worker
507*cf5a6c84SAndroid Build Coastguard Worker // Generate display string (260 bytes at end of toybuf) from struct ofield
string_field(struct procpid * tb,struct ofields * field)508*cf5a6c84SAndroid Build Coastguard Worker static char *string_field(struct procpid *tb, struct ofields *field)
509*cf5a6c84SAndroid Build Coastguard Worker {
510*cf5a6c84SAndroid Build Coastguard Worker char *buf = toybuf+sizeof(toybuf)-260, *out = buf, *s;
511*cf5a6c84SAndroid Build Coastguard Worker int which = field->which, sl = typos[which].slot;
512*cf5a6c84SAndroid Build Coastguard Worker long long *slot = tb->slot, ll = (sl >= 0) ? slot[sl&(XX-1)] : 0;
513*cf5a6c84SAndroid Build Coastguard Worker
514*cf5a6c84SAndroid Build Coastguard Worker // numbers, mostly from /proc/$PID/stat
515*cf5a6c84SAndroid Build Coastguard Worker if (which <= PS_BIT) {
516*cf5a6c84SAndroid Build Coastguard Worker char *fmt = "%lld";
517*cf5a6c84SAndroid Build Coastguard Worker
518*cf5a6c84SAndroid Build Coastguard Worker if (which==PS_PRI) ll = 39-ll;
519*cf5a6c84SAndroid Build Coastguard Worker if (which==PS_ADDR) fmt = "%llx";
520*cf5a6c84SAndroid Build Coastguard Worker else if (which==PS_SZ) ll >>= 12;
521*cf5a6c84SAndroid Build Coastguard Worker else if (which==PS_RSS) ll <<= 2;
522*cf5a6c84SAndroid Build Coastguard Worker else if (which==PS_VSZ) ll >>= 10;
523*cf5a6c84SAndroid Build Coastguard Worker else if (which==PS_PR && ll<-9) fmt="RT";
524*cf5a6c84SAndroid Build Coastguard Worker else if ((which==PS_RTPRIO || which==PS_BIT) && ll == 0) fmt="-";
525*cf5a6c84SAndroid Build Coastguard Worker sprintf(out, fmt, ll);
526*cf5a6c84SAndroid Build Coastguard Worker
527*cf5a6c84SAndroid Build Coastguard Worker // String fields
528*cf5a6c84SAndroid Build Coastguard Worker } else if (sl < 0) {
529*cf5a6c84SAndroid Build Coastguard Worker out = tb->str;
530*cf5a6c84SAndroid Build Coastguard Worker sl *= -1;
531*cf5a6c84SAndroid Build Coastguard Worker // First string slot has offset 0, others are offset[-slot-2]
532*cf5a6c84SAndroid Build Coastguard Worker if (--sl) out += tb->offset[--sl];
533*cf5a6c84SAndroid Build Coastguard Worker if (which==PS_ARGS || which==PS_COMM) {
534*cf5a6c84SAndroid Build Coastguard Worker int i;
535*cf5a6c84SAndroid Build Coastguard Worker
536*cf5a6c84SAndroid Build Coastguard Worker s = out;
537*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; (which==PS_ARGS) ? i < slot[SLOT_argv0len] : out[i]; i++)
538*cf5a6c84SAndroid Build Coastguard Worker if (out[i] == '/') s = out+i+1;
539*cf5a6c84SAndroid Build Coastguard Worker out = s;
540*cf5a6c84SAndroid Build Coastguard Worker }
541*cf5a6c84SAndroid Build Coastguard Worker if (which>=PS_COMM && !*out) sprintf(out = buf, "[%s]", tb->str);
542*cf5a6c84SAndroid Build Coastguard Worker
543*cf5a6c84SAndroid Build Coastguard Worker // user/group
544*cf5a6c84SAndroid Build Coastguard Worker } else if (which <= PS_RGROUP) {
545*cf5a6c84SAndroid Build Coastguard Worker sprintf(out, "%lld", ll);
546*cf5a6c84SAndroid Build Coastguard Worker if (sl&XX) {
547*cf5a6c84SAndroid Build Coastguard Worker if (which > PS_RUSER) {
548*cf5a6c84SAndroid Build Coastguard Worker struct group *gr = bufgetgrgid(ll);
549*cf5a6c84SAndroid Build Coastguard Worker
550*cf5a6c84SAndroid Build Coastguard Worker if (gr) out = gr->gr_name;
551*cf5a6c84SAndroid Build Coastguard Worker } else {
552*cf5a6c84SAndroid Build Coastguard Worker struct passwd *pw = bufgetpwuid(ll);
553*cf5a6c84SAndroid Build Coastguard Worker
554*cf5a6c84SAndroid Build Coastguard Worker if (pw) out = pw->pw_name;
555*cf5a6c84SAndroid Build Coastguard Worker }
556*cf5a6c84SAndroid Build Coastguard Worker }
557*cf5a6c84SAndroid Build Coastguard Worker
558*cf5a6c84SAndroid Build Coastguard Worker // Clock displays
559*cf5a6c84SAndroid Build Coastguard Worker } else if (which <= PS_TIME_) {
560*cf5a6c84SAndroid Build Coastguard Worker int unit = 60, pad = 2, j = TT.ticks;
561*cf5a6c84SAndroid Build Coastguard Worker time_t seconds;
562*cf5a6c84SAndroid Build Coastguard Worker
563*cf5a6c84SAndroid Build Coastguard Worker if (which!=PS_TIME_) unit *= 60*24;
564*cf5a6c84SAndroid Build Coastguard Worker else pad = 0;
565*cf5a6c84SAndroid Build Coastguard Worker // top adjusts slot[SLOT_upticks], we want original meaning.
566*cf5a6c84SAndroid Build Coastguard Worker if (which==PS_ELAPSED) ll = (slot[SLOT_uptime]*j)-slot[SLOT_starttime];
567*cf5a6c84SAndroid Build Coastguard Worker seconds = ll/j;
568*cf5a6c84SAndroid Build Coastguard Worker
569*cf5a6c84SAndroid Build Coastguard Worker // Output days-hours:mins:secs, skipping non-required fields with zero
570*cf5a6c84SAndroid Build Coastguard Worker // TIME has 3 required fields, ETIME has 2. (Posix!) TIME+ is from top
571*cf5a6c84SAndroid Build Coastguard Worker for (s = 0, j = 2*(which==PS_TIME_); j<4; j++) {
572*cf5a6c84SAndroid Build Coastguard Worker if (!s && (seconds>unit || j == 1+(which!=PS_TIME))) s = out;
573*cf5a6c84SAndroid Build Coastguard Worker if (s) {
574*cf5a6c84SAndroid Build Coastguard Worker s += sprintf(s, j ? "%0*ld": "%*ld", pad, (long)(seconds/unit));
575*cf5a6c84SAndroid Build Coastguard Worker pad = 2;
576*cf5a6c84SAndroid Build Coastguard Worker if ((*s = "-::"[j])) s++;
577*cf5a6c84SAndroid Build Coastguard Worker }
578*cf5a6c84SAndroid Build Coastguard Worker seconds %= unit;
579*cf5a6c84SAndroid Build Coastguard Worker unit /= j ? 60 : 24;
580*cf5a6c84SAndroid Build Coastguard Worker }
581*cf5a6c84SAndroid Build Coastguard Worker if (which==PS_TIME_ && s-out<8)
582*cf5a6c84SAndroid Build Coastguard Worker sprintf(s, ".%02lld", (100*(ll%TT.ticks))/TT.ticks);
583*cf5a6c84SAndroid Build Coastguard Worker
584*cf5a6c84SAndroid Build Coastguard Worker // Percentage displays
585*cf5a6c84SAndroid Build Coastguard Worker } else if (which <= PS__CPU) {
586*cf5a6c84SAndroid Build Coastguard Worker ll = slot[sl&(XX-1)]*1000;
587*cf5a6c84SAndroid Build Coastguard Worker if (which==PS__VSZ || which==PS__MEM)
588*cf5a6c84SAndroid Build Coastguard Worker ll /= slot[SLOT_totalram]/((which==PS__VSZ) ? 1024 : 4096);
589*cf5a6c84SAndroid Build Coastguard Worker else if (slot[SLOT_upticks]) ll /= slot[SLOT_upticks];
590*cf5a6c84SAndroid Build Coastguard Worker sl = ll;
591*cf5a6c84SAndroid Build Coastguard Worker if (which==PS_C) sl += 5;
592*cf5a6c84SAndroid Build Coastguard Worker sprintf(out, "%d", sl/10);
593*cf5a6c84SAndroid Build Coastguard Worker if (which!=PS_C && sl<1000) sprintf(out+strlen(out), ".%d", sl%10);
594*cf5a6c84SAndroid Build Coastguard Worker
595*cf5a6c84SAndroid Build Coastguard Worker // Human readable
596*cf5a6c84SAndroid Build Coastguard Worker } else if (which <= PS_DIO) {
597*cf5a6c84SAndroid Build Coastguard Worker int i = abs(field->len);
598*cf5a6c84SAndroid Build Coastguard Worker
599*cf5a6c84SAndroid Build Coastguard Worker if (i<4) i = 4;
600*cf5a6c84SAndroid Build Coastguard Worker s = out;
601*cf5a6c84SAndroid Build Coastguard Worker if ((ll = slot[typos[which].slot])<0) {
602*cf5a6c84SAndroid Build Coastguard Worker ll = -ll;
603*cf5a6c84SAndroid Build Coastguard Worker *s++ = '-';
604*cf5a6c84SAndroid Build Coastguard Worker if (i>4) i--;
605*cf5a6c84SAndroid Build Coastguard Worker }
606*cf5a6c84SAndroid Build Coastguard Worker if (which <= PS_SHR) ll *= sysconf(_SC_PAGESIZE);
607*cf5a6c84SAndroid Build Coastguard Worker if (TT.forcek) sprintf(out, "%lldk", ll/1024);
608*cf5a6c84SAndroid Build Coastguard Worker else human_readable_long(s, ll, i-1, 0, 0);
609*cf5a6c84SAndroid Build Coastguard Worker
610*cf5a6c84SAndroid Build Coastguard Worker // Posix doesn't specify what flags should say. Man page says
611*cf5a6c84SAndroid Build Coastguard Worker // 1 for PF_FORKNOEXEC and 4 for PF_SUPERPRIV from linux/sched.h
612*cf5a6c84SAndroid Build Coastguard Worker } else if (which==PS_F) sprintf(out, "%llo", (slot[SLOT_flags]>>6)&5);
613*cf5a6c84SAndroid Build Coastguard Worker else if (which==PS_S || which==PS_STAT) {
614*cf5a6c84SAndroid Build Coastguard Worker s = out;
615*cf5a6c84SAndroid Build Coastguard Worker *s++ = tb->state;
616*cf5a6c84SAndroid Build Coastguard Worker if (which==PS_STAT) {
617*cf5a6c84SAndroid Build Coastguard Worker // TODO l = multithreaded
618*cf5a6c84SAndroid Build Coastguard Worker if (slot[SLOT_nice]<0) *s++ = '<';
619*cf5a6c84SAndroid Build Coastguard Worker else if (slot[SLOT_nice]>0) *s++ = 'N';
620*cf5a6c84SAndroid Build Coastguard Worker if (slot[SLOT_sid]==*slot) *s++ = 's';
621*cf5a6c84SAndroid Build Coastguard Worker if (slot[SLOT_vmlck]) *s++ = 'L';
622*cf5a6c84SAndroid Build Coastguard Worker if (slot[SLOT_ttypgrp]==*slot) *s++ = '+';
623*cf5a6c84SAndroid Build Coastguard Worker }
624*cf5a6c84SAndroid Build Coastguard Worker *s = 0;
625*cf5a6c84SAndroid Build Coastguard Worker } else if (which==PS_STIME) {
626*cf5a6c84SAndroid Build Coastguard Worker time_t t = time(0)-slot[SLOT_uptime]+slot[SLOT_starttime]/TT.ticks;
627*cf5a6c84SAndroid Build Coastguard Worker
628*cf5a6c84SAndroid Build Coastguard Worker // Padding behavior's a bit odd: default field size is just hh:mm.
629*cf5a6c84SAndroid Build Coastguard Worker // Increasing stime:size reveals more data at left until full,
630*cf5a6c84SAndroid Build Coastguard Worker // so move start address so yyyy-mm-dd hh:mm revealed on left at :16,
631*cf5a6c84SAndroid Build Coastguard Worker // then add :ss on right for :19.
632*cf5a6c84SAndroid Build Coastguard Worker strftime(out, 260, "%F %T", localtime(&t));
633*cf5a6c84SAndroid Build Coastguard Worker out = out+strlen(out)-3-abs(field->len);
634*cf5a6c84SAndroid Build Coastguard Worker if (out<buf) out = buf;
635*cf5a6c84SAndroid Build Coastguard Worker
636*cf5a6c84SAndroid Build Coastguard Worker } else if (which==PS_PCY) sprintf(out, "%.2s", tb->pcy);
637*cf5a6c84SAndroid Build Coastguard Worker else if (CFG_TOYBOX_DEBUG) error_exit("bad which %d", which);
638*cf5a6c84SAndroid Build Coastguard Worker
639*cf5a6c84SAndroid Build Coastguard Worker return out;
640*cf5a6c84SAndroid Build Coastguard Worker }
641*cf5a6c84SAndroid Build Coastguard Worker
642*cf5a6c84SAndroid Build Coastguard Worker // Display process data that get_ps() read from /proc, formatting via TT.fields
show_ps(void * p)643*cf5a6c84SAndroid Build Coastguard Worker static void show_ps(void *p)
644*cf5a6c84SAndroid Build Coastguard Worker {
645*cf5a6c84SAndroid Build Coastguard Worker struct procpid *tb = p;
646*cf5a6c84SAndroid Build Coastguard Worker struct ofields *field = TT.fields;
647*cf5a6c84SAndroid Build Coastguard Worker int pad, len, width = TT.width, abslen, sign, olen, scroll, extra = 0;
648*cf5a6c84SAndroid Build Coastguard Worker
649*cf5a6c84SAndroid Build Coastguard Worker // Skip TT.scroll many fields (but not last one)
650*cf5a6c84SAndroid Build Coastguard Worker for (scroll = TT.scroll; scroll && field->next; scroll--) field = field->next;
651*cf5a6c84SAndroid Build Coastguard Worker
652*cf5a6c84SAndroid Build Coastguard Worker // Loop through fields to display
653*cf5a6c84SAndroid Build Coastguard Worker for (; field; field = field->next) {
654*cf5a6c84SAndroid Build Coastguard Worker char *out = string_field(tb, field);
655*cf5a6c84SAndroid Build Coastguard Worker
656*cf5a6c84SAndroid Build Coastguard Worker // Output the field, appropriately padded
657*cf5a6c84SAndroid Build Coastguard Worker
658*cf5a6c84SAndroid Build Coastguard Worker // Minimum one space between each field
659*cf5a6c84SAndroid Build Coastguard Worker if (width<2) break;
660*cf5a6c84SAndroid Build Coastguard Worker if (field != TT.fields) {
661*cf5a6c84SAndroid Build Coastguard Worker putchar(' ');
662*cf5a6c84SAndroid Build Coastguard Worker width--;
663*cf5a6c84SAndroid Build Coastguard Worker }
664*cf5a6c84SAndroid Build Coastguard Worker
665*cf5a6c84SAndroid Build Coastguard Worker // Don't truncate number fields, but try to reclaim extra offset from later
666*cf5a6c84SAndroid Build Coastguard Worker // fields that can naturally be shorter
667*cf5a6c84SAndroid Build Coastguard Worker abslen = abs(field->len);
668*cf5a6c84SAndroid Build Coastguard Worker sign = field->len<0 ? -1 : 1;
669*cf5a6c84SAndroid Build Coastguard Worker olen = (TT.tty) ? utf8len(out) : strlen(out);
670*cf5a6c84SAndroid Build Coastguard Worker if ((field->which<=PS_BIT || FLAG(w)) && olen>abslen) {
671*cf5a6c84SAndroid Build Coastguard Worker // overflow but remember by how much
672*cf5a6c84SAndroid Build Coastguard Worker extra += olen-abslen;
673*cf5a6c84SAndroid Build Coastguard Worker abslen = olen;
674*cf5a6c84SAndroid Build Coastguard Worker } else if (extra && olen<abslen) {
675*cf5a6c84SAndroid Build Coastguard Worker int unused = abslen-olen;
676*cf5a6c84SAndroid Build Coastguard Worker
677*cf5a6c84SAndroid Build Coastguard Worker // If later fields have slack space, take back overflow
678*cf5a6c84SAndroid Build Coastguard Worker if (unused>extra) unused = extra;
679*cf5a6c84SAndroid Build Coastguard Worker abslen -= unused;
680*cf5a6c84SAndroid Build Coastguard Worker extra -= unused;
681*cf5a6c84SAndroid Build Coastguard Worker }
682*cf5a6c84SAndroid Build Coastguard Worker if (abslen>width) abslen = width;
683*cf5a6c84SAndroid Build Coastguard Worker len = pad = abslen;
684*cf5a6c84SAndroid Build Coastguard Worker pad *= sign;
685*cf5a6c84SAndroid Build Coastguard Worker
686*cf5a6c84SAndroid Build Coastguard Worker // If last field is left justified, no trailing spaces.
687*cf5a6c84SAndroid Build Coastguard Worker if (!field->next && sign<0) {
688*cf5a6c84SAndroid Build Coastguard Worker pad = -1;
689*cf5a6c84SAndroid Build Coastguard Worker len = width;
690*cf5a6c84SAndroid Build Coastguard Worker }
691*cf5a6c84SAndroid Build Coastguard Worker
692*cf5a6c84SAndroid Build Coastguard Worker // If we truncated a left-justified field, show + instead of last char
693*cf5a6c84SAndroid Build Coastguard Worker if (olen>len && len>1 && sign<0) {
694*cf5a6c84SAndroid Build Coastguard Worker width--;
695*cf5a6c84SAndroid Build Coastguard Worker len--;
696*cf5a6c84SAndroid Build Coastguard Worker if (field->next) pad++;
697*cf5a6c84SAndroid Build Coastguard Worker abslen = 0;
698*cf5a6c84SAndroid Build Coastguard Worker }
699*cf5a6c84SAndroid Build Coastguard Worker
700*cf5a6c84SAndroid Build Coastguard Worker if (TT.tty) width -= draw_trim(out, pad, len);
701*cf5a6c84SAndroid Build Coastguard Worker else width -= printf("%*.*s", pad, len, out);
702*cf5a6c84SAndroid Build Coastguard Worker if (!abslen) putchar('+');
703*cf5a6c84SAndroid Build Coastguard Worker if (!width) break;
704*cf5a6c84SAndroid Build Coastguard Worker }
705*cf5a6c84SAndroid Build Coastguard Worker putchar(TT.time ? '\r' : '\n');
706*cf5a6c84SAndroid Build Coastguard Worker }
707*cf5a6c84SAndroid Build Coastguard Worker
708*cf5a6c84SAndroid Build Coastguard Worker // dirtree callback: read data about a process, then display or store it.
709*cf5a6c84SAndroid Build Coastguard Worker // Fills toybuf with struct procpid and either DIRTREE_SAVEs a copy to ->extra
710*cf5a6c84SAndroid Build Coastguard Worker // (in -k mode) or calls show_ps directly on toybuf (for low memory systems).
get_ps(struct dirtree * new)711*cf5a6c84SAndroid Build Coastguard Worker static int get_ps(struct dirtree *new)
712*cf5a6c84SAndroid Build Coastguard Worker {
713*cf5a6c84SAndroid Build Coastguard Worker struct {
714*cf5a6c84SAndroid Build Coastguard Worker char *name; // Path under /proc/$PID directory
715*cf5a6c84SAndroid Build Coastguard Worker long long bits; // Only fetch extra data if an -o field is displaying it
716*cf5a6c84SAndroid Build Coastguard Worker } fetch[] = {
717*cf5a6c84SAndroid Build Coastguard Worker // sources for procpid->offset[] data
718*cf5a6c84SAndroid Build Coastguard Worker {"fd/", _PS_TTY}, {"wchan", _PS_WCHAN}, {"attr/current", _PS_LABEL},
719*cf5a6c84SAndroid Build Coastguard Worker {"exe", _PS_COMMAND|_PS_COMM}, {"cmdline", _PS_CMDLINE|_PS_ARGS|_PS_NAME},
720*cf5a6c84SAndroid Build Coastguard Worker {"", _PS_NAME}
721*cf5a6c84SAndroid Build Coastguard Worker };
722*cf5a6c84SAndroid Build Coastguard Worker struct procpid *tb = (void *)toybuf;
723*cf5a6c84SAndroid Build Coastguard Worker long long *slot = tb->slot;
724*cf5a6c84SAndroid Build Coastguard Worker char *name, *s, *buf = tb->str, *end = 0;
725*cf5a6c84SAndroid Build Coastguard Worker FILE *fp;
726*cf5a6c84SAndroid Build Coastguard Worker struct sysinfo si;
727*cf5a6c84SAndroid Build Coastguard Worker int i, j, fd;
728*cf5a6c84SAndroid Build Coastguard Worker off_t len;
729*cf5a6c84SAndroid Build Coastguard Worker
730*cf5a6c84SAndroid Build Coastguard Worker // Recurse one level into /proc children, skip non-numeric entries
731*cf5a6c84SAndroid Build Coastguard Worker if (!new->parent)
732*cf5a6c84SAndroid Build Coastguard Worker return DIRTREE_RECURSE|DIRTREE_SHUTUP|DIRTREE_PROC
733*cf5a6c84SAndroid Build Coastguard Worker |(DIRTREE_SAVE*(TT.threadparent||!TT.show_process));
734*cf5a6c84SAndroid Build Coastguard Worker
735*cf5a6c84SAndroid Build Coastguard Worker // Grab PID and figure out if we're a thread or a process
736*cf5a6c84SAndroid Build Coastguard Worker memset(slot, 0, sizeof(tb->slot));
737*cf5a6c84SAndroid Build Coastguard Worker slot[SLOT_tid] = *slot = atol(new->name);
738*cf5a6c84SAndroid Build Coastguard Worker if (TT.threadparent && TT.threadparent->extra) {
739*cf5a6c84SAndroid Build Coastguard Worker struct procpid *tb2 = (struct procpid *)TT.threadparent->extra;
740*cf5a6c84SAndroid Build Coastguard Worker
741*cf5a6c84SAndroid Build Coastguard Worker *slot = *tb2->slot;
742*cf5a6c84SAndroid Build Coastguard Worker // Parent also shows up as a thread, but we need to reread task/stat fields
743*cf5a6c84SAndroid Build Coastguard Worker // to get non-collated info for just parent thread (vs whole process).
744*cf5a6c84SAndroid Build Coastguard Worker if (*slot == slot[SLOT_tid]) slot = tb2->slot;
745*cf5a6c84SAndroid Build Coastguard Worker }
746*cf5a6c84SAndroid Build Coastguard Worker fd = dirtree_parentfd(new);
747*cf5a6c84SAndroid Build Coastguard Worker
748*cf5a6c84SAndroid Build Coastguard Worker // Read /proc/$PID/stat into half of toybuf.
749*cf5a6c84SAndroid Build Coastguard Worker len = 2048;
750*cf5a6c84SAndroid Build Coastguard Worker sprintf(buf, "%lld/stat", slot[SLOT_tid]);
751*cf5a6c84SAndroid Build Coastguard Worker if (!readfileat(fd, buf, buf, &len)) return 0;
752*cf5a6c84SAndroid Build Coastguard Worker
753*cf5a6c84SAndroid Build Coastguard Worker // parse oddball fields: the first field is same as new->name (skip it)
754*cf5a6c84SAndroid Build Coastguard Worker // and the second and third (name and state) are the only non-numeric fields.
755*cf5a6c84SAndroid Build Coastguard Worker // Name has (parentheses) around it, and can have embedded ')' so match
756*cf5a6c84SAndroid Build Coastguard Worker // _last_ ')' (VFS limits filenames to 255 bytes max, sanity check that).
757*cf5a6c84SAndroid Build Coastguard Worker // TODO: kernel task struct actually limits name to 16 chars?
758*cf5a6c84SAndroid Build Coastguard Worker if (!(name = strchr(buf, '('))) return 0;
759*cf5a6c84SAndroid Build Coastguard Worker for (s = ++name; *s; s++) if (*s == ')') end = s;
760*cf5a6c84SAndroid Build Coastguard Worker if (!end || end-name>255) return 0;
761*cf5a6c84SAndroid Build Coastguard Worker if (1>sscanf(s = end, ") %c%n", &tb->state, &i)) return 0;
762*cf5a6c84SAndroid Build Coastguard Worker
763*cf5a6c84SAndroid Build Coastguard Worker // All remaining fields should be numeric, parse them into slot[] array
764*cf5a6c84SAndroid Build Coastguard Worker // (skipping first 3 stat fields and first slot[], both were handled above)
765*cf5a6c84SAndroid Build Coastguard Worker // yes this means the alignment's off: stat[4] becomes slot[1]
766*cf5a6c84SAndroid Build Coastguard Worker for (j = SLOT_ppid; j<SLOT_upticks; j++)
767*cf5a6c84SAndroid Build Coastguard Worker if (1>sscanf(s += i, " %lld%n", slot+j, &i)) break;
768*cf5a6c84SAndroid Build Coastguard Worker
769*cf5a6c84SAndroid Build Coastguard Worker // Now we've read the data, move status and name right after slot[] array,
770*cf5a6c84SAndroid Build Coastguard Worker // and convert low chars to ? for non-tty display while we're at it.
771*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i<end-name; i++)
772*cf5a6c84SAndroid Build Coastguard Worker if ((tb->str[i] = name[i]) < ' ')
773*cf5a6c84SAndroid Build Coastguard Worker if (!TT.tty) tb->str[i] = '?';
774*cf5a6c84SAndroid Build Coastguard Worker buf = tb->str+i;
775*cf5a6c84SAndroid Build Coastguard Worker *buf++ = 0;
776*cf5a6c84SAndroid Build Coastguard Worker len = sizeof(toybuf)-(buf-toybuf);
777*cf5a6c84SAndroid Build Coastguard Worker
778*cf5a6c84SAndroid Build Coastguard Worker // Overwrite useless/obsolete stat fields with more interesting data.
779*cf5a6c84SAndroid Build Coastguard Worker
780*cf5a6c84SAndroid Build Coastguard Worker // save uid, ruid, gid, gid, and rgid int slots 31-34 (we don't use sigcatch
781*cf5a6c84SAndroid Build Coastguard Worker // or numeric wchan, and the remaining two are always zero), and vmlck into
782*cf5a6c84SAndroid Build Coastguard Worker // 18 (which is "obsolete, always 0" from stat)
783*cf5a6c84SAndroid Build Coastguard Worker slot[SLOT_uid] = new->st.st_uid;
784*cf5a6c84SAndroid Build Coastguard Worker slot[SLOT_gid] = new->st.st_gid;
785*cf5a6c84SAndroid Build Coastguard Worker
786*cf5a6c84SAndroid Build Coastguard Worker // TIME and TIME+ use combined value, ksort needs 'em added.
787*cf5a6c84SAndroid Build Coastguard Worker slot[SLOT_utime] += slot[SLOT_stime];
788*cf5a6c84SAndroid Build Coastguard Worker slot[SLOT_utime2] = slot[SLOT_utime];
789*cf5a6c84SAndroid Build Coastguard Worker
790*cf5a6c84SAndroid Build Coastguard Worker // Do we need to read "status"?
791*cf5a6c84SAndroid Build Coastguard Worker if ((TT.bits&(_PS_RGROUP|_PS_RUSER|_PS_STAT|_PS_RUID|_PS_RGID|_PS_SWAP
792*cf5a6c84SAndroid Build Coastguard Worker |_PS_IO|_PS_DIO)) || TT.GG.len || TT.UU.len)
793*cf5a6c84SAndroid Build Coastguard Worker {
794*cf5a6c84SAndroid Build Coastguard Worker off_t temp = len;
795*cf5a6c84SAndroid Build Coastguard Worker
796*cf5a6c84SAndroid Build Coastguard Worker sprintf(buf, "%lld/status", slot[SLOT_tid]);
797*cf5a6c84SAndroid Build Coastguard Worker if (!readfileat(fd, buf, buf, &temp)) *buf = 0;
798*cf5a6c84SAndroid Build Coastguard Worker s = strafter(buf, "\nUid:");
799*cf5a6c84SAndroid Build Coastguard Worker slot[SLOT_ruid] = s ? atol(s) : new->st.st_uid;
800*cf5a6c84SAndroid Build Coastguard Worker s = strafter(buf, "\nGid:");
801*cf5a6c84SAndroid Build Coastguard Worker slot[SLOT_rgid] = s ? atol(s) : new->st.st_gid;
802*cf5a6c84SAndroid Build Coastguard Worker if ((s = strafter(buf, "\nVmLck:"))) slot[SLOT_vmlck] = atoll(s)*1024;
803*cf5a6c84SAndroid Build Coastguard Worker if ((s = strafter(buf, "\nVmSwap:"))) slot[SLOT_swap] = atoll(s)*1024;
804*cf5a6c84SAndroid Build Coastguard Worker }
805*cf5a6c84SAndroid Build Coastguard Worker
806*cf5a6c84SAndroid Build Coastguard Worker // Do we need to read "io"?
807*cf5a6c84SAndroid Build Coastguard Worker if (TT.bits&(_PS_READ|_PS_WRITE|_PS_DREAD|_PS_DWRITE|_PS_IO|_PS_DIO)) {
808*cf5a6c84SAndroid Build Coastguard Worker off_t temp = len;
809*cf5a6c84SAndroid Build Coastguard Worker
810*cf5a6c84SAndroid Build Coastguard Worker sprintf(buf, "%lld/io", slot[SLOT_tid]);
811*cf5a6c84SAndroid Build Coastguard Worker if (!readfileat(fd, buf, buf, &temp)) *buf = 0;
812*cf5a6c84SAndroid Build Coastguard Worker if ((s = strafter(buf, "rchar:"))) slot[SLOT_rchar] = atoll(s);
813*cf5a6c84SAndroid Build Coastguard Worker if ((s = strafter(buf, "wchar:"))) slot[SLOT_wchar] = atoll(s);
814*cf5a6c84SAndroid Build Coastguard Worker if ((s = strafter(buf, "read_bytes:"))) slot[SLOT_rbytes] = atoll(s);
815*cf5a6c84SAndroid Build Coastguard Worker if ((s = strafter(buf, "write_bytes:"))) slot[SLOT_wbytes] = atoll(s);
816*cf5a6c84SAndroid Build Coastguard Worker slot[SLOT_iobytes] = slot[SLOT_rchar]+slot[SLOT_wchar]+slot[SLOT_swap];
817*cf5a6c84SAndroid Build Coastguard Worker slot[SLOT_diobytes] = slot[SLOT_rbytes]+slot[SLOT_wbytes]+slot[SLOT_swap];
818*cf5a6c84SAndroid Build Coastguard Worker }
819*cf5a6c84SAndroid Build Coastguard Worker
820*cf5a6c84SAndroid Build Coastguard Worker // If we were updating thread parent with its own task info, we're done.
821*cf5a6c84SAndroid Build Coastguard Worker if (slot != tb->slot) return 0;
822*cf5a6c84SAndroid Build Coastguard Worker
823*cf5a6c84SAndroid Build Coastguard Worker // We now know enough to skip processes we don't care about.
824*cf5a6c84SAndroid Build Coastguard Worker if (TT.match_process && !TT.match_process(slot)) return 0;
825*cf5a6c84SAndroid Build Coastguard Worker
826*cf5a6c84SAndroid Build Coastguard Worker // /proc data is generated as it's read, so for maximum accuracy on slow
827*cf5a6c84SAndroid Build Coastguard Worker // systems (or ps | more) we re-fetch uptime as we fetch each /proc line.
828*cf5a6c84SAndroid Build Coastguard Worker sysinfo(&si);
829*cf5a6c84SAndroid Build Coastguard Worker slot[SLOT_uptime] = si.uptime;
830*cf5a6c84SAndroid Build Coastguard Worker slot[SLOT_totalram] = si.totalram;
831*cf5a6c84SAndroid Build Coastguard Worker slot[SLOT_upticks] = slot[SLOT_uptime]*TT.ticks - slot[SLOT_starttime];
832*cf5a6c84SAndroid Build Coastguard Worker
833*cf5a6c84SAndroid Build Coastguard Worker // Do we need to read "statm"?
834*cf5a6c84SAndroid Build Coastguard Worker if (TT.bits&(_PS_VIRT|_PS_SHR)) {
835*cf5a6c84SAndroid Build Coastguard Worker off_t temp = len;
836*cf5a6c84SAndroid Build Coastguard Worker
837*cf5a6c84SAndroid Build Coastguard Worker sprintf(buf, "%lld/statm", slot[SLOT_tid]);
838*cf5a6c84SAndroid Build Coastguard Worker if (!readfileat(fd, buf, buf, &temp)) *buf = 0;
839*cf5a6c84SAndroid Build Coastguard Worker
840*cf5a6c84SAndroid Build Coastguard Worker // Skip redundant RSS field, we got it from stat.
841*cf5a6c84SAndroid Build Coastguard Worker slot[SLOT_vsz] = slot[SLOT_shr] = 0;
842*cf5a6c84SAndroid Build Coastguard Worker sscanf(buf, "%lld %*d %lld", &slot[SLOT_vsz], &slot[SLOT_shr]);
843*cf5a6c84SAndroid Build Coastguard Worker }
844*cf5a6c84SAndroid Build Coastguard Worker
845*cf5a6c84SAndroid Build Coastguard Worker // Do we need to read "exe"?
846*cf5a6c84SAndroid Build Coastguard Worker if (TT.bits&_PS_BIT) {
847*cf5a6c84SAndroid Build Coastguard Worker off_t temp = 6;
848*cf5a6c84SAndroid Build Coastguard Worker
849*cf5a6c84SAndroid Build Coastguard Worker sprintf(buf, "%lld/exe", slot[SLOT_tid]);
850*cf5a6c84SAndroid Build Coastguard Worker if (readfileat(fd, buf, buf, &temp) && !smemcmp(buf, "\177ELF", 4)) {
851*cf5a6c84SAndroid Build Coastguard Worker if (buf[4] == 1) slot[SLOT_bits] = 32;
852*cf5a6c84SAndroid Build Coastguard Worker else if (buf[4] == 2) slot[SLOT_bits] = 64;
853*cf5a6c84SAndroid Build Coastguard Worker }
854*cf5a6c84SAndroid Build Coastguard Worker }
855*cf5a6c84SAndroid Build Coastguard Worker
856*cf5a6c84SAndroid Build Coastguard Worker // Do we need Android scheduling policy?
857*cf5a6c84SAndroid Build Coastguard Worker if (TT.bits&_PS_PCY) {
858*cf5a6c84SAndroid Build Coastguard Worker // Find the cpuset line in "/proc/$pid/cgroup", extract the final field,
859*cf5a6c84SAndroid Build Coastguard Worker // and translate it to one of Android's traditional 2-char names.
860*cf5a6c84SAndroid Build Coastguard Worker // TODO: if other Linux systems start using cgroups, conditionalize this.
861*cf5a6c84SAndroid Build Coastguard Worker sprintf(buf, "/proc/%lld/cgroup", slot[SLOT_tid]);
862*cf5a6c84SAndroid Build Coastguard Worker if ((fp = fopen(buf, "re"))) {
863*cf5a6c84SAndroid Build Coastguard Worker char *s, *line;
864*cf5a6c84SAndroid Build Coastguard Worker while ((line = xgetline(fp))) {
865*cf5a6c84SAndroid Build Coastguard Worker if ((s = strstr(line, ":cpuset:/"))) {
866*cf5a6c84SAndroid Build Coastguard Worker s += strlen(":cpuset:/");
867*cf5a6c84SAndroid Build Coastguard Worker if (!*s || !strcmp(s, "foreground")) strcpy(tb->pcy, "fg");
868*cf5a6c84SAndroid Build Coastguard Worker else if (!strcmp(s, "system-background")) strcpy(tb->pcy, " ");
869*cf5a6c84SAndroid Build Coastguard Worker else if (!strcmp(s, "background")) strcpy(tb->pcy, "bg");
870*cf5a6c84SAndroid Build Coastguard Worker else if (!strcmp(s, "top-app")) strcpy(tb->pcy, "ta");
871*cf5a6c84SAndroid Build Coastguard Worker else if (!strcmp(s, "restricted")) strcpy(tb->pcy, "rs");
872*cf5a6c84SAndroid Build Coastguard Worker else if (!strcmp(s, "foreground_window")) strcpy(tb->pcy, "wi");
873*cf5a6c84SAndroid Build Coastguard Worker else if (!strcmp(s, "camera-daemon")) strcpy(tb->pcy, "cd");
874*cf5a6c84SAndroid Build Coastguard Worker else strcpy(tb->pcy, "?");
875*cf5a6c84SAndroid Build Coastguard Worker }
876*cf5a6c84SAndroid Build Coastguard Worker free(line);
877*cf5a6c84SAndroid Build Coastguard Worker }
878*cf5a6c84SAndroid Build Coastguard Worker fclose(fp);
879*cf5a6c84SAndroid Build Coastguard Worker } else strcpy(tb->pcy, "-");
880*cf5a6c84SAndroid Build Coastguard Worker }
881*cf5a6c84SAndroid Build Coastguard Worker
882*cf5a6c84SAndroid Build Coastguard Worker // Done using buf[] (tb->str) as scratch space, now read string data,
883*cf5a6c84SAndroid Build Coastguard Worker // saving consective null terminated strings. (Save starting offsets into
884*cf5a6c84SAndroid Build Coastguard Worker // str->offset to avoid strlen() loop to find relevant string.)
885*cf5a6c84SAndroid Build Coastguard Worker
886*cf5a6c84SAndroid Build Coastguard Worker // Fetch string data while parentfd still available, appending to buf.
887*cf5a6c84SAndroid Build Coastguard Worker // (There's well over 3k of toybuf left. We could dynamically malloc, but
888*cf5a6c84SAndroid Build Coastguard Worker // it'd almost never get used, querying length of a proc file is awkward,
889*cf5a6c84SAndroid Build Coastguard Worker // fixed buffer is nommu friendly... Wait for somebody to complain. :)
890*cf5a6c84SAndroid Build Coastguard Worker
891*cf5a6c84SAndroid Build Coastguard Worker // The fetch[] array at the start of the function says what file to read
892*cf5a6c84SAndroid Build Coastguard Worker // and what -o display field outputs it (to skip the ones we don't need).
893*cf5a6c84SAndroid Build Coastguard Worker
894*cf5a6c84SAndroid Build Coastguard Worker slot[SLOT_argv0len] = 0;
895*cf5a6c84SAndroid Build Coastguard Worker for (j = 0; j<ARRAY_LEN(fetch); j++) {
896*cf5a6c84SAndroid Build Coastguard Worker tb->offset[j] = buf-(tb->str);
897*cf5a6c84SAndroid Build Coastguard Worker if (!(TT.bits&fetch[j].bits)) {
898*cf5a6c84SAndroid Build Coastguard Worker *buf++ = 0;
899*cf5a6c84SAndroid Build Coastguard Worker continue;
900*cf5a6c84SAndroid Build Coastguard Worker }
901*cf5a6c84SAndroid Build Coastguard Worker
902*cf5a6c84SAndroid Build Coastguard Worker // Determine available space: reserve 256 bytes (guaranteed minimum) for
903*cf5a6c84SAndroid Build Coastguard Worker // each string we haven't checked yet, tb->str starts after the numeric
904*cf5a6c84SAndroid Build Coastguard Worker // arrays in struct procpid, and we reserve 260 bytes scratch space at the
905*cf5a6c84SAndroid Build Coastguard Worker // end of toybuf for output conversion in string_field(). Other than that,
906*cf5a6c84SAndroid Build Coastguard Worker // each use all available space, and future strings that don't use their
907*cf5a6c84SAndroid Build Coastguard Worker // guaranteed minimum add to the pool.
908*cf5a6c84SAndroid Build Coastguard Worker len = sizeof(toybuf)-256*(ARRAY_LEN(fetch)-j)-(buf-toybuf)-260;
909*cf5a6c84SAndroid Build Coastguard Worker sprintf(buf, "%lld/%s", slot[SLOT_tid], fetch[j].name);
910*cf5a6c84SAndroid Build Coastguard Worker
911*cf5a6c84SAndroid Build Coastguard Worker // For exe (j==3) readlink() instead of reading file's contents
912*cf5a6c84SAndroid Build Coastguard Worker // for -o NAME (j==5) copy data from threadparent (PID) into thread (TID).
913*cf5a6c84SAndroid Build Coastguard Worker if (j==3 || j==5) {
914*cf5a6c84SAndroid Build Coastguard Worker struct procpid *ptb = 0;
915*cf5a6c84SAndroid Build Coastguard Worker int k;
916*cf5a6c84SAndroid Build Coastguard Worker
917*cf5a6c84SAndroid Build Coastguard Worker // Thread doesn't have exe or argv[0], so use parent's
918*cf5a6c84SAndroid Build Coastguard Worker if (TT.threadparent && TT.threadparent->extra)
919*cf5a6c84SAndroid Build Coastguard Worker ptb = (void *)TT.threadparent->extra;
920*cf5a6c84SAndroid Build Coastguard Worker
921*cf5a6c84SAndroid Build Coastguard Worker if (j==3 && !ptb) len = readlinkat0(fd, buf, buf, len);
922*cf5a6c84SAndroid Build Coastguard Worker else {
923*cf5a6c84SAndroid Build Coastguard Worker if (j==3) i = strlen(s = ptb->str+ptb->offset[3]);
924*cf5a6c84SAndroid Build Coastguard Worker else {
925*cf5a6c84SAndroid Build Coastguard Worker if (!ptb || slot[SLOT_argv0len]) ptb = tb;
926*cf5a6c84SAndroid Build Coastguard Worker i = ptb->slot[SLOT_argv0len];
927*cf5a6c84SAndroid Build Coastguard Worker s = ptb->str+ptb->offset[4];
928*cf5a6c84SAndroid Build Coastguard Worker while (-1!=(k = stridx(s, '/')) && k<i) {
929*cf5a6c84SAndroid Build Coastguard Worker s += k+1;
930*cf5a6c84SAndroid Build Coastguard Worker i -= k+1;
931*cf5a6c84SAndroid Build Coastguard Worker }
932*cf5a6c84SAndroid Build Coastguard Worker }
933*cf5a6c84SAndroid Build Coastguard Worker if (i<len) len = i;
934*cf5a6c84SAndroid Build Coastguard Worker memcpy(buf, s, len);
935*cf5a6c84SAndroid Build Coastguard Worker buf[len] = 0;
936*cf5a6c84SAndroid Build Coastguard Worker }
937*cf5a6c84SAndroid Build Coastguard Worker
938*cf5a6c84SAndroid Build Coastguard Worker // Turning stat's SLOT_ttynr into a string is an outright heuristic ordeal.
939*cf5a6c84SAndroid Build Coastguard Worker } else if (!j) {
940*cf5a6c84SAndroid Build Coastguard Worker int rdev = slot[SLOT_ttynr];
941*cf5a6c84SAndroid Build Coastguard Worker struct stat st;
942*cf5a6c84SAndroid Build Coastguard Worker
943*cf5a6c84SAndroid Build Coastguard Worker // Call no tty "?" rather than "0:0".
944*cf5a6c84SAndroid Build Coastguard Worker strcpy(buf, "?");
945*cf5a6c84SAndroid Build Coastguard Worker if (rdev) {
946*cf5a6c84SAndroid Build Coastguard Worker // Can we readlink() our way to a name?
947*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i<3; i++) {
948*cf5a6c84SAndroid Build Coastguard Worker sprintf(buf, "%lld/fd/%i", slot[SLOT_tid], i);
949*cf5a6c84SAndroid Build Coastguard Worker if (!fstatat(fd, buf, &st, 0) && S_ISCHR(st.st_mode)
950*cf5a6c84SAndroid Build Coastguard Worker && st.st_rdev == rdev && (len = readlinkat0(fd, buf, buf, len)))
951*cf5a6c84SAndroid Build Coastguard Worker break;
952*cf5a6c84SAndroid Build Coastguard Worker }
953*cf5a6c84SAndroid Build Coastguard Worker
954*cf5a6c84SAndroid Build Coastguard Worker // Couldn't find it, try all the tty drivers.
955*cf5a6c84SAndroid Build Coastguard Worker if (i == 3) {
956*cf5a6c84SAndroid Build Coastguard Worker int tty_major = 0, maj = dev_major(rdev), min = dev_minor(rdev);
957*cf5a6c84SAndroid Build Coastguard Worker
958*cf5a6c84SAndroid Build Coastguard Worker if ((fp = fopen("/proc/tty/drivers", "r"))) {
959*cf5a6c84SAndroid Build Coastguard Worker while (fscanf(fp, "%*s %256s %d %*s %*s", buf, &tty_major) == 2) {
960*cf5a6c84SAndroid Build Coastguard Worker // TODO: we could parse the minor range too.
961*cf5a6c84SAndroid Build Coastguard Worker if (tty_major == maj) {
962*cf5a6c84SAndroid Build Coastguard Worker len = strlen(buf);
963*cf5a6c84SAndroid Build Coastguard Worker len += sprintf(buf+len, "%d", min);
964*cf5a6c84SAndroid Build Coastguard Worker if (!stat(buf, &st) && S_ISCHR(st.st_mode) && st.st_rdev==rdev)
965*cf5a6c84SAndroid Build Coastguard Worker break;
966*cf5a6c84SAndroid Build Coastguard Worker }
967*cf5a6c84SAndroid Build Coastguard Worker tty_major = 0;
968*cf5a6c84SAndroid Build Coastguard Worker }
969*cf5a6c84SAndroid Build Coastguard Worker fclose(fp);
970*cf5a6c84SAndroid Build Coastguard Worker }
971*cf5a6c84SAndroid Build Coastguard Worker
972*cf5a6c84SAndroid Build Coastguard Worker // Really couldn't find it, so just show major:minor.
973*cf5a6c84SAndroid Build Coastguard Worker if (!tty_major) len = sprintf(buf, "%d:%d", maj, min);
974*cf5a6c84SAndroid Build Coastguard Worker }
975*cf5a6c84SAndroid Build Coastguard Worker
976*cf5a6c84SAndroid Build Coastguard Worker s = buf;
977*cf5a6c84SAndroid Build Coastguard Worker if (strstart(&s, "/dev/")) memmove(buf, s, len -= 4);
978*cf5a6c84SAndroid Build Coastguard Worker }
979*cf5a6c84SAndroid Build Coastguard Worker
980*cf5a6c84SAndroid Build Coastguard Worker // For the rest, the data we want is in a file we can just read.
981*cf5a6c84SAndroid Build Coastguard Worker } else {
982*cf5a6c84SAndroid Build Coastguard Worker int temp = 0;
983*cf5a6c84SAndroid Build Coastguard Worker
984*cf5a6c84SAndroid Build Coastguard Worker // When command has no arguments, don't space over the NUL
985*cf5a6c84SAndroid Build Coastguard Worker if (readfileat(fd, buf, buf, &len) && len>0) {
986*cf5a6c84SAndroid Build Coastguard Worker
987*cf5a6c84SAndroid Build Coastguard Worker // Trim trailing whitespace and NUL bytes
988*cf5a6c84SAndroid Build Coastguard Worker while (len)
989*cf5a6c84SAndroid Build Coastguard Worker if (!buf[len-1] || isspace(buf[len-1])) buf[--len] = 0;
990*cf5a6c84SAndroid Build Coastguard Worker else break;
991*cf5a6c84SAndroid Build Coastguard Worker
992*cf5a6c84SAndroid Build Coastguard Worker // Turn NUL to space, other low ascii to ? (in non-tty mode), except
993*cf5a6c84SAndroid Build Coastguard Worker // cmdline has a trailing NUL that we don't want to turn to space.
994*cf5a6c84SAndroid Build Coastguard Worker for (i=0; i<len-1; i++) {
995*cf5a6c84SAndroid Build Coastguard Worker char c = buf[i];
996*cf5a6c84SAndroid Build Coastguard Worker
997*cf5a6c84SAndroid Build Coastguard Worker if (!c) {
998*cf5a6c84SAndroid Build Coastguard Worker if (!temp) temp = i;
999*cf5a6c84SAndroid Build Coastguard Worker c = ' ';
1000*cf5a6c84SAndroid Build Coastguard Worker } else if (!TT.tty && c<' ') c = '?';
1001*cf5a6c84SAndroid Build Coastguard Worker buf[i] = c;
1002*cf5a6c84SAndroid Build Coastguard Worker }
1003*cf5a6c84SAndroid Build Coastguard Worker } else *buf = len = 0;
1004*cf5a6c84SAndroid Build Coastguard Worker
1005*cf5a6c84SAndroid Build Coastguard Worker // Store end of argv[0] so ARGS and CMDLINE can differ.
1006*cf5a6c84SAndroid Build Coastguard Worker // We do it for each file string slot but last is cmdline, which sticks.
1007*cf5a6c84SAndroid Build Coastguard Worker slot[SLOT_argv0len] = temp ? : len; // Position of _first_ NUL
1008*cf5a6c84SAndroid Build Coastguard Worker }
1009*cf5a6c84SAndroid Build Coastguard Worker
1010*cf5a6c84SAndroid Build Coastguard Worker // Each case above calculated/retained len, so we don't need to re-strlen.
1011*cf5a6c84SAndroid Build Coastguard Worker buf += len+1;
1012*cf5a6c84SAndroid Build Coastguard Worker }
1013*cf5a6c84SAndroid Build Coastguard Worker
1014*cf5a6c84SAndroid Build Coastguard Worker // Record that we saw another process, and display/return now if appropriate
1015*cf5a6c84SAndroid Build Coastguard Worker TT.kcount++;
1016*cf5a6c84SAndroid Build Coastguard Worker if (TT.show_process && !TT.threadparent) {
1017*cf5a6c84SAndroid Build Coastguard Worker TT.show_process(tb);
1018*cf5a6c84SAndroid Build Coastguard Worker
1019*cf5a6c84SAndroid Build Coastguard Worker return 0;
1020*cf5a6c84SAndroid Build Coastguard Worker }
1021*cf5a6c84SAndroid Build Coastguard Worker
1022*cf5a6c84SAndroid Build Coastguard Worker // We're retaining data (probably to sort it), save copy in list.
1023*cf5a6c84SAndroid Build Coastguard Worker s = xmalloc(buf-toybuf);
1024*cf5a6c84SAndroid Build Coastguard Worker new->extra = (long)s;
1025*cf5a6c84SAndroid Build Coastguard Worker memcpy(s, toybuf, buf-toybuf);
1026*cf5a6c84SAndroid Build Coastguard Worker
1027*cf5a6c84SAndroid Build Coastguard Worker return DIRTREE_SAVE;
1028*cf5a6c84SAndroid Build Coastguard Worker }
1029*cf5a6c84SAndroid Build Coastguard Worker
1030*cf5a6c84SAndroid Build Coastguard Worker // wrapper for get_ps() that also collects threads under each processes
get_threads(struct dirtree * new)1031*cf5a6c84SAndroid Build Coastguard Worker static int get_threads(struct dirtree *new)
1032*cf5a6c84SAndroid Build Coastguard Worker {
1033*cf5a6c84SAndroid Build Coastguard Worker struct dirtree *dt;
1034*cf5a6c84SAndroid Build Coastguard Worker struct procpid *tb;
1035*cf5a6c84SAndroid Build Coastguard Worker unsigned pid, kcount;
1036*cf5a6c84SAndroid Build Coastguard Worker
1037*cf5a6c84SAndroid Build Coastguard Worker if (!new->parent) return get_ps(new);
1038*cf5a6c84SAndroid Build Coastguard Worker pid = atol(new->name);
1039*cf5a6c84SAndroid Build Coastguard Worker
1040*cf5a6c84SAndroid Build Coastguard Worker TT.threadparent = new;
1041*cf5a6c84SAndroid Build Coastguard Worker if (!get_ps(new)) {
1042*cf5a6c84SAndroid Build Coastguard Worker // it exited out from under us
1043*cf5a6c84SAndroid Build Coastguard Worker TT.threadparent = 0;
1044*cf5a6c84SAndroid Build Coastguard Worker
1045*cf5a6c84SAndroid Build Coastguard Worker return 0;
1046*cf5a6c84SAndroid Build Coastguard Worker }
1047*cf5a6c84SAndroid Build Coastguard Worker
1048*cf5a6c84SAndroid Build Coastguard Worker // Recurse down into tasks, retaining thread groups.
1049*cf5a6c84SAndroid Build Coastguard Worker // Disable show_process at least until we can calculate tcount
1050*cf5a6c84SAndroid Build Coastguard Worker kcount = TT.kcount;
1051*cf5a6c84SAndroid Build Coastguard Worker sprintf(toybuf, "/proc/%u/task", pid);
1052*cf5a6c84SAndroid Build Coastguard Worker new->child = dirtree_flagread(toybuf, DIRTREE_SHUTUP|DIRTREE_PROC, get_ps);
1053*cf5a6c84SAndroid Build Coastguard Worker if (new->child == DIRTREE_ABORTVAL) new->child = 0;
1054*cf5a6c84SAndroid Build Coastguard Worker TT.threadparent = 0;
1055*cf5a6c84SAndroid Build Coastguard Worker kcount = TT.kcount-kcount+1;
1056*cf5a6c84SAndroid Build Coastguard Worker tb = (void *)new->extra;
1057*cf5a6c84SAndroid Build Coastguard Worker tb->slot[SLOT_tcount] = kcount;
1058*cf5a6c84SAndroid Build Coastguard Worker
1059*cf5a6c84SAndroid Build Coastguard Worker // Fill out tid and thread count for each entry in group (if it didn't exit
1060*cf5a6c84SAndroid Build Coastguard Worker // out from under us again; asynchronous reads of unlocked data are fun!)
1061*cf5a6c84SAndroid Build Coastguard Worker if (new->child) for (dt = new->child->child; dt; dt = dt->next) {
1062*cf5a6c84SAndroid Build Coastguard Worker tb = (void *)dt->extra;
1063*cf5a6c84SAndroid Build Coastguard Worker tb->slot[SLOT_pid] = pid;
1064*cf5a6c84SAndroid Build Coastguard Worker tb->slot[SLOT_tcount] = kcount;
1065*cf5a6c84SAndroid Build Coastguard Worker }
1066*cf5a6c84SAndroid Build Coastguard Worker
1067*cf5a6c84SAndroid Build Coastguard Worker // Save or display
1068*cf5a6c84SAndroid Build Coastguard Worker if (!TT.show_process) return DIRTREE_SAVE;
1069*cf5a6c84SAndroid Build Coastguard Worker TT.show_process((void *)new->extra);
1070*cf5a6c84SAndroid Build Coastguard Worker if ((dt = new->child)) {
1071*cf5a6c84SAndroid Build Coastguard Worker new->child = 0;
1072*cf5a6c84SAndroid Build Coastguard Worker while (dt->child) {
1073*cf5a6c84SAndroid Build Coastguard Worker new = dt->child->next;
1074*cf5a6c84SAndroid Build Coastguard Worker TT.show_process((void *)dt->child->extra);
1075*cf5a6c84SAndroid Build Coastguard Worker free(dt->child);
1076*cf5a6c84SAndroid Build Coastguard Worker dt->child = new;
1077*cf5a6c84SAndroid Build Coastguard Worker }
1078*cf5a6c84SAndroid Build Coastguard Worker free(dt);
1079*cf5a6c84SAndroid Build Coastguard Worker }
1080*cf5a6c84SAndroid Build Coastguard Worker
1081*cf5a6c84SAndroid Build Coastguard Worker return 0;
1082*cf5a6c84SAndroid Build Coastguard Worker }
1083*cf5a6c84SAndroid Build Coastguard Worker
1084*cf5a6c84SAndroid Build Coastguard Worker // Parse one FIELD argument (with optional =name :width) into struct ofields
parse_ko(void * data,char * type,int length)1085*cf5a6c84SAndroid Build Coastguard Worker static char *parse_ko(void *data, char *type, int length)
1086*cf5a6c84SAndroid Build Coastguard Worker {
1087*cf5a6c84SAndroid Build Coastguard Worker struct ofields *field;
1088*cf5a6c84SAndroid Build Coastguard Worker char *width, *title, *end, *s;
1089*cf5a6c84SAndroid Build Coastguard Worker int i, j, k;
1090*cf5a6c84SAndroid Build Coastguard Worker
1091*cf5a6c84SAndroid Build Coastguard Worker // Caller's WOULD_EXIT catches -o help and prints help
1092*cf5a6c84SAndroid Build Coastguard Worker if (length==4 && !strncasecmp(type, "HELP", length)) xexit();
1093*cf5a6c84SAndroid Build Coastguard Worker
1094*cf5a6c84SAndroid Build Coastguard Worker // Get title, length of title, type, end of type, and display width
1095*cf5a6c84SAndroid Build Coastguard Worker
1096*cf5a6c84SAndroid Build Coastguard Worker // Chip off =name to display
1097*cf5a6c84SAndroid Build Coastguard Worker if ((end = strchr(type, '=')) && length>(end-type)) {
1098*cf5a6c84SAndroid Build Coastguard Worker title = end+1;
1099*cf5a6c84SAndroid Build Coastguard Worker length -= (end-type)+1;
1100*cf5a6c84SAndroid Build Coastguard Worker } else {
1101*cf5a6c84SAndroid Build Coastguard Worker end = type+length;
1102*cf5a6c84SAndroid Build Coastguard Worker title = 0;
1103*cf5a6c84SAndroid Build Coastguard Worker }
1104*cf5a6c84SAndroid Build Coastguard Worker
1105*cf5a6c84SAndroid Build Coastguard Worker // Chip off :width to display
1106*cf5a6c84SAndroid Build Coastguard Worker if ((width = strchr(type, ':')) && width<end) {
1107*cf5a6c84SAndroid Build Coastguard Worker if (!title) length = width-type;
1108*cf5a6c84SAndroid Build Coastguard Worker } else width = 0;
1109*cf5a6c84SAndroid Build Coastguard Worker
1110*cf5a6c84SAndroid Build Coastguard Worker // Allocate structure plus extra space to append a copy of title data
1111*cf5a6c84SAndroid Build Coastguard Worker // (this way it's same lifetime, freeing struct automatically frees title)
1112*cf5a6c84SAndroid Build Coastguard Worker field = xzalloc(sizeof(struct ofields)+(length+1)*!!title);
1113*cf5a6c84SAndroid Build Coastguard Worker if (title) {
1114*cf5a6c84SAndroid Build Coastguard Worker memcpy(field->title = (char *)(field+1), title, length);
1115*cf5a6c84SAndroid Build Coastguard Worker field->title[field->len = length] = 0;
1116*cf5a6c84SAndroid Build Coastguard Worker }
1117*cf5a6c84SAndroid Build Coastguard Worker
1118*cf5a6c84SAndroid Build Coastguard Worker if (width) {
1119*cf5a6c84SAndroid Build Coastguard Worker field->len = strtol(++width, &title, 10);
1120*cf5a6c84SAndroid Build Coastguard Worker if (!isdigit(*width) || title != end) return title;
1121*cf5a6c84SAndroid Build Coastguard Worker end = --width;
1122*cf5a6c84SAndroid Build Coastguard Worker }
1123*cf5a6c84SAndroid Build Coastguard Worker
1124*cf5a6c84SAndroid Build Coastguard Worker // Find type
1125*cf5a6c84SAndroid Build Coastguard Worker field->reverse = 1;
1126*cf5a6c84SAndroid Build Coastguard Worker if (*type == '-') field->reverse = -1;
1127*cf5a6c84SAndroid Build Coastguard Worker else if (*type != '+') type--;
1128*cf5a6c84SAndroid Build Coastguard Worker type++;
1129*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i<ARRAY_LEN(typos); i++) {
1130*cf5a6c84SAndroid Build Coastguard Worker field->which = i;
1131*cf5a6c84SAndroid Build Coastguard Worker for (j = 0; j<2; j++) {
1132*cf5a6c84SAndroid Build Coastguard Worker if (!j) s = typos[i].name;
1133*cf5a6c84SAndroid Build Coastguard Worker // posix requires alternate names for some fields
1134*cf5a6c84SAndroid Build Coastguard Worker else if (-1==(k = stridx((char []){PS_NI, PS_SCH, PS_ELAPSED, PS__CPU,
1135*cf5a6c84SAndroid Build Coastguard Worker PS_VSZ, PS_USER, 0}, i))) continue;
1136*cf5a6c84SAndroid Build Coastguard Worker else
1137*cf5a6c84SAndroid Build Coastguard Worker s = ((char *[]){"NICE", "SCHED", "ETIME", "PCPU", "VSIZE", "UNAME"})[k];
1138*cf5a6c84SAndroid Build Coastguard Worker
1139*cf5a6c84SAndroid Build Coastguard Worker if (!strncasecmp(type, s, end-type) && strlen(s)==end-type) break;
1140*cf5a6c84SAndroid Build Coastguard Worker }
1141*cf5a6c84SAndroid Build Coastguard Worker if (j!=2) break;
1142*cf5a6c84SAndroid Build Coastguard Worker }
1143*cf5a6c84SAndroid Build Coastguard Worker if (i==ARRAY_LEN(typos)) return type;
1144*cf5a6c84SAndroid Build Coastguard Worker if (!field->title) field->title = typos[field->which].name;
1145*cf5a6c84SAndroid Build Coastguard Worker k = i<2 ? TT.pidlen : typos[field->which].width;
1146*cf5a6c84SAndroid Build Coastguard Worker if (!field->len) field->len = k;
1147*cf5a6c84SAndroid Build Coastguard Worker else if (k<0) field->len *= -1;
1148*cf5a6c84SAndroid Build Coastguard Worker dlist_add_nomalloc(data, (void *)field);
1149*cf5a6c84SAndroid Build Coastguard Worker
1150*cf5a6c84SAndroid Build Coastguard Worker return 0;
1151*cf5a6c84SAndroid Build Coastguard Worker }
1152*cf5a6c84SAndroid Build Coastguard Worker
1153*cf5a6c84SAndroid Build Coastguard Worker // Write FIELD list into display header string (truncating at blen),
1154*cf5a6c84SAndroid Build Coastguard Worker // and return bitfield of which FIELDs are used.
get_headers(struct ofields * field,char * buf,int blen)1155*cf5a6c84SAndroid Build Coastguard Worker static long long get_headers(struct ofields *field, char *buf, int blen)
1156*cf5a6c84SAndroid Build Coastguard Worker {
1157*cf5a6c84SAndroid Build Coastguard Worker long long bits = 0;
1158*cf5a6c84SAndroid Build Coastguard Worker int len = 0, scroll;
1159*cf5a6c84SAndroid Build Coastguard Worker
1160*cf5a6c84SAndroid Build Coastguard Worker // Skip TT.scroll many fields (but not last one)
1161*cf5a6c84SAndroid Build Coastguard Worker for (scroll = TT.scroll; scroll && field->next; scroll--) field = field->next;
1162*cf5a6c84SAndroid Build Coastguard Worker
1163*cf5a6c84SAndroid Build Coastguard Worker for (; field; field = field->next) {
1164*cf5a6c84SAndroid Build Coastguard Worker len += snprintf(buf+len, blen-len, " %*s"+!bits, field->len,
1165*cf5a6c84SAndroid Build Coastguard Worker field->title);
1166*cf5a6c84SAndroid Build Coastguard Worker bits |= 1LL<<field->which;
1167*cf5a6c84SAndroid Build Coastguard Worker }
1168*cf5a6c84SAndroid Build Coastguard Worker
1169*cf5a6c84SAndroid Build Coastguard Worker return bits;
1170*cf5a6c84SAndroid Build Coastguard Worker }
1171*cf5a6c84SAndroid Build Coastguard Worker
1172*cf5a6c84SAndroid Build Coastguard Worker // Parse command line options -p -s -t -u -U -g -G
parse_rest(void * data,char * str,int len)1173*cf5a6c84SAndroid Build Coastguard Worker static char *parse_rest(void *data, char *str, int len)
1174*cf5a6c84SAndroid Build Coastguard Worker {
1175*cf5a6c84SAndroid Build Coastguard Worker struct ps_ptr_len *pl = (struct ps_ptr_len *)data;
1176*cf5a6c84SAndroid Build Coastguard Worker long *ll = pl->ptr;
1177*cf5a6c84SAndroid Build Coastguard Worker char *end;
1178*cf5a6c84SAndroid Build Coastguard Worker int num = 0;
1179*cf5a6c84SAndroid Build Coastguard Worker
1180*cf5a6c84SAndroid Build Coastguard Worker // Allocate next chunk of data
1181*cf5a6c84SAndroid Build Coastguard Worker if (!(15&pl->len))
1182*cf5a6c84SAndroid Build Coastguard Worker ll = pl->ptr = xrealloc(pl->ptr, sizeof(long)*(pl->len+16));
1183*cf5a6c84SAndroid Build Coastguard Worker
1184*cf5a6c84SAndroid Build Coastguard Worker // Parse numerical input
1185*cf5a6c84SAndroid Build Coastguard Worker if (isdigit(*str)) {
1186*cf5a6c84SAndroid Build Coastguard Worker ll[pl->len] = xstrtol(str, &end, 10);
1187*cf5a6c84SAndroid Build Coastguard Worker if (end==(len+str)) num++;
1188*cf5a6c84SAndroid Build Coastguard Worker // For pkill, -s 0 represents pkill's session id.
1189*cf5a6c84SAndroid Build Coastguard Worker if (pl==&TT.ss && ll[pl->len]==0) ll[pl->len] = getsid(0);
1190*cf5a6c84SAndroid Build Coastguard Worker }
1191*cf5a6c84SAndroid Build Coastguard Worker
1192*cf5a6c84SAndroid Build Coastguard Worker // PID can't be zero but SID can be 0 before the init task calls setsid().
1193*cf5a6c84SAndroid Build Coastguard Worker if (pl==&TT.pp || pl==&TT.ss) {
1194*cf5a6c84SAndroid Build Coastguard Worker if (num && ll[pl->len]>-(pl==&TT.ss)) {
1195*cf5a6c84SAndroid Build Coastguard Worker pl->len++;
1196*cf5a6c84SAndroid Build Coastguard Worker
1197*cf5a6c84SAndroid Build Coastguard Worker return 0;
1198*cf5a6c84SAndroid Build Coastguard Worker }
1199*cf5a6c84SAndroid Build Coastguard Worker } else if (pl==&TT.tt) {
1200*cf5a6c84SAndroid Build Coastguard Worker // -t pts = 12,pts/12 tty = /dev/tty2,tty2,S0
1201*cf5a6c84SAndroid Build Coastguard Worker if (!num) {
1202*cf5a6c84SAndroid Build Coastguard Worker if (strstart(&str, strcpy(toybuf, "/dev/"))) len -= 5;
1203*cf5a6c84SAndroid Build Coastguard Worker if (strstart(&str, "pts/")) {
1204*cf5a6c84SAndroid Build Coastguard Worker len -= 4;
1205*cf5a6c84SAndroid Build Coastguard Worker num++;
1206*cf5a6c84SAndroid Build Coastguard Worker } else if (strstart(&str, "tty")) len -= 3;
1207*cf5a6c84SAndroid Build Coastguard Worker }
1208*cf5a6c84SAndroid Build Coastguard Worker if (len<256 && (!(end = strchr(str, '/')) || end-str>len)) {
1209*cf5a6c84SAndroid Build Coastguard Worker struct stat st;
1210*cf5a6c84SAndroid Build Coastguard Worker
1211*cf5a6c84SAndroid Build Coastguard Worker end = toybuf + sprintf(toybuf, "/dev/%s", num ? "pts/" : "tty");
1212*cf5a6c84SAndroid Build Coastguard Worker memcpy(end, str, len);
1213*cf5a6c84SAndroid Build Coastguard Worker end[len] = 0;
1214*cf5a6c84SAndroid Build Coastguard Worker xstat(toybuf, &st);
1215*cf5a6c84SAndroid Build Coastguard Worker ll[pl->len++] = st.st_rdev;
1216*cf5a6c84SAndroid Build Coastguard Worker
1217*cf5a6c84SAndroid Build Coastguard Worker return 0;
1218*cf5a6c84SAndroid Build Coastguard Worker }
1219*cf5a6c84SAndroid Build Coastguard Worker } else if (len<255) {
1220*cf5a6c84SAndroid Build Coastguard Worker char name[256];
1221*cf5a6c84SAndroid Build Coastguard Worker
1222*cf5a6c84SAndroid Build Coastguard Worker if (num) {
1223*cf5a6c84SAndroid Build Coastguard Worker pl->len++;
1224*cf5a6c84SAndroid Build Coastguard Worker
1225*cf5a6c84SAndroid Build Coastguard Worker return 0;
1226*cf5a6c84SAndroid Build Coastguard Worker }
1227*cf5a6c84SAndroid Build Coastguard Worker
1228*cf5a6c84SAndroid Build Coastguard Worker memcpy(name, str, len);
1229*cf5a6c84SAndroid Build Coastguard Worker name[len] = 0;
1230*cf5a6c84SAndroid Build Coastguard Worker if (pl==&TT.gg || pl==&TT.GG) {
1231*cf5a6c84SAndroid Build Coastguard Worker struct group *gr = getgrnam(name);
1232*cf5a6c84SAndroid Build Coastguard Worker if (gr) {
1233*cf5a6c84SAndroid Build Coastguard Worker ll[pl->len++] = gr->gr_gid;
1234*cf5a6c84SAndroid Build Coastguard Worker
1235*cf5a6c84SAndroid Build Coastguard Worker return 0;
1236*cf5a6c84SAndroid Build Coastguard Worker }
1237*cf5a6c84SAndroid Build Coastguard Worker } else if (pl==&TT.uu || pl==&TT.UU) {
1238*cf5a6c84SAndroid Build Coastguard Worker struct passwd *pw = getpwnam(name);
1239*cf5a6c84SAndroid Build Coastguard Worker if (pw) {
1240*cf5a6c84SAndroid Build Coastguard Worker ll[pl->len++] = pw->pw_uid;
1241*cf5a6c84SAndroid Build Coastguard Worker
1242*cf5a6c84SAndroid Build Coastguard Worker return 0;
1243*cf5a6c84SAndroid Build Coastguard Worker }
1244*cf5a6c84SAndroid Build Coastguard Worker }
1245*cf5a6c84SAndroid Build Coastguard Worker }
1246*cf5a6c84SAndroid Build Coastguard Worker
1247*cf5a6c84SAndroid Build Coastguard Worker // Return error
1248*cf5a6c84SAndroid Build Coastguard Worker return str;
1249*cf5a6c84SAndroid Build Coastguard Worker }
1250*cf5a6c84SAndroid Build Coastguard Worker
1251*cf5a6c84SAndroid Build Coastguard Worker // sort processes by FIELD(s) listed in option -k
ksort(void * aa,void * bb)1252*cf5a6c84SAndroid Build Coastguard Worker static int ksort(void *aa, void *bb)
1253*cf5a6c84SAndroid Build Coastguard Worker {
1254*cf5a6c84SAndroid Build Coastguard Worker struct ofields *field;
1255*cf5a6c84SAndroid Build Coastguard Worker struct procpid *ta = *(struct procpid **)aa, *tb = *(struct procpid **)bb;
1256*cf5a6c84SAndroid Build Coastguard Worker int ret = 0, slot;
1257*cf5a6c84SAndroid Build Coastguard Worker
1258*cf5a6c84SAndroid Build Coastguard Worker for (field = TT.kfields; field && !ret; field = field->next) {
1259*cf5a6c84SAndroid Build Coastguard Worker slot = typos[field->which].slot;
1260*cf5a6c84SAndroid Build Coastguard Worker
1261*cf5a6c84SAndroid Build Coastguard Worker // Can we do numeric sort?
1262*cf5a6c84SAndroid Build Coastguard Worker if (!(slot&XX)) {
1263*cf5a6c84SAndroid Build Coastguard Worker if (ta->slot[slot]<tb->slot[slot]) ret = -1;
1264*cf5a6c84SAndroid Build Coastguard Worker if (ta->slot[slot]>tb->slot[slot]) ret = 1;
1265*cf5a6c84SAndroid Build Coastguard Worker }
1266*cf5a6c84SAndroid Build Coastguard Worker
1267*cf5a6c84SAndroid Build Coastguard Worker // fallback to string sort
1268*cf5a6c84SAndroid Build Coastguard Worker if (!ret) {
1269*cf5a6c84SAndroid Build Coastguard Worker memccpy(toybuf, string_field(ta, field), 0, 2048);
1270*cf5a6c84SAndroid Build Coastguard Worker toybuf[2048] = 0;
1271*cf5a6c84SAndroid Build Coastguard Worker ret = strcmp(toybuf, string_field(tb, field));
1272*cf5a6c84SAndroid Build Coastguard Worker }
1273*cf5a6c84SAndroid Build Coastguard Worker ret *= field->reverse;
1274*cf5a6c84SAndroid Build Coastguard Worker }
1275*cf5a6c84SAndroid Build Coastguard Worker
1276*cf5a6c84SAndroid Build Coastguard Worker return ret;
1277*cf5a6c84SAndroid Build Coastguard Worker }
1278*cf5a6c84SAndroid Build Coastguard Worker
1279*cf5a6c84SAndroid Build Coastguard Worker // Collect ->extra field from leaf nodes DIRTREE_SAVEd by get_ps() into array
1280*cf5a6c84SAndroid Build Coastguard Worker // (recursion because tree from get_thread() isn't flat list of siblings)
collate_leaves(struct procpid ** tb,struct dirtree * dt)1281*cf5a6c84SAndroid Build Coastguard Worker static struct procpid **collate_leaves(struct procpid **tb, struct dirtree *dt)
1282*cf5a6c84SAndroid Build Coastguard Worker {
1283*cf5a6c84SAndroid Build Coastguard Worker while (dt) {
1284*cf5a6c84SAndroid Build Coastguard Worker struct dirtree *next = dt->next;
1285*cf5a6c84SAndroid Build Coastguard Worker
1286*cf5a6c84SAndroid Build Coastguard Worker if (dt->extra) *(tb++) = (void *)dt->extra;
1287*cf5a6c84SAndroid Build Coastguard Worker if (dt->child) tb = collate_leaves(tb, dt->child);
1288*cf5a6c84SAndroid Build Coastguard Worker free(dt);
1289*cf5a6c84SAndroid Build Coastguard Worker dt = next;
1290*cf5a6c84SAndroid Build Coastguard Worker }
1291*cf5a6c84SAndroid Build Coastguard Worker
1292*cf5a6c84SAndroid Build Coastguard Worker return tb;
1293*cf5a6c84SAndroid Build Coastguard Worker }
1294*cf5a6c84SAndroid Build Coastguard Worker
1295*cf5a6c84SAndroid Build Coastguard Worker // Allocate struct procpid array of length count and populate it with ->extra
1296*cf5a6c84SAndroid Build Coastguard Worker // fields from dirtree leaf nodes. (top diffs old & new array to show changes)
collate(int count,struct dirtree * dt)1297*cf5a6c84SAndroid Build Coastguard Worker static struct procpid **collate(int count, struct dirtree *dt)
1298*cf5a6c84SAndroid Build Coastguard Worker {
1299*cf5a6c84SAndroid Build Coastguard Worker struct procpid **tbsort = xmalloc(count*sizeof(struct procpid *));
1300*cf5a6c84SAndroid Build Coastguard Worker
1301*cf5a6c84SAndroid Build Coastguard Worker collate_leaves(tbsort, dt);
1302*cf5a6c84SAndroid Build Coastguard Worker
1303*cf5a6c84SAndroid Build Coastguard Worker return tbsort;
1304*cf5a6c84SAndroid Build Coastguard Worker }
1305*cf5a6c84SAndroid Build Coastguard Worker
1306*cf5a6c84SAndroid Build Coastguard Worker // parse command line arguments (ala -k -o) with a comma separated FIELD list
default_ko(char * s,void * fields,char * err,struct arg_list * arg)1307*cf5a6c84SAndroid Build Coastguard Worker static void default_ko(char *s, void *fields, char *err, struct arg_list *arg)
1308*cf5a6c84SAndroid Build Coastguard Worker {
1309*cf5a6c84SAndroid Build Coastguard Worker struct arg_list def;
1310*cf5a6c84SAndroid Build Coastguard Worker int x;
1311*cf5a6c84SAndroid Build Coastguard Worker
1312*cf5a6c84SAndroid Build Coastguard Worker memset(&def, 0, sizeof(struct arg_list));
1313*cf5a6c84SAndroid Build Coastguard Worker def.arg = s;
1314*cf5a6c84SAndroid Build Coastguard Worker WOULD_EXIT(x, comma_args(arg ? arg : &def, fields, err, parse_ko));
1315*cf5a6c84SAndroid Build Coastguard Worker if (x) help_help();
1316*cf5a6c84SAndroid Build Coastguard Worker }
1317*cf5a6c84SAndroid Build Coastguard Worker
common_setup(void)1318*cf5a6c84SAndroid Build Coastguard Worker static void common_setup(void)
1319*cf5a6c84SAndroid Build Coastguard Worker {
1320*cf5a6c84SAndroid Build Coastguard Worker char buf[128];
1321*cf5a6c84SAndroid Build Coastguard Worker int i;
1322*cf5a6c84SAndroid Build Coastguard Worker
1323*cf5a6c84SAndroid Build Coastguard Worker TT.ticks = sysconf(_SC_CLK_TCK); // units for starttime/uptime
1324*cf5a6c84SAndroid Build Coastguard Worker
1325*cf5a6c84SAndroid Build Coastguard Worker if (-1 != (i = tty_fd())) {
1326*cf5a6c84SAndroid Build Coastguard Worker struct stat st;
1327*cf5a6c84SAndroid Build Coastguard Worker
1328*cf5a6c84SAndroid Build Coastguard Worker if (!fstat(i, &st)) TT.tty = st.st_rdev;
1329*cf5a6c84SAndroid Build Coastguard Worker }
1330*cf5a6c84SAndroid Build Coastguard Worker
1331*cf5a6c84SAndroid Build Coastguard Worker if (readfile("/proc/sys/kernel/pid_max", buf, 128))
1332*cf5a6c84SAndroid Build Coastguard Worker while (isdigit(buf[TT.pidlen])) TT.pidlen++;
1333*cf5a6c84SAndroid Build Coastguard Worker else TT.pidlen = 6;
1334*cf5a6c84SAndroid Build Coastguard Worker }
1335*cf5a6c84SAndroid Build Coastguard Worker
ps_main(void)1336*cf5a6c84SAndroid Build Coastguard Worker void ps_main(void)
1337*cf5a6c84SAndroid Build Coastguard Worker {
1338*cf5a6c84SAndroid Build Coastguard Worker char **arg;
1339*cf5a6c84SAndroid Build Coastguard Worker struct dirtree *dt;
1340*cf5a6c84SAndroid Build Coastguard Worker char *not_o;
1341*cf5a6c84SAndroid Build Coastguard Worker int i;
1342*cf5a6c84SAndroid Build Coastguard Worker
1343*cf5a6c84SAndroid Build Coastguard Worker common_setup();
1344*cf5a6c84SAndroid Build Coastguard Worker
1345*cf5a6c84SAndroid Build Coastguard Worker // If we can't query terminal size pad to 80 but do -w
1346*cf5a6c84SAndroid Build Coastguard Worker TT.width = 80;
1347*cf5a6c84SAndroid Build Coastguard Worker if (!isatty(1) || !terminal_size(&TT.width, 0)) toys.optflags |= FLAG_w;
1348*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(w)) TT.width = 99999;
1349*cf5a6c84SAndroid Build Coastguard Worker
1350*cf5a6c84SAndroid Build Coastguard Worker // parse command line options other than -o
1351*cf5a6c84SAndroid Build Coastguard Worker comma_args(TT.ps.P, &TT.PP, "bad -P", parse_rest);
1352*cf5a6c84SAndroid Build Coastguard Worker comma_args(TT.ps.p, &TT.pp, "bad -p", parse_rest);
1353*cf5a6c84SAndroid Build Coastguard Worker comma_args(TT.ps.t, &TT.tt, "bad -t", parse_rest);
1354*cf5a6c84SAndroid Build Coastguard Worker comma_args(TT.ps.s, &TT.ss, "bad -s", parse_rest);
1355*cf5a6c84SAndroid Build Coastguard Worker comma_args(TT.ps.u, &TT.uu, "bad -u", parse_rest);
1356*cf5a6c84SAndroid Build Coastguard Worker comma_args(TT.ps.U, &TT.UU, "bad -U", parse_rest);
1357*cf5a6c84SAndroid Build Coastguard Worker comma_args(TT.ps.g, &TT.gg, "bad -g", parse_rest);
1358*cf5a6c84SAndroid Build Coastguard Worker comma_args(TT.ps.G, &TT.GG, "bad -G", parse_rest);
1359*cf5a6c84SAndroid Build Coastguard Worker comma_args(TT.ps.k, &TT.kfields, "bad -k", parse_ko);
1360*cf5a6c84SAndroid Build Coastguard Worker dlist_terminate(TT.kfields);
1361*cf5a6c84SAndroid Build Coastguard Worker
1362*cf5a6c84SAndroid Build Coastguard Worker // It's undocumented, but traditionally extra arguments are extra -p args
1363*cf5a6c84SAndroid Build Coastguard Worker for (arg = toys.optargs; *arg; arg++)
1364*cf5a6c84SAndroid Build Coastguard Worker if (parse_rest(&TT.pp, *arg, strlen(*arg))) error_exit("bad %s", *arg);
1365*cf5a6c84SAndroid Build Coastguard Worker
1366*cf5a6c84SAndroid Build Coastguard Worker // Figure out which fields to display
1367*cf5a6c84SAndroid Build Coastguard Worker not_o = "%sTTY,TIME,CMD";
1368*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(f))
1369*cf5a6c84SAndroid Build Coastguard Worker sprintf(not_o = toybuf+128,
1370*cf5a6c84SAndroid Build Coastguard Worker "USER:12=UID,%%sPPID,%s,STIME,TTY,TIME,ARGS=CMD", FLAG(T) ? "TCNT" :"C");
1371*cf5a6c84SAndroid Build Coastguard Worker else if (FLAG(l))
1372*cf5a6c84SAndroid Build Coastguard Worker not_o = "F,S,UID,%sPPID,C,PRI,NI,BIT,SZ,WCHAN,TTY,TIME,CMD";
1373*cf5a6c84SAndroid Build Coastguard Worker else if (CFG_TOYBOX_ON_ANDROID)
1374*cf5a6c84SAndroid Build Coastguard Worker sprintf(not_o = toybuf+128,
1375*cf5a6c84SAndroid Build Coastguard Worker "USER,%%sPPID,VSIZE:10,RSS,WCHAN:10,ADDR:10,S,%s",
1376*cf5a6c84SAndroid Build Coastguard Worker FLAG(T) ? "CMD" : "NAME");
1377*cf5a6c84SAndroid Build Coastguard Worker sprintf(toybuf, not_o, FLAG(T) ? "PID,TID," : "PID,");
1378*cf5a6c84SAndroid Build Coastguard Worker
1379*cf5a6c84SAndroid Build Coastguard Worker // Init TT.fields. This only uses toybuf if TT.ps.o is NULL
1380*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(Z)) default_ko("LABEL", &TT.fields, 0, 0);
1381*cf5a6c84SAndroid Build Coastguard Worker default_ko(toybuf, &TT.fields, "bad -o", TT.ps.o);
1382*cf5a6c84SAndroid Build Coastguard Worker
1383*cf5a6c84SAndroid Build Coastguard Worker if (TT.ps.O) {
1384*cf5a6c84SAndroid Build Coastguard Worker if (TT.fields) TT.fields = ((struct ofields *)TT.fields)->prev;
1385*cf5a6c84SAndroid Build Coastguard Worker comma_args(TT.ps.O, &TT.fields, "bad -O", parse_ko);
1386*cf5a6c84SAndroid Build Coastguard Worker if (TT.fields) TT.fields = ((struct ofields *)TT.fields)->next;
1387*cf5a6c84SAndroid Build Coastguard Worker }
1388*cf5a6c84SAndroid Build Coastguard Worker dlist_terminate(TT.fields);
1389*cf5a6c84SAndroid Build Coastguard Worker
1390*cf5a6c84SAndroid Build Coastguard Worker // -f and -n change the meaning of some fields
1391*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(f)||FLAG(n)) {
1392*cf5a6c84SAndroid Build Coastguard Worker struct ofields *field;
1393*cf5a6c84SAndroid Build Coastguard Worker
1394*cf5a6c84SAndroid Build Coastguard Worker for (field = TT.fields; field; field = field->next) {
1395*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(n) && field->which>=PS_UID
1396*cf5a6c84SAndroid Build Coastguard Worker && field->which<=PS_RGROUP && (typos[field->which].slot&XX))
1397*cf5a6c84SAndroid Build Coastguard Worker field->which--;
1398*cf5a6c84SAndroid Build Coastguard Worker }
1399*cf5a6c84SAndroid Build Coastguard Worker }
1400*cf5a6c84SAndroid Build Coastguard Worker
1401*cf5a6c84SAndroid Build Coastguard Worker // Calculate seen fields bit array, and if we aren't deferring printing
1402*cf5a6c84SAndroid Build Coastguard Worker // print headers now (for low memory/nommu systems).
1403*cf5a6c84SAndroid Build Coastguard Worker TT.bits = get_headers(TT.fields, toybuf, sizeof(toybuf));
1404*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(M)) printf("%.*s\n", TT.width, toybuf);
1405*cf5a6c84SAndroid Build Coastguard Worker if (!(FLAG(k)||FLAG(M))) TT.show_process = show_ps;
1406*cf5a6c84SAndroid Build Coastguard Worker TT.match_process = ps_match_process;
1407*cf5a6c84SAndroid Build Coastguard Worker dt = dirtree_flagread("/proc", DIRTREE_SHUTUP|DIRTREE_PROC,
1408*cf5a6c84SAndroid Build Coastguard Worker (FLAG(T) || (TT.bits&(_PS_TID|_PS_TCNT)))
1409*cf5a6c84SAndroid Build Coastguard Worker ? get_threads : get_ps);
1410*cf5a6c84SAndroid Build Coastguard Worker
1411*cf5a6c84SAndroid Build Coastguard Worker if ((dt != DIRTREE_ABORTVAL) && (FLAG(k)||FLAG(M))) {
1412*cf5a6c84SAndroid Build Coastguard Worker struct procpid **tbsort = collate(TT.kcount, dt);
1413*cf5a6c84SAndroid Build Coastguard Worker
1414*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(M)) {
1415*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i<TT.kcount; i++) {
1416*cf5a6c84SAndroid Build Coastguard Worker struct ofields *field;
1417*cf5a6c84SAndroid Build Coastguard Worker
1418*cf5a6c84SAndroid Build Coastguard Worker for (field = TT.fields; field; field = field->next) {
1419*cf5a6c84SAndroid Build Coastguard Worker int len = strlen(string_field(tbsort[i], field));
1420*cf5a6c84SAndroid Build Coastguard Worker
1421*cf5a6c84SAndroid Build Coastguard Worker if (abs(field->len)<len) field->len = (field->len<0) ? -len : len;
1422*cf5a6c84SAndroid Build Coastguard Worker }
1423*cf5a6c84SAndroid Build Coastguard Worker }
1424*cf5a6c84SAndroid Build Coastguard Worker
1425*cf5a6c84SAndroid Build Coastguard Worker // Now that we've recalculated field widths, re-pad headers again
1426*cf5a6c84SAndroid Build Coastguard Worker get_headers(TT.fields, toybuf, sizeof(toybuf));
1427*cf5a6c84SAndroid Build Coastguard Worker printf("%.*s\n", TT.width, toybuf);
1428*cf5a6c84SAndroid Build Coastguard Worker }
1429*cf5a6c84SAndroid Build Coastguard Worker
1430*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(k)) qsort(tbsort, TT.kcount, sizeof(void *), (void *)ksort);
1431*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i<TT.kcount; i++) {
1432*cf5a6c84SAndroid Build Coastguard Worker show_ps(tbsort[i]);
1433*cf5a6c84SAndroid Build Coastguard Worker free(tbsort[i]);
1434*cf5a6c84SAndroid Build Coastguard Worker }
1435*cf5a6c84SAndroid Build Coastguard Worker if (CFG_TOYBOX_FREE) free(tbsort);
1436*cf5a6c84SAndroid Build Coastguard Worker }
1437*cf5a6c84SAndroid Build Coastguard Worker
1438*cf5a6c84SAndroid Build Coastguard Worker if (!TT.kcount) toys.exitval = 1;
1439*cf5a6c84SAndroid Build Coastguard Worker if (CFG_TOYBOX_FREE) {
1440*cf5a6c84SAndroid Build Coastguard Worker free(TT.gg.ptr);
1441*cf5a6c84SAndroid Build Coastguard Worker free(TT.GG.ptr);
1442*cf5a6c84SAndroid Build Coastguard Worker free(TT.pp.ptr);
1443*cf5a6c84SAndroid Build Coastguard Worker free(TT.PP.ptr);
1444*cf5a6c84SAndroid Build Coastguard Worker free(TT.ss.ptr);
1445*cf5a6c84SAndroid Build Coastguard Worker free(TT.tt.ptr);
1446*cf5a6c84SAndroid Build Coastguard Worker free(TT.uu.ptr);
1447*cf5a6c84SAndroid Build Coastguard Worker free(TT.UU.ptr);
1448*cf5a6c84SAndroid Build Coastguard Worker llist_traverse(TT.fields, free);
1449*cf5a6c84SAndroid Build Coastguard Worker }
1450*cf5a6c84SAndroid Build Coastguard Worker }
1451*cf5a6c84SAndroid Build Coastguard Worker
1452*cf5a6c84SAndroid Build Coastguard Worker #define FOR_top
1453*cf5a6c84SAndroid Build Coastguard Worker #include "generated/flags.h"
1454*cf5a6c84SAndroid Build Coastguard Worker
1455*cf5a6c84SAndroid Build Coastguard Worker // select which of the -o fields to sort by
setsort(int pos)1456*cf5a6c84SAndroid Build Coastguard Worker static void setsort(int pos)
1457*cf5a6c84SAndroid Build Coastguard Worker {
1458*cf5a6c84SAndroid Build Coastguard Worker struct ofields *field, *field2;
1459*cf5a6c84SAndroid Build Coastguard Worker int i = 0;
1460*cf5a6c84SAndroid Build Coastguard Worker
1461*cf5a6c84SAndroid Build Coastguard Worker if (pos<0) pos = 0;
1462*cf5a6c84SAndroid Build Coastguard Worker
1463*cf5a6c84SAndroid Build Coastguard Worker for (field = TT.fields; field; field = field->next) {
1464*cf5a6c84SAndroid Build Coastguard Worker if ((TT.sortpos = i++)<pos && field->next) continue;
1465*cf5a6c84SAndroid Build Coastguard Worker field2 = TT.kfields;
1466*cf5a6c84SAndroid Build Coastguard Worker field2->which = field->which;
1467*cf5a6c84SAndroid Build Coastguard Worker field2->len = field->len;
1468*cf5a6c84SAndroid Build Coastguard Worker break;
1469*cf5a6c84SAndroid Build Coastguard Worker }
1470*cf5a6c84SAndroid Build Coastguard Worker }
1471*cf5a6c84SAndroid Build Coastguard Worker
1472*cf5a6c84SAndroid Build Coastguard Worker // If we have both, adjust slot[deltas[]] to be relative to previous
1473*cf5a6c84SAndroid Build Coastguard Worker // measurement rather than process start. Stomping old.data is fine
1474*cf5a6c84SAndroid Build Coastguard Worker // because we free it after displaying.
merge_deltas(long long * oslot,long long * nslot,int milis)1475*cf5a6c84SAndroid Build Coastguard Worker static int merge_deltas(long long *oslot, long long *nslot, int milis)
1476*cf5a6c84SAndroid Build Coastguard Worker {
1477*cf5a6c84SAndroid Build Coastguard Worker char deltas[] = {SLOT_utime2, SLOT_iobytes, SLOT_diobytes, SLOT_rchar,
1478*cf5a6c84SAndroid Build Coastguard Worker SLOT_wchar, SLOT_rbytes, SLOT_wbytes, SLOT_swap};
1479*cf5a6c84SAndroid Build Coastguard Worker int i;
1480*cf5a6c84SAndroid Build Coastguard Worker
1481*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i<ARRAY_LEN(deltas); i++)
1482*cf5a6c84SAndroid Build Coastguard Worker oslot[deltas[i]] = nslot[deltas[i]] - oslot[deltas[i]];
1483*cf5a6c84SAndroid Build Coastguard Worker oslot[SLOT_upticks] = (milis*TT.ticks)/1000;
1484*cf5a6c84SAndroid Build Coastguard Worker
1485*cf5a6c84SAndroid Build Coastguard Worker return 1;
1486*cf5a6c84SAndroid Build Coastguard Worker }
1487*cf5a6c84SAndroid Build Coastguard Worker
header_line(int line,int rev)1488*cf5a6c84SAndroid Build Coastguard Worker static int header_line(int line, int rev)
1489*cf5a6c84SAndroid Build Coastguard Worker {
1490*cf5a6c84SAndroid Build Coastguard Worker if (!line) return 0;
1491*cf5a6c84SAndroid Build Coastguard Worker
1492*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(b)) puts(toybuf);
1493*cf5a6c84SAndroid Build Coastguard Worker else {
1494*cf5a6c84SAndroid Build Coastguard Worker printf("%s%-*.*s%s\r\n", rev?"\e[7m":"", rev?TT.width:0, TT.width, toybuf,
1495*cf5a6c84SAndroid Build Coastguard Worker rev?"\e[0m":"");
1496*cf5a6c84SAndroid Build Coastguard Worker }
1497*cf5a6c84SAndroid Build Coastguard Worker
1498*cf5a6c84SAndroid Build Coastguard Worker return line-1;
1499*cf5a6c84SAndroid Build Coastguard Worker }
1500*cf5a6c84SAndroid Build Coastguard Worker
top_cursor_cleanup(void)1501*cf5a6c84SAndroid Build Coastguard Worker static void top_cursor_cleanup(void)
1502*cf5a6c84SAndroid Build Coastguard Worker {
1503*cf5a6c84SAndroid Build Coastguard Worker xputsn("\e[?25h");
1504*cf5a6c84SAndroid Build Coastguard Worker }
1505*cf5a6c84SAndroid Build Coastguard Worker
1506*cf5a6c84SAndroid Build Coastguard Worker // Show a three color bar graph. spans: 0 total size, 1used, 2 nice, 3 sys
bargraph(char * label,unsigned width,unsigned long span[4])1507*cf5a6c84SAndroid Build Coastguard Worker static void bargraph(char *label, unsigned width, unsigned long span[4])
1508*cf5a6c84SAndroid Build Coastguard Worker {
1509*cf5a6c84SAndroid Build Coastguard Worker char percent[16];
1510*cf5a6c84SAndroid Build Coastguard Worker long long ll;
1511*cf5a6c84SAndroid Build Coastguard Worker unsigned i, color, len;
1512*cf5a6c84SAndroid Build Coastguard Worker
1513*cf5a6c84SAndroid Build Coastguard Worker if (!*span) ++*span;
1514*cf5a6c84SAndroid Build Coastguard Worker i = ((span[1]+(unsigned long long)span[2]+span[3])*1000)/ *span;
1515*cf5a6c84SAndroid Build Coastguard Worker len = sprintf(percent, "%u.%u", i/10, i%10);
1516*cf5a6c84SAndroid Build Coastguard Worker
1517*cf5a6c84SAndroid Build Coastguard Worker printf("%s[", label);
1518*cf5a6c84SAndroid Build Coastguard Worker for (ll = i = color = 0; i<width; i++) {
1519*cf5a6c84SAndroid Build Coastguard Worker while (ll<1 && color<4) {
1520*cf5a6c84SAndroid Build Coastguard Worker if (color++!=3) {
1521*cf5a6c84SAndroid Build Coastguard Worker ll += span[color]*width;
1522*cf5a6c84SAndroid Build Coastguard Worker if (ll<*span/2) continue;
1523*cf5a6c84SAndroid Build Coastguard Worker }
1524*cf5a6c84SAndroid Build Coastguard Worker // green, red, blue, grey
1525*cf5a6c84SAndroid Build Coastguard Worker if (color==4) printf("\e[1;2;37m");
1526*cf5a6c84SAndroid Build Coastguard Worker else printf("\e[%um", (char[]){32,34,31}[color-1]);
1527*cf5a6c84SAndroid Build Coastguard Worker break;
1528*cf5a6c84SAndroid Build Coastguard Worker }
1529*cf5a6c84SAndroid Build Coastguard Worker if (color<4) ll -= *span;
1530*cf5a6c84SAndroid Build Coastguard Worker printf("%c", width-i>len ? (color==4 ? ' ' : '|') : percent[len-(width-i)]);
1531*cf5a6c84SAndroid Build Coastguard Worker }
1532*cf5a6c84SAndroid Build Coastguard Worker printf("\e[0m]");
1533*cf5a6c84SAndroid Build Coastguard Worker }
1534*cf5a6c84SAndroid Build Coastguard Worker
top_common(int (* filter)(long long * oslot,long long * nslot,int milis))1535*cf5a6c84SAndroid Build Coastguard Worker static void top_common(
1536*cf5a6c84SAndroid Build Coastguard Worker int (*filter)(long long *oslot, long long *nslot, int milis))
1537*cf5a6c84SAndroid Build Coastguard Worker {
1538*cf5a6c84SAndroid Build Coastguard Worker long long timeout = 0, now, stats[16];
1539*cf5a6c84SAndroid Build Coastguard Worker struct proclist {
1540*cf5a6c84SAndroid Build Coastguard Worker struct procpid **tb;
1541*cf5a6c84SAndroid Build Coastguard Worker int count;
1542*cf5a6c84SAndroid Build Coastguard Worker long long whence;
1543*cf5a6c84SAndroid Build Coastguard Worker } plist[2], *plold, *plnew, old, new, mix;
1544*cf5a6c84SAndroid Build Coastguard Worker char scratch[16], *pos, *cpufields[] = {"user", "nice", "sys", "idle",
1545*cf5a6c84SAndroid Build Coastguard Worker "iow", "irq", "sirq", "host"};
1546*cf5a6c84SAndroid Build Coastguard Worker unsigned tock = 0;
1547*cf5a6c84SAndroid Build Coastguard Worker int i, lines, topoff = 0, done = 0;
1548*cf5a6c84SAndroid Build Coastguard Worker
1549*cf5a6c84SAndroid Build Coastguard Worker if (!TT.fields) perror_exit("no -o");
1550*cf5a6c84SAndroid Build Coastguard Worker
1551*cf5a6c84SAndroid Build Coastguard Worker // Avoid flicker and hide the cursor in interactive mode.
1552*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(b)) {
1553*cf5a6c84SAndroid Build Coastguard Worker sigatexit(top_cursor_cleanup);
1554*cf5a6c84SAndroid Build Coastguard Worker xputsn("\e[?25l");
1555*cf5a6c84SAndroid Build Coastguard Worker }
1556*cf5a6c84SAndroid Build Coastguard Worker
1557*cf5a6c84SAndroid Build Coastguard Worker toys.signal = SIGWINCH;
1558*cf5a6c84SAndroid Build Coastguard Worker TT.bits = get_headers(TT.fields, toybuf, sizeof(toybuf));
1559*cf5a6c84SAndroid Build Coastguard Worker *scratch = 0;
1560*cf5a6c84SAndroid Build Coastguard Worker memset(plist, 0, sizeof(plist));
1561*cf5a6c84SAndroid Build Coastguard Worker memset(stats, 0, sizeof(stats));
1562*cf5a6c84SAndroid Build Coastguard Worker do {
1563*cf5a6c84SAndroid Build Coastguard Worker struct dirtree *dt;
1564*cf5a6c84SAndroid Build Coastguard Worker int recalc = 1;
1565*cf5a6c84SAndroid Build Coastguard Worker
1566*cf5a6c84SAndroid Build Coastguard Worker plold = plist+(tock++&1);
1567*cf5a6c84SAndroid Build Coastguard Worker plnew = plist+(tock&1);
1568*cf5a6c84SAndroid Build Coastguard Worker plnew->whence = millitime();
1569*cf5a6c84SAndroid Build Coastguard Worker dt = dirtree_flagread("/proc", DIRTREE_SHUTUP|DIRTREE_PROC,
1570*cf5a6c84SAndroid Build Coastguard Worker (FLAG(H) || (TT.bits&(_PS_TID|_PS_TCNT))) ? get_threads : get_ps);
1571*cf5a6c84SAndroid Build Coastguard Worker if (dt == DIRTREE_ABORTVAL) error_exit("no /proc");
1572*cf5a6c84SAndroid Build Coastguard Worker plnew->tb = collate(plnew->count = TT.kcount, dt);
1573*cf5a6c84SAndroid Build Coastguard Worker TT.kcount = 0;
1574*cf5a6c84SAndroid Build Coastguard Worker
1575*cf5a6c84SAndroid Build Coastguard Worker if (readfile("/proc/stat", pos = toybuf, sizeof(toybuf))) {
1576*cf5a6c84SAndroid Build Coastguard Worker long long *st = stats+8*(tock&1);
1577*cf5a6c84SAndroid Build Coastguard Worker
1578*cf5a6c84SAndroid Build Coastguard Worker // user nice system idle iowait irq softirq host
1579*cf5a6c84SAndroid Build Coastguard Worker sscanf(pos, "cpu %lld %lld %lld %lld %lld %lld %lld %lld",
1580*cf5a6c84SAndroid Build Coastguard Worker st, st+1, st+2, st+3, st+4, st+5, st+6, st+7);
1581*cf5a6c84SAndroid Build Coastguard Worker }
1582*cf5a6c84SAndroid Build Coastguard Worker
1583*cf5a6c84SAndroid Build Coastguard Worker // First time, wait a quarter of a second to collect a little delta data.
1584*cf5a6c84SAndroid Build Coastguard Worker if (!plold->tb) {
1585*cf5a6c84SAndroid Build Coastguard Worker msleep(250);
1586*cf5a6c84SAndroid Build Coastguard Worker continue;
1587*cf5a6c84SAndroid Build Coastguard Worker }
1588*cf5a6c84SAndroid Build Coastguard Worker
1589*cf5a6c84SAndroid Build Coastguard Worker // Collate old and new into "mix", depends on /proc read in pid sort order
1590*cf5a6c84SAndroid Build Coastguard Worker old = *plold;
1591*cf5a6c84SAndroid Build Coastguard Worker new = *plnew;
1592*cf5a6c84SAndroid Build Coastguard Worker mix.tb = xmalloc((old.count+new.count)*sizeof(struct procpid));
1593*cf5a6c84SAndroid Build Coastguard Worker mix.count = 0;
1594*cf5a6c84SAndroid Build Coastguard Worker
1595*cf5a6c84SAndroid Build Coastguard Worker while (old.count || new.count) {
1596*cf5a6c84SAndroid Build Coastguard Worker struct procpid *otb = old.count ? *old.tb : 0,
1597*cf5a6c84SAndroid Build Coastguard Worker *ntb = new.count ? *new.tb : 0;
1598*cf5a6c84SAndroid Build Coastguard Worker
1599*cf5a6c84SAndroid Build Coastguard Worker // If we just have old for this process, it exited. Discard it.
1600*cf5a6c84SAndroid Build Coastguard Worker if (old.count && (!new.count || *otb->slot < *ntb->slot)) {
1601*cf5a6c84SAndroid Build Coastguard Worker old.tb++;
1602*cf5a6c84SAndroid Build Coastguard Worker old.count--;
1603*cf5a6c84SAndroid Build Coastguard Worker
1604*cf5a6c84SAndroid Build Coastguard Worker continue;
1605*cf5a6c84SAndroid Build Coastguard Worker }
1606*cf5a6c84SAndroid Build Coastguard Worker
1607*cf5a6c84SAndroid Build Coastguard Worker // If we just have new, use it verbatim
1608*cf5a6c84SAndroid Build Coastguard Worker if (!old.count || *otb->slot > *ntb->slot) mix.tb[mix.count] = ntb;
1609*cf5a6c84SAndroid Build Coastguard Worker else {
1610*cf5a6c84SAndroid Build Coastguard Worker // Keep or discard
1611*cf5a6c84SAndroid Build Coastguard Worker if (filter(otb->slot, ntb->slot, new.whence-old.whence)) {
1612*cf5a6c84SAndroid Build Coastguard Worker mix.tb[mix.count] = otb;
1613*cf5a6c84SAndroid Build Coastguard Worker mix.count++;
1614*cf5a6c84SAndroid Build Coastguard Worker }
1615*cf5a6c84SAndroid Build Coastguard Worker old.tb++;
1616*cf5a6c84SAndroid Build Coastguard Worker old.count--;
1617*cf5a6c84SAndroid Build Coastguard Worker }
1618*cf5a6c84SAndroid Build Coastguard Worker new.tb++;
1619*cf5a6c84SAndroid Build Coastguard Worker new.count--;
1620*cf5a6c84SAndroid Build Coastguard Worker }
1621*cf5a6c84SAndroid Build Coastguard Worker
1622*cf5a6c84SAndroid Build Coastguard Worker // Don't re-fetch data if it's not time yet, just re-display existing data.
1623*cf5a6c84SAndroid Build Coastguard Worker for (;;) {
1624*cf5a6c84SAndroid Build Coastguard Worker char was, is;
1625*cf5a6c84SAndroid Build Coastguard Worker
1626*cf5a6c84SAndroid Build Coastguard Worker if (recalc) {
1627*cf5a6c84SAndroid Build Coastguard Worker qsort(mix.tb, mix.count, sizeof(struct procpid *), (void *)ksort);
1628*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(b)) {
1629*cf5a6c84SAndroid Build Coastguard Worker printf("\e[H\e[J");
1630*cf5a6c84SAndroid Build Coastguard Worker if (toys.signal) {
1631*cf5a6c84SAndroid Build Coastguard Worker toys.signal = 0;
1632*cf5a6c84SAndroid Build Coastguard Worker terminal_probesize(&TT.width, &TT.height);
1633*cf5a6c84SAndroid Build Coastguard Worker }
1634*cf5a6c84SAndroid Build Coastguard Worker }
1635*cf5a6c84SAndroid Build Coastguard Worker if (TT.top.m) TT.height = TT.top.m+5;
1636*cf5a6c84SAndroid Build Coastguard Worker lines = TT.height;
1637*cf5a6c84SAndroid Build Coastguard Worker }
1638*cf5a6c84SAndroid Build Coastguard Worker if (recalc && !FLAG(q)) {
1639*cf5a6c84SAndroid Build Coastguard Worker // Display "top" header.
1640*cf5a6c84SAndroid Build Coastguard Worker if (*toys.which->name == 't') {
1641*cf5a6c84SAndroid Build Coastguard Worker struct ofields field;
1642*cf5a6c84SAndroid Build Coastguard Worker char hr[4][32];
1643*cf5a6c84SAndroid Build Coastguard Worker long long ll, up = 0;
1644*cf5a6c84SAndroid Build Coastguard Worker long run[6];
1645*cf5a6c84SAndroid Build Coastguard Worker int j, k, cpus = sysconf(_SC_NPROCESSORS_CONF);
1646*cf5a6c84SAndroid Build Coastguard Worker
1647*cf5a6c84SAndroid Build Coastguard Worker
1648*cf5a6c84SAndroid Build Coastguard Worker // Count running, sleeping, stopped, zombie processes.
1649*cf5a6c84SAndroid Build Coastguard Worker // The kernel has more states (and different sets in different
1650*cf5a6c84SAndroid Build Coastguard Worker // versions), so we need to map them. (R)unning and (Z)ombie are
1651*cf5a6c84SAndroid Build Coastguard Worker // easy enough, and since "stopped" is rare (just T and t as of
1652*cf5a6c84SAndroid Build Coastguard Worker // Linux 4.20), we assume everything else is "sleeping".
1653*cf5a6c84SAndroid Build Coastguard Worker field.which = PS_S;
1654*cf5a6c84SAndroid Build Coastguard Worker memset(run, 0, sizeof(run));
1655*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i<mix.count; i++)
1656*cf5a6c84SAndroid Build Coastguard Worker run[1+stridx("RTtZ", *string_field(mix.tb[i], &field))]++;
1657*cf5a6c84SAndroid Build Coastguard Worker sprintf(toybuf,
1658*cf5a6c84SAndroid Build Coastguard Worker "%ss: %d total, %3ld running, %3ld sleeping, %3ld stopped, "
1659*cf5a6c84SAndroid Build Coastguard Worker "%3ld zombie", FLAG(H) ? "Thread" : "Task", mix.count, run[1],
1660*cf5a6c84SAndroid Build Coastguard Worker run[0], run[2]+run[3], run[4]);
1661*cf5a6c84SAndroid Build Coastguard Worker lines = header_line(lines, 0);
1662*cf5a6c84SAndroid Build Coastguard Worker
1663*cf5a6c84SAndroid Build Coastguard Worker if (readfile("/proc/meminfo", toybuf+256, sizeof(toybuf)-256)) {
1664*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i<6; i++) {
1665*cf5a6c84SAndroid Build Coastguard Worker j = i%3;
1666*cf5a6c84SAndroid Build Coastguard Worker pos = strafter(toybuf+256, (char *[]){"MemTotal:","\nMemFree:",
1667*cf5a6c84SAndroid Build Coastguard Worker "\nBuffers:","\nSwapTotal:","\nSwapFree:","\nCached:"}[i]);
1668*cf5a6c84SAndroid Build Coastguard Worker run[i] = pos ? atol(pos) : 0;
1669*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(h)) continue;
1670*cf5a6c84SAndroid Build Coastguard Worker k = (*run>=10000000);
1671*cf5a6c84SAndroid Build Coastguard Worker human_readable_long(hr[j+!!j], run[i]>>(10*k), 9, k+1, HR_NODOT);
1672*cf5a6c84SAndroid Build Coastguard Worker if (j==1) human_readable_long(hr[1], (run[i-1]-run[i])>>(10*k),
1673*cf5a6c84SAndroid Build Coastguard Worker 8, k+1, HR_NODOT);
1674*cf5a6c84SAndroid Build Coastguard Worker else if (j==2) {
1675*cf5a6c84SAndroid Build Coastguard Worker sprintf(toybuf, " %s:%10s total,%10s used,%10s free,%10s %s",
1676*cf5a6c84SAndroid Build Coastguard Worker (i<3) ? " Mem" : "Swap", hr[0], hr[1], hr[2], hr[3],
1677*cf5a6c84SAndroid Build Coastguard Worker (i<3) ? "buffers" : "cached");
1678*cf5a6c84SAndroid Build Coastguard Worker lines = header_line(lines, 0);
1679*cf5a6c84SAndroid Build Coastguard Worker }
1680*cf5a6c84SAndroid Build Coastguard Worker }
1681*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(h)) {
1682*cf5a6c84SAndroid Build Coastguard Worker unsigned long swp[] = {run[3], 0, 0, run[3]-run[4]},
1683*cf5a6c84SAndroid Build Coastguard Worker mem[] = {run[0], run[0]-run[1]-run[2]-run[5], run[2], run[5]};
1684*cf5a6c84SAndroid Build Coastguard Worker
1685*cf5a6c84SAndroid Build Coastguard Worker bargraph("Mem", 34, mem);
1686*cf5a6c84SAndroid Build Coastguard Worker bargraph(" Swp", 34, swp);
1687*cf5a6c84SAndroid Build Coastguard Worker xprintf("\r\n");
1688*cf5a6c84SAndroid Build Coastguard Worker }
1689*cf5a6c84SAndroid Build Coastguard Worker }
1690*cf5a6c84SAndroid Build Coastguard Worker pos = toybuf;
1691*cf5a6c84SAndroid Build Coastguard Worker pos += sprintf(pos, "%d%%cpu", cpus*100);
1692*cf5a6c84SAndroid Build Coastguard Worker j = 4+(cpus>10);
1693*cf5a6c84SAndroid Build Coastguard Worker
1694*cf5a6c84SAndroid Build Coastguard Worker // If a processor goes idle it's powered down and its idle ticks don't
1695*cf5a6c84SAndroid Build Coastguard Worker // advance, so calculate idle time as potential time - used.
1696*cf5a6c84SAndroid Build Coastguard Worker if (mix.count) up = mix.tb[0]->slot[SLOT_upticks];
1697*cf5a6c84SAndroid Build Coastguard Worker if (!up) up = 1;
1698*cf5a6c84SAndroid Build Coastguard Worker now = up*cpus;
1699*cf5a6c84SAndroid Build Coastguard Worker ll = stats[3] = stats[11] = 0;
1700*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i<8; i++) ll += stats[i]-stats[i+8];
1701*cf5a6c84SAndroid Build Coastguard Worker stats[3] = now - llabs(ll);
1702*cf5a6c84SAndroid Build Coastguard Worker
1703*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i<8; i++) {
1704*cf5a6c84SAndroid Build Coastguard Worker ll = (llabs(stats[i]-stats[i+8])*1000)/up;
1705*cf5a6c84SAndroid Build Coastguard Worker pos += sprintf(pos, "% *lld%%%s", j, (ll+5)/10, cpufields[i]);
1706*cf5a6c84SAndroid Build Coastguard Worker }
1707*cf5a6c84SAndroid Build Coastguard Worker // Display "iotop" header.
1708*cf5a6c84SAndroid Build Coastguard Worker } else {
1709*cf5a6c84SAndroid Build Coastguard Worker struct ofields *field;
1710*cf5a6c84SAndroid Build Coastguard Worker struct procpid tb;
1711*cf5a6c84SAndroid Build Coastguard Worker
1712*cf5a6c84SAndroid Build Coastguard Worker memset(&tb, 0, sizeof(struct procpid));
1713*cf5a6c84SAndroid Build Coastguard Worker pos = stpcpy(toybuf, "Totals:");
1714*cf5a6c84SAndroid Build Coastguard Worker for (field = TT.fields; field; field = field->next) {
1715*cf5a6c84SAndroid Build Coastguard Worker long long ll, bits = 0;
1716*cf5a6c84SAndroid Build Coastguard Worker int slot = typos[field->which].slot&(XX-1);
1717*cf5a6c84SAndroid Build Coastguard Worker
1718*cf5a6c84SAndroid Build Coastguard Worker if (field->which<PS_C || field->which>PS_DIO) continue;
1719*cf5a6c84SAndroid Build Coastguard Worker ll = 1LL<<field->which;
1720*cf5a6c84SAndroid Build Coastguard Worker if (bits&ll) continue;
1721*cf5a6c84SAndroid Build Coastguard Worker bits |= ll;
1722*cf5a6c84SAndroid Build Coastguard Worker for (i=0; i<mix.count; i++)
1723*cf5a6c84SAndroid Build Coastguard Worker tb.slot[slot] += mix.tb[i]->slot[slot];
1724*cf5a6c84SAndroid Build Coastguard Worker pos += snprintf(pos, sizeof(toybuf)/2-(pos-toybuf),
1725*cf5a6c84SAndroid Build Coastguard Worker " %s: %*s,", typos[field->which].name,
1726*cf5a6c84SAndroid Build Coastguard Worker field->len, string_field(&tb, field));
1727*cf5a6c84SAndroid Build Coastguard Worker }
1728*cf5a6c84SAndroid Build Coastguard Worker *--pos = 0;
1729*cf5a6c84SAndroid Build Coastguard Worker }
1730*cf5a6c84SAndroid Build Coastguard Worker
1731*cf5a6c84SAndroid Build Coastguard Worker lines = header_line(lines, 0);
1732*cf5a6c84SAndroid Build Coastguard Worker // print line of header labels for currently displayed fields
1733*cf5a6c84SAndroid Build Coastguard Worker get_headers(TT.fields, pos = toybuf, sizeof(toybuf));
1734*cf5a6c84SAndroid Build Coastguard Worker for (i = 0, is = ' '; *pos; pos++) {
1735*cf5a6c84SAndroid Build Coastguard Worker was = is;
1736*cf5a6c84SAndroid Build Coastguard Worker is = *pos;
1737*cf5a6c84SAndroid Build Coastguard Worker if (isspace(was) && !isspace(is) && i++==TT.sortpos && pos!=toybuf)
1738*cf5a6c84SAndroid Build Coastguard Worker pos[-1] = '[';
1739*cf5a6c84SAndroid Build Coastguard Worker if (!isspace(was) && isspace(is) && i==TT.sortpos+1) *pos = ']';
1740*cf5a6c84SAndroid Build Coastguard Worker }
1741*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(b)) while (isspace(*(pos-1))) --pos;
1742*cf5a6c84SAndroid Build Coastguard Worker *pos = 0;
1743*cf5a6c84SAndroid Build Coastguard Worker lines = header_line(lines, 1);
1744*cf5a6c84SAndroid Build Coastguard Worker }
1745*cf5a6c84SAndroid Build Coastguard Worker if (!recalc && !FLAG(b)) printf("\e[%dH\e[J", 1+TT.height-lines);
1746*cf5a6c84SAndroid Build Coastguard Worker
1747*cf5a6c84SAndroid Build Coastguard Worker for (i = 0; i<lines && i+topoff<mix.count; i++) {
1748*cf5a6c84SAndroid Build Coastguard Worker // Running processes are shown in bold.
1749*cf5a6c84SAndroid Build Coastguard Worker int bold = !FLAG(b) && mix.tb[i+topoff]->state == 'R';
1750*cf5a6c84SAndroid Build Coastguard Worker
1751*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(b) && i) putchar('\n');
1752*cf5a6c84SAndroid Build Coastguard Worker if (bold) printf("\e[1m");
1753*cf5a6c84SAndroid Build Coastguard Worker show_ps(mix.tb[i+topoff]);
1754*cf5a6c84SAndroid Build Coastguard Worker if (bold) printf("\e[m");
1755*cf5a6c84SAndroid Build Coastguard Worker }
1756*cf5a6c84SAndroid Build Coastguard Worker
1757*cf5a6c84SAndroid Build Coastguard Worker if (TT.top.n && !--TT.top.n) {
1758*cf5a6c84SAndroid Build Coastguard Worker done++;
1759*cf5a6c84SAndroid Build Coastguard Worker break;
1760*cf5a6c84SAndroid Build Coastguard Worker }
1761*cf5a6c84SAndroid Build Coastguard Worker
1762*cf5a6c84SAndroid Build Coastguard Worker now = millitime();
1763*cf5a6c84SAndroid Build Coastguard Worker if (timeout<=now) timeout = new.whence+TT.top.d;
1764*cf5a6c84SAndroid Build Coastguard Worker if (timeout<=now || timeout>now+TT.top.d) timeout = now+TT.top.d;
1765*cf5a6c84SAndroid Build Coastguard Worker
1766*cf5a6c84SAndroid Build Coastguard Worker fflush(stdout);
1767*cf5a6c84SAndroid Build Coastguard Worker
1768*cf5a6c84SAndroid Build Coastguard Worker // In batch mode, we ignore the keyboard.
1769*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(b)) {
1770*cf5a6c84SAndroid Build Coastguard Worker msleep(timeout-now);
1771*cf5a6c84SAndroid Build Coastguard Worker // Make an obvious gap between datasets.
1772*cf5a6c84SAndroid Build Coastguard Worker xputs("\n\n");
1773*cf5a6c84SAndroid Build Coastguard Worker break;
1774*cf5a6c84SAndroid Build Coastguard Worker }
1775*cf5a6c84SAndroid Build Coastguard Worker
1776*cf5a6c84SAndroid Build Coastguard Worker recalc = 1;
1777*cf5a6c84SAndroid Build Coastguard Worker i = scan_key_getsize(scratch, timeout-now, &TT.width, &TT.height);
1778*cf5a6c84SAndroid Build Coastguard Worker if (i==-1 || i==3 || toupper(i)=='Q') {
1779*cf5a6c84SAndroid Build Coastguard Worker done++;
1780*cf5a6c84SAndroid Build Coastguard Worker break;
1781*cf5a6c84SAndroid Build Coastguard Worker }
1782*cf5a6c84SAndroid Build Coastguard Worker if (i==-2) break;
1783*cf5a6c84SAndroid Build Coastguard Worker if (i==-3) continue;
1784*cf5a6c84SAndroid Build Coastguard Worker
1785*cf5a6c84SAndroid Build Coastguard Worker // Flush unknown escape sequences.
1786*cf5a6c84SAndroid Build Coastguard Worker if (i==27) while (0<scan_key_getsize(scratch, 0, &TT.width, &TT.height));
1787*cf5a6c84SAndroid Build Coastguard Worker else if (i=='\r' || i==' ') {
1788*cf5a6c84SAndroid Build Coastguard Worker timeout = 0;
1789*cf5a6c84SAndroid Build Coastguard Worker break;
1790*cf5a6c84SAndroid Build Coastguard Worker } else if (toupper(i)=='R')
1791*cf5a6c84SAndroid Build Coastguard Worker ((struct ofields *)TT.kfields)->reverse *= -1;
1792*cf5a6c84SAndroid Build Coastguard Worker else {
1793*cf5a6c84SAndroid Build Coastguard Worker i -= 256;
1794*cf5a6c84SAndroid Build Coastguard Worker if (i == (KEY_SHIFT|KEY_LEFT)) setsort(TT.sortpos-1);
1795*cf5a6c84SAndroid Build Coastguard Worker else if (i == (KEY_SHIFT|KEY_RIGHT)) setsort(TT.sortpos+1);
1796*cf5a6c84SAndroid Build Coastguard Worker else if (i == KEY_RIGHT) TT.scroll++;
1797*cf5a6c84SAndroid Build Coastguard Worker else if (i == KEY_LEFT && TT.scroll) TT.scroll--;
1798*cf5a6c84SAndroid Build Coastguard Worker else if (recalc-- && i == KEY_UP) topoff--;
1799*cf5a6c84SAndroid Build Coastguard Worker else if (i == KEY_DOWN) topoff++;
1800*cf5a6c84SAndroid Build Coastguard Worker else if (i == KEY_PGDN) topoff += lines;
1801*cf5a6c84SAndroid Build Coastguard Worker else if (i == KEY_PGUP) topoff -= lines;
1802*cf5a6c84SAndroid Build Coastguard Worker else continue;
1803*cf5a6c84SAndroid Build Coastguard Worker if (topoff<0) topoff = 0;
1804*cf5a6c84SAndroid Build Coastguard Worker if (topoff>mix.count) topoff = mix.count;
1805*cf5a6c84SAndroid Build Coastguard Worker }
1806*cf5a6c84SAndroid Build Coastguard Worker }
1807*cf5a6c84SAndroid Build Coastguard Worker
1808*cf5a6c84SAndroid Build Coastguard Worker free(mix.tb);
1809*cf5a6c84SAndroid Build Coastguard Worker for (i=0; i<plold->count; i++) free(plold->tb[i]);
1810*cf5a6c84SAndroid Build Coastguard Worker free(plold->tb);
1811*cf5a6c84SAndroid Build Coastguard Worker } while (!done);
1812*cf5a6c84SAndroid Build Coastguard Worker
1813*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(b)) tty_reset();
1814*cf5a6c84SAndroid Build Coastguard Worker }
1815*cf5a6c84SAndroid Build Coastguard Worker
top_setup(char * defo,char * defk)1816*cf5a6c84SAndroid Build Coastguard Worker static void top_setup(char *defo, char *defk)
1817*cf5a6c84SAndroid Build Coastguard Worker {
1818*cf5a6c84SAndroid Build Coastguard Worker common_setup();
1819*cf5a6c84SAndroid Build Coastguard Worker
1820*cf5a6c84SAndroid Build Coastguard Worker // Are we doing "batch" output or interactive?
1821*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(b)) TT.width = TT.height = 99999;
1822*cf5a6c84SAndroid Build Coastguard Worker else {
1823*cf5a6c84SAndroid Build Coastguard Worker // Grab starting time, make terminal raw, switch off cursor,
1824*cf5a6c84SAndroid Build Coastguard Worker // set signal handler to put terminal/cursor back to normal at exit.
1825*cf5a6c84SAndroid Build Coastguard Worker TT.time = millitime();
1826*cf5a6c84SAndroid Build Coastguard Worker start_redraw(&TT.width, &TT.height);
1827*cf5a6c84SAndroid Build Coastguard Worker }
1828*cf5a6c84SAndroid Build Coastguard Worker
1829*cf5a6c84SAndroid Build Coastguard Worker comma_args(TT.top.u, &TT.uu, "bad -u", parse_rest);
1830*cf5a6c84SAndroid Build Coastguard Worker comma_args(TT.top.p, &TT.pp, "bad -p", parse_rest);
1831*cf5a6c84SAndroid Build Coastguard Worker TT.match_process = shared_match_process;
1832*cf5a6c84SAndroid Build Coastguard Worker
1833*cf5a6c84SAndroid Build Coastguard Worker default_ko(defo, &TT.fields, "bad -o", TT.top.o);
1834*cf5a6c84SAndroid Build Coastguard Worker dlist_terminate(TT.fields);
1835*cf5a6c84SAndroid Build Coastguard Worker
1836*cf5a6c84SAndroid Build Coastguard Worker // First (dummy) sort field is overwritten by setsort()
1837*cf5a6c84SAndroid Build Coastguard Worker default_ko("-S", &TT.kfields, 0, 0);
1838*cf5a6c84SAndroid Build Coastguard Worker default_ko(defk, &TT.kfields, "bad -k", TT.top.k);
1839*cf5a6c84SAndroid Build Coastguard Worker dlist_terminate(TT.kfields);
1840*cf5a6c84SAndroid Build Coastguard Worker setsort(TT.top.s-1);
1841*cf5a6c84SAndroid Build Coastguard Worker }
1842*cf5a6c84SAndroid Build Coastguard Worker
top_main(void)1843*cf5a6c84SAndroid Build Coastguard Worker void top_main(void)
1844*cf5a6c84SAndroid Build Coastguard Worker {
1845*cf5a6c84SAndroid Build Coastguard Worker sprintf(toybuf, "%cID,USER,%s%%CPU,%%MEM,TIME+,%s", FLAG(H) ? 'T' : 'P',
1846*cf5a6c84SAndroid Build Coastguard Worker TT.top.O ? "" : "PR,NI,VIRT,RES,SHR,S,",
1847*cf5a6c84SAndroid Build Coastguard Worker FLAG(H) ? "CMD:15=THREAD,NAME=PROCESS" : "ARGS");
1848*cf5a6c84SAndroid Build Coastguard Worker if (!TT.top.s) TT.top.s = TT.top.O ? 3 : 9;
1849*cf5a6c84SAndroid Build Coastguard Worker top_setup(toybuf, "-%CPU,-ETIME,-PID");
1850*cf5a6c84SAndroid Build Coastguard Worker if (TT.top.O) {
1851*cf5a6c84SAndroid Build Coastguard Worker struct ofields *field = TT.fields;
1852*cf5a6c84SAndroid Build Coastguard Worker
1853*cf5a6c84SAndroid Build Coastguard Worker field = field->next->next;
1854*cf5a6c84SAndroid Build Coastguard Worker comma_args(TT.top.O, &field, "bad -O", parse_ko);
1855*cf5a6c84SAndroid Build Coastguard Worker }
1856*cf5a6c84SAndroid Build Coastguard Worker
1857*cf5a6c84SAndroid Build Coastguard Worker top_common(merge_deltas);
1858*cf5a6c84SAndroid Build Coastguard Worker }
1859*cf5a6c84SAndroid Build Coastguard Worker
1860*cf5a6c84SAndroid Build Coastguard Worker #define FOR_iotop
1861*cf5a6c84SAndroid Build Coastguard Worker #include "generated/flags.h"
1862*cf5a6c84SAndroid Build Coastguard Worker
1863*cf5a6c84SAndroid Build Coastguard Worker // Compare old and new proces lists to measure changes
iotop_filter(long long * oslot,long long * nslot,int milis)1864*cf5a6c84SAndroid Build Coastguard Worker static int iotop_filter(long long *oslot, long long *nslot, int milis)
1865*cf5a6c84SAndroid Build Coastguard Worker {
1866*cf5a6c84SAndroid Build Coastguard Worker // Current I/O, or accumulated since process start?
1867*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(a)) merge_deltas(oslot, nslot, milis);
1868*cf5a6c84SAndroid Build Coastguard Worker else oslot[SLOT_upticks] = ((millitime()-TT.time)*TT.ticks)/1000;
1869*cf5a6c84SAndroid Build Coastguard Worker
1870*cf5a6c84SAndroid Build Coastguard Worker return !FLAG(O) || oslot[SLOT_iobytes+!FLAG(A)];
1871*cf5a6c84SAndroid Build Coastguard Worker }
1872*cf5a6c84SAndroid Build Coastguard Worker
iotop_main(void)1873*cf5a6c84SAndroid Build Coastguard Worker void iotop_main(void)
1874*cf5a6c84SAndroid Build Coastguard Worker {
1875*cf5a6c84SAndroid Build Coastguard Worker char *s1 = 0, *s2 = 0, *d = "D"+FLAG(A);
1876*cf5a6c84SAndroid Build Coastguard Worker
1877*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(K)) TT.forcek++;
1878*cf5a6c84SAndroid Build Coastguard Worker
1879*cf5a6c84SAndroid Build Coastguard Worker top_setup(s1 = xmprintf("PID,PR,USER,%sREAD,%sWRITE,SWAP,%sIO,COMM",d,d,d),
1880*cf5a6c84SAndroid Build Coastguard Worker s2 = xmprintf("-%sIO,-ETIME,-PID",d));
1881*cf5a6c84SAndroid Build Coastguard Worker free(s1);
1882*cf5a6c84SAndroid Build Coastguard Worker free(s2);
1883*cf5a6c84SAndroid Build Coastguard Worker top_common(iotop_filter);
1884*cf5a6c84SAndroid Build Coastguard Worker }
1885*cf5a6c84SAndroid Build Coastguard Worker
1886*cf5a6c84SAndroid Build Coastguard Worker // pkill's plumbing wraps pgrep's and thus mostly takes place in pgrep's flag
1887*cf5a6c84SAndroid Build Coastguard Worker // context, so force pgrep's flags on even when building pkill standalone.
1888*cf5a6c84SAndroid Build Coastguard Worker // (All the pgrep/pkill functions drop out when building ps standalone.)
1889*cf5a6c84SAndroid Build Coastguard Worker #define FORCE_FLAGS
1890*cf5a6c84SAndroid Build Coastguard Worker #define FOR_pgrep
1891*cf5a6c84SAndroid Build Coastguard Worker #include "generated/flags.h"
1892*cf5a6c84SAndroid Build Coastguard Worker
1893*cf5a6c84SAndroid Build Coastguard Worker struct regex_list {
1894*cf5a6c84SAndroid Build Coastguard Worker struct regex_list *next;
1895*cf5a6c84SAndroid Build Coastguard Worker regex_t reg;
1896*cf5a6c84SAndroid Build Coastguard Worker };
1897*cf5a6c84SAndroid Build Coastguard Worker
do_pgk(struct procpid * tb)1898*cf5a6c84SAndroid Build Coastguard Worker static void do_pgk(struct procpid *tb)
1899*cf5a6c84SAndroid Build Coastguard Worker {
1900*cf5a6c84SAndroid Build Coastguard Worker if (TT.pgrep.signal) {
1901*cf5a6c84SAndroid Build Coastguard Worker if (kill(*tb->slot, TT.pgrep.signal)) {
1902*cf5a6c84SAndroid Build Coastguard Worker char *s = num_to_sig(TT.pgrep.signal);
1903*cf5a6c84SAndroid Build Coastguard Worker
1904*cf5a6c84SAndroid Build Coastguard Worker if (!s) sprintf(s = toybuf, "%d", TT.pgrep.signal);
1905*cf5a6c84SAndroid Build Coastguard Worker perror_msg("%s->%lld", s, *tb->slot);
1906*cf5a6c84SAndroid Build Coastguard Worker }
1907*cf5a6c84SAndroid Build Coastguard Worker }
1908*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(c) && (!TT.pgrep.signal || TT.tty)) {
1909*cf5a6c84SAndroid Build Coastguard Worker printf("%lld", *tb->slot);
1910*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(l)) printf(" %s", tb->str+tb->offset[4]*FLAG(f));
1911*cf5a6c84SAndroid Build Coastguard Worker printf("%s", TT.pgrep.d ? TT.pgrep.d : "\n");
1912*cf5a6c84SAndroid Build Coastguard Worker }
1913*cf5a6c84SAndroid Build Coastguard Worker }
1914*cf5a6c84SAndroid Build Coastguard Worker
match_pgrep(void * p)1915*cf5a6c84SAndroid Build Coastguard Worker static void match_pgrep(void *p)
1916*cf5a6c84SAndroid Build Coastguard Worker {
1917*cf5a6c84SAndroid Build Coastguard Worker struct procpid *tb = p;
1918*cf5a6c84SAndroid Build Coastguard Worker regmatch_t match;
1919*cf5a6c84SAndroid Build Coastguard Worker struct regex_list *reg;
1920*cf5a6c84SAndroid Build Coastguard Worker char *name = tb->str+tb->offset[4]*FLAG(f);
1921*cf5a6c84SAndroid Build Coastguard Worker
1922*cf5a6c84SAndroid Build Coastguard Worker // Never match ourselves.
1923*cf5a6c84SAndroid Build Coastguard Worker if (TT.pgrep.self == *tb->slot) return;
1924*cf5a6c84SAndroid Build Coastguard Worker
1925*cf5a6c84SAndroid Build Coastguard Worker if (TT.pgrep.regexes) {
1926*cf5a6c84SAndroid Build Coastguard Worker for (reg = TT.pgrep.regexes; reg; reg = reg->next) {
1927*cf5a6c84SAndroid Build Coastguard Worker if (regexec(®->reg, name, 1, &match, 0)) continue;
1928*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(x))
1929*cf5a6c84SAndroid Build Coastguard Worker if (match.rm_so || match.rm_eo!=strlen(name)) continue;
1930*cf5a6c84SAndroid Build Coastguard Worker break;
1931*cf5a6c84SAndroid Build Coastguard Worker }
1932*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(v) == !reg) return;
1933*cf5a6c84SAndroid Build Coastguard Worker }
1934*cf5a6c84SAndroid Build Coastguard Worker
1935*cf5a6c84SAndroid Build Coastguard Worker // pgrep should return success if there's a match.
1936*cf5a6c84SAndroid Build Coastguard Worker toys.exitval = 0;
1937*cf5a6c84SAndroid Build Coastguard Worker
1938*cf5a6c84SAndroid Build Coastguard Worker // Repurpose a field for -c count.
1939*cf5a6c84SAndroid Build Coastguard Worker TT.sortpos++;
1940*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(n)||FLAG(o)) {
1941*cf5a6c84SAndroid Build Coastguard Worker long long ll = tb->slot[SLOT_starttime];
1942*cf5a6c84SAndroid Build Coastguard Worker
1943*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(o)) ll *= -1;
1944*cf5a6c84SAndroid Build Coastguard Worker if (TT.time && TT.time>ll) return;
1945*cf5a6c84SAndroid Build Coastguard Worker TT.time = ll;
1946*cf5a6c84SAndroid Build Coastguard Worker free(TT.pgrep.snapshot);
1947*cf5a6c84SAndroid Build Coastguard Worker TT.pgrep.snapshot = xmemdup(toybuf, (name+strlen(name)+1)-toybuf);
1948*cf5a6c84SAndroid Build Coastguard Worker } else do_pgk(tb);
1949*cf5a6c84SAndroid Build Coastguard Worker }
1950*cf5a6c84SAndroid Build Coastguard Worker
pgrep_match_process(long long * slot)1951*cf5a6c84SAndroid Build Coastguard Worker static int pgrep_match_process(long long *slot)
1952*cf5a6c84SAndroid Build Coastguard Worker {
1953*cf5a6c84SAndroid Build Coastguard Worker return !FLAG(v) == !!shared_match_process(slot);
1954*cf5a6c84SAndroid Build Coastguard Worker }
1955*cf5a6c84SAndroid Build Coastguard Worker
pgrep_main(void)1956*cf5a6c84SAndroid Build Coastguard Worker void pgrep_main(void)
1957*cf5a6c84SAndroid Build Coastguard Worker {
1958*cf5a6c84SAndroid Build Coastguard Worker char **arg;
1959*cf5a6c84SAndroid Build Coastguard Worker struct regex_list *reg;
1960*cf5a6c84SAndroid Build Coastguard Worker
1961*cf5a6c84SAndroid Build Coastguard Worker TT.pgrep.self = getpid();
1962*cf5a6c84SAndroid Build Coastguard Worker
1963*cf5a6c84SAndroid Build Coastguard Worker // No signal names start with "L", so no need for "L: " in optstr.
1964*cf5a6c84SAndroid Build Coastguard Worker if (TT.pgrep.L && 1>(TT.pgrep.signal = sig_to_num(TT.pgrep.L)))
1965*cf5a6c84SAndroid Build Coastguard Worker error_exit("bad -L '%s'", TT.pgrep.L);
1966*cf5a6c84SAndroid Build Coastguard Worker
1967*cf5a6c84SAndroid Build Coastguard Worker comma_args(TT.pgrep.G, &TT.GG, "bad -G", parse_rest);
1968*cf5a6c84SAndroid Build Coastguard Worker comma_args(TT.pgrep.g, &TT.gg, "bad -g", parse_rest);
1969*cf5a6c84SAndroid Build Coastguard Worker comma_args(TT.pgrep.P, &TT.PP, "bad -P", parse_rest);
1970*cf5a6c84SAndroid Build Coastguard Worker comma_args(TT.pgrep.s, &TT.ss, "bad -s", parse_rest);
1971*cf5a6c84SAndroid Build Coastguard Worker comma_args(TT.pgrep.t, &TT.tt, "bad -t", parse_rest);
1972*cf5a6c84SAndroid Build Coastguard Worker comma_args(TT.pgrep.U, &TT.UU, "bad -U", parse_rest);
1973*cf5a6c84SAndroid Build Coastguard Worker comma_args(TT.pgrep.u, &TT.uu, "bad -u", parse_rest);
1974*cf5a6c84SAndroid Build Coastguard Worker
1975*cf5a6c84SAndroid Build Coastguard Worker if ((toys.optflags&(FLAG_x|FLAG_f)) ||
1976*cf5a6c84SAndroid Build Coastguard Worker !(toys.optflags&(FLAG_G|FLAG_g|FLAG_P|FLAG_s|FLAG_t|FLAG_U|FLAG_u)))
1977*cf5a6c84SAndroid Build Coastguard Worker if (!toys.optc) help_exit("No PATTERN");
1978*cf5a6c84SAndroid Build Coastguard Worker
1979*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(f)) TT.bits |= _PS_CMDLINE;
1980*cf5a6c84SAndroid Build Coastguard Worker for (arg = toys.optargs; *arg; arg++) {
1981*cf5a6c84SAndroid Build Coastguard Worker reg = xmalloc(sizeof(struct regex_list));
1982*cf5a6c84SAndroid Build Coastguard Worker xregcomp(®->reg, *arg, REG_EXTENDED);
1983*cf5a6c84SAndroid Build Coastguard Worker reg->next = TT.pgrep.regexes;
1984*cf5a6c84SAndroid Build Coastguard Worker TT.pgrep.regexes = reg;
1985*cf5a6c84SAndroid Build Coastguard Worker }
1986*cf5a6c84SAndroid Build Coastguard Worker TT.match_process = pgrep_match_process;
1987*cf5a6c84SAndroid Build Coastguard Worker TT.show_process = match_pgrep;
1988*cf5a6c84SAndroid Build Coastguard Worker
1989*cf5a6c84SAndroid Build Coastguard Worker // pgrep should return failure if there are no matches.
1990*cf5a6c84SAndroid Build Coastguard Worker toys.exitval = 1;
1991*cf5a6c84SAndroid Build Coastguard Worker
1992*cf5a6c84SAndroid Build Coastguard Worker dirtree_flagread("/proc", DIRTREE_SHUTUP|DIRTREE_PROC, get_ps);
1993*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(c)) printf("%d\n", TT.sortpos);
1994*cf5a6c84SAndroid Build Coastguard Worker if (TT.pgrep.snapshot) {
1995*cf5a6c84SAndroid Build Coastguard Worker do_pgk(TT.pgrep.snapshot);
1996*cf5a6c84SAndroid Build Coastguard Worker if (CFG_TOYBOX_FREE) free(TT.pgrep.snapshot);
1997*cf5a6c84SAndroid Build Coastguard Worker }
1998*cf5a6c84SAndroid Build Coastguard Worker if (TT.pgrep.d) xputc('\n');
1999*cf5a6c84SAndroid Build Coastguard Worker }
2000*cf5a6c84SAndroid Build Coastguard Worker
2001*cf5a6c84SAndroid Build Coastguard Worker #define FOR_pkill
2002*cf5a6c84SAndroid Build Coastguard Worker #include "generated/flags.h"
2003*cf5a6c84SAndroid Build Coastguard Worker
pkill_main(void)2004*cf5a6c84SAndroid Build Coastguard Worker void pkill_main(void)
2005*cf5a6c84SAndroid Build Coastguard Worker {
2006*cf5a6c84SAndroid Build Coastguard Worker char **args = toys.optargs;
2007*cf5a6c84SAndroid Build Coastguard Worker
2008*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(l) && *args && **args=='-') TT.pgrep.L = *(args++)+1;
2009*cf5a6c84SAndroid Build Coastguard Worker if (!TT.pgrep.L) TT.pgrep.signal = SIGTERM;
2010*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(V)) TT.tty = 1;
2011*cf5a6c84SAndroid Build Coastguard Worker pgrep_main();
2012*cf5a6c84SAndroid Build Coastguard Worker }
2013