1 #include <ctype.h>
2 #include <dirent.h>
3 #include <fcntl.h>
4 #include <inttypes.h>
5 #include <pwd.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/stat.h>
10 #include <sys/types.h>
11 #include <unistd.h>
12
13 #include <cutils/sched_policy.h>
14
nexttoksep(char ** strp,char * sep)15 static char *nexttoksep(char **strp, char *sep)
16 {
17 char *p = strsep(strp,sep);
18 return (p == 0) ? "" : p;
19 }
nexttok(char ** strp)20 static char *nexttok(char **strp)
21 {
22 return nexttoksep(strp, " ");
23 }
24
25 #define SHOW_PRIO 1
26 #define SHOW_TIME 2
27 #define SHOW_POLICY 4
28 #define SHOW_CPU 8
29 #define SHOW_MACLABEL 16
30 #define SHOW_NUMERIC_UID 32
31 #define SHOW_ABI 64
32
33 #if __LP64__
34 #define PC_WIDTH 10 /* Realistically, the top bits will be 0, so don't waste space. */
35 #else
36 #define PC_WIDTH (2*sizeof(uintptr_t))
37 #endif
38
39 static int display_flags = 0;
40 static int ppid_filter = 0;
41
42 static void print_exe_abi(int pid);
43
ps_line(int pid,int tid)44 static int ps_line(int pid, int tid)
45 {
46 char statline[1024];
47 char cmdline[1024];
48 char macline[1024];
49 char user[32];
50 struct stat stats;
51 int r;
52 char *ptr, *name, *state;
53 int ppid;
54 unsigned rss, vss;
55 uintptr_t eip;
56 unsigned utime, stime;
57 int prio, nice, rtprio, sched, psr;
58 struct passwd *pw;
59
60 sprintf(statline, "/proc/%d", tid ? tid : pid);
61 stat(statline, &stats);
62
63 if(tid) {
64 sprintf(statline, "/proc/%d/task/%d/stat", pid, tid);
65 cmdline[0] = 0;
66 snprintf(macline, sizeof(macline), "/proc/%d/task/%d/attr/current", pid, tid);
67 } else {
68 sprintf(statline, "/proc/%d/stat", pid);
69 sprintf(cmdline, "/proc/%d/cmdline", pid);
70 snprintf(macline, sizeof(macline), "/proc/%d/attr/current", pid);
71 int fd = open(cmdline, O_RDONLY);
72 if(fd == 0) {
73 r = 0;
74 } else {
75 r = read(fd, cmdline, 1023);
76 close(fd);
77 if(r < 0) r = 0;
78 }
79 cmdline[r] = 0;
80 }
81
82 int fd = open(statline, O_RDONLY);
83 if(fd == 0) return -1;
84 r = read(fd, statline, 1023);
85 close(fd);
86 if(r < 0) return -1;
87 statline[r] = 0;
88
89 ptr = statline;
90 nexttok(&ptr); // skip pid
91 ptr++; // skip "("
92
93 name = ptr;
94 ptr = strrchr(ptr, ')'); // Skip to *last* occurence of ')',
95 *ptr++ = '\0'; // and null-terminate name.
96
97 ptr++; // skip " "
98 state = nexttok(&ptr);
99 ppid = atoi(nexttok(&ptr));
100 nexttok(&ptr); // pgrp
101 nexttok(&ptr); // sid
102 nexttok(&ptr); // tty
103 nexttok(&ptr); // tpgid
104 nexttok(&ptr); // flags
105 nexttok(&ptr); // minflt
106 nexttok(&ptr); // cminflt
107 nexttok(&ptr); // majflt
108 nexttok(&ptr); // cmajflt
109 #if 1
110 utime = atoi(nexttok(&ptr));
111 stime = atoi(nexttok(&ptr));
112 #else
113 nexttok(&ptr); // utime
114 nexttok(&ptr); // stime
115 #endif
116 nexttok(&ptr); // cutime
117 nexttok(&ptr); // cstime
118 prio = atoi(nexttok(&ptr));
119 nice = atoi(nexttok(&ptr));
120 nexttok(&ptr); // threads
121 nexttok(&ptr); // itrealvalue
122 nexttok(&ptr); // starttime
123 vss = strtoul(nexttok(&ptr), 0, 10); // vsize
124 rss = strtoul(nexttok(&ptr), 0, 10); // rss
125 nexttok(&ptr); // rlim
126 nexttok(&ptr); // startcode
127 nexttok(&ptr); // endcode
128 nexttok(&ptr); // startstack
129 nexttok(&ptr); // kstkesp
130 eip = strtoul(nexttok(&ptr), 0, 10); // kstkeip
131 nexttok(&ptr); // signal
132 nexttok(&ptr); // blocked
133 nexttok(&ptr); // sigignore
134 nexttok(&ptr); // sigcatch
135 nexttok(&ptr); // wchan
136 nexttok(&ptr); // nswap
137 nexttok(&ptr); // cnswap
138 nexttok(&ptr); // exit signal
139 psr = atoi(nexttok(&ptr)); // processor
140 rtprio = atoi(nexttok(&ptr)); // rt_priority
141 sched = atoi(nexttok(&ptr)); // scheduling policy
142
143 nexttok(&ptr); // tty
144
145 if(tid != 0) {
146 ppid = pid;
147 pid = tid;
148 }
149
150 pw = getpwuid(stats.st_uid);
151 if(pw == 0 || (display_flags & SHOW_NUMERIC_UID)) {
152 sprintf(user,"%d",(int)stats.st_uid);
153 } else {
154 strcpy(user,pw->pw_name);
155 }
156
157 if(ppid_filter != 0 && ppid != ppid_filter) {
158 return 0;
159 }
160
161 if (display_flags & SHOW_MACLABEL) {
162 fd = open(macline, O_RDONLY);
163 strcpy(macline, "-");
164 if (fd >= 0) {
165 r = read(fd, macline, sizeof(macline)-1);
166 close(fd);
167 if (r > 0)
168 macline[r] = 0;
169 }
170 printf("%-30s ", macline);
171 }
172
173 printf("%-9s %-5d %-5d %-6d %-5d", user, pid, ppid, vss / 1024, rss * 4);
174 if (display_flags & SHOW_CPU)
175 printf(" %-2d", psr);
176 if (display_flags & SHOW_PRIO)
177 printf(" %-5d %-5d %-5d %-5d", prio, nice, rtprio, sched);
178 if (display_flags & SHOW_POLICY) {
179 SchedPolicy p;
180 if (get_sched_policy(pid, &p) < 0)
181 printf(" un ");
182 else
183 printf(" %.2s ", get_sched_policy_name(p));
184 }
185 char path[PATH_MAX];
186 snprintf(path, sizeof(path), "/proc/%d/wchan", pid);
187 char wchan[10];
188 fd = open(path, O_RDONLY);
189 ssize_t wchan_len = read(fd, wchan, sizeof(wchan));
190 if (wchan_len == -1) {
191 wchan[wchan_len = 0] = '\0';
192 }
193 close(fd);
194 printf(" %10.*s %0*" PRIxPTR " %s ", (int) wchan_len, wchan, (int) PC_WIDTH, eip, state);
195 if (display_flags & SHOW_ABI) {
196 print_exe_abi(pid);
197 }
198 printf("%s", cmdline[0] ? cmdline : name);
199 if(display_flags&SHOW_TIME)
200 printf(" (u:%d, s:%d)", utime, stime);
201
202 printf("\n");
203 return 0;
204 }
205
print_exe_abi(int pid)206 static void print_exe_abi(int pid)
207 {
208 int fd, r;
209 char exeline[1024];
210
211 sprintf(exeline, "/proc/%d/exe", pid);
212 fd = open(exeline, O_RDONLY);
213 if(fd == 0) {
214 printf(" ");
215 return;
216 }
217 r = read(fd, exeline, 5 /* 4 byte ELFMAG + 1 byte EI_CLASS */);
218 close(fd);
219 if(r < 0) {
220 printf(" ");
221 return;
222 }
223 if (memcmp("\177ELF", exeline, 4) != 0) {
224 printf("?? ");
225 return;
226 }
227 switch (exeline[4]) {
228 case 1:
229 printf("32 ");
230 return;
231 case 2:
232 printf("64 ");
233 return;
234 default:
235 printf("?? ");
236 return;
237 }
238 }
239
ps_threads(int pid)240 void ps_threads(int pid)
241 {
242 char tmp[128];
243 DIR *d;
244 struct dirent *de;
245
246 sprintf(tmp,"/proc/%d/task",pid);
247 d = opendir(tmp);
248 if(d == 0) return;
249
250 while((de = readdir(d)) != 0){
251 if(isdigit(de->d_name[0])){
252 int tid = atoi(de->d_name);
253 if(tid == pid) continue;
254 ps_line(pid, tid);
255 }
256 }
257 closedir(d);
258 }
259
ps_main(int argc,char ** argv)260 int ps_main(int argc, char **argv)
261 {
262 DIR *d;
263 struct dirent *de;
264 int pidfilter = 0;
265 int threads = 0;
266
267 while(argc > 1){
268 if(!strcmp(argv[1],"-t")) {
269 threads = 1;
270 } else if(!strcmp(argv[1],"-n")) {
271 display_flags |= SHOW_NUMERIC_UID;
272 } else if(!strcmp(argv[1],"-x")) {
273 display_flags |= SHOW_TIME;
274 } else if(!strcmp(argv[1], "-Z")) {
275 display_flags |= SHOW_MACLABEL;
276 } else if(!strcmp(argv[1],"-P")) {
277 display_flags |= SHOW_POLICY;
278 } else if(!strcmp(argv[1],"-p")) {
279 display_flags |= SHOW_PRIO;
280 } else if(!strcmp(argv[1],"-c")) {
281 display_flags |= SHOW_CPU;
282 } else if(!strcmp(argv[1],"--abi")) {
283 display_flags |= SHOW_ABI;
284 } else if(!strcmp(argv[1],"--ppid")) {
285 ppid_filter = atoi(argv[2]);
286 if (ppid_filter == 0) {
287 /* Bug 26554285: Use printf because some apps require at least
288 * one line of output to stdout even for errors.
289 */
290 printf("bad ppid '%s'\n", argv[2]);
291 return 1;
292 }
293 argc--;
294 argv++;
295 } else {
296 pidfilter = atoi(argv[1]);
297 if (pidfilter == 0) {
298 /* Bug 26554285: Use printf because some apps require at least
299 * one line of output to stdout even for errors.
300 */
301 printf("bad pid '%s'\n", argv[1]);
302 return 1;
303 }
304 }
305 argc--;
306 argv++;
307 }
308
309 if (display_flags & SHOW_MACLABEL) {
310 printf("LABEL ");
311 }
312 printf("USER PID PPID VSIZE RSS %s%s %sWCHAN %*s %sNAME\n",
313 (display_flags&SHOW_CPU)?"CPU ":"",
314 (display_flags&SHOW_PRIO)?"PRIO NICE RTPRI SCHED ":"",
315 (display_flags&SHOW_POLICY)?"PCY " : "",
316 (int) PC_WIDTH, "PC",
317 (display_flags&SHOW_ABI)?"ABI " : "");
318
319 d = opendir("/proc");
320 if(d == 0) return -1;
321
322 while((de = readdir(d)) != 0){
323 if(isdigit(de->d_name[0])){
324 int pid = atoi(de->d_name);
325 if(!pidfilter || (pidfilter == pid)) {
326 ps_line(pid, 0);
327 if(threads) ps_threads(pid);
328 }
329 }
330 }
331 closedir(d);
332 return 0;
333 }
334
335