Skip to content

Instantly share code, notes, and snippets.

@funglaub
Created March 15, 2012 16:08
Show Gist options
  • Save funglaub/2044990 to your computer and use it in GitHub Desktop.
Save funglaub/2044990 to your computer and use it in GitHub Desktop.
#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