78e08066f2
There is at least one app that assumes that you will always get at least one line of output in stdout from ps. To fix this, move error output to stdout, and move the check of whether /proc can be opened until after the ps header is printed. Bug: 26554285 Change-Id: I6d9342aafd5c6f728735507cdd87a48a8e0373ac
334 lines
8.6 KiB
C
334 lines
8.6 KiB
C
#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 statline[1024];
|
|
char cmdline[1024];
|
|
char macline[1024];
|
|
char user[32];
|
|
struct stat stats;
|
|
int 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", tid ? tid : 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);
|
|
int 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;
|
|
}
|
|
|
|
int 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 (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 ", macline);
|
|
}
|
|
|
|
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];
|
|
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 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);
|
|
}
|
|
}
|
|
closedir(d);
|
|
}
|
|
|
|
int ps_main(int argc, char **argv)
|
|
{
|
|
DIR *d;
|
|
struct dirent *de;
|
|
int pidfilter = 0;
|
|
int threads = 0;
|
|
|
|
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]);
|
|
if (ppid_filter == 0) {
|
|
/* Bug 26554285: Use printf because some apps require at least
|
|
* one line of output to stdout even for errors.
|
|
*/
|
|
printf("bad ppid '%s'\n", argv[2]);
|
|
return 1;
|
|
}
|
|
argc--;
|
|
argv++;
|
|
} else {
|
|
pidfilter = atoi(argv[1]);
|
|
if (pidfilter == 0) {
|
|
/* Bug 26554285: Use printf because some apps require at least
|
|
* one line of output to stdout even for errors.
|
|
*/
|
|
printf("bad pid '%s'\n", argv[1]);
|
|
return 1;
|
|
}
|
|
}
|
|
argc--;
|
|
argv++;
|
|
}
|
|
|
|
if (display_flags & SHOW_MACLABEL) {
|
|
printf("LABEL ");
|
|
}
|
|
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 " : "");
|
|
|
|
d = opendir("/proc");
|
|
if(d == 0) return -1;
|
|
|
|
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);
|
|
if(threads) ps_threads(pid);
|
|
}
|
|
}
|
|
}
|
|
closedir(d);
|
|
return 0;
|
|
}
|
|
|