• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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