#include <ctype.h> #include <dirent.h> #include <fcntl.h> #include <inttypes.h> #include <pwd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include <cutils/sched_policy.h> static char *nexttoksep(char **strp, char *sep) { char *p = strsep(strp,sep); return (p == 0) ? "" : p; } static char *nexttok(char **strp) { return nexttoksep(strp, " "); } #define SHOW_PRIO 1 #define SHOW_TIME 2 #define SHOW_POLICY 4 #define SHOW_CPU 8 #define SHOW_MACLABEL 16 #define SHOW_NUMERIC_UID 32 #define SHOW_ABI 64 #if __LP64__ #define PC_WIDTH 10 /* Realistically, the top bits will be 0, so don't waste space. */ #else #define PC_WIDTH (2*sizeof(uintptr_t)) #endif static int display_flags = 0; static int ppid_filter = 0; static void print_exe_abi(int pid); static int ps_line(int pid, int tid, char *namefilter) { char statline[1024]; char cmdline[1024]; char macline[1024]; char user[32]; struct stat stats; int fd, r; char *ptr, *name, *state; int ppid; unsigned rss, vss; uintptr_t eip; unsigned utime, stime; int prio, nice, rtprio, sched, psr; struct passwd *pw; sprintf(statline, "/proc/%d", pid); stat(statline, &stats); if(tid) { sprintf(statline, "/proc/%d/task/%d/stat", pid, tid); cmdline[0] = 0; snprintf(macline, sizeof(macline), "/proc/%d/task/%d/attr/current", pid, tid); } else { sprintf(statline, "/proc/%d/stat", pid); sprintf(cmdline, "/proc/%d/cmdline", pid); snprintf(macline, sizeof(macline), "/proc/%d/attr/current", pid); fd = open(cmdline, O_RDONLY); if(fd == 0) { r = 0; } else { r = read(fd, cmdline, 1023); close(fd); if(r < 0) r = 0; } cmdline[r] = 0; } fd = open(statline, O_RDONLY); if(fd == 0) return -1; r = read(fd, statline, 1023); close(fd); if(r < 0) return -1; statline[r] = 0; ptr = statline; nexttok(&ptr); // skip pid ptr++; // skip "(" name = ptr; ptr = strrchr(ptr, ')'); // Skip to *last* occurence of ')', *ptr++ = '\0'; // and null-terminate name. ptr++; // skip " " state = nexttok(&ptr); ppid = atoi(nexttok(&ptr)); nexttok(&ptr); // pgrp nexttok(&ptr); // sid nexttok(&ptr); // tty nexttok(&ptr); // tpgid nexttok(&ptr); // flags nexttok(&ptr); // minflt nexttok(&ptr); // cminflt nexttok(&ptr); // majflt nexttok(&ptr); // cmajflt #if 1 utime = atoi(nexttok(&ptr)); stime = atoi(nexttok(&ptr)); #else nexttok(&ptr); // utime nexttok(&ptr); // stime #endif nexttok(&ptr); // cutime nexttok(&ptr); // cstime prio = atoi(nexttok(&ptr)); nice = atoi(nexttok(&ptr)); nexttok(&ptr); // threads nexttok(&ptr); // itrealvalue nexttok(&ptr); // starttime vss = strtoul(nexttok(&ptr), 0, 10); // vsize rss = strtoul(nexttok(&ptr), 0, 10); // rss nexttok(&ptr); // rlim nexttok(&ptr); // startcode nexttok(&ptr); // endcode nexttok(&ptr); // startstack nexttok(&ptr); // kstkesp eip = strtoul(nexttok(&ptr), 0, 10); // kstkeip nexttok(&ptr); // signal nexttok(&ptr); // blocked nexttok(&ptr); // sigignore nexttok(&ptr); // sigcatch nexttok(&ptr); // wchan nexttok(&ptr); // nswap nexttok(&ptr); // cnswap nexttok(&ptr); // exit signal psr = atoi(nexttok(&ptr)); // processor rtprio = atoi(nexttok(&ptr)); // rt_priority sched = atoi(nexttok(&ptr)); // scheduling policy nexttok(&ptr); // tty if(tid != 0) { ppid = pid; pid = tid; } pw = getpwuid(stats.st_uid); if(pw == 0 || (display_flags & SHOW_NUMERIC_UID)) { sprintf(user,"%d",(int)stats.st_uid); } else { strcpy(user,pw->pw_name); } if(ppid_filter != 0 && ppid != ppid_filter) { return 0; } if(!namefilter || !strncmp(cmdline[0] ? cmdline : name, namefilter, strlen(namefilter))) { if (display_flags & SHOW_MACLABEL) { fd = open(macline, O_RDONLY); strcpy(macline, "-"); if (fd >= 0) { r = read(fd, macline, sizeof(macline)-1); close(fd); if (r > 0) macline[r] = 0; } printf("%-30s %-9s %-5d %-5d %s\n", macline, user, pid, ppid, cmdline[0] ? cmdline : name); return 0; } printf("%-9s %-5d %-5d %-6d %-5d", user, pid, ppid, vss / 1024, rss * 4); if (display_flags & SHOW_CPU) printf(" %-2d", psr); if (display_flags & SHOW_PRIO) printf(" %-5d %-5d %-5d %-5d", prio, nice, rtprio, sched); if (display_flags & SHOW_POLICY) { SchedPolicy p; if (get_sched_policy(pid, &p) < 0) printf(" un "); else printf(" %.2s ", get_sched_policy_name(p)); } char path[PATH_MAX]; snprintf(path, sizeof(path), "/proc/%d/wchan", pid); char wchan[10]; int fd = open(path, O_RDONLY); ssize_t wchan_len = read(fd, wchan, sizeof(wchan)); if (wchan_len == -1) { wchan[wchan_len = 0] = '\0'; } close(fd); printf(" %10.*s %0*" PRIxPTR " %s ", (int) wchan_len, wchan, (int) PC_WIDTH, eip, state); if (display_flags & SHOW_ABI) { print_exe_abi(pid); } printf("%s", cmdline[0] ? cmdline : name); if(display_flags&SHOW_TIME) printf(" (u:%d, s:%d)", utime, stime); printf("\n"); } return 0; } static void print_exe_abi(int pid) { int fd, r; char exeline[1024]; sprintf(exeline, "/proc/%d/exe", pid); fd = open(exeline, O_RDONLY); if(fd == 0) { printf(" "); return; } r = read(fd, exeline, 5 /* 4 byte ELFMAG + 1 byte EI_CLASS */); close(fd); if(r < 0) { printf(" "); return; } if (memcmp("\177ELF", exeline, 4) != 0) { printf("?? "); return; } switch (exeline[4]) { case 1: printf("32 "); return; case 2: printf("64 "); return; default: printf("?? "); return; } } void ps_threads(int pid, char *namefilter) { char tmp[128]; DIR *d; struct dirent *de; sprintf(tmp,"/proc/%d/task",pid); d = opendir(tmp); if(d == 0) return; while((de = readdir(d)) != 0){ if(isdigit(de->d_name[0])){ int tid = atoi(de->d_name); if(tid == pid) continue; ps_line(pid, tid, namefilter); } } closedir(d); } int ps_main(int argc, char **argv) { DIR *d; struct dirent *de; char *namefilter = 0; int pidfilter = 0; int threads = 0; d = opendir("/proc"); if(d == 0) return -1; while(argc > 1){ if(!strcmp(argv[1],"-t")) { threads = 1; } else if(!strcmp(argv[1],"-n")) { display_flags |= SHOW_NUMERIC_UID; } else if(!strcmp(argv[1],"-x")) { display_flags |= SHOW_TIME; } else if(!strcmp(argv[1], "-Z")) { display_flags |= SHOW_MACLABEL; } else if(!strcmp(argv[1],"-P")) { display_flags |= SHOW_POLICY; } else if(!strcmp(argv[1],"-p")) { display_flags |= SHOW_PRIO; } else if(!strcmp(argv[1],"-c")) { display_flags |= SHOW_CPU; } else if(!strcmp(argv[1],"--abi")) { display_flags |= SHOW_ABI; } else if(!strcmp(argv[1],"--ppid")) { ppid_filter = atoi(argv[2]); argc--; argv++; } else if(isdigit(argv[1][0])){ pidfilter = atoi(argv[1]); } else { namefilter = argv[1]; } argc--; argv++; } if (display_flags & SHOW_MACLABEL) { printf("LABEL USER PID PPID NAME\n"); } else { printf("USER PID PPID VSIZE RSS %s%s %sWCHAN %*s %sNAME\n", (display_flags&SHOW_CPU)?"CPU ":"", (display_flags&SHOW_PRIO)?"PRIO NICE RTPRI SCHED ":"", (display_flags&SHOW_POLICY)?"PCY " : "", (int) PC_WIDTH, "PC", (display_flags&SHOW_ABI)?"ABI " : ""); } while((de = readdir(d)) != 0){ if(isdigit(de->d_name[0])){ int pid = atoi(de->d_name); if(!pidfilter || (pidfilter == pid)) { ps_line(pid, 0, namefilter); if(threads) ps_threads(pid, namefilter); } } } closedir(d); return 0; }