diff -ru -x CVS -x '*~' -x '*.o' monit.orig/http/cervlet.c monit/http/cervlet.c --- monit.orig/http/cervlet.c 2003-02-14 09:22:33.000000000 +0100 +++ monit/http/cervlet.c 2003-03-04 16:35:19.000000000 +0100 @@ -877,17 +877,25 @@ printf_ssl_socket(res->ssl, "Process '%s' is running with pid [%d]\n\tUptime: %s " - "CPU: %.1f%% Memory: %.1f%% [%ldkB]\n\tMonitoring status: %s\n", + "CPU: %.1f%% Memory w/o children: %.1f%% [%ldkB]\n" + "\tChildren: %i Memory w/ children: %ldkB\n" + "\tMonitoring status: %s\n", p->name, (int)pid, uptime, pi->cpu_percent/10.0, - pi->mem_percent/10.0,pi->mem_kbyte, statusnames[p->do_validate]); + pi->mem_percent/10.0,pi->mem_kbyte, + pi->children,pi->total_mem_kbyte, + statusnames[p->do_validate]); } else { fprintf(out, "Process '%s' is running with pid [%d]\n\tUptime: %s " - "CPU: %.1f%% Memory: %.1f%% [%ldkB]\n\tMonitoring status: %s\n", + "CPU: %.1f%% Memory w/o children: %.1f%% [%ldkB]\n" + "\tChildren: %i Memory w/ children: %ldkB\n" + "\tMonitoring status: %s\n", p->name, (int)pid, uptime, pi->cpu_percent/10.0, - pi->mem_percent/10.0,pi->mem_kbyte, statusnames[p->do_validate]); + pi->mem_percent/10.0,pi->mem_kbyte, + pi->children,pi->total_mem_kbyte, + statusnames[p->do_validate]); } diff -ru -x CVS -x '*~' -x '*.o' monit.orig/l.l monit/l.l --- monit.orig/l.l 2003-02-11 22:27:39.000000000 +0100 +++ monit/l.l 2003-03-05 14:45:40.000000000 +0100 @@ -153,6 +153,8 @@ cpuusage { return CPUUSAGE; } memusage { return MEMUSAGE; } memkbyte { return MEMKBYTE; } +children { return CHILDREN; } +totalmemkbyte { return TOTALMEMKBYTE; } timestamp { return TIMESTAMP; } second(s)? { return SECOND; } minute(s)? { return MINUTE; } diff -ru -x CVS -x '*~' -x '*.o' monit.orig/monit_process.c monit/monit_process.c --- monit.orig/monit_process.c 2003-02-11 22:27:39.000000000 +0100 +++ monit/monit_process.c 2003-03-05 15:13:31.000000000 +0100 @@ -58,6 +58,7 @@ #include "monitor.h" #include "monit_process.h" #include "process/process.h" +#include "process/sysdep.h" /** * General purpose /proc methods. @@ -102,9 +103,10 @@ * @param pid The process id * @return TRUE if succeeded otherwise FALSE. */ -int update_process_data(Process_T p, pid_t pid) { +int update_process_data(Process_T p, ProcessTree_T *pt, int treesize, pid_t pid) { ProcInfo_T pi; + ProcessTree_T *leaf; ASSERT(p); @@ -117,6 +119,18 @@ } + if ((leaf = findprocess(pid, pt, treesize)) != NULL ) { + + pi->children=leaf->children_sum; + pi->total_mem_kbyte=leaf->mem_kbyte_sum; + + } else { + + pi->children=0; + pi->total_mem_kbyte=pi->mem_kbyte; + + } + return TRUE; } @@ -135,3 +149,132 @@ return TRUE; } + + +/** + * Initilize the process tree + * @param reference reference of ProcessTree + * @return treesize>=0 if succeeded otherwise <0. + */ +int initprocesstree(ProcessTree_T ** reference) { + + int treesize; + int i; + ProcessTree_T * pt; + + ASSERT(reference); + + if ((treesize = initprocesstree_sysdep(reference)) <= 0) { + + return 0; + + } + + pt = * reference; + + for ( i = 0; i < treesize; i ++ ) { + + if ( pt[i].ppid == 0 ) { + + continue; + + } + + pt[i].parent = (struct myprocesstree *) findprocess(pt[i].ppid, pt, treesize); + + if ( pt[i].parent == NULL ) { + + /* inconsitancy found, most probably a race condition + we might lack accuracy but we remain stable! */ + + pt[i].pid=0; + + continue; + + } + + if (! connectchild((ProcessTree_T *) pt[i].parent, &pt[i])) { + + /* connection to parent process has failed, this is + usually caused in the part above */ + + pt[i].pid=0; + + continue; + + } + + } + + fillprocesstree((struct myprocesstree *) findprocess(1, pt, treesize)); + + return treesize; + +} + + +/** + * Search a leaf in the processtree + * @param pid pid of the process + * @param pt processtree + * @param treesize size of the processtree + * @return pointer of the process if succeeded otherwise NULL. + */ +ProcessTree_T * findprocess(int pid, ProcessTree_T * pt, int size) { + + int i; + + ASSERT(pt); + + if (( pid == 0 ) || ( size <= 0 )) { + + return NULL; + + } + + for ( i = 0; i < size; i ++ ) { + + if ( pid == pt[i].pid ) { + + return &pt[i]; + + } + + } + + return NULL; + +} + +/** + * Initilize the process tree + * @param pt processtree + * @param treesize size of the processtree + */ +void delprocesstree(ProcessTree_T * pt, int treesize) { + + int i; + + ASSERT(pt); + + if ( treesize <= 0 ) { + + return; + + } + + for ( i = 0; i < treesize; i ++ ) { + + if ( pt[i].children!=NULL ) { + + free(pt[i].children); + + } + + } + + free(pt); + + return; + +} diff -ru -x CVS -x '*~' -x '*.o' monit.orig/monit_process.h monit/monit_process.h --- monit.orig/monit_process.h 2003-02-11 22:27:39.000000000 +0100 +++ monit/monit_process.h 2003-03-05 14:37:12.000000000 +0100 @@ -42,10 +42,19 @@ #define RESOURCE_ID_LOAD1 4 #define RESOURCE_ID_LOAD5 5 #define RESOURCE_ID_LOAD15 6 +#define RESOURCE_ID_CHILDREN 7 +#define RESOURCE_ID_TOTAL_MEM_KBYTE 8 -int update_process_data(Process_T p, pid_t pid); + +int update_process_data(Process_T p, ProcessTree_T *, int treesize, pid_t pid); int init_process_info(void); int update_loadavg(void); + +ProcessTree_T * findprocess(int, ProcessTree_T *, int); +int initprocesstree(ProcessTree_T **); +void delprocesstree(ProcessTree_T *, int); + + #endif diff -ru -x CVS -x '*~' -x '*.o' monit.orig/monitor.h monit/monitor.h --- monit.orig/monitor.h 2003-03-02 15:15:22.000000000 +0100 +++ monit/monitor.h 2003-03-03 11:08:08.000000000 +0100 @@ -252,10 +252,15 @@ /** Defines procfs (or other mechanism) data */ typedef struct myprocinfo { int pid; + int ppid; int status_flag; long mem_kbyte; int mem_percent; /**< pecentage * 10 */ int cpu_percent; /**< pecentage * 10 */ + + int children; + long total_mem_kbyte; + /* private for calculating cpu_percent */ double time_prev; /**< 1/10 seconds */ long cputime; /**< 1/10 seconds */ @@ -309,6 +314,23 @@ struct myprocess *next_depend; /**< next depend process in chain */ } *Process_T; +/** Defines process tree */ +typedef struct myprocesstree { + + int pid; + int ppid; + long mem_kbyte; + + int children_num; + struct myprocesstree ** children; + + struct myprocesstree * parent; + + long mem_kbyte_sum; + int children_sum; + +} ProcessTree_T; + /* ------ Global variables ------------------------------------------------- */ Process_T processlist; /**< The process list (created in p.y) */ diff -ru -x CVS -x '*~' -x '*.o' monit.orig/p.y monit/p.y --- monit.orig/p.y 2003-02-14 09:22:33.000000000 +0100 +++ monit/p.y 2003-03-05 14:47:05.000000000 +0100 @@ -196,7 +196,8 @@ %token MAILBODY %token NUMBER %token REAL -%token CPUUSAGE MEMUSAGE MEMKBYTE RESOURCE LOADAVG1 LOADAVG5 LOADAVG15 +%token CPUUSAGE MEMUSAGE MEMKBYTE TOTALMEMKBYTE CHILDREN RESOURCE +%token LOADAVG1 LOADAVG5 LOADAVG15 %token AUTOSTART MODE ACTIVE PASSIVE MANUAL %token GROUP REQUEST DEPENDS %token TIMESTAMP SECOND MINUTE HOUR DAY @@ -581,6 +582,16 @@ resourceset.operator= $2; resourceset.limit= (int) $3; } + | TOTALMEMKBYTE operator NUMBER { + resourceset.resource_id= RESOURCE_ID_TOTAL_MEM_KBYTE; + resourceset.operator= $2; + resourceset.limit= (int) $3; + } + | CHILDREN operator NUMBER { + resourceset.resource_id= RESOURCE_ID_CHILDREN; + resourceset.operator= $2; + resourceset.limit= (int) $3; + } | resourceload operator REAL { resourceset.resource_id= $1; resourceset.operator= $2; diff -ru -x CVS -x '*~' -x '*.o' monit.orig/process/common.c monit/process/common.c --- monit.orig/process/common.c 2003-02-11 22:27:40.000000000 +0100 +++ monit/process/common.c 2003-03-05 09:43:03.000000000 +0100 @@ -63,6 +63,7 @@ #include "process.h" +#include "sysdep.h" /** @@ -163,3 +164,134 @@ } + + +/** + * Write process data in processtree entry + * @param pid pid of the process + * @param entry process tree + * @return TRUE if succeeded otherwise FALSE. + */ +int getdatafromproc(int pid, ProcessTree_T *entry) { + + ProcInfo_T pi=NEW(pi); + + pi->pid=pid; + + if (! get_process_info_sysdep(pi)) { + + return FALSE; + + } + + entry->pid=pid; + entry->mem_kbyte=pi->mem_kbyte; + entry->ppid=pi->ppid; + + free(pi); + return TRUE; + +} + + +/** + * Connects child and parent in a process treee + * @param parent pointer to parents process tree entry + * @param child pointer to childs process tree entry + * @return TRUE if succeeded otherwise FALSE. + */ +int connectchild(ProcessTree_T * parent, ProcessTree_T * child) { + + ProcessTree_T ** tmp; + + ASSERT(child); + ASSERT(parent); + + if ( parent->pid == 0 || child->pid == 0 ) { + + return FALSE; + + } + + parent->children_num++; + + tmp = xcalloc(sizeof(ProcessTree_T *), parent->children_num); + + if ( parent->children != NULL ) { + + memcpy(tmp, parent->children, sizeof(ProcessTree_T *) * (parent->children_num - 1)); + free(parent->children); + + } + + parent->children = (struct myprocesstree **) tmp; + parent->children[parent->children_num - 1] = (struct myprocesstree *) child; + + return TRUE; + +} + + +/** + * Fill data in the process tree by recusively walking through it + * @param pt process tree + * @return TRUE if succeeded otherwise FALSE. + */ +void fillprocesstree(ProcessTree_T * pt) { + + int i; + ProcessTree_T *parent_pt; + + ASSERT(pt); + + if ( pt->pid==0 ) { + + return; + + } + + pt->children_sum= pt->children_num; + pt->mem_kbyte_sum= pt->mem_kbyte; + + for( i = 0; i < pt->children_num; i++) { + + fillprocesstree(pt->children[i]); + + } + + if ( pt->parent != NULL ) { + + parent_pt=pt->parent; + parent_pt->children_sum+=pt->children_sum; + parent_pt->mem_kbyte_sum+=pt->mem_kbyte_sum; + + } + +} + + +/** + * Transfer child information from process tree to process info structre + * @param pi process info structure + * @param pt process tree + * @param treesize size of the process tree + * @return TRUE if succeeded otherwise FALSE. + */ +int enterchildinfo(ProcInfo_T pi, ProcessTree_T * pt, int treesize) { + + ProcessTree_T *leaf; + + leaf = findprocess(pi->pid, pt, treesize); + + if (NULL == (leaf = findprocess(pi->pid, pt, treesize))) { + + return FALSE; + + } + + pi->children = leaf->children_sum; + pi->total_mem_kbyte = leaf->mem_kbyte_sum; + + return TRUE; + +} diff -ru -x CVS -x '*~' -x '*.o' monit.orig/process/process.h monit/process/process.h --- monit.orig/process/process.h 2003-02-11 22:27:40.000000000 +0100 +++ monit/process/process.h 2003-03-04 12:06:16.000000000 +0100 @@ -25,11 +25,18 @@ #include "monitor.h" #include "monit_process.h" + int get_process_info(ProcInfo_T p); int get_process_info_sysdep(ProcInfo_T p); int init_process_info_sysdep(void); int read_proc_file(char *buf, int buf_size, char * name, int pid); double get_float_time(void); +void fillprocesstree(ProcessTree_T *); +int getdatafromproc(int pid, ProcessTree_T *); +int connectchild(ProcessTree_T * , ProcessTree_T *); + + + #endif diff -ru -x CVS -x '*~' -x '*.o' monit.orig/process/sysdep.h monit/process/sysdep.h --- monit.orig/process/sysdep.h 2003-02-11 22:27:40.000000000 +0100 +++ monit/process/sysdep.h 2003-03-03 11:05:02.000000000 +0100 @@ -22,8 +22,13 @@ #include +#include "monitor.h" +#include "monit_process.h" +#include "process.h" + int get_process_info_sysdep(ProcInfo_T); int init_proc_info_sysdep(void); +int initprocesstree_sysdep(ProcessTree_T **); #ifdef HPUX diff -ru -x CVS -x '*~' -x '*.o' monit.orig/process/sysdep_DARWIN.c monit/process/sysdep_DARWIN.c --- monit.orig/process/sysdep_DARWIN.c 2003-02-11 22:27:40.000000000 +0100 +++ monit/process/sysdep_DARWIN.c 2003-03-05 15:14:44.000000000 +0100 @@ -312,3 +312,16 @@ return TRUE; } + +/** + * Read all processes of the proc files system to initilize + * the process tree (sysdep version... but should work for + * all procfs based unices) + * @param reference reference of ProcessTree + * @return treesize>0 if succeeded otherwise =0. + */ +int initprocesstree_sysdep(ProcessTree_T ** reference) { + + return 0; + +} diff -ru -x CVS -x '*~' -x '*.o' monit.orig/process/sysdep_FREEBSD.c monit/process/sysdep_FREEBSD.c --- monit.orig/process/sysdep_FREEBSD.c 2003-02-11 22:27:40.000000000 +0100 +++ monit/process/sysdep_FREEBSD.c 2003-03-05 15:23:54.000000000 +0100 @@ -329,3 +329,16 @@ return TRUE; } + +/** + * Read all processes of the proc files system to initilize + * the process tree (sysdep version... but should work for + * all procfs based unices) + * @param reference reference of ProcessTree + * @return treesize>0 if succeeded otherwise =0. + */ +int initprocesstree_sysdep(ProcessTree_T ** reference) { + + return 0; + +} diff -ru -x CVS -x '*~' -x '*.o' monit.orig/process/sysdep_HPUX.c monit/process/sysdep_HPUX.c --- monit.orig/process/sysdep_HPUX.c 2003-02-11 22:27:40.000000000 +0100 +++ monit/process/sysdep_HPUX.c 2003-03-05 15:24:27.000000000 +0100 @@ -174,3 +174,16 @@ return TRUE; } + +/** + * Read all processes of the proc files system to initilize + * the process tree (sysdep version... but should work for + * all procfs based unices) + * @param reference reference of ProcessTree + * @return treesize>0 if succeeded otherwise =0. + */ +int initprocesstree_sysdep(ProcessTree_T ** reference) { + + return 0; + +} diff -ru -x CVS -x '*~' -x '*.o' monit.orig/process/sysdep_LINUX.c monit/process/sysdep_LINUX.c --- monit.orig/process/sysdep_LINUX.c 2003-02-11 22:27:40.000000000 +0100 +++ monit/process/sysdep_LINUX.c 2003-03-05 15:04:03.000000000 +0100 @@ -55,6 +55,8 @@ #include #include #include +#include + #include "process.h" #include "sysdep.h" @@ -106,6 +108,7 @@ long stat_item_cutime; long stat_item_cstime; long stat_item_rss; + int stat_ppid; if (!read_proc_file(buf,4096, "stat", p->pid)) { @@ -120,16 +123,19 @@ /* This implementation is done by using fs/procfs/array.c as a basis it is also worth looking into the source of the procps utils */ - sscanf(tmp,"%c %*d %*d %*d %*d %*d %*u %*u" + sscanf(tmp,"%c %d %*d %*d %*d %*d %*u %*u" "%*u %*u %*u %lu %lu %ld %ld %*d %*d %*d " "%*d %*u %*u %ld %*u %*u %*u %*u %*u " "%*u %*u %*u %*u %*u %*u %*u %*u %*d %*d\n", - &stat_item_state, &stat_item_utime, &stat_item_stime, + &stat_item_state, &stat_ppid, + &stat_item_utime, &stat_item_stime, &stat_item_cutime, &stat_item_cstime, &stat_item_rss); /* abs to please the compiler... we dont want to shift negatively. why doesn't C understand this??? */ + p->ppid= stat_ppid; + if ( PAGE_TO_KBYTE_SHIFT < 0 ) { p->mem_kbyte= stat_item_rss >> abs(PAGE_TO_KBYTE_SHIFT); @@ -174,3 +180,62 @@ return TRUE; } + + +/** + * Read all processes of the proc files system to initilize + * the process tree (sysdep version... but should work for + * all procfs based unices) + * @param reference reference of ProcessTree + * @return treesize>0 if succeeded otherwise =0. + */ +int initprocesstree_sysdep(ProcessTree_T ** reference) { + + int pid; + int i; + int treesize; + + ProcessTree_T * pt; + + glob_t globbuf; + + ASSERT(reference); + + /* Find all processes in the /proc directory */ + + if ( glob("/proc/[0-9]*", GLOB_ONLYDIR, NULL, &globbuf) != 0 ) { + + return 0; + + } + + treesize = globbuf.gl_pathc; + + /* Allocate the tree */ + + pt = xcalloc(sizeof(ProcessTree_T), treesize); + memset( pt, 0, sizeof(ProcessTree_T)*globbuf.gl_pathc ); + + /* Insert data from /proc directory */ + + for ( i = 0; i < treesize; i ++ ) { + + pid=atoi(globbuf.gl_pathv[i]+strlen("/proc/")); + + if (! getdatafromproc(pid, &pt[i] )) { + + continue; + + } + + } + + * reference = pt; + + /* Free globbing buffer */ + + globfree(&globbuf); + + return treesize; + +} diff -ru -x CVS -x '*~' -x '*.o' monit.orig/process/sysdep_SOLARIS.c monit/process/sysdep_SOLARIS.c --- monit.orig/process/sysdep_SOLARIS.c 2003-02-11 22:27:40.000000000 +0100 +++ monit/process/sysdep_SOLARIS.c 2003-03-05 15:11:59.000000000 +0100 @@ -54,6 +54,7 @@ #include #include +#include #include "process.h" #include "sysdep.h" @@ -103,6 +104,7 @@ } + p->ppid = pstatus->pr_ppid; if ( p->status_flag != PROCESS_ZOMBIE ) { /* We can't access /proc/$pid/status of a zombie */ @@ -146,3 +148,62 @@ return TRUE; } + + +/** + * Read all processes of the proc files system to initilize + * the process tree (sysdep version... but should work for + * all procfs based unices) + * @param reference reference of ProcessTree + * @return treesize>=0 if succeeded otherwise <0. + */ +int initprocesstree_sysdep(ProcessTree_T ** reference) { + + int pid; + int i; + int treesize; + + ProcessTree_T * pt; + + glob_t globbuf; + + ASSERT(reference); + + /* Find all processes in the /proc directory */ + + if (glob("/proc/[0-9]*", NULL , NULL, &globbuf) != 0 ) { + + return 0; + + } + + treesize = globbuf.gl_pathc; + + /* Allocate the tree */ + + pt = xcalloc(sizeof(ProcessTree_T), treesize); + memset( pt, 0, sizeof(ProcessTree_T)*globbuf.gl_pathc ); + + /* Insert data from /proc directory */ + + for ( i = 0; i < treesize; i ++ ) { + + pid=atoi(globbuf.gl_pathv[i]+strlen("/proc/")); + + if (! getdatafromproc(pid, &pt[i] )) { + + continue; + + } + + } + + * reference = pt; + + /* Free globbing buffer */ + + globfree(&globbuf); + + return treesize; + +} diff -ru -x CVS -x '*~' -x '*.o' monit.orig/validate.c monit/validate.c --- monit.orig/validate.c 2003-02-18 14:55:32.000000000 +0100 +++ monit/validate.c 2003-03-05 14:44:01.000000000 +0100 @@ -44,7 +44,7 @@ static sigjmp_buf timeout; /* Private Prototypes */ -static void do_validate(Process_T); +static void do_validate(Process_T, ProcessTree_T *, int); static void do_restart(Process_T, char *, ...) ; static void do_start(Process_T, char *, ...) ; static void do_stop(Process_T, char *, ...); @@ -90,6 +90,14 @@ void validate() { Process_T p; + ProcessTree_T * pt; + int treesize = 0; + + if (Run.doprocess) { + + treesize = initprocesstree(&pt); + + } if(! update_loadavg()) { @@ -100,11 +108,17 @@ for(p= processlist; p; p= p->next) { if(p->visited) continue; - do_validate(p); + do_validate(p, pt, treesize); } reset_depend(); + if (Run.doprocess) { + + delprocesstree(pt, treesize); + + } + } @@ -119,7 +133,7 @@ * * We block for the signals SIGTERM while in this function. */ -static void do_validate(Process_T p) { +static void do_validate(Process_T p, ProcessTree_T * pt, int treesize) { Port_T pp; Resource_T pr; @@ -166,7 +180,7 @@ if(Run.doprocess) { - if(update_process_data(p, pid)) { + if(update_process_data(p, pt, treesize, pid)) { if(! check_process_state(p, report)) { @@ -753,6 +767,54 @@ } break; + case RESOURCE_ID_CHILDREN: + + if(compare_value(pr->operator, pi->children, pr->limit)) { + + vlog(report, STRLEN, p, + "children of %i matches resource limit " + "[children%s%i]", + pi->children, operatorshortnames[pr->operator], + pr->limit); + + okay= FALSE; + + } else { + + if(Run.debug) { + + log("'%s' children check passed " + "[current children=%i]\n", + p->name, pi->children); + + } + } + break; + + case RESOURCE_ID_TOTAL_MEM_KBYTE: + + if(compare_value(pr->operator, pi->total_mem_kbyte, pr->limit)) { + + vlog(report, STRLEN, p, + "total mem amount of %ldkB matches resource limit" + " [total mem amount%s%ldkB]", + pi->total_mem_kbyte, operatorshortnames[pr->operator], + pr->limit); + + okay= FALSE; + + } else { + + if(Run.debug) { + + log("'%s' total mem amount check passed" + " [current total mem amount=%ldkB]\n", + p->name, pi->total_mem_kbyte); + + } + } + break; + default: log("'%s' error: unknow resource ID: [%d]\n", p->name, pr->resource_id);