Home | History | Annotate | Download | only in toolbox
      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