1#include <stdio.h>
2#include <stdlib.h>
3#include <ctype.h>
4#include <fcntl.h>
5
6#include <string.h>
7
8#include <sys/stat.h>
9#include <sys/types.h>
10#include <dirent.h>
11
12#include <pwd.h>
13
14#include <cutils/sched_policy.h>
15
16static char *nexttoksep(char **strp, char *sep)
17{
18    char *p = strsep(strp,sep);
19    return (p == 0) ? "" : p;
20}
21static char *nexttok(char **strp)
22{
23    return nexttoksep(strp, " ");
24}
25
26#define SHOW_PRIO 1
27#define SHOW_TIME 2
28#define SHOW_POLICY 4
29#define SHOW_CPU  8
30#define SHOW_MACLABEL 16
31
32static int display_flags = 0;
33
34static int ps_line(int pid, int tid, char *namefilter)
35{
36    char statline[1024];
37    char cmdline[1024];
38    char macline[1024];
39    char user[32];
40    struct stat stats;
41    int fd, r;
42    char *ptr, *name, *state;
43    int ppid, tty;
44    unsigned wchan, rss, vss, eip;
45    unsigned utime, stime;
46    int prio, nice, rtprio, sched, psr;
47    struct passwd *pw;
48
49    sprintf(statline, "/proc/%d", pid);
50    stat(statline, &stats);
51
52    if(tid) {
53        sprintf(statline, "/proc/%d/task/%d/stat", pid, tid);
54        cmdline[0] = 0;
55        snprintf(macline, sizeof(macline), "/proc/%d/task/%d/attr/current", pid, tid);
56    } else {
57        sprintf(statline, "/proc/%d/stat", pid);
58        sprintf(cmdline, "/proc/%d/cmdline", pid);
59        snprintf(macline, sizeof(macline), "/proc/%d/attr/current", pid);
60        fd = open(cmdline, O_RDONLY);
61        if(fd == 0) {
62            r = 0;
63        } else {
64            r = read(fd, cmdline, 1023);
65            close(fd);
66            if(r < 0) r = 0;
67        }
68        cmdline[r] = 0;
69    }
70
71    fd = open(statline, O_RDONLY);
72    if(fd == 0) return -1;
73    r = read(fd, statline, 1023);
74    close(fd);
75    if(r < 0) return -1;
76    statline[r] = 0;
77
78    ptr = statline;
79    nexttok(&ptr); // skip pid
80    ptr++;          // skip "("
81
82    name = ptr;
83    ptr = strrchr(ptr, ')'); // Skip to *last* occurence of ')',
84    *ptr++ = '\0';           // and null-terminate name.
85
86    ptr++;          // skip " "
87    state = nexttok(&ptr);
88    ppid = atoi(nexttok(&ptr));
89    nexttok(&ptr); // pgrp
90    nexttok(&ptr); // sid
91    tty = atoi(nexttok(&ptr));
92
93    nexttok(&ptr); // tpgid
94    nexttok(&ptr); // flags
95    nexttok(&ptr); // minflt
96    nexttok(&ptr); // cminflt
97    nexttok(&ptr); // majflt
98    nexttok(&ptr); // cmajflt
99#if 1
100    utime = atoi(nexttok(&ptr));
101    stime = atoi(nexttok(&ptr));
102#else
103    nexttok(&ptr); // utime
104    nexttok(&ptr); // stime
105#endif
106    nexttok(&ptr); // cutime
107    nexttok(&ptr); // cstime
108    prio = atoi(nexttok(&ptr));
109    nice = atoi(nexttok(&ptr));
110    nexttok(&ptr); // threads
111    nexttok(&ptr); // itrealvalue
112    nexttok(&ptr); // starttime
113    vss = strtoul(nexttok(&ptr), 0, 10); // vsize
114    rss = strtoul(nexttok(&ptr), 0, 10); // rss
115    nexttok(&ptr); // rlim
116    nexttok(&ptr); // startcode
117    nexttok(&ptr); // endcode
118    nexttok(&ptr); // startstack
119    nexttok(&ptr); // kstkesp
120    eip = strtoul(nexttok(&ptr), 0, 10); // kstkeip
121    nexttok(&ptr); // signal
122    nexttok(&ptr); // blocked
123    nexttok(&ptr); // sigignore
124    nexttok(&ptr); // sigcatch
125    wchan = strtoul(nexttok(&ptr), 0, 10); // wchan
126    nexttok(&ptr); // nswap
127    nexttok(&ptr); // cnswap
128    nexttok(&ptr); // exit signal
129    psr = atoi(nexttok(&ptr)); // processor
130    rtprio = atoi(nexttok(&ptr)); // rt_priority
131    sched = atoi(nexttok(&ptr)); // scheduling policy
132
133    tty = atoi(nexttok(&ptr));
134
135    if(tid != 0) {
136        ppid = pid;
137        pid = tid;
138    }
139
140    pw = getpwuid(stats.st_uid);
141    if(pw == 0) {
142        sprintf(user,"%d",(int)stats.st_uid);
143    } else {
144        strcpy(user,pw->pw_name);
145    }
146
147    if(!namefilter || !strncmp(name, namefilter, strlen(namefilter))) {
148        if (display_flags & SHOW_MACLABEL) {
149            fd = open(macline, O_RDONLY);
150            strcpy(macline, "-");
151            if (fd >= 0) {
152                r = read(fd, macline, sizeof(macline)-1);
153                close(fd);
154                if (r > 0)
155                    macline[r] = 0;
156            }
157            printf("%-30s %-9s %-5d %-5d %s\n", macline, user, pid, ppid, cmdline[0] ? cmdline : name);
158            return 0;
159        }
160
161        printf("%-9s %-5d %-5d %-6d %-5d", user, pid, ppid, vss / 1024, rss * 4);
162        if (display_flags & SHOW_CPU)
163            printf(" %-2d", psr);
164        if (display_flags & SHOW_PRIO)
165            printf(" %-5d %-5d %-5d %-5d", prio, nice, rtprio, sched);
166        if (display_flags & SHOW_POLICY) {
167            SchedPolicy p;
168            if (get_sched_policy(pid, &p) < 0)
169                printf(" un ");
170            else
171                printf(" %.2s ", get_sched_policy_name(p));
172        }
173        printf(" %08x %08x %s %s", wchan, eip, state, cmdline[0] ? cmdline : name);
174        if(display_flags&SHOW_TIME)
175            printf(" (u:%d, s:%d)", utime, stime);
176
177        printf("\n");
178    }
179    return 0;
180}
181
182
183void ps_threads(int pid, char *namefilter)
184{
185    char tmp[128];
186    DIR *d;
187    struct dirent *de;
188
189    sprintf(tmp,"/proc/%d/task",pid);
190    d = opendir(tmp);
191    if(d == 0) return;
192
193    while((de = readdir(d)) != 0){
194        if(isdigit(de->d_name[0])){
195            int tid = atoi(de->d_name);
196            if(tid == pid) continue;
197            ps_line(pid, tid, namefilter);
198        }
199    }
200    closedir(d);
201}
202
203int ps_main(int argc, char **argv)
204{
205    DIR *d;
206    struct dirent *de;
207    char *namefilter = 0;
208    int pidfilter = 0;
209    int threads = 0;
210
211    d = opendir("/proc");
212    if(d == 0) return -1;
213
214    while(argc > 1){
215        if(!strcmp(argv[1],"-t")) {
216            threads = 1;
217        } else if(!strcmp(argv[1],"-x")) {
218            display_flags |= SHOW_TIME;
219        } else if(!strcmp(argv[1], "-Z")) {
220            display_flags |= SHOW_MACLABEL;
221        } else if(!strcmp(argv[1],"-P")) {
222            display_flags |= SHOW_POLICY;
223        } else if(!strcmp(argv[1],"-p")) {
224            display_flags |= SHOW_PRIO;
225        } else if(!strcmp(argv[1],"-c")) {
226            display_flags |= SHOW_CPU;
227        }  else if(isdigit(argv[1][0])){
228            pidfilter = atoi(argv[1]);
229        } else {
230            namefilter = argv[1];
231        }
232        argc--;
233        argv++;
234    }
235
236    if (display_flags & SHOW_MACLABEL) {
237        printf("LABEL                          USER     PID   PPID  NAME\n");
238    } else {
239        printf("USER     PID   PPID  VSIZE  RSS   %s%s %s WCHAN    PC         NAME\n",
240               (display_flags&SHOW_CPU)?"CPU ":"",
241               (display_flags&SHOW_PRIO)?"PRIO  NICE  RTPRI SCHED ":"",
242               (display_flags&SHOW_POLICY)?"PCY " : "");
243    }
244    while((de = readdir(d)) != 0){
245        if(isdigit(de->d_name[0])){
246            int pid = atoi(de->d_name);
247            if(!pidfilter || (pidfilter == pid)) {
248                ps_line(pid, 0, namefilter);
249                if(threads) ps_threads(pid, namefilter);
250            }
251        }
252    }
253    closedir(d);
254    return 0;
255}
256
257