diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7c9cc65 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.o +utop diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..459df90 --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +CFLAGS = -g -Wall -Wextra -pedantic +LDFLAGS = -g -lncurses + +.PHONY: clean + +utop: main.o proc.o gui.o util.o + ${CC} ${LDFLAGS} -o $@ $^ + +clean: + @rm -f *.o utop + +gui.o: gui.c proc.h gui.h util.h +main.o: main.c proc.h gui.h +proc.o: proc.c proc.h +util.o: util.c diff --git a/gui.c b/gui.c new file mode 100644 index 0000000..197c33f --- /dev/null +++ b/gui.c @@ -0,0 +1,87 @@ +#include +#include + +#include "proc.h" +#include "gui.h" +#include "util.h" + +int pos_y = 0; + +void gui_init() +{ + initscr(); + noecho(); + cbreak(); + raw(); + + nonl(); + intrflush(stdscr, FALSE); + keypad(stdscr, TRUE); + + halfdelay(2); /* x/10s of a second wait */ + + if(has_colors()){ + start_color(); + use_default_colors(); + init_pair(COLOR_BLACK, -1, -1); + init_pair(COLOR_GREEN, COLOR_GREEN, -1); + init_pair(COLOR_WHITE, COLOR_WHITE, -1); + init_pair(COLOR_RED, COLOR_RED, -1); + init_pair(COLOR_CYAN, COLOR_CYAN, -1); + init_pair(COLOR_MAGENTA, COLOR_MAGENTA, -1); + init_pair(COLOR_BLUE, COLOR_BLUE, -1); + init_pair(COLOR_YELLOW, COLOR_YELLOW, -1); + } +} + +void gui_term() +{ + endwin(); +} + +void showprocs(struct proc **procs) +{ + struct proc *p = proc_to_list(procs); + char buf[256]; + int y; + + y = pos_y; + + while(p->next && y --> 0) + p = p->next; + + for(y = 0; y < LINES && p; y++, p = p->next){ + snprintf(buf, sizeof buf, "%s - %d", p->cmd, p->pc_cpu); + mvaddnstr(y, 0, buf, COLS - 1); + } + + move(0, 0); +} + +void gui_run(struct proc **procs) +{ + long last_update = 0; + int fin = 0; + + do{ + const long now = mstime(); + int ch, nprocs; + + if(last_update + 500 < now){ + last_update = now; + proc_update(procs, &nprocs); + fprintf(stderr, "proc_update: %d, pos_y: %d\n", nprocs, pos_y); + } + + clear(); + showprocs(procs); + + ch = getch(); + switch(ch){ + case 'q': fin = 1; break; + + case 'k': if(pos_y > 0) pos_y--; break; + case 'j': if(pos_y < nprocs-1) pos_y++; break; + } + }while(!fin); +} diff --git a/gui.h b/gui.h new file mode 100644 index 0000000..d5452a9 --- /dev/null +++ b/gui.h @@ -0,0 +1,8 @@ +#ifndef GUI_H +#define GUI_H + +void gui_init(); +void gui_term(); +void gui_run(struct proc **); + +#endif diff --git a/main.c b/main.c new file mode 100644 index 0000000..466bbd6 --- /dev/null +++ b/main.c @@ -0,0 +1,23 @@ +#include +#include +#include + +#include "proc.h" +#include "gui.h" + +#define MS_TO_US(n) ((n) * 1000) + +int main(void) +{ + struct proc **proclist; + + gui_init(); + + proclist = proc_init(); + + gui_run(proclist); + + gui_term(); + + return 0; +} diff --git a/proc.c b/proc.c new file mode 100644 index 0000000..0b49fc1 --- /dev/null +++ b/proc.c @@ -0,0 +1,203 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "proc.h" + +/*#define PHONY 1*/ + +struct proc *proc_to_list(struct proc **procs) +{ + struct proc *first, **next = &first; + int i; + + for(i = 0; i < NPROCS; i++){ + struct proc *p; + for(p = procs[i]; p; p = p->hash_next){ + *next = p; + next = &p->next; + } + } + *next = NULL; + return first; +} + +void proc_free(struct proc *p) +{ + free(p->argv0); + free(p->proc_path); + free(p->cmd); + free(p); +} + +struct proc *proc_frompid(pid_t pid) +{ + struct proc *this = NULL; + FILE *f; + char cmdln[32]; + + snprintf(cmdln, sizeof cmdln, "/proc/%d/cmdline", pid); + + f = fopen(cmdln, "r"); + if(f){ + char buffer[256]; + + if(fgets(buffer, sizeof buffer, f)){ + char *p; + + this = malloc(sizeof *this); + if(!this){ + perror("malloc()"); + exit(1); + } + memset(this, 0, sizeof *this); + + this->pid = pid; + this->argv0 = strdup(buffer); + this->proc_path = strdup(cmdln); + this->cmd = strdup(buffer); + + if(!this->argv0 || !this->proc_path || !this->cmd){ + perror("malloc()"); + exit(1); + } + + p = strchr(this->cmd, ' '); + if(p) + *p = '\0'; + } + + fclose(f); + } + + return this; +} + +int proc_listcontains(struct proc **list, pid_t pid) +{ + struct proc *p; + + for(p = list[pid % NPROCS]; p; p = p->hash_next) + if(p->pid == pid) + return 1; + + return 0; +} + +void proc_addto(struct proc **list, struct proc *p) +{ + struct proc *last; + + last = list[p->pid % NPROCS]; + if(last){ + while(last->hash_next) + last = last->hash_next; + last->hash_next = p; + }else{ + list[p->pid % NPROCS] = p; + } +} + +struct proc **proc_init() +{ + int n = sizeof(struct proc *) * NPROCS; + struct proc **p = malloc(n); + memset(p, 0, n); +#ifdef PHONY + p[0] = proc_frompid(1); + p[1 % NPROCS] = proc_frompid(getpid()); +#endif + return p; +} + +void proc_listall(struct proc **list, int *np) +{ + /* TODO: kernel threads */ + DIR *d = opendir("/proc"); + struct dirent *ent; + int n = *np; + + if(!d){ + perror("opendir()"); + exit(1); + } + + errno = 0; + while((errno = 0, ent = readdir(d))){ + int pid; + + if(sscanf(ent->d_name, "%d", &pid) && !proc_listcontains(list, pid)){ + struct proc *p = proc_frompid(pid); + + if(p){ + proc_addto(list, p); + n++; + } + } + } + + if(errno){ + fprintf(stderr, "readdir(): %s\n", strerror(errno)); + exit(1); + } + + *np = n; + closedir(d); +} + +void proc_update_single(struct proc *proc) +{ + /* + char buf[256]; + char path[32]; + + snprintf(path, sizeof path, "%s/stat", proc->proc_path); + if(!fline(path, buf, sizeof buf)){ + char *start = strrchr(buf, ')') + 2; + + + } + */ + + proc->pc_cpu = rand(); +} + +void proc_update(struct proc **list, int *np) +{ + int i; + int n; + +#ifdef PHONY + *np = 2; + return; +#endif + + for(i = n = 0; i < NPROCS; i++){ + struct proc *p; + struct proc **changeme = &list[i]; + + for(p = list[i]; p; p = p->hash_next){ + struct stat st; + + if(stat(p->proc_path, &st)){ + *changeme = p->hash_next; + + proc_free(p); + }else{ + proc_update_single(p); + n++; + } + + changeme = &p->hash_next; + } + } + + *np = n; + proc_listall(list, np); +} diff --git a/proc.h b/proc.h new file mode 100644 index 0000000..60da13f --- /dev/null +++ b/proc.h @@ -0,0 +1,21 @@ +#ifndef PROC_H +#define PROC_H + +struct proc +{ + char *proc_path; + char *cmd, *argv0; + pid_t pid; + + int pc_cpu; + + struct proc *hash_next, *next; /* hash list */ +}; + +struct proc **proc_init(); +struct proc *proc_to_list(struct proc **); +void proc_update(struct proc **list, int *); + +#define NPROCS 128 + +#endif diff --git a/util.c b/util.c new file mode 100644 index 0000000..f2a3ae8 --- /dev/null +++ b/util.c @@ -0,0 +1,27 @@ +#include +#include +#include + +#include "util.h" + +long mstime() +{ + struct timeval t; + gettimeofday(&t, NULL); + return t.tv_sec * 1000 + t.tv_usec / 1000; +} + +int fline(const char *path, char *buf, int len) +{ + FILE *f = fopen(path, "r"); + int ret = 0; + + if(!f) + return 1; + + if(fgets(buf, len, f) == NULL) + ret = 1; + + fclose(f); + return ret; +} diff --git a/util.h b/util.h new file mode 100644 index 0000000..2ff24b3 --- /dev/null +++ b/util.h @@ -0,0 +1,7 @@ +#ifndef UTIL_H +#define UTIL_H + +long mstime(); +int fline(const char *path, char *buf, int len); + +#endif