From ae5b540ca86e0e3a13d72d971759b9bf83ca92a9 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Thu, 7 Jul 2011 00:23:19 +0100 Subject: [PATCH] Initial commit --- .gitignore | 2 + Makefile | 15 ++++ gui.c | 87 +++++++++++++++++++++++ gui.h | 8 +++ main.c | 23 ++++++ proc.c | 203 +++++++++++++++++++++++++++++++++++++++++++++++++++++ proc.h | 21 ++++++ util.c | 27 +++++++ util.h | 7 ++ 9 files changed, 393 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 gui.c create mode 100644 gui.h create mode 100644 main.c create mode 100644 proc.c create mode 100644 proc.h create mode 100644 util.c create mode 100644 util.h 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