Created
March 15, 2012 16:08
-
-
Save funglaub/2044990 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <sys/param.h> | |
#include <sys/errno.h> | |
#include <sys/file.h> | |
#include <sys/proc.h> | |
#include <sys/resource.h> | |
#include <sys/rtprio.h> | |
#include <sys/signal.h> | |
#include <sys/sysctl.h> | |
#include <sys/time.h> | |
#include <sys/user.h> | |
#include <sys/vmmeter.h> | |
#include <err.h> | |
#include <kvm.h> | |
#include <math.h> | |
#include <nlist.h> | |
#include <paths.h> | |
#include <pwd.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <strings.h> | |
#include <unistd.h> | |
#include <vis.h> | |
#include <grp.h> | |
#define MAXARGV_SIZ 256 | |
int num_procs = 0; | |
struct myproc | |
{ | |
pid_t pid, ppid; | |
char *name, *unam, *gnam, *state; | |
char **argv; | |
uid_t uid; | |
gid_t gid; | |
dev_t tty; | |
unsigned nice; | |
struct myproc *hash_next; | |
struct myproc *child_first, *child_next; | |
}; | |
void *umalloc(size_t l) | |
{ | |
void *p = malloc(l); | |
if(!p){ | |
perror("malloc()"); | |
abort(); | |
} | |
memset(p, 0, l); | |
return p; | |
} | |
char *ustrdup(const char *s) | |
{ | |
char *r = umalloc(strlen(s) + 1); | |
strcpy(r, s); | |
return r; | |
} | |
struct myproc *proc_get(struct myproc **procs, pid_t pid) | |
{ | |
struct myproc *p; | |
if(pid >= 0) | |
for(p = procs[pid % num_procs]; p; p = p->hash_next) | |
if(p->pid == pid) | |
return p; | |
return NULL; | |
} | |
int proc_listcontains(struct myproc **procs, pid_t pid) | |
{ | |
return !!proc_get(procs, pid); | |
} | |
const char *proc_to_str(struct myproc *p) | |
{ | |
static char buf[256]; | |
if (p->child_first != NULL) { | |
snprintf(buf, sizeof buf, | |
"{ name=%s, state=%s, pid=%d, ppid=%d, id=%d, group_id=%d, user_name=%s, group_name=%s, child_first=%d, tty=%d}", | |
p->name, p->state, p->pid, p->ppid, p->uid, p->gid, p->unam, p->gnam, p->child_first->pid, p->tty); | |
} else{ | |
snprintf(buf, sizeof buf, | |
"{ name=%s, state=%s, pid=%d, ppid=%d, user_id=%d, group_id=%d, user_name=%s, group_name=%s, tty=%d}", | |
p->name, p->state, p->pid, p->ppid, p->uid, p->gid, p->unam, p->gnam, p->tty); | |
} | |
return buf; | |
} | |
void proc_argv(struct myproc *proc) { | |
if (proc->pid == 0 || proc->argv == NULL) | |
return; | |
/* char *buf = (char *)malloc(sizeof(proc->argv)); */ | |
int len = (sizeof(proc->argv)/(sizeof(char))); | |
printf("argv length: %d\n", len); | |
for (int i=0; i < len; i++) { | |
printf("argv %d: %s\n", i, proc->argv[i]); | |
//strcat(buf, proc->argv[i]); | |
} | |
/* return buf; */ | |
} | |
static char *proc_state(char state) { | |
char *status = umalloc(17*sizeof(char)); | |
switch (state) { | |
case SRUN: | |
strcpy(status, "RUN"); | |
break; | |
default: | |
strcpy(status, "SLEEP"); | |
break; | |
} | |
return status; | |
} | |
static int compare_pid(const void *p1, const void *p2) | |
{ | |
const struct myproc * const *pp1 = p1; | |
const struct myproc * const *pp2 = p2; | |
if ((*pp2)->pid < 0 || (*pp1)->pid < 0) | |
abort(); | |
return ((*pp1)->pid - (*pp2)->pid); | |
} | |
void print_tree(struct myproc *node) { | |
if (node != NULL) { | |
printf("PID: %s\n", proc_to_str(node)); | |
/* proc_argv(node); */ | |
print_tree(node->child_first); | |
} | |
} | |
/* void proc_addto(struct myproc **procs, struct myproc *p) */ | |
/* { */ | |
/* struct myproc *last; */ | |
/* last = procs[p->pid % num_procs]; */ | |
/* if(last){ */ | |
/* while(last->hash_next) */ | |
/* last = last->hash_next; */ | |
/* last->hash_next = p; */ | |
/* }else{ */ | |
/* procs[p->pid % num_procs] = p; */ | |
/* } */ | |
/* } */ | |
struct myproc *proc_new(struct kinfo_proc *pp, kvm_t *kd) { | |
struct myproc *this = NULL; | |
this = umalloc(sizeof(*this)); | |
this = (struct myproc *)malloc(sizeof(struct proc)); | |
this->pid = pp->ki_pid; | |
this->name = pp->ki_comm; | |
this->ppid = pp->ki_ppid; | |
this->state = ustrdup(proc_state(pp->ki_stat)); | |
this->uid = pp->ki_ruid; | |
this->gid = pp->ki_rgid; | |
this->argv = kvm_getargv(kd, pp, 0); // this is not working for PID 0 | |
this->tty = pp->ki_tdev; | |
this->child_first = NULL; | |
this->child_next = NULL; | |
struct passwd *passwd; | |
struct group *group; | |
#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); \ | |
} \ | |
GETPW(this->uid, this->unam, passwd, getpwuid, pw_name); | |
GETPW(this->gid, this->gnam, group, getgrgid, gr_name); | |
return this; | |
} | |
int main(int argc, char **argv) | |
{ | |
int i = 0; | |
static struct kinfo_proc *pbase, *pp; // defined in /usr/include/sys/user.h | |
static kvm_t *kd = NULL; | |
struct myproc **procs; | |
// get a kd handle for kvm | |
if ((kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open")) == NULL) { | |
perror("kd"); | |
abort(); | |
} | |
// get all processes | |
pbase = kvm_getprocs(kd, KERN_PROC_PROC, 0, &num_procs); | |
// malloc memory for all myproc structures | |
procs = malloc(sizeof(struct proc *) * num_procs); | |
// populate my myproc and add them to procs | |
for (pp = pbase, i = 0; i < num_procs; pp++, i++) { | |
struct myproc *p = proc_new(pp, kd); | |
if (p) | |
procs[i] = p; | |
} | |
// Sort by increasing pid's | |
qsort(procs, num_procs, sizeof(*procs), compare_pid); | |
// add relations between processes | |
for(i=0; i < num_procs; i++) { | |
struct myproc *this = procs[i]; | |
struct myproc *iter = NULL; | |
if (i == num_procs -1) | |
this->hash_next = NULL; | |
else { | |
this->hash_next = procs[i+1]; | |
/* printf("Hash next of pid %d has pid %d\n", this->pid, this->hash_next->pid); */ | |
} | |
struct myproc *parent = proc_get(procs, this->ppid); | |
if (parent) { | |
/* printf("Found parent of %d with PPID %d\n", this->pid, parent->pid); */ | |
if(parent->child_first){ | |
iter = parent->child_first; | |
while(iter->child_next) | |
iter = iter->child_next; | |
iter->child_next = this; | |
} else { | |
parent->child_first = this; | |
} | |
} | |
/* printf("%s\n", proc_to_str(procs[i])); */ | |
/* printf("------------------\n"); */ | |
} | |
// Test stuff | |
// ------------------------------ | |
if (proc_listcontains(procs, 1)) { | |
struct myproc *tmp = proc_get(procs, 1); | |
struct myproc *iter = NULL; | |
for (iter=tmp; iter; iter=iter->hash_next) | |
print_tree(iter); | |
} | |
// ------------------------------ | |
for(i=0; i < num_procs; i++) { | |
struct myproc *this = procs[i]; | |
free(this->state); | |
free(this->unam); | |
free(this->gnam); | |
free(this); | |
} | |
if (procs) free(procs); | |
if (kd) kvm_close(kd); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment