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 15 static char *nexttoksep(char **strp, char *sep) 16 { 17 char *p = strsep(strp,sep); 18 return (p == 0) ? "" : p; 19 } 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 44 static int ps_line(int pid, int tid, char *namefilter) 45 { 46 char statline[1024]; 47 char cmdline[1024]; 48 char macline[1024]; 49 char user[32]; 50 struct stat stats; 51 int fd, 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", 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 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 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(!namefilter || !strncmp(cmdline[0] ? cmdline : name, namefilter, strlen(namefilter))) { 162 if (display_flags & SHOW_MACLABEL) { 163 fd = open(macline, O_RDONLY); 164 strcpy(macline, "-"); 165 if (fd >= 0) { 166 r = read(fd, macline, sizeof(macline)-1); 167 close(fd); 168 if (r > 0) 169 macline[r] = 0; 170 } 171 printf("%-30s %-9s %-5d %-5d %s\n", macline, user, pid, ppid, cmdline[0] ? cmdline : name); 172 return 0; 173 } 174 175 printf("%-9s %-5d %-5d %-6d %-5d", user, pid, ppid, vss / 1024, rss * 4); 176 if (display_flags & SHOW_CPU) 177 printf(" %-2d", psr); 178 if (display_flags & SHOW_PRIO) 179 printf(" %-5d %-5d %-5d %-5d", prio, nice, rtprio, sched); 180 if (display_flags & SHOW_POLICY) { 181 SchedPolicy p; 182 if (get_sched_policy(pid, &p) < 0) 183 printf(" un "); 184 else 185 printf(" %.2s ", get_sched_policy_name(p)); 186 } 187 char path[PATH_MAX]; 188 snprintf(path, sizeof(path), "/proc/%d/wchan", pid); 189 char wchan[10]; 190 int fd = open(path, O_RDONLY); 191 ssize_t wchan_len = read(fd, wchan, sizeof(wchan)); 192 if (wchan_len == -1) { 193 wchan[wchan_len = 0] = '\0'; 194 } 195 close(fd); 196 printf(" %10.*s %0*" PRIxPTR " %s ", (int) wchan_len, wchan, (int) PC_WIDTH, eip, state); 197 if (display_flags & SHOW_ABI) { 198 print_exe_abi(pid); 199 } 200 printf("%s", cmdline[0] ? cmdline : name); 201 if(display_flags&SHOW_TIME) 202 printf(" (u:%d, s:%d)", utime, stime); 203 204 printf("\n"); 205 } 206 return 0; 207 } 208 209 static void print_exe_abi(int pid) 210 { 211 int fd, r; 212 char exeline[1024]; 213 214 sprintf(exeline, "/proc/%d/exe", pid); 215 fd = open(exeline, O_RDONLY); 216 if(fd == 0) { 217 printf(" "); 218 return; 219 } 220 r = read(fd, exeline, 5 /* 4 byte ELFMAG + 1 byte EI_CLASS */); 221 close(fd); 222 if(r < 0) { 223 printf(" "); 224 return; 225 } 226 if (memcmp("\177ELF", exeline, 4) != 0) { 227 printf("?? "); 228 return; 229 } 230 switch (exeline[4]) { 231 case 1: 232 printf("32 "); 233 return; 234 case 2: 235 printf("64 "); 236 return; 237 default: 238 printf("?? "); 239 return; 240 } 241 } 242 243 void ps_threads(int pid, char *namefilter) 244 { 245 char tmp[128]; 246 DIR *d; 247 struct dirent *de; 248 249 sprintf(tmp,"/proc/%d/task",pid); 250 d = opendir(tmp); 251 if(d == 0) return; 252 253 while((de = readdir(d)) != 0){ 254 if(isdigit(de->d_name[0])){ 255 int tid = atoi(de->d_name); 256 if(tid == pid) continue; 257 ps_line(pid, tid, namefilter); 258 } 259 } 260 closedir(d); 261 } 262 263 int ps_main(int argc, char **argv) 264 { 265 DIR *d; 266 struct dirent *de; 267 char *namefilter = 0; 268 int pidfilter = 0; 269 int threads = 0; 270 271 d = opendir("/proc"); 272 if(d == 0) return -1; 273 274 while(argc > 1){ 275 if(!strcmp(argv[1],"-t")) { 276 threads = 1; 277 } else if(!strcmp(argv[1],"-n")) { 278 display_flags |= SHOW_NUMERIC_UID; 279 } else if(!strcmp(argv[1],"-x")) { 280 display_flags |= SHOW_TIME; 281 } else if(!strcmp(argv[1], "-Z")) { 282 display_flags |= SHOW_MACLABEL; 283 } else if(!strcmp(argv[1],"-P")) { 284 display_flags |= SHOW_POLICY; 285 } else if(!strcmp(argv[1],"-p")) { 286 display_flags |= SHOW_PRIO; 287 } else if(!strcmp(argv[1],"-c")) { 288 display_flags |= SHOW_CPU; 289 } else if(!strcmp(argv[1],"--abi")) { 290 display_flags |= SHOW_ABI; 291 } else if(!strcmp(argv[1],"--ppid")) { 292 ppid_filter = atoi(argv[2]); 293 argc--; 294 argv++; 295 } else if(isdigit(argv[1][0])){ 296 pidfilter = atoi(argv[1]); 297 } else { 298 namefilter = argv[1]; 299 } 300 argc--; 301 argv++; 302 } 303 304 if (display_flags & SHOW_MACLABEL) { 305 printf("LABEL USER PID PPID NAME\n"); 306 } else { 307 printf("USER PID PPID VSIZE RSS %s%s %sWCHAN %*s %sNAME\n", 308 (display_flags&SHOW_CPU)?"CPU ":"", 309 (display_flags&SHOW_PRIO)?"PRIO NICE RTPRI SCHED ":"", 310 (display_flags&SHOW_POLICY)?"PCY " : "", 311 (int) PC_WIDTH, "PC", 312 (display_flags&SHOW_ABI)?"ABI " : ""); 313 } 314 while((de = readdir(d)) != 0){ 315 if(isdigit(de->d_name[0])){ 316 int pid = atoi(de->d_name); 317 if(!pidfilter || (pidfilter == pid)) { 318 ps_line(pid, 0, namefilter); 319 if(threads) ps_threads(pid, namefilter); 320 } 321 } 322 } 323 closedir(d); 324 return 0; 325 } 326 327