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) 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 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 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 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