blob: 20dd98ee76ee424cc0ee790bf741d335f7033f3c [file] [log] [blame] [raw]
/* ps - toolbox
Copyright 2015 libdll.so
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <pwd.h>
#ifdef __INTERIX
static char *nextline(char **s) {
while(**s && *(*s)++ != '\n');
return *s;
}
static char *getvalue(char **s) {
while(**s && *(*s)++ != ' ');
return *s;
}
#else
static char *nexttoksep(char **strp, const char *sep) {
char *p = strsep(strp, sep);
return p ? : "";
}
static char *nexttok(char **strp) {
return nexttoksep(strp, " ");
}
#endif
#define SHOW_PRIO 1
#define SHOW_TIME 2
//#define SHOW_POLICY 4
#define SHOW_CPU 8
#define SHOW_MACLABEL 16
static int display_flags = 0;
static int ps_line(int pid, int tid, const char *namefilter) {
char statline[1024];
char command[1024];
char macline[1024];
char user[32];
struct stat stats;
int fd, r;
char *ptr, *name, *state;
int ppid, tty;
unsigned int wchan, rss = 0, vss, eip = 0;
unsigned int utime, stime;
int prio = 0, nice = 0, rtprio = 0, sched = 0, psr = 0;
struct passwd *pw;
sprintf(statline, "/proc/%d", pid);
stat(statline, &stats);
#ifdef __linux__
if(tid) {
sprintf(statline, "/proc/%d/task/%d/stat", pid, tid);
command[0] = 0;
snprintf(macline, sizeof(macline), "/proc/%d/task/%d/attr/current", pid, tid);
} else {
#endif
#ifdef __FreeBSD__
sprintf(statline, "/proc/%d/status", pid);
#else
sprintf(statline, "/proc/%d/stat", pid);
#endif
sprintf(command, "/proc/%d/cmdline", pid);
#ifdef __linux__
snprintf(macline, sizeof(macline), "/proc/%d/attr/current", pid);
#endif
fd = open(command, O_RDONLY);
if(fd == -1) {
r = 0;
} else {
r = read(fd, command, 1023);
close(fd);
if(r < 0) r = 0;
}
command[r] = 0;
#ifdef __linux__
}
#endif
fd = open(statline, O_RDONLY);
if(fd == -1) return -1;
r = read(fd, statline, 1023);
close(fd);
if(r < 0) return -1;
statline[r] = 0;
ptr = statline;
#ifdef __FreeBSD__
name = ptr;
nexttok(&ptr)[-1] = 0;
#elif defined __INTERIX
name = getvalue(&ptr);
nextline(&ptr)[-1] = 0;
#else
nexttok(&ptr); // skip pid
ptr++; // skip "("
name = ptr;
ptr = strrchr(ptr, ')'); // Skip to *last* occurence of ')',
*ptr++ = '\0'; // and null-terminate name.
#endif
#ifdef __INTERIX
nextline(&ptr); // skip pid
ppid = atoi(getvalue(&ptr));
nextline(&ptr);
nextline(&ptr); // pgrp
nextline(&ptr); // ruser
nextline(&ptr); // user
nextline(&ptr); // rgroup
nextline(&ptr); // group
utime = atoi(getvalue(&ptr));
nextline(&ptr);
stime = atoi(getvalue(&ptr));
nextline(&ptr);
nextline(&ptr); // cutime
nextline(&ptr); // cstime
tty = atoi(getvalue(&ptr));
nextline(&ptr);
state = getvalue(&ptr);
nextline(&ptr)[-1] = 0;
nextline(&ptr); // flags
nextline(&ptr); // etime
vss = strtoul(getvalue(&ptr), 0, 10); // vsize
nextline(&ptr);
nextline(&ptr); // wsize
nextline(&ptr); // sid
nextline(&ptr); // inpsx
nextline(&ptr); // natpid
nextline(&ptr); // natsid
nice = atoi(getvalue(&ptr));
nextline(&ptr);
wchan = strtoul(getvalue(&ptr), 0, 10); // wchan
nextline(&ptr);
#if 0
nextline(&ptr); // sttime
nextline(&ptr); // openfdcount
#endif
#else
ptr++; // skip " "
state = nexttok(&ptr);
ppid = atoi(nexttok(&ptr));
nexttok(&ptr); // pgrp
nexttok(&ptr); // sid
tty = atoi(nexttok(&ptr));
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
wchan = strtoul(nexttok(&ptr), 0, 10); // 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
tty = atoi(nexttok(&ptr));
#ifdef __linux__
if(tid != 0) {
ppid = pid;
pid = tid;
}
#endif
#endif
pw = getpwuid(stats.st_uid);
if(!pw) {
sprintf(user, "%d", (int)stats.st_uid);
} else {
strcpy(user, pw->pw_name);
}
if(!namefilter || strcmp(name, namefilter) == 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 %-9s %-5d %-5d %s\n", macline, user, pid, ppid, command[0] ? command : 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);
printf(" %08x %08x %s %s", wchan, eip, state, command[0] ? command : name);
if(display_flags&SHOW_TIME) printf(" (u:%d, s:%d)", utime, stime);
putchar('\n');
}
return 0;
}
#ifdef __linux__
static void ps_threads(int pid, const char *namefilter) {
char tmp[128];
DIR *d;
struct dirent *de;
sprintf(tmp,"/proc/%d/task",pid);
d = opendir(tmp);
if(!d) return;
while((de = readdir(d))) {
if(isdigit(de->d_name[0])) {
int tid = atoi(de->d_name);
if(tid == pid) continue;
ps_line(pid, tid, namefilter);
}
}
closedir(d);
}
#endif
int ps_main(int argc, char **argv) {
DIR *d;
struct dirent *de;
const char *namefilter = 0;
int pidfilter = 0;
#ifdef __linux__
int threads = 0;
#endif
d = opendir("/proc");
if(!d) {
perror("/proc");
return -1;
}
while(argc > 1) {
#ifdef __linux__
if(strcmp(argv[1], "-t") == 0) {
threads = 1;
} else
#endif
if(strcmp(argv[1],"-x") == 0) {
display_flags |= SHOW_TIME;
#ifdef __linux__
} else if(strcmp(argv[1], "-Z") == 0) {
display_flags |= SHOW_MACLABEL;
#endif
} else if(strcmp(argv[1], "-p") == 0) {
display_flags |= SHOW_PRIO;
} else if(strcmp(argv[1], "-c") == 0) {
display_flags |= SHOW_CPU;
} 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 WCHAN PC NAME\n",
(display_flags & SHOW_CPU) ? "CPU " : "",
(display_flags & SHOW_PRIO) ? "PRIO NICE RTPRI SCHED " : "");
}
while((de = readdir(d))) {
if(isdigit(de->d_name[0])) {
int pid = atoi(de->d_name);
if(!pidfilter || pidfilter == pid) {
ps_line(pid, 0, namefilter);
#ifdef __linux__
if(threads) ps_threads(pid, namefilter);
#endif
}
}
}
closedir(d);
return 0;
}