diff -ru --exclude CVS monit.orig/event.c monit/event.c --- monit.orig/event.c 2005-01-06 21:51:49.000000000 +0100 +++ monit/event.c 2005-07-29 12:25:27.000000000 +0200 @@ -59,6 +59,7 @@ {EVENT_PERMISSION, "Permission failed", "Permission passed"}, {EVENT_RESOURCE, "Resource limit matched", "Resource limit passed"}, {EVENT_SIZE, "Size failed", "Size passed"}, + {EVENT_MATCH, "Regex match", "No regex match"}, {EVENT_TIMEOUT, "Timeout", "Timeout recovery"}, {EVENT_TIMESTAMP, "Timestamp failed", "Timestamp passed"}, {EVENT_UID, "UID failed", "UID passed"}, diff -ru --exclude CVS monit.orig/event.h monit/event.h --- monit.orig/event.h 2005-01-06 21:51:49.000000000 +0100 +++ monit/event.h 2005-07-29 12:24:29.000000000 +0200 @@ -38,6 +38,7 @@ #define EVENT_EXEC 0x1000 #define EVENT_CHANGED 0x2000 #define EVENT_ICMP 0x4000 +#define EVENT_MATCH 0x8000 #define EVENT_DESCRIPTION(E) Event_get_description(E) #define IS_EVENT_SET(value, mask) ((value & mask) != 0) diff -ru --exclude CVS monit.orig/gc.c monit/gc.c --- monit.orig/gc.c 2005-01-24 02:04:36.000000000 +0100 +++ monit/gc.c 2005-07-29 13:25:34.000000000 +0200 @@ -50,6 +50,7 @@ static void _gc_inf(Info_T *); static void _gcpdl(Dependant_T *); static void _gcso(Size_T *); +static void _gcmatch(Match_T *); static void _gcchecksum(Checksum_T *); static void _gcperm(Perm_T *); static void _gcuid(Uid_T *); @@ -173,6 +174,9 @@ if((*s)->sizelist) _gcso(&(*s)->sizelist); + if((*s)->matchlist) + _gcmatch(&(*s)->matchlist); + if((*s)->checksum) _gcchecksum(&(*s)->checksum); @@ -435,6 +439,22 @@ } +static void _gcmatch(Match_T *s) { + + ASSERT(s); + + if((*s)->next) + _gcmatch(&(*s)->next); + + if((*s)->action) + _gc_eventaction(&(*s)->action); + + FREE((*s)->regex_string); + FREE((*s)->regex_comp); + FREE(*s); + +} + static void _gcchecksum(Checksum_T *s) { diff -ru --exclude CVS monit.orig/http/cervlet.c monit/http/cervlet.c --- monit.orig/http/cervlet.c 2005-04-05 21:52:57.000000000 +0200 +++ monit/http/cervlet.c 2005-07-29 13:36:12.000000000 +0200 @@ -111,6 +111,7 @@ static void print_service_rules_timestamp(HttpResponse, Service_T); static void print_service_rules_device(HttpResponse, Service_T); static void print_service_rules_size(HttpResponse, Service_T); +static void print_service_rules_match(HttpResponse, Service_T); static void print_service_rules_checksum(HttpResponse, Service_T); static void print_service_rules_process(HttpResponse, Service_T); static void print_service_params_port(HttpResponse, Service_T); @@ -121,6 +122,7 @@ static void print_service_params_timestamp(HttpResponse, Service_T); static void print_service_params_device(HttpResponse, Service_T); static void print_service_params_size(HttpResponse, Service_T); +static void print_service_params_match(HttpResponse, Service_T); static void print_service_params_checksum(HttpResponse, Service_T); static void print_service_params_process(HttpResponse, Service_T); static void print_status(HttpRequest, HttpResponse); @@ -774,6 +776,7 @@ print_service_params_timestamp(res, s); print_service_params_device(res, s); print_service_params_size(res, s); + print_service_params_match(res, s); print_service_params_checksum(res, s); print_service_params_process(res, s); @@ -786,6 +789,7 @@ print_service_rules_timestamp(res, s); print_service_rules_device(res, s); print_service_rules_size(res, s); + print_service_rules_match(res, s); print_service_rules_checksum(res, s); print_service_rules_process(res, s); @@ -1305,6 +1309,8 @@ out_print(res, "Resource "); if(IS_EVENT_SET(r->events, EVENT_SIZE)) out_print(res, "Size "); + if(IS_EVENT_SET(r->events, EVENT_MATCH)) + out_print(res, "Match "); if(IS_EVENT_SET(r->events, EVENT_TIMEOUT)) out_print(res, "Timeout "); if(IS_EVENT_SET(r->events, EVENT_TIMESTAMP)) @@ -1570,6 +1576,27 @@ } } +static void print_service_rules_match(HttpResponse res, Service_T s) { + + if(s->matchlist) { + + Match_T ml; + EventAction_T a; + + for(ml= s->matchlist; ml; ml= ml->next) { + + a= ml->action; + + + out_print(res, + "Associated sizeIf match \"%s\" then %s", + ml->regex_string, + actionnames[a->failed->id]); + + } + } +} + static void print_service_rules_checksum(HttpResponse res, Service_T s) { @@ -1963,6 +1990,25 @@ } } +static void print_service_params_match(HttpResponse res, Service_T s) { + + if(s->type == TYPE_FILE) { + + if(!Util_hasServiceStatus(s)) { + + out_print(res, + "Match regex-"); + + } else { + + out_print(res, + "Match regex%s", + (s->error & EVENT_MATCH)?" color='#ff0000'":"", + (s->error & EVENT_MATCH)?"yes":"no"); + } + } +} + static void print_service_params_checksum(HttpResponse res, Service_T s) { diff -ru --exclude CVS monit.orig/l.l monit/l.l --- monit.orig/l.l 2005-04-03 13:56:51.000000000 +0200 +++ monit/l.l 2005-07-29 11:57:24.000000000 +0200 @@ -234,6 +234,7 @@ perm(ission)? { return PERMISSION; } exec(ute)? { return EXEC; } size { return SIZE; } +match { return MATCH; } connection { return CONNECTION; } unmonitor { return UNMONITOR; } icmp { return ICMP; } diff -ru --exclude CVS monit.orig/monit.pod monit/monit.pod --- monit.orig/monit.pod 2005-04-05 21:52:57.000000000 +0200 +++ monit/monit.pod 2005-07-29 17:15:13.000000000 +0200 @@ -1237,6 +1237,13 @@ check file su with path /bin/su if size != 95564 then exec "/sbin/ifconfig eth0 down" +=over 4 + +=item IF MATCH regex THEN action + +=back + +... blah ... =head2 SPACE TESTING diff -ru --exclude CVS monit.orig/monitor.h monit/monitor.h --- monit.orig/monitor.h 2005-04-23 02:48:40.000000000 +0200 +++ monit/monitor.h 2005-07-29 14:13:22.000000000 +0200 @@ -553,6 +553,18 @@ EventAction_T action; /**< Description of the action upon event occurence */ } *Perm_T; +/** Defines match object */ +typedef struct mymatch { + char *regex_string; /**< Match string */ +#ifdef HAVE_REGEX_H + regex_t *regex_comp; /**< Match compile */ +#endif + EventAction_T action; /**< Description of the action upon event occurence */ + + /** For internal use */ + struct mymatch *next; /**< next match in chain */ +} *Match_T; + /** Defines uid object */ typedef struct myuid { @@ -588,6 +600,7 @@ mode_t st_mode; /**< Permission */ uid_t st_uid; /**< Owner's uid */ gid_t st_gid; /**< Owner's gid */ + ino_t st_ino; /**< Inode */ time_t timestamp; /**< Timestamp */ /* Device specific */ @@ -605,6 +618,8 @@ /* File specific */ size_t st_size; /**< Size */ + size_t readpos; /**< Position for regex matching */ + ino_t st_ino_prev; /**< Previous inode for regex matching */ char *cs_sum; /**< Checksum */ /* Process specific */ @@ -621,7 +636,6 @@ int cpu_percent; /**< pecentage * 10 */ int total_cpu_percent; /**< pecentage * 10 */ time_t uptime; /**< Process uptime */ - } *Info_T; @@ -660,6 +674,7 @@ Port_T portlist; /**< Portnumbers to check, either local or at a host */ Resource_T resourcelist; /**< Resouce check list */ Size_T sizelist; /**< Size check list */ + Match_T matchlist; /**< Content Match list */ Timestamp_T timestamplist; /**< Timestamp check list */ Uid_T uid; /**< Uid check */ diff -ru --exclude CVS monit.orig/monitrc monit/monitrc --- monit.orig/monitrc 2005-04-01 10:07:33.000000000 +0200 +++ monit/monitrc 2005-07-29 17:28:55.000000000 +0200 @@ -121,6 +121,8 @@ # # size -- Must be followed by compare operator, number, optional # a size unit and an action. +# +# match -- Must be followed by a regular expression and an action. # # every -- Only check the service at every n cycles. # diff -ru --exclude CVS monit.orig/p.y monit/p.y --- monit.orig/p.y 2005-04-03 13:56:51.000000000 +0200 +++ monit/p.y 2005-07-29 13:27:00.000000000 +0200 @@ -150,6 +150,7 @@ static struct myuid uidset; static struct myperm permset; static struct mysize sizeset; + static struct mymatch matchset; static struct myicmp icmpset; static struct mymail mailset; static struct myport portset; @@ -188,6 +189,7 @@ static gid_t get_gid(char *, gid_t); static void addchecksum(Checksum_T); static void addperm(Perm_T); + static void addmatch(Match_T); static void adduid(Uid_T); static void addgid(Gid_T); static void addeuid(uid_t); @@ -257,7 +259,7 @@ %token TIMESTAMP CHANGED SECOND MINUTE HOUR DAY %token SSLAUTO SSLV2 SSLV3 TLSV1 CERTMD5 %token BYTE KILOBYTE MEGABYTE GIGABYTE -%token INODE SPACE PERMISSION SIZE +%token INODE SPACE PERMISSION SIZE MATCH %token EXEC UNMONITOR ICMP ICMPECHO NONEXIST INVALID DATA RECOVERED %token URL CONTENT PID PPID %token URLOBJECT @@ -325,6 +327,7 @@ | gid | checksum | size + | match | mode | group | depend @@ -970,6 +973,7 @@ | PERMISSION { eventset |= EVENT_PERMISSION; } | RESOURCE { eventset |= EVENT_RESOURCE; } | SIZE { eventset |= EVENT_SIZE; } + | MATCH { eventset |= EVENT_MATCH; } | TIMEOUT { eventset |= EVENT_TIMEOUT; } | TIMESTAMP { eventset |= EVENT_TIMESTAMP; } | UID { eventset |= EVENT_UID; } @@ -1249,8 +1253,15 @@ } ; +match : IF MATCH STRING THEN action1 recovery { + matchset.regex_string= xstrdup($3); + addeventaction(&(matchset).action, $5, $6); + addmatch(&matchset); + } + ; + size : IF SIZE operator NUMBER unit THEN action1 recovery { - sizeset.operator= $3; + sizeset.operator= $4; sizeset.size= ((unsigned long)$4 * $5); addeventaction(&(sizeset).action, $7, $8); addsize(&sizeset, FALSE); @@ -1897,6 +1908,37 @@ } +/* + * Set Perm object in the current service + */ +static void addmatch(Match_T ms) { + + Match_T m; + int reg_return; + + ASSERT(ms); + +#ifdef HAVE_REGEX_H + NEW(m); + NEW(m->regex_comp); + + m->regex_string= ms->regex_string; + m->action= ms->action; + reg_return= regcomp(m->regex_comp, ms->regex_string, REG_NOSUB|REG_EXTENDED); + + if (reg_return!=0) { + char errbuf[STRLEN]; + regerror(reg_return, ms->regex_comp, errbuf, STRLEN); + yyerror2("regex parsing error:%s", errbuf); + } + + m->next= current->matchlist; + current->matchlist= m; +#else + yyerror2("regex matching requires regex support!", ); +#endif +} + /* * Set Uid object in the current service diff -ru --exclude CVS monit.orig/util.c monit/util.c --- monit.orig/util.c 2005-04-12 00:27:53.000000000 +0200 +++ monit/util.c 2005-07-29 15:45:42.000000000 +0200 @@ -1529,10 +1529,12 @@ */ void Util_resetInfo(Service_T s) { memset(s->inf, 0, sizeof *(s->inf)); - s->inf->_pid= -1; - s->inf->_ppid= -1; - s->inf->pid= -1; - s->inf->ppid= -1; + s->inf->_pid= -1; + s->inf->_ppid= -1; + s->inf->pid= -1; + s->inf->ppid= -1; + s->inf->st_ino_prev= 0; + s->inf->readpos= 0; } diff -ru --exclude CVS monit.orig/validate.c monit/validate.c --- monit.orig/validate.c 2005-05-11 23:28:02.000000000 +0200 +++ monit/validate.c 2005-08-01 14:32:47.000000000 +0200 @@ -102,6 +102,7 @@ static void check_gid(Service_T); static void check_size(Service_T); static void check_perm(Service_T); +static void check_match(Service_T); static int check_skip(Service_T); static int check_timeout(Service_T); static void check_checksum(Service_T); @@ -282,6 +283,13 @@ return FALSE; } else { s->inf->st_mode= stat_buf.st_mode; + if (s->inf->st_ino==0) { + s->inf->st_ino_prev= stat_buf.st_ino; + s->inf->readpos= stat_buf.st_size; + } else { + s->inf->st_ino_prev= s->inf->st_ino; + } + s->inf->st_ino= stat_buf.st_ino; s->inf->st_uid= stat_buf.st_uid; s->inf->st_gid= stat_buf.st_gid; s->inf->st_size= stat_buf.st_size; @@ -319,6 +327,9 @@ if(s->timestamplist) check_timestamp(s); + if(s->matchlist) + check_match(s); + return TRUE; } @@ -950,6 +961,95 @@ } } +/** + * Match content + */ +static void check_match(Service_T s) { + Match_T ml; + char line[STRLEN]; + FILE *file; + int regex_return; + int inode_checked=FALSE; + + ASSERT(s && s->matchlist); + + while (TRUE) { + /* did inode change -> read position = 0 */ + if((inode_checked==FALSE) && (s->inf->st_ino != s->inf->st_ino_prev)) { + s->inf->readpos= 0; + } + inode_checked= TRUE; + + /* did file decrease (readpos > file_size) -> read position = 0 */ + if(s->inf->readpos > s->inf->st_size) { + s->inf->readpos= 0; + } + + /* Do we need to match? (readpos < file_size) */ + if(!(s->inf->readpos < s->inf->st_size)){ + break; + } + + /* Open the file */ + if(NULL==(file=fopen(s->path, "r"))) { + /* We can't open the file */ + /* ==> ERROR */ + break; + } + + /* Seek to the read position */ + if (fseek(file, s->inf->readpos, SEEK_SET)!=0) { + /* We can not seek to the read position */ + /* ==> ERROR */ + fclose(file); + break; + } + + if(NULL==fgets(line, STRLEN-1, file)) { + /* We can not read the content! */ + /* ==> ERROR */ + fclose(file); + break; + } + + /* Close the file */ + fclose(file); + + /* Empty line? Should not happen... but who knows */ + if (strlen(line) == 0) { + /* ==> ERROR */ + break; + } + + /* Complete line oder just beginning? (igore full buffers) */ + if ((strlen(line)<(STRLEN-1)) && (line[strlen(line)-1] != '\n')) { + /* we gonna read it next time */ + break; + } + + for(ml= s->matchlist; ml; ml= ml->next) { + regex_return=regexec(ml->regex_comp, + line, + 0, + NULL, + 0); + + if(regex_return==0) { + /* We match! */ + Event_post(s, EVENT_MATCH, TRUE, ml->action, + "'%s' content line matches regular expression", + s->name); + + /* ==> more talkative! */ + } else { + DEBUG("FILE: Regular expression does not match on content line\n"); + } + } + + /* Set read position to the end of last read */ + s->inf->readpos+=strlen(line); + } +} /** * Device test