blob: b1e23713ef2d0b08e9d3547a6f3271a419b0602b [file] [log] [blame] [raw]
/* ps - toolbox
Copyright 2015-2023 Rivoreo
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 <string.h>
#include <sys/types.h>
#include <pwd.h>
#include <procstat.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;
#if 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
#endif
#ifdef _LP64
#define ADDRESS_FORMAT "%016lx"
#else
#define ADDRESS_FORMAT "%08lx"
#endif
static int page_size;
static int page_size_ki;
static int ps_print(struct procstat_handle *psh, struct procstat *ps, void *arg) {
char user[32];
struct passwd *pw = getpwuid(ps->ruid);
if(pw) {
size_t len = strlen(pw->pw_name);
if(len > sizeof user - 1) len = sizeof user - 1;
memcpy(user, pw->pw_name, len);
user[len] = 0;
} else {
sprintf(user, "%d", (int)ps->ruid);
}
char *command = NULL;
procstat_get_command_line(psh, ps->pid, &command);
if (display_flags & SHOW_MACLABEL) {
char *mac_label = NULL;
procstat_get_mac_label(psh, ps->pid, &mac_label);
printf("%-30s %-9s %-5d %-5d %s\n",
mac_label ? mac_label : "-", user, (int)ps->pid, (int)ps->ppid, command ? command : ps->comm);
free(mac_label);
} else {
printf("%-9s %-5d %-5d %-6zu %-5zu", user, (int)ps->pid, (int)ps->ppid, ps->size * page_size_ki, ps->rssize * page_size_ki);
if(display_flags & SHOW_CPU) printf(" %-2d", ps->on_psr);
if(display_flags & SHOW_PRIO) {
printf(" %-5ld %-5hhd %-5d %-5d", ps->priority, ps->nice, ps->rt_priority, ps->sched_class);
}
printf(" " ADDRESS_FORMAT " " ADDRESS_FORMAT " %c %s",
(unsigned long int)ps->wchan, (unsigned long int)ps->ip, ps->state, command ? command : ps->comm);
if(display_flags & SHOW_TIME) printf(" %llu", (unsigned long long int)ps->time);
putchar('\n');
}
free(command);
return 1;
}
int ps_main(int argc, char **argv) {
struct procstat_handle *psh = procstat_open();
if(!psh) {
perror("procstat_open");
return 1;
}
int threads = 0;
while(argc > 1) {
if(strcmp(argv[1], "-t") == 0) {
threads = 1;
} else 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 {
fprintf(stderr, "%s: Incorrect command line usage\n", argv[0]);
return -1;
}
argc--;
argv++;
}
page_size = sysconf(_SC_PAGESIZE);
page_size_ki = page_size / 1024;
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 " : "");
}
procstat_walk(psh, threads ? PROCSTAT_WALK_THREADS : PROCSTAT_WALK_ALL, 0, ps_print, NULL);
procstat_close(psh);
return 0;
}