From 2e6042e8d08bd45918d52e94c5097ae5c72b155f Mon Sep 17 00:00:00 2001 From: Florian Unglaub Date: Sat, 24 Mar 2012 20:17:19 +0100 Subject: [PATCH] working FreeBSD version --- Makefile | 6 +- gui.c | 142 ++++++++---- gui.h | 2 +- main.c | 17 +- main.h | 8 + proc.c | 683 ++++++++++++++++++++++++++++++++----------------------- proc.h | 82 +++++-- util.c | 43 ---- util.h | 1 + utop.1 | 4 +- 10 files changed, 578 insertions(+), 410 deletions(-) create mode 100644 main.h diff --git a/Makefile b/Makefile index 31dd1ad..985c300 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -CFLAGS = -g -Wall -Wextra -pedantic -std=c99 -D_POSIX_SOURCE -LDFLAGS = -g -lncurses -PREFIX = /usr/local +CFLAGS = -g -Wall -Wextra -pedantic -std=c99 +LDFLAGS = -g -lncurses -lkvm +PREFIX = /usr OBJ = main.o proc.o gui.o util.o .PHONY: clean install uninstall diff --git a/gui.c b/gui.c index 7b95ae6..f962cc1 100644 --- a/gui.c +++ b/gui.c @@ -13,15 +13,36 @@ #include "util.h" #include "config.h" + +// TODO: +// rewrite exposed functions from proc.c: +// [x] proc_get +// [x] proc_to_idx +// [x] prox_from_idx +// [x] proc_find_n +// [x] proc_update + +#define HALF_DELAY_TIME 10 + +/* 1000ms */ +#define WAIT_TIME (HALF_DELAY_TIME * 100) +/* 60s */ +#define FULL_WAIT_TIME (WAIT_TIME * 60) + +#define LOCK_CHAR CTRL_AND('k') + +#define CTRL_AND(c) ((c) & 037) +#define INDENT " " #define STATUS(y, x, ...) do{ mvprintw(y, x, __VA_ARGS__); clrtoeol(); }while(0) #define WAIT_STATUS(...) do{ STATUS(0, 0, __VA_ARGS__); ungetch(getch()); }while(0) static int pos_top = 0, pos_y = 0; + static int search = 0; static int search_idx = 0, search_offset = 0, search_pid = 0; static char search_str[32] = { 0 }; -static struct proc *search_proc = NULL; +static struct myproc *search_proc = NULL; static pid_t lock_proc_pid = -1; @@ -74,19 +95,29 @@ void gui_term() endwin(); } -int search_proc_to_idx(int *y, struct proc **procs) +struct myproc *gui_proc_first(struct myproc **procs) +{ + struct myproc *init = proc_get(procs, 1); + + if(!init) + return proc_any(procs); + + return init; +} + +int search_proc_to_idx(int *y, struct myproc **procs) { - struct proc *init = proc_get(procs, 1); + struct myproc *init = gui_proc_first(procs); if(search_proc == init) return 0; *y = 1; return proc_to_idx(search_proc, init, y); } -struct proc *curproc(struct proc **procs) +struct myproc *curproc(struct myproc **procs) { int i = pos_y; - return proc_from_idx(proc_get(procs, 1), &i); + return proc_from_idx(gui_proc_first(procs), &i); } void position(int newy) @@ -102,19 +133,19 @@ void position(int newy) pos_top = pos_y; } -void goto_proc(struct proc **procs, struct proc *p) +void goto_proc(struct myproc **procs, struct myproc *p) { int y = 1; - proc_to_idx(p, proc_get(procs, 1), &y); + proc_to_idx(p, gui_proc_first(procs), &y); position(y); } -void goto_me(struct proc **procs) +void goto_me(struct myproc **procs) { goto_proc(procs, proc_get(procs, getpid())); } -void goto_lock(struct proc **procs) +void goto_lock(struct myproc **procs) { if(lock_proc_pid == -1){ attron( COLOR_PAIR(1 + COLOR_RED)); @@ -125,24 +156,31 @@ void goto_lock(struct proc **procs) } } -void showproc(struct proc *proc, int *py, int indent) +void showproc(struct myproc *proc, int *py, int indent) { - struct proc *p; + struct myproc *p; int y = *py; int i; + proc->displayed = 1; + if(y >= LINES) - return; + return; /* FIXME */ if(y > 0){ extern int global_uid; + const int owned = proc->uid == (unsigned)global_uid; extern int max_unam_len, max_gnam_len; - const int owned = proc->uid == global_uid; char buf[256]; int len = LINES; int lock = proc->pid == lock_proc_pid; +#define ATTR_NOT_OWNED A_BOLD | COLOR_PAIR(1 + COLOR_BLACK) +#define ATTR_SEARCH A_BOLD | COLOR_PAIR(1 + COLOR_RED) +#define ATTR_BASENAME A_BOLD | COLOR_PAIR(1 + COLOR_CYAN) +#define ATTR_LOCK A_BOLD | COLOR_PAIR(1 + COLOR_YELLOW) + move(y, 0); if(lock) @@ -153,7 +191,7 @@ void showproc(struct proc *proc, int *py, int indent) attron(ATTR_NOT_OWNED); len -= snprintf(buf, sizeof buf, - "% 7d %c " + "% 7d %-7s " "%-*s %-*s " "% 4d" , @@ -164,12 +202,12 @@ void showproc(struct proc *proc, int *py, int indent) ); addstr(buf); - if(proc->state == 'R'){ - int y, x; - getyx(stdscr, y, x); - mvchgat(y, 8, 1, 0, COLOR_GREEN + 1, NULL); - move(y, x); - } + /* if(proc->state == 'R'){ */ + /* int y, x; */ + /* getyx(stdscr, y, x); */ + /* mvchgat(y, 8, 1, 0, COLOR_GREEN + 1, NULL); */ + /* move(y, x); */ + /* } */ i = indent; while(i -->= 0){ @@ -177,14 +215,14 @@ void showproc(struct proc *proc, int *py, int indent) len -= 2; } - i = getcurx(stdscr) + proc->basename_offset; + i = getcurx(stdscr); /* + proc->basename_offset; */ addnstr(proc->cmd, COLS - indent - len - 1); clrtoeol(); if(owned && !lock) attron(ATTR_BASENAME); - mvaddnstr(y, i, proc->basename, COLS - indent - len - 1); + mvaddnstr(y, i, proc->cmd, COLS - indent - len - 1); if(lock) attroff(ATTR_LOCK); @@ -205,11 +243,15 @@ void showproc(struct proc *proc, int *py, int indent) *py = y; } -void showprocs(struct proc **procs, struct procstat *pst) +void showprocs(struct myproc **procs, struct procstat *pst) { int y = -pos_top + 1; + struct myproc *topproc; - showproc(proc_get(procs, 1), &y, 0); + procs_mark_undisplayed(procs); + + for(topproc = gui_proc_first(procs); topproc; topproc = proc_undisplayed(procs)) + showproc(topproc, &y, 0); clrtobot(); @@ -235,8 +277,8 @@ void showprocs(struct proc **procs, struct procstat *pst) }else{ int y; - STATUS(0, 0, "%d processes, %d running, %d owned", - pst->count, pst->running, pst->owned); + STATUS(0, 0, "%d processes, %d running, %d owned, %d zombies, %d lastpid", + pst->count, pst->running, pst->owned, pst->zombies, pst->lastpid); clrtoeol(); y = 1 + pos_y - pos_top; @@ -280,7 +322,7 @@ int confirm(const char *fmt, ...) return 0; } -void delete(struct proc *p) +void delete(struct myproc *p) { char sig[8]; int i, wait = 0; @@ -326,7 +368,7 @@ void delete(struct proc *p) getch_delay(1); } -void external(const char *cmd, struct proc *p) +void external(const char *cmd, struct myproc *p) { char buf[16]; @@ -341,17 +383,26 @@ void external(const char *cmd, struct proc *p) gui_init(); } -void strace(struct proc *p) + +void ktrace(struct myproc *p) { - external("strace", p); + external("ktrace -ti -p", p); } -void lsof(struct proc *p) +void lsof(struct myproc *p) { external("lsof", p); } -void info(struct proc *p) +void gdb(struct myproc *p) +{ + // Attach to a running process: gdb + char cmd[256]; + snprintf(cmd, sizeof cmd, "gdb %s", p->basename); + external(cmd, p); +} + +void info(struct myproc *p) { int y, x; int i; @@ -360,13 +411,13 @@ void info(struct proc *p) mvprintw(0, 0, "pid: %d, ppid: %d\n" "uid: %d (%s), gid: %d (%s)\n" - "state: %c\n" - "tty: %d, pgrp: %d\n" + "state: %s\n" + "tty: %s\n" , p->pid, p->ppid, p->uid, p->unam, p->gid, p->gnam, p->state, - p->tty, p->pgrp); + p->tty); for(i = 0; p->argv[i]; i++) printw("argv[%d] = \"%s\"\n", i, p->argv[i]); @@ -377,11 +428,11 @@ void info(struct proc *p) waitch(y + 1, 0); } -void on_curproc(const char *fstr, void (*f)(struct proc *), int ask, struct proc **procs) +void on_curproc(const char *fstr, void (*f)(struct myproc *), int ask, struct myproc **procs) { extern int global_force; - struct proc *p; + struct myproc *p; if(lock_proc_pid == -1 || !(p = proc_get(procs, lock_proc_pid))){ p = search_proc ? search_proc : curproc(procs); @@ -399,7 +450,7 @@ void on_curproc(const char *fstr, void (*f)(struct proc *), int ask, struct proc } } -void lock_to(struct proc *p) +void lock_to(struct myproc *p) { if(p){ if(lock_proc_pid == p->pid){ @@ -419,7 +470,7 @@ void lock_to(struct proc *p) } } -void gui_search(int ch, struct proc **procs) +void gui_search(int ch, struct myproc **procs) { int do_lock = 0; @@ -468,10 +519,8 @@ void gui_search(int ch, struct proc **procs) do_lock = 1; break; - case SEARCH_NEXT_CHAR: - search_offset++; - break; - case SEARCH_PREVIOUS_CHAR: + case CTRL_AND('n'): search_offset++; break; + case CTRL_AND('p'): if(search_offset > 0) search_offset--; break; @@ -505,7 +554,7 @@ void gui_search(int ch, struct proc **procs) lock_to(search_proc); } -void gui_run(struct proc **procs) +void gui_run(struct myproc **procs) { struct procstat pst; long last_update = 0, last_full_refresh; @@ -609,8 +658,11 @@ void gui_run(struct proc **procs) on_curproc("lsof", lsof, 1, procs); break; case STRACE_CHAR: - on_curproc("strace", strace, 1, procs); + on_curproc("ktrace", ktrace, 1, procs); break; + case 'a': + on_curproc("gdb", gdb, 1, procs); + break; case GOTO_LOCKED_CHAR: goto_lock(procs); diff --git a/gui.h b/gui.h index d5452a9..5a2c8bd 100644 --- a/gui.h +++ b/gui.h @@ -3,6 +3,6 @@ void gui_init(); void gui_term(); -void gui_run(struct proc **); +void gui_run(struct myproc **procs); #endif diff --git a/main.c b/main.c index d42c4ec..1dc5f74 100644 --- a/main.c +++ b/main.c @@ -7,11 +7,13 @@ #include "proc.h" #include "gui.h" #include "util.h" +#include "main.h" #define MS_TO_US(n) ((n) * 1000) -int global_uid = 0; -int global_force = 0; +uid_t global_uid = 0; +int global_force = 0; +int global_debug = 0; int max_unam_len, max_gnam_len; @@ -26,21 +28,26 @@ void extra_init() int main(int argc, char **argv) { - static struct proc **proclist; + static struct myproc **proclist; int i; - for(i = 1; i < argc; i++) + for(i = 1; i < argc; i++){ if(!strcmp(argv[i], "-f")){ global_force = 1; + }else if(!strcmp(argv[i], "-d")){ + global_debug = 1; }else{ fprintf(stderr, - "Usage: %s [-f]\n" + "Usage: %s [-f] [-d]\n" " -f: Don't prompt for lsof and strace\n" + " -d: Debug mode\n" , *argv); return 1; } + } extra_init(); + gui_init(); proclist = proc_init(); diff --git a/main.h b/main.h new file mode 100644 index 0000000..181a9d8 --- /dev/null +++ b/main.h @@ -0,0 +1,8 @@ +#ifndef MAIN_H +#define MAIN_H + +extern uid_t global_uid; +extern int max_unam_len, max_gnam_len; +extern int global_force, global_debug; + +#endif diff --git a/proc.c b/proc.c index 850d5e2..227ba31 100644 --- a/proc.c +++ b/proc.c @@ -1,79 +1,142 @@ +#include +#include +#include +#include +#include +#include + #include #include #include -#include -#include -#include #include #include #include #include #include +#include +#include #include "proc.h" #include "util.h" +#include "main.h" +#define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var)) #define ITER_PROCS(i, p, ps) \ - for(i = 0; i < NPROCS; i++) \ - for(p = ps[i]; p; p = p->hash_next) + for(i = 0; i < HASH_TABLE_SIZE; i++) \ + for(p = ps[i]; p; p = p->hash_next) + +/* Processes are saved into a hash table with size HASH_TABLE_SIZE and + * key pid % HASH_TABLE_SIZE. If the key already exists, the new + * element is appended to the last one throught hash_next: + +[ 0] = { NULL }, +[ 1] = { { "vim", 4321 }, NULL }, +[ 2] = { { "sh", 9821 }, { "xterm", 9801 }, NULL } +... +[NPROCS] = { NULL }, + +*/ + +static void proc_update_single(struct myproc *proc, struct myproc **procs, struct procstat *pst); +static void proc_handle_rename(struct myproc *p); + +static kvm_t *kd = NULL; // kvm handle + +// States taken from top(8) +/* these are for detailing the cpu states */ +int cpu_states[CPUSTATES]; +char *cpustatenames[] = { + "user", "nice", "system", "interrupt", "idle", NULL +}; + +/* these are for detailing the memory statistics */ -static void proc_update_single(struct proc *proc, struct proc **procs, struct procstat *pst); -static void proc_handle_rename(struct proc *p); +int memory_stats[7]; +char *memorynames[] = { + "K Active, ", "K Inact, ", "K Wired, ", "K Cache, ", "K Buf, ", + "K Free", NULL +}; -void proc_free(struct proc *p) +int swap_stats[7]; +char *swapnames[] = { + "K Total, ", "K Used, ", "K Free, ", "% Inuse, ", "K In, ", "K Out", + NULL +}; + +// Process states - short form +const char *state_abbrev[] = { + "", "START", "RUN\0\0\0", "SLEEP", "STOP", "ZOMB", "WAIT", "LOCK" +}; + +static void getsysctl(const char *name, void *ptr, size_t len) { - char **iter; - if(p->argv) - for(iter = p->argv; *iter; iter++) - free(*iter); - free(p->argv); - free(p->proc_path); - free(p->cmd); - free(p->basename); - free(p->unam); - free(p->gnam); - free(p); + size_t nlen = len; + + if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { + fprintf(stderr, "top: sysctl(%s...) failed: %s\n", name, + strerror(errno)); + abort(); + } + if (nlen != len) { + fprintf(stderr, "top: sysctl(%s...) expected %lu, got %lu\n", + name, (unsigned long)len, (unsigned long)nlen); + abort(); + } +} + +void proc_free(struct myproc *p) +{ + char **iter; + if (p->argv) + for(iter = p->argv; *iter; iter++) + free(*iter); + free(p->cmd); + free(p->state); + free(p->argv); + free(p->unam); + free(p->gnam); + free(p); } static void getprocstat(struct procstat *pst) { #ifdef CPU_PERCENTAGE - static time_t last; - time_t now; + static time_t last; + time_t now; - if(last + 3 < (now = time(NULL))){ - FILE *f; - char buf[1024]; - unsigned long usertime, nicetime, systemtime, irq, sirq, idletime, iowait, steal, guest; + if(last + 3 < (now = time(NULL))){ + FILE *f; + char buf[1024]; + unsigned long usertime, nicetime, systemtime, irq, sirq, idletime, iowait, steal, guest; - last = now; + last = now; - if((f = fopen("/proc/stat", "r"))){ - for(;;){ - unsigned long totaltime, totalperiod; + if((f = fopen("/proc/stat", "r"))){ + for(;;){ + unsigned long totaltime, totalperiod; - if(!fgets(buf, sizeof buf - 1, f)) - break; + if(!fgets(buf, sizeof buf - 1, f)) + break; - if(sscanf(buf, "cpu %lu %lu %lu %lu %lu %lu %lu %lu %lu", - &usertime, &nicetime, &systemtime, &idletime, &iowait, - &irq, &sirq, &steal, &guest) == 10){ + if(sscanf(buf, "cpu %lu %lu %lu %lu %lu %lu %lu %lu %lu", + &usertime, &nicetime, &systemtime, &idletime, &iowait, + &irq, &sirq, &steal, &guest) == 10){ - totaltime = - usertime + - nicetime + - systemtime + - irq + - sirq + - idletime + - iowait + - steal + - guest; + totaltime = + usertime + + nicetime + + systemtime + + irq + + sirq + + idletime + + iowait + + steal + + guest; - totalperiod = totaltime - pst->cputime_total; + totalperiod = totaltime - pst->cputime_total; - pst->cputime_total = totaltime; - pst->cputime_period = totalperiod; + pst->cputime_total = totaltime; + pst->cputime_period = totalperiod; break; } @@ -87,296 +150,310 @@ static void getprocstat(struct procstat *pst) NIL(pst->cputime_total); NIL(pst->cputime_period); #undef NIL + + GETSYSCTL("kern.lastpid", pst->lastpid); + GETSYSCTL("vm.loadavg", pst->load_average); } -struct proc *proc_new(pid_t pid) -{ - struct proc *this = NULL; - char cmdln[32]; - struct stat st; - - snprintf(cmdln, sizeof cmdln, "/proc/%d/cmdline", pid); - - this = umalloc(sizeof *this); - memset(this, 0, sizeof *this); - - this->proc_path = ustrdup(cmdln); - *strrchr(this->proc_path, '/') = '\0'; - - snprintf(cmdln, sizeof cmdln, "/proc/%d/task/%d/", pid, pid); - if(!stat(cmdln, &st)){ - struct passwd *passwd; - struct group *group; - -#define GETPW(idvar, var, truct, fn, member, id) \ - truct = fn(id); \ - idvar = id; \ - if(truct){ \ - var = ustrdup(truct->member); \ - }else{ \ - char buf[8]; \ - snprintf(buf, sizeof buf, "%d", id); \ - var = ustrdup(buf); \ - } \ - - GETPW(this->uid, this->unam, passwd, getpwuid, pw_name, st.st_uid) - GETPW(this->gid, this->gnam, group, getgrgid, gr_name, st.st_gid) - } +char *proc_state(struct kinfo_proc *pp) { + char state; + char *status = umalloc(16 * sizeof(char)); + + if (pp) { + state = pp->ki_stat; + + switch (state) { + case SRUN: + if (pp->ki_oncpu != 0xff) + sprintf(status, "CPU%d", pp->ki_oncpu); + else + strcpy(status, "RUN"); + break; + case SLOCK: + if (pp->ki_kiflag & KI_LOCKBLOCK) { + sprintf(status, "*%.6s", pp->ki_lockname); + break; + } + /* fall through */ + case SSLEEP: + if (pp->ki_wmesg != NULL) { + sprintf(status, "%.6s", pp->ki_wmesg); + break; + } + /* FALLTHROUGH */ + default: + if (state >= 0 && + state < (signed) (sizeof(state_abbrev) / sizeof(*state_abbrev))) + sprintf(status, "%.6s", state_abbrev[(int)state]); + else + sprintf(status, "?%5d", state); + break; + } + } else { + strcpy(status, " "); + } + + return status; +} + +struct myproc *proc_new(struct kinfo_proc *pp) { + struct myproc *this = NULL; + + this = umalloc(sizeof(*this)); + + + this->basename = ustrdup(pp->ki_comm); + this->uid = pp->ki_uid; + this->gid = pp->ki_rgid; - this->pid = pid; - this->ppid = -1; + struct passwd *passwd; + struct group *group; - proc_handle_rename(this); +#define GETPW(id, var, truct, fn, member) \ + truct = fn(id); \ + if(truct){ \ + var = ustrdup(truct->member); \ + }else{ \ + char buf[8]; \ + snprintf(buf, sizeof buf, "%d", id); \ + var = ustrdup(buf); \ + } \ - return this; + GETPW(this->uid, this->unam, passwd, getpwuid, pw_name); + GETPW(this->gid, this->gnam, group, getgrgid, gr_name); + + this->pid = pp->ki_pid; + this->ppid = -1; + + proc_handle_rename(this); + + return this; } -struct proc *proc_get(struct proc **procs, pid_t pid) +struct myproc *proc_get(struct myproc **procs, pid_t pid) { - struct proc *p; + struct myproc *p; if(pid >= 0) - for(p = procs[pid % NPROCS]; p; p = p->hash_next) + for(p = procs[pid % HASH_TABLE_SIZE]; p; p = p->hash_next) if(p->pid == pid) return p; return NULL; } -int proc_listcontains(struct proc **procs, pid_t pid) +int proc_listcontains(struct myproc **procs, pid_t pid) { return !!proc_get(procs, pid); } -void proc_addto(struct proc **procs, struct proc *p) +// Add a struct myproc pointer to the hash table +void proc_addto(struct myproc **procs, struct myproc *p) { - struct proc *last; + struct myproc *last; - last = procs[p->pid % NPROCS]; + last = procs[p->pid % HASH_TABLE_SIZE]; if(last){ while(last->hash_next) last = last->hash_next; last->hash_next = p; - }else{ - procs[p->pid % NPROCS] = p; - } -} - -struct proc **proc_init() + }else { - int n = sizeof(struct proc *) * NPROCS; - struct proc **p = umalloc(n); - memset(p, 0, n); - return p; + procs[p->pid % HASH_TABLE_SIZE] = p; + } } -void proc_listall(struct proc **procs, struct procstat *stat) +// initialize hash table and kvm +struct myproc **proc_init() { - /* TODO: kernel threads */ - DIR *d = opendir("/proc"); - struct dirent *ent; - if(!d){ - perror("opendir()"); - exit(1); + if((kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, NULL)) == NULL){ + perror("kd"); + abort(); } - while((errno = 0, ent = readdir(d))){ - int pid; - - if(sscanf(ent->d_name, "%d", &pid) && !proc_listcontains(procs, pid)){ - struct proc *p = proc_new(pid); - - if(p){ - proc_addto(procs, p); - stat->count++; - } - } - } - - if(errno){ - fprintf(stderr, "readdir(): %s\n", strerror(errno)); - exit(1); - } - - closedir(d); + return umalloc(HASH_TABLE_SIZE * sizeof *proc_init()); +} +/* struct myproc **p = NULL; */ +/* // get a kd handle for kvm */ +/* if ((kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, NULL)) == NULL) { */ +/* perror("kd"); */ +/* abort(); */ +/* } */ + +/* int num_procs = 0; // This is the number of processes that kvm_getprocs returns */ + +/* /\* // get all processes *\/ */ +/* if (kvm_getprocs(kd, KERN_PROC_PROC, 0, &num_procs) != NULL) { */ +/* // malloc memory for all myproc structures */ +/* int n = sizeof(struct myproc *) * HASH_TABLE_SIZE; */ +/* p = umalloc(n); */ +/* memset(p, 0, n); */ + +/* return p; */ +/* } else { */ +/* return NULL; */ +/* } */ +/* } */ + +void proc_listall(struct myproc **procs, struct procstat *stat) +{ + // This is the number of processes that kvm_getprocs returns + int num_procs = 0; + + // get all processes + struct kinfo_proc *pbase; // defined in /usr/include/sys/user.h + + if ((pbase = kvm_getprocs(kd, KERN_PROC_PROC, 0, &num_procs) )) { + struct kinfo_proc *pp; + int i; + + // We iterate over each kinfo_struct pointer and check if it + // exists already in our hash table. If it is not present yet, add + // it to the table and increase the global process counter + for(pp = pbase, i = 0; i < num_procs; pp++, i++) { + if(!proc_listcontains(procs, pp->ki_pid)) { + struct myproc *p = proc_new(pp); + + // Skip zombies here + if(p) { + proc_addto(procs, p); + stat->count++; + if(pp->ki_stat == SZOMB) + stat->zombies++; + } + } + } + } } -const char *proc_str(struct proc *p) +static void proc_handle_rename(struct myproc *this) { - static char buf[256]; + struct kinfo_proc *proc = NULL; + int num_procs = 0; - snprintf(buf, sizeof buf, - "{ pid=%d, ppid=%d, state=%c, cmd=\"%s\" }", - p->pid, p->ppid, p->state, p->cmd); + if((proc = kvm_getprocs(kd, KERN_PROC_PID, this->pid, &num_procs)) != NULL){ + char **iter, **argv; - return buf; -} + argv = kvm_getargv(kd, proc, 0); -static void proc_handle_rename(struct proc *this) -{ - char cmdln[32]; - char *buffer, *p, *argv0end; - int len, i, argc; + /* dup argv */ + if(argv){ + int i, argc, slen; + char *cmd; - buffer = argv0end = NULL; - len = 0; + /* free old argv */ + for(i = 0; i < this->argc; i++) + free(this->argv[i]); + free(this->argv); - snprintf(cmdln, sizeof cmdln, "/proc/%d/cmdline", this->pid); + argc = slen = 0; - if(fline(cmdln, &buffer, &len)){ - argc = 0; - for(i = 0, argc = 1; i < len; i++) - if(!buffer[i]) + for(iter = argv; *iter; iter++) argc++; - if(this->argv){ - for(i = 0; this->argv[i]; i++) - free(this->argv[i]); - free(this->argv); - } + this->argv = umalloc((argc+1) * sizeof *this->argv); - this->argv = umalloc((argc + 1) * sizeof *this->argv); - for(p = buffer, i = argc = 0; i < len; i++) - switch(buffer[i]){ - case '\0': - if(!argv0end) - argv0end = buffer + i; - - this->argv[argc++] = ustrdup(p); - p = buffer + i + 1; - case '\n': - buffer[i] = ' '; + for(i = 0; i < argc; i++){ + slen += strlen(argv[i]) + 1 /* space */; + this->argv[i] = ustrdup(argv[i]); } - buffer[len] = '\0'; - - free(this->basename); - if(!argv0end) - argv0end = buffer + len; - - *argv0end = '\0'; - if((p = strchr(buffer, ':'))){ - *p = '\0'; - this->basename = ustrdup(buffer); - *p = ':'; - this->basename_offset = 0; - }else{ - this->basename = strrchr(buffer, '/'); - if(!this->basename++) - this->basename = buffer; - this->basename_offset = this->basename - buffer; - this->basename = ustrdup(this->basename); + this->argv[argc] = NULL; + this->argc = argc; + + /* recreate this->cmd from argv */ + free(this->cmd); + cmd = this->cmd = umalloc(slen + 1); + for(int i = 0; i < argc; i++) + cmd += sprintf(cmd, "%s ", argv[i]); + + if(global_debug){ + fprintf(stderr, "recreated argv for %s\n", this->basename); + for(i = 0; this->argv[i]; i++) + fprintf(stderr, "argv[%d] = %s\n", i, argv[i]); + fprintf(stderr, "argv[%d] = %s\n", i, argv[i]); + } } - *argv0end = ' '; - - if(!argc) - this->argv[argc++] = ustrdup(this->basename); - this->argv[argc] = NULL; - - free(this->cmd); - this->cmd = buffer; - }else{ - this->cmd = ustrdup(""); } } -static void proc_update_single(struct proc *proc, struct proc **procs, struct procstat *pst) +static void proc_update_single(struct myproc *proc, struct myproc **procs, struct procstat *pst) { - char *buf; - char path[32]; - - snprintf(path, sizeof path, "%s/stat", proc->proc_path); - - (void)pst; - - if(fline(path, &buf, NULL)){ - char *start = strrchr(buf, ')') + 2; - char *iter; - int i = 0; - /*unsigned long prevtime;*/ - pid_t oldppid = proc->ppid; - - /*prevtime = proc->utime + proc->stime;*/ - - for(iter = strtok(start, " \t"); iter; iter = strtok(NULL, " \t")){ -#define INT(n, fmt, x) case n: sscanf(iter, fmt, x); break - switch(i++){ - INT(0, "%c", (char *)&proc->state); - INT(1, "%d", &proc->ppid); - INT(4, "%d", &proc->tty); - INT(5, "%d", &proc->pgrp); - - INT(11, "%lu", &proc->utime); - INT(12, "%lu", &proc->stime); - INT(13, "%lu", &proc->cutime); - INT(14, "%lu", &proc->cstime); -#undef INT - } + struct kinfo_proc *pp = NULL; // defined in /usr/include/sys/user.h + int num_procs = 0; // This is the number of processes that kvm_getprocs returns + pid_t oldppid = proc->ppid; + + // Get the kinfo_proc pointer to the current PID + if ( (pp = kvm_getprocs(kd, KERN_PROC_PID, proc->pid, &num_procs)) != NULL ) { + proc->basename = ustrdup(pp->ki_comm); + proc->pid = pp->ki_pid; + proc->ppid = pp->ki_ppid; + proc->state = proc_state(pp); + proc->uid = pp->ki_ruid; + proc->gid = pp->ki_rgid; + + // Set tty + char buf[8]; + devname_r(pp->ki_tdev, S_IFCHR, buf, 8); + /* if(!strcmp(buf, "#NODEV")) */ + /* proc->tty = ustrdup(" "); */ + /* else */ + proc->tty = ustrdup(buf); + + if(proc->ppid && oldppid != proc->ppid){ + struct myproc *parent = proc_get(procs, proc->ppid); + struct myproc *iter; + + if (parent) { + if(parent->child_first){ + iter = parent->child_first; + + while(iter->child_next) + iter = iter->child_next; + + iter->child_next = proc; + }else{ + parent->child_first = proc; + } + } } + } +} -#ifdef CPU_PERCENTAGE - proc->pc_cpu = - (proc->utime + proc->stime - prevtime) / - pst->cputime_period * 100.f; -#endif - -#if 0 - fprintf(stderr, "proc[%d]->cpu = (%lu + %lu - %lu) / %lu = %d\n", - proc->pid, - proc->utime, proc->stime, prevtime, - pst->cputime_total, proc->pc_cpu); -#endif - -#if 0 - cpu = cpuusage(root); - mem = int(head("%s/statm" % root).split(' ')[0]); - time = self.time(stats[11]) # usermode time; - proc->pc_cpu = 0; -#endif - - free(buf); - - if(proc->ppid && oldppid != proc->ppid){ - struct proc *parent = proc_get(procs, proc->ppid); - struct proc *iter; - - if(parent->child_first){ - iter = parent->child_first; +const char *proc_str(struct myproc *p) +{ + static char buf[256]; - while(iter->child_next) - iter = iter->child_next; + snprintf(buf, sizeof buf, + "{ pid=%d, ppid=%d, state=%s, cmd=\"%s\" }", + p->pid, p->ppid, p->state, p->basename); - iter->child_next = proc; - }else{ - parent->child_first = proc; - } - } - } + return buf; } -void proc_update(struct proc **procs, struct procstat *pst) +void proc_update(struct myproc **procs, struct procstat *pst) { int i; int count, running, owned; + int num_procs = 0; getprocstat(pst); - count = 1; /* init */ - running = owned = 0; + count = running = owned = 0; - for(i = 0; i < NPROCS; i++){ - struct proc **change_me; - struct proc *p; + for(i = 0; i < HASH_TABLE_SIZE; i++){ + struct myproc **change_me; + struct myproc *p; change_me = &procs[i]; - for(p = procs[i]; p; ){ - if(access(p->proc_path, F_OK)){ - struct proc *next = p->hash_next; - struct proc *parent = proc_get(procs, p->ppid); + for(p = procs[i]; p; ) { + if(kvm_getprocs(kd, KERN_PROC_PID, p->pid, &num_procs) == NULL) { + struct myproc *next = p->hash_next; + struct myproc *parent = proc_get(procs, p->ppid); if(parent){ - struct proc *iter, **prev; + struct myproc *iter, **prev; prev = &parent->child_first; for(iter = parent->child_first; iter; iter = iter->child_next) @@ -389,19 +466,18 @@ void proc_update(struct proc **procs, struct procstat *pst) } *change_me = next; - proc_free(p); + if (p) + proc_free(p); p = next; }else{ if(p){ - extern int global_uid; - proc_update_single(p, procs, pst); - if(p->ppid != 0 && p->ppid != 2) + if(p->ppid != 2) count++; /* else it's kthreadd or init */ - if(p->state == 'R') - running++; - if(p->uid == global_uid) + /* if(p->state) // TODO */ + /* running++; */ + if(p->uid == (unsigned)global_uid) owned++; } @@ -415,47 +491,47 @@ void proc_update(struct proc **procs, struct procstat *pst) pst->running = running; pst->owned = owned; - proc_listall(procs, pst); + proc_listall(procs, pst); } -void proc_handle_renames(struct proc **ps) +void proc_handle_renames(struct myproc **ps) { - struct proc *p; + struct myproc *p; int i; ITER_PROCS(i, p, ps) proc_handle_rename(p); } -void proc_dump(struct proc **ps, FILE *f) +void proc_dump(struct myproc **ps, FILE *f) { - struct proc *p; + struct myproc *p; int i; ITER_PROCS(i, p, ps) fprintf(f, "%s\n", proc_str(p)); } -struct proc *proc_find(const char *str, struct proc **ps) +struct myproc *proc_find(const char *str, struct myproc **ps) { return proc_find_n(str, ps, 0); } -struct proc *proc_find_n(const char *str, struct proc **ps, int n) +struct myproc *proc_find_n(const char *str, struct myproc **ps, int n) { - struct proc *p; + struct myproc *p; int i; ITER_PROCS(i, p, ps) - if(p->cmd && strstr(p->cmd, str) && n-- <= 0) + if(strstr(p->cmd, str) && n-- <= 0) return p; return NULL; } -int proc_to_idx(struct proc *p, struct proc *parent, int *py) +int proc_to_idx(struct myproc *p, struct myproc *parent, int *py) { - struct proc *iter; + struct myproc *iter; int ret = 0; int y; @@ -473,9 +549,9 @@ int proc_to_idx(struct proc *p, struct proc *parent, int *py) return ret; } -struct proc *proc_from_idx(struct proc *parent, int *idx) +struct myproc *proc_from_idx(struct myproc *parent, int *idx) { - struct proc *iter, *ret = NULL; + struct myproc *iter, *ret = NULL; int i = *idx; #define RET(x) do{ ret = x; goto fin; }while(0) @@ -486,7 +562,7 @@ struct proc *proc_from_idx(struct proc *parent, int *idx) if(--i <= 0){ RET(iter); }else{ - struct proc *p = proc_from_idx(iter, &i); + struct myproc *p = proc_from_idx(iter, &i); if(p) RET(p); } @@ -496,3 +572,32 @@ struct proc *proc_from_idx(struct proc *parent, int *idx) *idx = i; return ret; } + +struct myproc *proc_any(struct myproc **procs) +{ + struct myproc *p; + int i; + ITER_PROCS(i, p, procs) + return p; + + fputs("no procs\n", stderr); + abort(); +} + +void procs_mark_undisplayed(struct myproc **procs) +{ + struct myproc *p; + int i; + ITER_PROCS(i, p, procs) + p->displayed = 0; +} + +struct myproc *proc_undisplayed(struct myproc **procs) +{ + struct myproc *p; + int i; + ITER_PROCS(i, p, procs) + if(!p->displayed) + return p; + return NULL; +} diff --git a/proc.h b/proc.h index 05bf3ed..2dbf581 100644 --- a/proc.h +++ b/proc.h @@ -1,52 +1,88 @@ #ifndef PROC_H #define PROC_H -struct proc +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct myproc { - char *proc_path; pid_t pid, ppid; - int uid, gid; + uid_t uid; + gid_t gid; char *unam, *gnam; char *cmd; char *basename; char **argv; + int argc; int basename_offset; - int state, tty, pgrp; + char *state; + char *tty; + gid_t pgrp; int pc_cpu; unsigned long utime, stime, cutime, cstime; - struct proc *hash_next; /* important */ + /* important */ + struct myproc *hash_next; + struct myproc *child_first, *child_next; /* only used for arrangement */ - struct proc *child_first, *child_next; - struct proc *next; + struct myproc *next; + int displayed; }; - struct procstat { - int count, running, owned; - + int count, running, owned, zombies; + pid_t lastpid; + struct loadavg load_average; unsigned long cputime_total, cputime_period; }; -struct proc **proc_init(); -struct proc *proc_get( struct proc **, pid_t); -void proc_update(struct proc **, struct procstat *); -void proc_handle_renames(struct proc **); +struct myproc **proc_init(); +struct myproc *proc_get( struct myproc **, pid_t); +void proc_update(struct myproc **, struct procstat *); +void proc_handle_renames(struct myproc **); + +struct myproc *proc_to_list(struct myproc **); +struct myproc *proc_to_tree(struct myproc **); +struct myproc *proc_find( const char *, struct myproc **); +struct myproc *proc_find_n(const char *, struct myproc **, int); +const char *proc_str(struct myproc *p); +int proc_to_idx(struct myproc *p, struct myproc *parent, int *y); +struct myproc *proc_from_idx(struct myproc *parent, int *idx); + +struct myproc *proc_any( struct myproc **procs); +struct myproc *proc_undisplayed(struct myproc **procs); -struct proc *proc_to_list(struct proc **); -struct proc *proc_to_tree(struct proc **); -struct proc *proc_find( const char *, struct proc **); -struct proc *proc_find_n(const char *, struct proc **, int); -const char *proc_str(struct proc *p); -int proc_to_idx(struct proc *p, struct proc *parent, int *y); -struct proc *proc_from_idx(struct proc *parent, int *idx); +void procs_mark_undisplayed(struct myproc **procs); -void proc_dump(struct proc **ps, FILE *f); +void proc_dump(struct myproc **ps, FILE *f); -#define NPROCS 128 +#define HASH_TABLE_SIZE 128 #endif diff --git a/util.c b/util.c index beff2d4..cfc21b8 100644 --- a/util.c +++ b/util.c @@ -42,49 +42,6 @@ long mstime() return t.tv_sec * 1000 + t.tv_usec / 1000; } -char *fline(const char *path, char **pbuf, int *plen) -{ - FILE *f; - char *ret; - int c; - int len; - int i; - - f = fopen(path, "r"); - if(!f) - return NULL; - - len = 64; - ret = umalloc(len + 1); - memset(ret, 0, len); - - i = 0; - while((c = fgetc(f)) != EOF){ - ret[i++] = c; - if(i == len){ - len += 64; - ret = urealloc(ret, len + 1); - memset(ret + i + 1, 0, 64); - } - } - - if(ferror(f)){ - /* process exited while we were reading, for e.g. */ - /*perror("read()");*/ - /*abort();*/ - free(ret); - ret = NULL; - i = 0; - } - fclose(f); - - *pbuf = ret; - if(plen) - *plen = i; - - return ret; -} - int str_to_sig(const char *s) { #define SIG(i) { #i, SIG##i } diff --git a/util.h b/util.h index 4a5b785..86271a9 100644 --- a/util.h +++ b/util.h @@ -5,6 +5,7 @@ long mstime(); char *fline(const char *path, char **buf, int *len); void *umalloc(size_t l); +void *urealloc(void *p, size_t l); char *ustrdup(const char *s); int str_to_sig(const char *); diff --git a/utop.1 b/utop.1 index 87f6ebc..2057b3a 100644 --- a/utop.1 +++ b/utop.1 @@ -31,7 +31,9 @@ l - lsof selected process .PP i - info on selected process .PP -s - strace selected process +s - ktrace selected process +.PP +a - attach gdb to the selected process .PP o - goto locked process .PP