monit-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

initial patch for device/file/directory stuff


From: Martin Pala
Subject: initial patch for device/file/directory stuff
Date: Wed, 23 Apr 2003 11:02:03 +0200
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3) Gecko/20030314

Hi,

there's initial patch for device/file and directory monitoring.

It isn't yet completed and has lot of issues, for example:

- documentation
- cervlet reports cleanup and extension
- configuration options filtering (support only appropriate subset of options for different types of monitoring tasks) - file/directory monitoring tasks extension ('size' test, etc.) - current patch is concentrated on device tests - port/test of get_fsusage() and get_device() functions for FreeBSD, HP/UX, AIX, MACOSX (present code tested on linux and solaris only, i don't have access to other systems)


Happy Easter :)

Martin

diff -Naur monit.20030423.base/CHANGES.txt monit.20030423/CHANGES.txt
--- monit.20030423.base/CHANGES.txt     Sun Mar  9 15:25:26 2003
+++ monit.20030423/CHANGES.txt  Wed Apr 23 10:47:46 2003
@@ -1,8 +1,8 @@
-                        CHANGES version 3.3
+                        CHANGES version 4.0
 
             This file summarizes changes made since 1.0
 
-Version 3.3
+Version 4.0
 
 *  This release utilize a state file to save significant process data.
    This allows data to be persistent and survive a monit reload and
@@ -11,6 +11,9 @@
 
 *  Fixes of monit rc script and monit.spec
 
+*  Support for device checks. Monit is able to watch space and inodes
+   and do custom action in the case of problem.
+
 
 Version 3.2
 
diff -Naur monit.20030423.base/Makefile.in monit.20030423/Makefile.in
--- monit.20030423.base/Makefile.in     Fri Feb 14 10:20:05 2003
+++ monit.20030423/Makefile.in  Wed Apr 23 10:47:46 2003
@@ -68,7 +68,7 @@
 YACC           = @YACC@
 
 LINKFLAGS      = @LDFLAGS@
-CFLAGS         = @CFLAGS@ $(DEFINES) @CPPFLAGS@ $(INCDIR) 
+CFLAGS         = @CFLAGS@ $(DEFINES) @CPPFLAGS@ $(INCDIR)
 LEXFLAGS       = -i
 YACCFLAGS      = -dt
 
diff -Naur monit.20030423.base/configure.ac monit.20030423/configure.ac
--- monit.20030423.base/configure.ac    Mon Mar 10 14:13:47 2003
+++ monit.20030423/configure.ac Wed Apr 23 10:47:46 2003
@@ -7,7 +7,7 @@
 AC_PREREQ([2.53])
 
 # Init autoconf and automake
-AC_INIT([monit], [3.3], address@hidden)
+AC_INIT([monit], [4.0], address@hidden)
 
 # Package info
 AC_REVISION([$Revision: 1.23 $])
@@ -48,7 +48,7 @@
 AC_HEADER_SYS_WAIT
 AC_HEADER_STAT
 AC_HEADER_TIME
-AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h netdb.h netinet/in.h string.h 
strings.h sys/ioctl.h unistd.h sys/socket.h syslog.h sys/loadavg.h asm/param.h 
limits.h stropts.h getopt.h sys/filio.h string.h sys/time.h errno.h])
+AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h netdb.h netinet/in.h string.h 
strings.h sys/ioctl.h unistd.h sys/socket.h syslog.h sys/loadavg.h asm/param.h 
limits.h stropts.h getopt.h sys/filio.h string.h sys/time.h errno.h sys/vfs.h 
sys/statvfs.h mntent.h sys/mnttab.h])
 
 # Check for types.
 AC_TYPE_MODE_T
@@ -82,6 +82,8 @@
 AC_FUNC_MALLOC
 AC_FUNC_STAT
 AC_FUNC_STRFTIME
+AC_CHECK_FUNCS(statfs)
+AC_CHECK_FUNCS(statvfs)
 
 # Find the right directory to put the root-mode PID file in
 AC_MSG_CHECKING([pid file location])
diff -Naur monit.20030423.base/files.c monit.20030423/files.c
--- monit.20030423.base/files.c Mon Mar 10 14:13:47 2003
+++ monit.20030423/files.c      Wed Apr 23 10:47:46 2003
@@ -47,10 +47,31 @@
 #include <fcntl.h>
 #endif
 
+#ifdef HAVE_SYS_VFS_H
+# include <sys/vfs.h>
+#endif
+
+#ifdef HAVE_SYS_STATVFS_H
+# include <sys/statvfs.h>
+#endif
+
+#ifdef HAVE_MNTENT_H
+#include <mntent.h>
+#endif
+
+#ifdef HAVE_SYS_MNTTAB_H
+# include <sys/mnttab.h>
+#endif
+
 
 #include "monitor.h"
 
 
+#if defined HAVE_STATVFS
+#define statfs statvfs
+#endif
+
+
 /**
  *  Utilities used for managing files used by monit.
  *
@@ -370,5 +391,143 @@
 
   return TRUE;
 
+}
+
+
+/**
+ * This function validates if given object is valid for filesystem
+ * informations statistics. Valid objects are file or directory that
+ * is part of requested filesystem or block special device. In the
+ * case of file or directory the result is original object, in the
+ * case of block special device mountpoint is returned. In any case,
+ * filesystem must be mounted.
+ * @param path String to store result
+ * @param path_length Defines max. length of the resulting string
+ * @param object Identifies appropriate device object
+ * @return NULL in the case of failure otherwise pointer to
+ * resulting path
+ */
+char *get_device(char *path, unsigned path_length, char *object) { 
+
+  struct stat buf;
+
+  ASSERT(path && object);
+
+  if(stat(object, &buf) != 0) {
+    log("%s: Cannot stat '%s' -- %s\n", prog, object, STRERROR);
+    return NULL;
+  }
+
+  memset(path, '\0', path_length);
+
+  if(S_ISREG(buf.st_mode) || S_ISDIR(buf.st_mode)) {
+
+    return strncpy(path, object, path_length-1);
+
+  } else if(S_ISBLK(buf.st_mode)) {
+
+    FILE *mntfd;
+
+    #ifdef HAVE_MTAB
+
+    struct mntent *mnt;
+
+    if((mntfd= setmntent("/etc/mtab", "r")) == NULL) {
+      log("%s: Cannot open /etc/mtab file", prog);
+      return NULL;
+    }
+
+    /* Last match is significant */
+    while((mnt= getmntent(mntfd)) != NULL) {
+
+      if(is(object, mnt->mnt_fsname))
+        strncpy(path, mnt->mnt_dir, path_length-1);
+
+    }
+
+    endmntent(mntfd);
+
+    #elif defined HAVE_MNTTAB
+
+    struct mnttab mnt;
+
+    if((mntfd= fopen("/etc/mnttab", "r")) == NULL) {
+      log("%s: Cannot open /etc/mnttab file", prog);
+      return NULL;
+    }
+
+    /* Last match is significant */
+    while(getmntent(mntfd, &mnt) == 0) {
+
+      if(is(object, mnt.mnt_special))
+        strncpy(path, mnt.mnt_mountp, path_length-1);
+
+    }
+
+    fclose(mntfd);
+
+    #else
+
+    log("%s: Unsupported mounted filesystem information method", prog);
+    return NULL;
+
+    #endif
+
+    return path;
+
+  }
+
+  log("%s: Not file, directory or block special device: '%s'", prog, object);
+
+  return NULL;
+
+}
+
+
+/**
+ * Filesystem usage statistics
+ * @param object Identifies requested device
+ * @param buf Information structure where resulting data will be stored
+ * @return TRUE if informations were succesfully read otherwise FALSE
+ */
+int get_fsusage(char *object, DeviceInfo_T buf) { 
+
+  #if (defined HAVE_STATFS) || (defined HAVE_STATVFS)
+
+  struct statfs usage;
+
+  #else
+
+  log("%s: Unsupported filesystem informations gathering method\n", prog);
+
+  return FALSE;
+
+  #endif
+
+  char path[STRLEN];
+
+  ASSERT(object);
+  ASSERT(buf);
+
+  if(!get_device(path, STRLEN, object)) {
+    log("%s: Error looking for filesystem '%s'\n", prog, object);
+    return FALSE;
+  }
+
+  if(statfs(path, &usage) != 0) {
+    log("%s: Error getting usage statistics for device '%s' -- %s\n",
+       prog, object, STRERROR);
+    return FALSE;
+  }
+
+  buf->f_bsize=           usage.f_bsize;
+  buf->f_blocks=          usage.f_blocks;
+  buf->f_blocksfree=      usage.f_bavail;
+  buf->f_blocksfreetotal= usage.f_bfree;
+  buf->f_files=           usage.f_files;
+  buf->f_filesfree=       usage.f_ffree;
+
+  return TRUE;
+
 }
 
diff -Naur monit.20030423.base/gc.c monit.20030423/gc.c
--- monit.20030423.base/gc.c    Fri Mar  7 15:24:05 2003
+++ monit.20030423/gc.c Wed Apr 23 10:47:46 2003
@@ -33,6 +33,7 @@
 static void _gcpcl(Checksum_T*);
 static void _gcpql(Resource_T*);
 static void _gcppil(ProcInfo_T*);
+static void _gcpdil(DeviceInfo_T*);
 static void _gcptl(Timestamp_T*);
 static void _gcpdl(Dependant_T *d);
 
@@ -97,6 +98,12 @@
 
   }
   
+  if((*p)->devinfo) {
+
+    _gcpdil(&(*p)->devinfo);
+
+  }
+  
   if((*p)->timestamplist) {
     
     _gcptl(&(*p)->timestamplist);
@@ -110,7 +117,7 @@
   }
 
   free((*p)->name);
-  free((*p)->pidfile);
+  free((*p)->path);
   free((*p)->group);
   if((*p)->start) {
     for(i= 0; (*p)->start->arg[i]; i++)
@@ -234,6 +241,16 @@
 
 }
 
+
+static void _gcpdil(DeviceInfo_T *di) {
+
+  ASSERT(di);
+
+  free(*di);
+  *di= NULL;
+
+}
+
 
 static void _gcptl(Timestamp_T *p) {
   
diff -Naur monit.20030423.base/http/cervlet.c monit.20030423/http/cervlet.c
--- monit.20030423.base/http/cervlet.c  Fri Feb 14 09:22:33 2003
+++ monit.20030423/http/cervlet.c       Wed Apr 23 10:47:46 2003
@@ -66,6 +66,10 @@
 static void doGet(HttpRequest, HttpResponse);
 static void doPost(HttpRequest, HttpResponse);
 static void do_home(HttpRequest, HttpResponse);
+static void do_home_device(HttpRequest, HttpResponse);
+static void do_home_directory(HttpRequest, HttpResponse);
+static void do_home_file(HttpRequest, HttpResponse);
+static void do_home_process(HttpRequest, HttpResponse);
 static void do_about(HttpRequest, HttpResponse);
 static void not_found(HttpRequest, HttpResponse);
 static void do_runtime(HttpRequest, HttpResponse);
@@ -73,7 +77,11 @@
 static void handle_action(HttpRequest, HttpResponse);
 static void print_status(Process_T, HttpResponse res);
 static void is_monit_running(HttpRequest, HttpResponse);
-static void do_process(HttpRequest, HttpResponse, char *);
+static void do_task(HttpRequest, HttpResponse, char *);
+static void do_task_device(HttpRequest, HttpResponse, Process_T);
+static void do_task_directory(HttpRequest, HttpResponse, Process_T);
+static void do_task_file(HttpRequest, HttpResponse, Process_T);
+static void do_task_process(HttpRequest, HttpResponse, Process_T);
 
 extern ssl_server_connection * mySSLServerConnection;
 
@@ -208,117 +216,32 @@
 
 static void do_home(HttpRequest req, HttpResponse res) {
 
-  int on= TRUE;
-  struct myprocess *p;
   char *uptime= get_process_uptime(Run.pidfile);
  
-  if ( Run.doprocess ) {
-  HEAD("", Run.polltime)
-      out_print(res,
-"<table cellspacing=\"0\" cellpadding=\"5\" width=\"100%%\" border=\"0\">"
-" <tr bgcolor=\"#BBDDFF\">"
-"  <td colspan=2 valign=\"top\" align=\"left\" bgcolor=\"#EFF7FF\" 
width=\"100%%\">"
-"  <br><h2 align=\"center\">Monit Process Manager</h2>"
-"  <p align=\"center\">Monit is <a href='/_runtime'>running</a> on %s "
-"  with <i>uptime, %s</i> and monitoring:</p><br>"
-"  </td>"
-" </tr>"
-"</table>"
-"<table cellspacing=\"0\" cellpadding=\"0\" width=\"100%%\" border=\"0\">"
-"  <tr valign=\"middle\" bgcolor=\"#6F6F6F\">"
-"    <td><img src=\"/_pixel\" width=\"1\" height=\"1\" alt=\"\"></td>"
-"  </tr>"
-"</table>"
-"<br><p>&nbsp;</p>"
-"<table cellspacing=0 cellpadding=3 border=0 width=\"70%\">"
-"<tr><td><h3><b>Server</b></h3></td>"
-"<td align=\"right\"><h3><b>Status</b></h3></td>"
-"<td align=\"right\"><h3><b>Uptime</b></h3></td>"
-"<td align=\"right\"><h3><b>CPU</b></h3></td>"
-"<td align=\"right\"><h3><b>Memory</b></h3></td>"
-"</tr>"
-"<tr><td>&nbsp;</td><td>&nbsp;</td></tr>", Run.localhostname, uptime);
-  } else {
   HEAD("", Run.polltime)
-      out_print(res,
-"<table cellspacing=\"0\" cellpadding=\"5\" width=\"100%%\" border=\"0\">"
-" <tr bgcolor=\"#BBDDFF\">"
-"  <td colspan=2 valign=\"top\" align=\"left\" bgcolor=\"#EFF7FF\" 
width=\"100%%\">"
-"  <br><h2 align=\"center\">Monit Process Manager</h2>"
-"  <p align=\"center\">Monit is <a href='/_runtime'>running</a> on %s "
-"  with <i>uptime, %s</i> and monitoring:</p><br>"
-"  </td>"
-" </tr>"
-"</table>"
-"<table cellspacing=\"0\" cellpadding=\"0\" width=\"100%%\" border=\"0\">"
-"  <tr valign=\"middle\" bgcolor=\"#6F6F6F\">"
-"    <td><img src=\"/_pixel\" width=\"1\" height=\"1\" alt=\"\"></td>"
-"  </tr>"
-"</table>"
-"<br><p>&nbsp;</p>"
-"<table cellspacing=0 cellpadding=3 border=0 width=\"70%\">"
-"<tr><td><h3><b>Server</b></h3></td>"
-"<td align=\"right\"><h3><b>Status</b></h3></td></tr>"
-"<tr><td>&nbsp;</td><td>&nbsp;</td></tr>", Run.localhostname, uptime);
-  }
+  out_print(res,
+    "<table cellspacing=\"0\" cellpadding=\"5\" width=\"100%%\" border=\"0\">"
+    " <tr bgcolor=\"#BBDDFF\">"
+    "  <td colspan=2 valign=\"top\" align=\"left\" bgcolor=\"#EFF7FF\" 
width=\"100%%\">"
+    "  <br><h2 align=\"center\">Monit Process Manager</h2>"
+    "  <p align=\"center\">Monit is <a href='/_runtime'>running</a> on %s "
+    "  with <i>uptime, %s</i> and monitoring:</p><br>"
+    "  </td>"
+    " </tr>"
+    "</table>"
+    "<table cellspacing=\"0\" cellpadding=\"0\" width=\"100%%\" border=\"0\">"
+    "  <tr valign=\"middle\" bgcolor=\"#6F6F6F\">"
+    "    <td><img src=\"/_pixel\" width=\"1\" height=\"1\" alt=\"\"></td>"
+    "  </tr>"
+    "</table>", Run.localhostname, uptime);
 
   free(uptime);
-  
-  for (p= processlist; p; p= p->next) {
-    
-    int isrunning= is_process_running(p);
-    char *uptime= get_process_uptime(p->pidfile);
-
-    if ( Run.doprocess ) {
-      ProcInfo_T pi= p->procinfo;
-      if ( isrunning ) {
-       out_print(res,"<tr %s><td><a href='/%s'>%s</a></td><td align=\"right\">"
-                 "%s</td><td align=\"right\">%s</td>"
-                 "<td align=\"right\">%.1f%%</td>"
-                 "<td align=\"right\">%.1f%% [%ldkB]</td></tr>",
-                 on?"bgcolor=\"#EFEFEF\"":"",
-                 p->name, p->name,
-                 p->has_checksum_error?
-                 "<font color='#ff0000'>Cheksum Error</font>": 
-                 isrunning?
-                 "<font color=green>running</font>":
-                 "<font color=red>not running</font>",
-                 uptime,
-                 pi->cpu_percent/10.0,
-                 pi->mem_percent/10.0,pi->mem_kbyte
-                 );
-      } else {
-       out_print(res,"<tr %s><td><a href='/%s'>%s</a></td>"
-                 "<td align=\"right\">%s</td>"
-                 "<td align=\"right\">-</td>"
-                 "<td align=\"right\">- </td>"
-                 "<td align=\"right\">- [-]</td></tr>",
-                 on?"bgcolor=\"#EFEFEF\"":"",
-                 p->name, p->name,
-                 p->has_checksum_error?
-                 "<font color='#ff0000'>Cheksum Error</font>": 
-                 "<font color=red>not running</font>"
-                 );
-      }
-    } else {
-      out_print(res,"<tr %s><td><a href='/%s'>%s</a></td><td align=\"right\">"
-               "%s %s</td></tr>",
-               on?"bgcolor=\"#EFEFEF\"":"",
-               p->name, p->name,
-               p->has_checksum_error?
-               "<font color='#ff0000'>Cheksum Error</font>":   
-               isrunning?
-               "<font color=green>running</font>":
-               "<font color=red>not running</font>",
-               isrunning?uptime:"");
-    }
 
-
-    on= on?FALSE:TRUE;
-    free(uptime);
-    
-  }
-  out_print(res, "</table>");
+  do_home_process(req, res);
+  do_home_device(req, res);
+  do_home_file(req, res);
+  do_home_directory(req, res);
+  
   FOOT
       
 }
@@ -533,7 +456,7 @@
     
     if(action) {
       
-      struct myprocess *p= get_process(name);
+      Process_T p= get_process(name);
       
       if( is(action, "start") ) {
 
@@ -599,7 +522,7 @@
     }
     
     LOCK(Run.mutex)
-       do_process(req, res, name);
+       do_task(req, res, name);
     END_LOCK;
     
   } else {
@@ -615,249 +538,37 @@
 }
 
 
-static void do_process(HttpRequest req, HttpResponse res, char *name) {
+static void do_task(HttpRequest req, HttpResponse res, char *name) {
   
-  struct myprocess *p= get_process(name);
-  int run= is_process_running(p);
+  Process_T p= get_process(name);
 
   HEAD(name, 1000)
-  out_print(res,
-    "<p><br><h3>Process status</h3><br>");
-  out_print(res,"<table cellspacing=0 cellpadding=3 border=1 width=\"90%\">"
-           "<tr><td width=\"30%\"><b>Parameter</b></td><td 
width=\"70%\"><b>Value</b></td></tr>");
-  out_print(res,
-    "<tr><td>Name</a></td><td>%s</td></tr>", p->name);
-  out_print(res,
-    "<tr><td>Group</a></td><td><font color='#0000ff'>%s</font></td></tr>",
-           p->group?p->group:"(not defined)");
-  out_print(res,
-    "<tr><td>Process id </a></td><td>%d</td></tr>", run);
-  out_print(res,
-    "<tr><td>Process status</a></td><td>%s %s</td></tr>",
-           run?"<font color='#00ff00'>Running</font>":
-           "<font color='#ff0000'>Not Running</font>",
-           p->has_checksum_error?
-           "<font color='#ff0000'><b>Checksum error!</b></font>":"");
-  out_print(res,
-    "<tr><td>Pid file</a></td><td>%s</td></tr>",
-           p->pidfile);
-  out_print(res,
-           "<tr><td>Monitoring mode</a></td><td>%s</td></tr>",
-           modenames[p->mode]);
-  out_print(res,
-           "<tr><td>Monitoring status</a></td><td>%s</td></tr>",
-           statusnames[p->do_validate]);
-  out_print(res,
-    "<tr><td>Start program</a></td><td>%s</td></tr>",
-           p->start?p->start->arg[0]:"(not defined)");
-  out_print(res,
-    "<tr><td>Stop program</a></td><td>%s</td></tr>",
-           p->stop?p->stop->arg[0]:"(not defined)");
-  {
-    struct mychecksum *c;
-    for(c= p->checksumlist; c; c= c->next)
-       out_print(res, "<tr><td>Associated checksum</a></td><td>%s %s</td>"
-                 "</tr>", c->md5, c->file);
-  }
-  {
-    Dependant_T d;
-
-    for(d= p->dependantlist; d; d= d->next) {
-      if(d->dependant != NULL) {
-       out_print(res,"<tr><td>Depends on Process </a></td>"
-                 "<td> <a href=%s> %s </a></td></tr>",
-                 d->dependant, d->dependant);
-      }
-    }
-  }
-  if ( Run.doprocess ) {
-    ProcInfo_T pi= p->procinfo;
-
-    out_print(res,
-             "<tr><td>CPU usage</a></td><td>%.1f%%</td></tr>",
-             pi->cpu_percent/10.0);
-    out_print(res,
-             "<tr><td>Memory usage</a></td><td>%.1f%% [%ldkB]</td></tr>",
-             pi->mem_percent/10.0,pi->mem_kbyte);
-  }
-  {
-    Port_T n;
-    for(n= p->portlist; n; n= n->next) {
-
-      if ( n->family == AF_INET ) {
-
-       if ( n->ssl != NULL ) {
-
-         out_print(res,
-                   "<tr><td>Host:Port</a></td><td>%s:%d%s [%s via 
SSL]</td></tr>",
-                   n->hostname, n->port, n->request?n->request:"",
-                   n->protocol->name);
-         
-         if ( n->certmd5 != NULL ) {
-
-           out_print(res,
-                     "<tr><td>Server certificate md5 
sum</a></td><td>%s</td></tr>",
-                     n->certmd5);
-
-         }
-
-
-       } else {
-
-         out_print(res,
-                   "<tr><td>Host:Port</a></td><td>%s:%d%s [%s]</td></tr>",
-                   n->hostname, n->port, n->request?n->request:"",
-                   n->protocol->name);
-
-       }
-
-      } else if ( n->family == AF_UNIX ) {
-
-       out_print(res,
-               "<tr><td>Unix Socket</a></td><td>%s [%s]</td></tr>",
-               n->pathname, n->protocol->name);
-
-      }
-    }
-  }
-  {
-    struct mytimestamp *t;
-    for(t= p->timestamplist; t; t= t->next)
-       out_print(res,
-         "<tr><td>Associated timestamp</a></td>"
-          "<td>If %s %s %d second(s) then %s</td></tr>",
-         t->pathname, operatornames[t->operator], t->time, 
actionnames[t->action]);
-  }
-  {
-    Resource_T q;
 
-    for (q= p->resourcelist; q; q= q->next) {
-      switch (q->resource_id) {
+    switch (p->task) {
 
-      case RESOURCE_ID_CPU_PERCENT: 
+    case TASK_DEVICE:
+      do_task_device(req, res, p);
+      break;
+
+    case TASK_DIRECTORY:
+      do_task_directory(req, res, p);
+      break;
+
+    case TASK_FILE:
+      do_task_file(req, res, p);
+      break;
+
+    case TASK_PROCESS:
+      do_task_process(req, res, p);
+      break;
 
-       out_print(res,"<tr><td>CPU usage limit</a></td>"
-                 "<td>If %s %.1f%% for %d cycle(s) then %s</td></tr>", 
-                 operatornames[q->operator],
-                 q->limit/10.0, q->max_cycle, 
-                 actionnames[q->action]);
-       break;
+    default:
+      break;
 
-      case RESOURCE_ID_MEM_PERCENT: 
-       
-       out_print(res,"<tr><td>Memory usage limit</a></td>"
-                 "<td>If %s %.1f%% for %d cycle(s) then %s</td></tr>", 
-                 operatornames[q->operator],
-                 q->limit/10.0, q->max_cycle, 
-                 actionnames[q->action]);
-       break;
-       
-      case RESOURCE_ID_MEM_KBYTE: 
-      
-       out_print(res,"<tr><td>Memory amount limit</a></td>"
-                 "<td>If %s %ld for %d cycle(s) then %s</td></tr>", 
-                 operatornames[q->operator],
-                 q->limit, q->max_cycle, 
-                 actionnames[q->action]);
-       break;
-       
-      case RESOURCE_ID_LOAD1: 
-      
-       out_print(res,"<tr><td>Load average (1min)</a></td>"
-                 "<td>If %s %.1f for %d cycle(s) then %s</td></tr>", 
-                 operatornames[q->operator],
-                 q->limit/10.0, q->max_cycle, 
-                 actionnames[q->action]);
-       break;
-       
-      case RESOURCE_ID_LOAD5: 
-      
-       out_print(res,"<tr><td>Load average (5min)</a></td>"
-                 "<td>If %s %.1f for %d cycle(s) then %s</td></tr>", 
-                 operatornames[q->operator],
-                 q->limit/10.0, q->max_cycle, 
-                 actionnames[q->action]);
-       break;
-       
-      case RESOURCE_ID_LOAD15: 
-       out_print(res,"<tr><td>Load average (15min)</a></td>"
-                 "<td>If %s %.1f for %d cycle(s) then %s</td></tr>", 
-                 operatornames[q->operator],
-                 q->limit/10.0, q->max_cycle, 
-                 actionnames[q->action]);
-       break;
-       
-      }    
-    }
-  }
-  out_print(res,
-           "<tr><td>Check process</a></td><td>Every %d cycle</td></tr>",
-           p->every?p->every:1);
-  out_print(res,
-    "<tr><td>Timeout</a></td><td>Timeout if %d restart within %d cycles"
-    "</td></tr>", p->to_start, p->to_cycle);
-  {
-    Mail_T r;
-    for(r= p->maillist; r; r= r->next) {
-      out_print(res,
-        "<tr bgcolor=\"#EFEFEF\"><td>Alert mail to</a></td><td>%s</td></tr>",
-               r->to?r->to:"");
-      out_print(res,
-       "<tr><td>Alert from</a></td><td>%s</td></tr>",
-              r->from?r->from:"(default)");
-      out_print(res,
-        "<tr><td>Alert subject</a></td><td>%s</td></tr>",
-             r->subject?r->subject:"(default)");
-      out_print(res,
-       "<tr><td>Alert message</a></td><td>%s</td></tr>",
-             r->message?r->message:"(default)");
-      out_print(res,
-       "<tr><td>Alert on timeout</a></td><td>%s</td></tr>",
-               r->alert_on_timeout?"yes":"no");
-      out_print(res,
-       "<tr><td>Alert on restart</a></td><td>%s</td></tr>",
-               r->alert_on_restart?"yes":"no");
-      out_print(res,
-       "<tr><td>Alert on checksum</a></td><td>%s</td></tr>",
-               r->alert_on_checksum?"yes":"no");
-      out_print(res,
-       "<tr><td>Alert on exceeded resource</a></td><td>%s</td></tr>",
-               r->alert_on_resource?"yes":"no");
-      out_print(res,
-       "<tr><td>Alert on stop</a></td><td>%s</td></tr>",
-               r->alert_on_stop?"yes":"no");
-      out_print(res,
-       "<tr><td>Alert on timestamp</a></td><td>%s</td></tr>",
-               r->alert_on_timestamp?"yes":"no");
     }
-  }
-  out_print(res, "</table>");
-  out_print(res, "<table cellspacing=16><tr nowrap><td><font size=+1>");
-  /* Start program */
-  if(p->start)
-     out_print(res, 
-       "<td><form method=GET action=/%s>"
-       "<input type=hidden value='start' name=action>"
-       "<input type=submit value='Start program' style='font-size: 
12pt'></font>"
-       "</form></td>", name);
-   /* Stop program */
-  if(p->stop)
-    out_print(res, 
-       "<td><form method=GET action=/%s>"
-       "<input type=hidden value='stop' name=action>"
-       "<input type=submit value='Stop program' style='font-size: 
12pt'></font>"
-       "</form></td>", name);
-  if(p->start && p->stop)
-    out_print(res, 
-       "<td><form method=GET action=/%s>"
-       "<input type=hidden value='restart' name=action>"
-       "<input type=submit value='Restart program' style='font-size: 
12pt'></font>"
-       "</form></td>", name);
-  out_print(res, "</tr></table>");
 
   FOOT
 
-  
 }
 
 
@@ -870,7 +581,7 @@
   
   if((pid= is_process_running(p))) {
     
-    char *uptime= get_process_uptime(p->pidfile);
+    char *uptime= get_process_uptime(p->path);
     ProcInfo_T pi= p->procinfo;
 
     if( Run.httpdssl ) {
@@ -961,3 +672,858 @@
   
 }
 
+
+static void do_home_process(HttpRequest req, HttpResponse res) {
+
+  int on= TRUE;
+  int header= TRUE;
+  Process_T p;
+
+  for (p= processlist; p; p= p->next) {
+
+    int isrunning;
+    char *uptime;
+
+    if(p->task != TASK_PROCESS) continue;
+
+    if(header) {
+
+      if ( Run.doprocess ) {
+
+        out_print(res,
+          "<br><p>&nbsp;</p>"
+          "<table cellspacing=0 cellpadding=3 border=0 width=\"70%\">"
+          "<tr><td><h3><b>Server</b></h3></td>"
+          "<td align=\"right\"><h3><b>Status</b></h3></td>"
+          "<td align=\"right\"><h3><b>Uptime</b></h3></td>"
+          "<td align=\"right\"><h3><b>CPU</b></h3></td>"
+          "<td align=\"right\"><h3><b>Memory</b></h3></td>"
+          "</tr>"
+          "<tr><td>&nbsp;</td><td>&nbsp;</td></tr>");
+
+      } else {
+
+        out_print(res,
+          "<table cellspacing=0 cellpadding=3 border=0 width=\"70%\">"
+          "<tr><td><h3><b>Server</b></h3></td>"
+          "<td align=\"right\"><h3><b>Status</b></h3></td></tr>"
+          "<tr><td>&nbsp;</td><td>&nbsp;</td></tr>");
+
+      }
+
+      header= FALSE;
+
+    }
+
+    isrunning= is_process_running(p);
+    uptime= get_process_uptime(p->path);
+
+    if ( Run.doprocess ) {
+      ProcInfo_T pi= p->procinfo;
+      if ( isrunning ) {
+        out_print(res,"<tr %s><td><a href='/%s'>%s</a></td><td 
align=\"right\">"
+                  "%s</td><td align=\"right\">%s</td>"
+                  "<td align=\"right\">%.1f%%</td>"
+                  "<td align=\"right\">%.1f%% [%ldkB]</td></tr>",
+                  on?"bgcolor=\"#EFEFEF\"":"",
+                  p->name, p->name,
+                  p->has_checksum_error?
+                  "<font color='#ff0000'>Cheksum Error</font>":
+                  isrunning?
+                  "<font color=green>running</font>":
+                  "<font color=red>not running</font>",
+                  uptime,
+                  pi->cpu_percent/10.0,
+                  pi->mem_percent/10.0,pi->mem_kbyte
+                  );
+      } else {
+        out_print(res,"<tr %s><td><a href='/%s'>%s</a></td>"
+                  "<td align=\"right\">%s</td>"
+                  "<td align=\"right\">-</td>"
+                  "<td align=\"right\">- </td>"
+                  "<td align=\"right\">- [-]</td></tr>",
+                  on?"bgcolor=\"#EFEFEF\"":"",
+                  p->name, p->name,
+                  p->has_checksum_error?
+                  "<font color='#ff0000'>Cheksum Error</font>":
+                  "<font color=red>not running</font>"
+                  );
+      }
+    } else {
+      out_print(res,"<tr %s><td><a href='/%s'>%s</a></td><td align=\"right\">"
+                "%s %s</td></tr>",
+                on?"bgcolor=\"#EFEFEF\"":"",
+                p->name, p->name,
+                p->has_checksum_error?
+                "<font color='#ff0000'>Cheksum Error</font>":
+                isrunning?
+                "<font color=green>running</font>":
+                "<font color=red>not running</font>",
+                isrunning?uptime:"");
+    }
+
+    on= on?FALSE:TRUE;
+    free(uptime);
+
+  }
+
+  out_print(res, "</table>");
+
+}
+
+
+static void do_home_device(HttpRequest req, HttpResponse res) {
+
+  int on= TRUE;
+  int header= TRUE;
+  Process_T p;
+
+  for (p= processlist; p; p= p->next) {
+
+    if( (p->task != TASK_DEVICE) || !get_fsusage(p->path, p->devinfo) ) 
continue;
+
+    if(header) {
+
+      out_print(res,
+        "<br><p>&nbsp;</p>"
+        "<table cellspacing=0 cellpadding=3 border=0 width=\"70%\">"
+        "<tr><td><h3><b>Device</b></h3></td>"
+        "<td align=\"right\"><h3><b>Space</b></h3></td>"
+        "<td align=\"right\"><h3><b>Inodes</b></h3></td>"
+        "</tr>"
+        "<tr><td>&nbsp;</td><td>&nbsp;</td></tr>");
+
+      header= FALSE;
+
+    }
+
+    out_print(res,
+      "<tr %s>"
+      "<td><a href='/%s'>%s</a></td>"
+      "<td align=\"right\">%.1f%% [%.1f MB]</td>"
+      "<td align=\"right\">%.1f%% [%d files]</td>"
+      "</tr>",
+      on?"bgcolor=\"#EFEFEF\"":"",
+      p->name, p->name,
+      (float) 100 * (p->devinfo->f_blocks - p->devinfo->f_blocksfree) / 
p->devinfo->f_blocks,
+      (float) (p->devinfo->f_blocks - p->devinfo->f_blocksfree) / 1048576 * 
p->devinfo->f_bsize,
+      (float) 100 * (p->devinfo->f_files - p->devinfo->f_filesfree) / 
p->devinfo->f_files,
+      p->devinfo->f_files - p->devinfo->f_filesfree
+      );
+
+    on= on?FALSE:TRUE;
+
+  }
+
+  out_print(res, "</table>");
+
+}
+
+
+static void do_home_file(HttpRequest req, HttpResponse res) {
+
+  int on= TRUE;
+  int header= TRUE;
+  Process_T p;
+
+  for (p= processlist; p; p= p->next) {
+
+    if(p->task != TASK_FILE) continue;
+
+    if(header) {
+
+      out_print(res,
+        "<br><p>&nbsp;</p>"
+        "<table cellspacing=0 cellpadding=3 border=0 width=\"70%\">"
+        "<tr><td><h3><b>File</b></h3></td>"
+        "</tr>"
+        "<tr><td>&nbsp;</td><td>&nbsp;</td></tr>");
+
+      header= FALSE;
+
+    }
+
+    out_print(res,
+      "<tr %s>"
+      "<td><a href='/%s'>%s</a></td>"
+      "</tr>",
+      on?"bgcolor=\"#EFEFEF\"":"",
+      p->name, p->name
+      );
+
+    on= on?FALSE:TRUE;
+
+  }
+
+  out_print(res, "</table>");
+
+}
+
+
+static void do_home_directory(HttpRequest req, HttpResponse res) {
+
+  int on= TRUE;
+  int header= TRUE;
+  Process_T p;
+
+  for (p= processlist; p; p= p->next) {
+
+    if(p->task != TASK_DIRECTORY) continue;
+
+    if(header) {
+
+      out_print(res,
+        "<br><p>&nbsp;</p>"
+        "<table cellspacing=0 cellpadding=3 border=0 width=\"70%\">"
+        "<tr><td><h3><b>Directory</b></h3></td>"
+        "</tr>"
+        "<tr><td>&nbsp;</td><td>&nbsp;</td></tr>");
+
+      header= FALSE;
+
+    }
+
+    out_print(res,
+      "<tr %s>"
+      "<td><a href='/%s'>%s</a></td>"
+      "</tr>",
+      on?"bgcolor=\"#EFEFEF\"":"",
+      p->name, p->name
+      );
+
+    on= on?FALSE:TRUE;
+
+  }
+
+  out_print(res, "</table>");
+
+}
+
+
+static void do_task_device(HttpRequest req, HttpResponse res, Process_T p) {
+
+  out_print(res,
+    "<p><br><h3>Device status</h3><br>");
+  out_print(res,"<table cellspacing=0 cellpadding=3 border=1 width=\"90%\">"
+           "<tr><td width=\"30%\"><b>Parameter</b></td><td 
width=\"70%\"><b>Value</b></td></tr>");
+  out_print(res,
+    "<tr><td>Name</a></td><td>%s</td></tr>", p->name);
+  out_print(res,
+    "<tr><td>Group</a></td><td><font color='#0000ff'>%s</font></td></tr>",
+           p->group?p->group:"(not defined)");
+  out_print(res,
+    "<tr><td>Path</a></td><td>%s</td></tr>",
+           p->path);
+  out_print(res,
+           "<tr><td>Monitoring mode</a></td><td>%s</td></tr>",
+           modenames[p->mode]);
+  out_print(res,
+           "<tr><td>Monitoring status</a></td><td>%s</td></tr>",
+           statusnames[p->do_validate]);
+  out_print(res,
+    "<tr><td>Start program</a></td><td>%s</td></tr>",
+           p->start?p->start->arg[0]:"(not defined)");
+  out_print(res,
+    "<tr><td>Stop program</a></td><td>%s</td></tr>",
+           p->stop?p->stop->arg[0]:"(not defined)");
+  {
+    Dependant_T d;
+
+    for(d= p->dependantlist; d; d= d->next) {
+      if(d->dependant != NULL) {
+       out_print(res,"<tr><td>Depends on Task </a></td>"
+                 "<td> <a href=%s> %s </a></td></tr>",
+                 d->dependant, d->dependant);
+      }
+    }
+  }
+
+  out_print(res,
+           "<tr><td>Check task</a></td><td>Every %d cycle</td></tr>",
+           p->every?p->every:1);
+  out_print(res,
+    "<tr><td>Timeout</a></td><td>Timeout if %d restart within %d cycles"
+    "</td></tr>", p->to_start, p->to_cycle);
+  {
+
+    Device_T dl;
+
+    if(p->devicelist && get_fsusage(p->path, p->devinfo)) {
+
+      for(dl= p->devicelist; dl; dl= dl->next) {
+
+        if(dl->resource == RESOURCE_INODE) {
+
+          out_print(res,
+            "<tr><td>Inodes usage limit</a></td><td>if %s %ld %s then 
%s</td></tr>",
+            operatornames[dl->operator],
+            (dl->limit_absolute > -1)?dl->limit_absolute:dl->limit_percent,
+            (dl->limit_absolute > -1)?"":"%",
+            actionnames[dl->action]);
+
+        } else if(dl->resource == RESOURCE_SPACE) {
+
+          out_print(res,
+            "<tr><td>Space usage limit</a></td><td>if %s %ld %s then 
%s</td></tr>",
+            operatornames[dl->operator],
+            (dl->limit_absolute > -1)?dl->limit_absolute:dl->limit_percent,
+            (dl->limit_absolute > -1)?"blocks":"%",
+            actionnames[dl->action]);
+
+        }
+
+      }
+
+    }
+
+  }
+  out_print(res,
+    "<tr><td>Blocks total</a></td><td>%ld [%.1f MB]</td></tr>",
+    p->devinfo->f_blocks,
+    (float) p->devinfo->f_blocks / 1048576 * p->devinfo->f_bsize);
+  out_print(res,
+    "<tr><td>Blocks free for non superuser</a></td><td><font color=green>%ld 
[%.1f MB] [%.1f%%]</font></td></tr>",
+    p->devinfo->f_blocksfree,
+    (float) p->devinfo->f_blocksfree / 1048576 * p->devinfo->f_bsize,
+    (float) 100 * p->devinfo->f_blocksfree / p->devinfo->f_blocks);
+  out_print(res,
+    "<tr><td>Blocks free total</a></td><td>%ld [%.1f MB] [%.1f%%]</td></tr>",
+    p->devinfo->f_blocksfreetotal,
+    (float) p->devinfo->f_blocksfreetotal / 1048576 * p->devinfo->f_bsize,
+    (float) 100 * p->devinfo->f_blocksfreetotal / p->devinfo->f_blocks);
+  out_print(res,
+    "<tr><td>Block size</a></td><td>%ld B</td></tr>",
+    p->devinfo->f_bsize);
+  out_print(res,
+    "<tr><td>Inodes total</a></td><td>%ld</td></tr>",
+    p->devinfo->f_files);
+  out_print(res,
+    "<tr><td>Inodes free</a></td><td><font color=green>%ld 
[%.1f%%]</font></td></tr>",
+    p->devinfo->f_filesfree,
+    (float) 100 * p->devinfo->f_filesfree / p->devinfo->f_files);
+  {
+    Mail_T r;
+    for(r= p->maillist; r; r= r->next) {
+      out_print(res,
+        "<tr bgcolor=\"#EFEFEF\"><td>Alert mail to</a></td><td>%s</td></tr>",
+               r->to?r->to:"");
+      out_print(res,
+       "<tr><td>Alert from</a></td><td>%s</td></tr>",
+              r->from?r->from:"(default)");
+      out_print(res,
+        "<tr><td>Alert subject</a></td><td>%s</td></tr>",
+             r->subject?r->subject:"(default)");
+      out_print(res,
+       "<tr><td>Alert message</a></td><td>%s</td></tr>",
+             r->message?r->message:"(default)");
+      out_print(res,
+       "<tr><td>Alert on timeout</a></td><td>%s</td></tr>",
+               r->alert_on_timeout?"yes":"no");
+      out_print(res,
+       "<tr><td>Alert on restart</a></td><td>%s</td></tr>",
+               r->alert_on_restart?"yes":"no");
+      out_print(res,
+       "<tr><td>Alert on checksum</a></td><td>%s</td></tr>",
+               r->alert_on_checksum?"yes":"no");
+      out_print(res,
+       "<tr><td>Alert on exceeded resource</a></td><td>%s</td></tr>",
+               r->alert_on_resource?"yes":"no");
+      out_print(res,
+       "<tr><td>Alert on stop</a></td><td>%s</td></tr>",
+               r->alert_on_stop?"yes":"no");
+      out_print(res,
+       "<tr><td>Alert on timestamp</a></td><td>%s</td></tr>",
+               r->alert_on_timestamp?"yes":"no");
+    }
+  }
+  out_print(res, "</table>");
+  out_print(res, "<table cellspacing=16><tr nowrap><td><font size=+1>");
+  /* Start program */
+  if(p->start)
+     out_print(res, 
+       "<td><form method=GET action=/%s>"
+       "<input type=hidden value='start' name=action>"
+       "<input type=submit value='Start program' style='font-size: 
12pt'></font>"
+       "</form></td>", p->name);
+   /* Stop program */
+  if(p->stop)
+    out_print(res, 
+       "<td><form method=GET action=/%s>"
+       "<input type=hidden value='stop' name=action>"
+       "<input type=submit value='Stop program' style='font-size: 
12pt'></font>"
+       "</form></td>", p->name);
+  if(p->start && p->stop)
+    out_print(res, 
+       "<td><form method=GET action=/%s>"
+       "<input type=hidden value='restart' name=action>"
+       "<input type=submit value='Restart program' style='font-size: 
12pt'></font>"
+       "</form></td>", p->name);
+  out_print(res, "</tr></table>");
+
+}
+
+
+static void do_task_directory(HttpRequest req, HttpResponse res, Process_T p) {
+
+  out_print(res,
+    "<p><br><h3>Directory status</h3><br>");
+  out_print(res,"<table cellspacing=0 cellpadding=3 border=1 width=\"90%\">"
+           "<tr><td width=\"30%\"><b>Parameter</b></td><td 
width=\"70%\"><b>Value</b></td></tr>");
+  out_print(res,
+    "<tr><td>Name</a></td><td>%s</td></tr>", p->name);
+  out_print(res,
+    "<tr><td>Group</a></td><td><font color='#0000ff'>%s</font></td></tr>",
+           p->group?p->group:"(not defined)");
+  out_print(res,
+    "<tr><td>Path</a></td><td>%s</td></tr>",
+           p->path);
+  out_print(res,
+           "<tr><td>Monitoring mode</a></td><td>%s</td></tr>",
+           modenames[p->mode]);
+  out_print(res,
+           "<tr><td>Monitoring status</a></td><td>%s</td></tr>",
+           statusnames[p->do_validate]);
+  out_print(res,
+    "<tr><td>Start program</a></td><td>%s</td></tr>",
+           p->start?p->start->arg[0]:"(not defined)");
+  out_print(res,
+    "<tr><td>Stop program</a></td><td>%s</td></tr>",
+           p->stop?p->stop->arg[0]:"(not defined)");
+  {
+    Dependant_T d;
+
+    for(d= p->dependantlist; d; d= d->next) {
+      if(d->dependant != NULL) {
+       out_print(res,"<tr><td>Depends on Task </a></td>"
+                 "<td> <a href=%s> %s </a></td></tr>",
+                 d->dependant, d->dependant);
+      }
+    }
+  }
+  out_print(res,
+           "<tr><td>Check task</a></td><td>Every %d cycle</td></tr>",
+           p->every?p->every:1);
+  out_print(res,
+    "<tr><td>Timeout</a></td><td>Timeout if %d restart within %d cycles"
+    "</td></tr>", p->to_start, p->to_cycle);
+  {
+    Mail_T r;
+    for(r= p->maillist; r; r= r->next) {
+      out_print(res,
+        "<tr bgcolor=\"#EFEFEF\"><td>Alert mail to</a></td><td>%s</td></tr>",
+               r->to?r->to:"");
+      out_print(res,
+       "<tr><td>Alert from</a></td><td>%s</td></tr>",
+              r->from?r->from:"(default)");
+      out_print(res,
+        "<tr><td>Alert subject</a></td><td>%s</td></tr>",
+             r->subject?r->subject:"(default)");
+      out_print(res,
+       "<tr><td>Alert message</a></td><td>%s</td></tr>",
+             r->message?r->message:"(default)");
+      out_print(res,
+       "<tr><td>Alert on timeout</a></td><td>%s</td></tr>",
+               r->alert_on_timeout?"yes":"no");
+      out_print(res,
+       "<tr><td>Alert on restart</a></td><td>%s</td></tr>",
+               r->alert_on_restart?"yes":"no");
+      out_print(res,
+       "<tr><td>Alert on checksum</a></td><td>%s</td></tr>",
+               r->alert_on_checksum?"yes":"no");
+      out_print(res,
+       "<tr><td>Alert on exceeded resource</a></td><td>%s</td></tr>",
+               r->alert_on_resource?"yes":"no");
+      out_print(res,
+       "<tr><td>Alert on stop</a></td><td>%s</td></tr>",
+               r->alert_on_stop?"yes":"no");
+      out_print(res,
+       "<tr><td>Alert on timestamp</a></td><td>%s</td></tr>",
+               r->alert_on_timestamp?"yes":"no");
+    }
+  }
+  out_print(res, "</table>");
+  out_print(res, "<table cellspacing=16><tr nowrap><td><font size=+1>");
+  /* Start program */
+  if(p->start)
+     out_print(res, 
+       "<td><form method=GET action=/%s>"
+       "<input type=hidden value='start' name=action>"
+       "<input type=submit value='Start program' style='font-size: 
12pt'></font>"
+       "</form></td>", p->name);
+   /* Stop program */
+  if(p->stop)
+    out_print(res, 
+       "<td><form method=GET action=/%s>"
+       "<input type=hidden value='stop' name=action>"
+       "<input type=submit value='Stop program' style='font-size: 
12pt'></font>"
+       "</form></td>", p->name);
+  if(p->start && p->stop)
+    out_print(res, 
+       "<td><form method=GET action=/%s>"
+       "<input type=hidden value='restart' name=action>"
+       "<input type=submit value='Restart program' style='font-size: 
12pt'></font>"
+       "</form></td>", p->name);
+  out_print(res, "</tr></table>");
+
+}
+
+
+static void do_task_file(HttpRequest req, HttpResponse res, Process_T p) {
+
+  out_print(res,
+    "<p><br><h3>File status</h3><br>");
+  out_print(res,"<table cellspacing=0 cellpadding=3 border=1 width=\"90%\">"
+           "<tr><td width=\"30%\"><b>Parameter</b></td><td 
width=\"70%\"><b>Value</b></td></tr>");
+  out_print(res,
+    "<tr><td>Name</a></td><td>%s</td></tr>", p->name);
+  out_print(res,
+    "<tr><td>Group</a></td><td><font color='#0000ff'>%s</font></td></tr>",
+           p->group?p->group:"(not defined)");
+  out_print(res,
+    "<tr><td>Path</a></td><td>%s</td></tr>",
+           p->path);
+  out_print(res,
+           "<tr><td>Monitoring mode</a></td><td>%s</td></tr>",
+           modenames[p->mode]);
+  out_print(res,
+           "<tr><td>Monitoring status</a></td><td>%s</td></tr>",
+           statusnames[p->do_validate]);
+  out_print(res,
+    "<tr><td>Start program</a></td><td>%s</td></tr>",
+           p->start?p->start->arg[0]:"(not defined)");
+  out_print(res,
+    "<tr><td>Stop program</a></td><td>%s</td></tr>",
+           p->stop?p->stop->arg[0]:"(not defined)");
+  {
+    struct mychecksum *c;
+    for(c= p->checksumlist; c; c= c->next)
+       out_print(res, "<tr><td>Associated checksum</a></td><td>%s %s</td>"
+                 "</tr>", c->md5, c->file);
+  }
+  {
+    Dependant_T d;
+
+    for(d= p->dependantlist; d; d= d->next) {
+      if(d->dependant != NULL) {
+       out_print(res,"<tr><td>Depends on Task </a></td>"
+                 "<td> <a href=%s> %s </a></td></tr>",
+                 d->dependant, d->dependant);
+      }
+    }
+  }
+  {
+    struct mytimestamp *t;
+    for(t= p->timestamplist; t; t= t->next)
+       out_print(res,
+         "<tr><td>Associated timestamp</a></td>"
+          "<td>If %s %s %d second(s) then %s</td></tr>",
+         t->pathname, operatornames[t->operator], t->time, 
actionnames[t->action]);
+  }
+  out_print(res,
+           "<tr><td>Check task</a></td><td>Every %d cycle</td></tr>",
+           p->every?p->every:1);
+  out_print(res,
+    "<tr><td>Timeout</a></td><td>Timeout if %d restart within %d cycles"
+    "</td></tr>", p->to_start, p->to_cycle);
+  {
+    Mail_T r;
+    for(r= p->maillist; r; r= r->next) {
+      out_print(res,
+        "<tr bgcolor=\"#EFEFEF\"><td>Alert mail to</a></td><td>%s</td></tr>",
+               r->to?r->to:"");
+      out_print(res,
+       "<tr><td>Alert from</a></td><td>%s</td></tr>",
+              r->from?r->from:"(default)");
+      out_print(res,
+        "<tr><td>Alert subject</a></td><td>%s</td></tr>",
+             r->subject?r->subject:"(default)");
+      out_print(res,
+       "<tr><td>Alert message</a></td><td>%s</td></tr>",
+             r->message?r->message:"(default)");
+      out_print(res,
+       "<tr><td>Alert on timeout</a></td><td>%s</td></tr>",
+               r->alert_on_timeout?"yes":"no");
+      out_print(res,
+       "<tr><td>Alert on restart</a></td><td>%s</td></tr>",
+               r->alert_on_restart?"yes":"no");
+      out_print(res,
+       "<tr><td>Alert on checksum</a></td><td>%s</td></tr>",
+               r->alert_on_checksum?"yes":"no");
+      out_print(res,
+       "<tr><td>Alert on exceeded resource</a></td><td>%s</td></tr>",
+               r->alert_on_resource?"yes":"no");
+      out_print(res,
+       "<tr><td>Alert on stop</a></td><td>%s</td></tr>",
+               r->alert_on_stop?"yes":"no");
+      out_print(res,
+       "<tr><td>Alert on timestamp</a></td><td>%s</td></tr>",
+               r->alert_on_timestamp?"yes":"no");
+    }
+  }
+  out_print(res, "</table>");
+  out_print(res, "<table cellspacing=16><tr nowrap><td><font size=+1>");
+  /* Start program */
+  if(p->start)
+     out_print(res, 
+       "<td><form method=GET action=/%s>"
+       "<input type=hidden value='start' name=action>"
+       "<input type=submit value='Start program' style='font-size: 
12pt'></font>"
+       "</form></td>", p->name);
+   /* Stop program */
+  if(p->stop)
+    out_print(res, 
+       "<td><form method=GET action=/%s>"
+       "<input type=hidden value='stop' name=action>"
+       "<input type=submit value='Stop program' style='font-size: 
12pt'></font>"
+       "</form></td>", p->name);
+  if(p->start && p->stop)
+    out_print(res, 
+       "<td><form method=GET action=/%s>"
+       "<input type=hidden value='restart' name=action>"
+       "<input type=submit value='Restart program' style='font-size: 
12pt'></font>"
+       "</form></td>", p->name);
+  out_print(res, "</tr></table>");
+
+}
+
+
+static void do_task_process(HttpRequest req, HttpResponse res, Process_T p) {
+
+  int run= is_process_running(p);
+
+  out_print(res,
+    "<p><br><h3>Process status</h3><br>");
+  out_print(res,"<table cellspacing=0 cellpadding=3 border=1 width=\"90%\">"
+           "<tr><td width=\"30%\"><b>Parameter</b></td><td 
width=\"70%\"><b>Value</b></td></tr>");
+  out_print(res,
+    "<tr><td>Name</a></td><td>%s</td></tr>", p->name);
+  out_print(res,
+    "<tr><td>Group</a></td><td><font color='#0000ff'>%s</font></td></tr>",
+           p->group?p->group:"(not defined)");
+  out_print(res,
+    "<tr><td>Process id </a></td><td>%d</td></tr>", run);
+  out_print(res,
+    "<tr><td>Process status</a></td><td>%s %s</td></tr>",
+           run?"<font color='#00ff00'>Running</font>":
+           "<font color='#ff0000'>Not Running</font>",
+           p->has_checksum_error?
+           "<font color='#ff0000'><b>Checksum error!</b></font>":"");
+  out_print(res,
+    "<tr><td>Pid file</a></td><td>%s</td></tr>",
+           p->path);
+  out_print(res,
+           "<tr><td>Monitoring mode</a></td><td>%s</td></tr>",
+           modenames[p->mode]);
+  out_print(res,
+           "<tr><td>Monitoring status</a></td><td>%s</td></tr>",
+           statusnames[p->do_validate]);
+  out_print(res,
+    "<tr><td>Start program</a></td><td>%s</td></tr>",
+           p->start?p->start->arg[0]:"(not defined)");
+  out_print(res,
+    "<tr><td>Stop program</a></td><td>%s</td></tr>",
+           p->stop?p->stop->arg[0]:"(not defined)");
+  {
+    struct mychecksum *c;
+    for(c= p->checksumlist; c; c= c->next)
+       out_print(res, "<tr><td>Associated checksum</a></td><td>%s %s</td>"
+                 "</tr>", c->md5, c->file);
+  }
+  {
+    Dependant_T d;
+
+    for(d= p->dependantlist; d; d= d->next) {
+      if(d->dependant != NULL) {
+       out_print(res,"<tr><td>Depends on Task </a></td>"
+                 "<td> <a href=%s> %s </a></td></tr>",
+                 d->dependant, d->dependant);
+      }
+    }
+  }
+  if ( Run.doprocess ) {
+    ProcInfo_T pi= p->procinfo;
+
+    out_print(res,
+             "<tr><td>CPU usage</a></td><td>%.1f%%</td></tr>",
+             pi->cpu_percent/10.0);
+    out_print(res,
+             "<tr><td>Memory usage</a></td><td>%.1f%% [%ldkB]</td></tr>",
+             pi->mem_percent/10.0,pi->mem_kbyte);
+  }
+  {
+    Port_T n;
+    for(n= p->portlist; n; n= n->next) {
+
+      if ( n->family == AF_INET ) {
+
+       if ( n->ssl != NULL ) {
+
+         out_print(res,
+                   "<tr><td>Host:Port</a></td><td>%s:%d%s [%s via 
SSL]</td></tr>",
+                   n->hostname, n->port, n->request?n->request:"",
+                   n->protocol->name);
+         
+         if ( n->certmd5 != NULL ) {
+
+           out_print(res,
+                     "<tr><td>Server certificate md5 
sum</a></td><td>%s</td></tr>",
+                     n->certmd5);
+
+         }
+
+
+       } else {
+
+         out_print(res,
+                   "<tr><td>Host:Port</a></td><td>%s:%d%s [%s]</td></tr>",
+                   n->hostname, n->port, n->request?n->request:"",
+                   n->protocol->name);
+
+       }
+
+      } else if ( n->family == AF_UNIX ) {
+
+       out_print(res,
+               "<tr><td>Unix Socket</a></td><td>%s [%s]</td></tr>",
+               n->pathname, n->protocol->name);
+
+      }
+    }
+  }
+  {
+    struct mytimestamp *t;
+    for(t= p->timestamplist; t; t= t->next)
+       out_print(res,
+         "<tr><td>Associated timestamp</a></td>"
+          "<td>If %s %s %d second(s) then %s</td></tr>",
+         t->pathname, operatornames[t->operator], t->time, 
actionnames[t->action]);
+  }
+  {
+    Resource_T q;
+
+    for (q= p->resourcelist; q; q= q->next) {
+      switch (q->resource_id) {
+
+      case RESOURCE_ID_CPU_PERCENT: 
+
+       out_print(res,"<tr><td>CPU usage limit</a></td>"
+                 "<td>If %s %.1f%% for %d cycle(s) then %s</td></tr>", 
+                 operatornames[q->operator],
+                 q->limit/10.0, q->max_cycle, 
+                 actionnames[q->action]);
+       break;
+
+      case RESOURCE_ID_MEM_PERCENT: 
+       
+       out_print(res,"<tr><td>Memory usage limit</a></td>"
+                 "<td>If %s %.1f%% for %d cycle(s) then %s</td></tr>", 
+                 operatornames[q->operator],
+                 q->limit/10.0, q->max_cycle, 
+                 actionnames[q->action]);
+       break;
+       
+      case RESOURCE_ID_MEM_KBYTE: 
+      
+       out_print(res,"<tr><td>Memory amount limit</a></td>"
+                 "<td>If %s %ld for %d cycle(s) then %s</td></tr>", 
+                 operatornames[q->operator],
+                 q->limit, q->max_cycle, 
+                 actionnames[q->action]);
+       break;
+       
+      case RESOURCE_ID_LOAD1: 
+      
+       out_print(res,"<tr><td>Load average (1min)</a></td>"
+                 "<td>If %s %.1f for %d cycle(s) then %s</td></tr>", 
+                 operatornames[q->operator],
+                 q->limit/10.0, q->max_cycle, 
+                 actionnames[q->action]);
+       break;
+       
+      case RESOURCE_ID_LOAD5: 
+      
+       out_print(res,"<tr><td>Load average (5min)</a></td>"
+                 "<td>If %s %.1f for %d cycle(s) then %s</td></tr>", 
+                 operatornames[q->operator],
+                 q->limit/10.0, q->max_cycle, 
+                 actionnames[q->action]);
+       break;
+       
+      case RESOURCE_ID_LOAD15: 
+       out_print(res,"<tr><td>Load average (15min)</a></td>"
+                 "<td>If %s %.1f for %d cycle(s) then %s</td></tr>", 
+                 operatornames[q->operator],
+                 q->limit/10.0, q->max_cycle, 
+                 actionnames[q->action]);
+       break;
+       
+      }    
+    }
+  }
+  out_print(res,
+           "<tr><td>Check task</a></td><td>Every %d cycle</td></tr>",
+           p->every?p->every:1);
+  out_print(res,
+    "<tr><td>Timeout</a></td><td>Timeout if %d restart within %d cycles"
+    "</td></tr>", p->to_start, p->to_cycle);
+  {
+    Mail_T r;
+    for(r= p->maillist; r; r= r->next) {
+      out_print(res,
+        "<tr bgcolor=\"#EFEFEF\"><td>Alert mail to</a></td><td>%s</td></tr>",
+               r->to?r->to:"");
+      out_print(res,
+       "<tr><td>Alert from</a></td><td>%s</td></tr>",
+              r->from?r->from:"(default)");
+      out_print(res,
+        "<tr><td>Alert subject</a></td><td>%s</td></tr>",
+             r->subject?r->subject:"(default)");
+      out_print(res,
+       "<tr><td>Alert message</a></td><td>%s</td></tr>",
+             r->message?r->message:"(default)");
+      out_print(res,
+       "<tr><td>Alert on timeout</a></td><td>%s</td></tr>",
+               r->alert_on_timeout?"yes":"no");
+      out_print(res,
+       "<tr><td>Alert on restart</a></td><td>%s</td></tr>",
+               r->alert_on_restart?"yes":"no");
+      out_print(res,
+       "<tr><td>Alert on checksum</a></td><td>%s</td></tr>",
+               r->alert_on_checksum?"yes":"no");
+      out_print(res,
+       "<tr><td>Alert on exceeded resource</a></td><td>%s</td></tr>",
+               r->alert_on_resource?"yes":"no");
+      out_print(res,
+       "<tr><td>Alert on stop</a></td><td>%s</td></tr>",
+               r->alert_on_stop?"yes":"no");
+      out_print(res,
+       "<tr><td>Alert on timestamp</a></td><td>%s</td></tr>",
+               r->alert_on_timestamp?"yes":"no");
+    }
+  }
+  out_print(res, "</table>");
+  out_print(res, "<table cellspacing=16><tr nowrap><td><font size=+1>");
+  /* Start program */
+  if(p->start)
+     out_print(res, 
+       "<td><form method=GET action=/%s>"
+       "<input type=hidden value='start' name=action>"
+       "<input type=submit value='Start program' style='font-size: 
12pt'></font>"
+       "</form></td>", p->name);
+   /* Stop program */
+  if(p->stop)
+    out_print(res, 
+       "<td><form method=GET action=/%s>"
+       "<input type=hidden value='stop' name=action>"
+       "<input type=submit value='Stop program' style='font-size: 
12pt'></font>"
+       "</form></td>", p->name);
+  if(p->start && p->stop)
+    out_print(res, 
+       "<td><form method=GET action=/%s>"
+       "<input type=hidden value='restart' name=action>"
+       "<input type=submit value='Restart program' style='font-size: 
12pt'></font>"
+       "</form></td>", p->name);
+  out_print(res, "</tr></table>");
+
+}
+
diff -Naur monit.20030423.base/l.l monit.20030423/l.l
--- monit.20030423.base/l.l     Fri Feb 14 10:20:05 2003
+++ monit.20030423/l.l  Wed Apr 23 10:47:46 2003
@@ -69,6 +69,11 @@
 loadavg15   load(avg)[ ]*\([ ]*15[ ]*(m|min)?[ ]*\)
 startarg    start{wws}(program)?{wws}["]  
 stoparg     stop{wws}(program)?{wws}["]   
+percent     ("percent"|"%")
+byte        ("byte"|"b")
+kilobyte    ("kilobyte"|"kb")
+megabyte    ("megabyte"|"mb")
+gigabyte    ("gigabyte"|"gb")
 
 %x ARGUMENT 
 
@@ -92,6 +97,7 @@
 sum               {/* EMPTY */}
 restarts          {/* EMPTY */}
 th(a|e)n          {/* EMPTY */}
+usage            {/* EMPTY */}
 
 {startarg}        { BEGIN(ARGUMENT); return START; }
 {stoparg}         { BEGIN(ARGUMENT); return STOP; }
@@ -113,6 +119,7 @@
 allow             { return ALLOW; }
 check             { return CHECK; }
 pidfile           { return PIDFILE; }
+path              { return PATHTOK; }
 start             { return START; }
 stop              { return STOP; }
 port(number)?     { return PORT; }
@@ -162,6 +169,18 @@
 sslv3             { return SSLV3; }
 tlsv1             { return TLSV1; }
 sslauto           { return SSLAUTO; }
+directory         { return DIRECTORY; }
+file              { return FILETOK; }
+device            { return DEVICE; }
+process           { return PROCESS; }
+inode(s)?         { return INODE; }
+space             { return SPACE; }
+
+{percent}         { return PERCENT; }
+{byte}            { return BYTE; }
+{kilobyte}        { return KILOBYTE; }
+{megabyte}        { return MEGABYTE; }
+{gigabyte}        { return GIGABYTE; }
 
 {loadavg1}        { return LOADAVG1; }
 {loadavg5}        { return LOADAVG5; }
@@ -204,6 +223,11 @@
                      yylval.string= xstrdup(yytext);
                     return PATH;
                   }
+
+"/"               {
+                     yylval.string= xstrdup(yytext);
+                    return PATH;
+                  }
 
 {noslash}/[/]     {
                      yyerror("A path must be fully qualified");
diff -Naur monit.20030423.base/monit_process.c monit.20030423/monit_process.c
--- monit.20030423.base/monit_process.c Fri Feb 14 10:20:05 2003
+++ monit.20030423/monit_process.c      Wed Apr 23 10:47:46 2003
@@ -79,6 +79,7 @@
                                "not equal to"};
 char operatorshortnames[][3]= {">", "<", "=", "!="};
 char statusnames[][STRLEN]=   {"not monitored", "monitored" };
+char tasknames[][STRLEN]=     {"Device Name", "Directory Name", "File Name", 
"Process Name" };
 
 int  include_children= TRUE;
 int  num_cpus=1;
diff -Naur monit.20030423.base/monit_process.h monit.20030423/monit_process.h
--- monit.20030423.base/monit_process.h Fri Feb 14 10:20:05 2003
+++ monit.20030423/monit_process.h      Wed Apr 23 10:47:46 2003
@@ -34,6 +34,7 @@
 extern char operatornames[][STRLEN];
 extern char operatorshortnames[][3];
 extern char statusnames[][STRLEN];
+extern char tasknames[][STRLEN];
 extern int num_cpus;
 
 #define RESOURCE_ID_CPU_PERCENT 1
diff -Naur monit.20030423.base/monitor.h monit.20030423/monitor.h
--- monit.20030423.base/monitor.h       Mon Mar 10 14:13:47 2003
+++ monit.20030423/monitor.h    Wed Apr 23 10:47:46 2003
@@ -83,6 +83,24 @@
 #define ACTION_RESTART     2
 #define ACTION_STOP        3
 
+#define TASK_DEVICE        0
+#define TASK_DIRECTORY     1
+#define TASK_FILE          2
+#define TASK_PROCESS       3
+
+#define RESOURCE_CPU       1
+#define RESOURCE_MEM       2
+#define RESOURCE_LOAD1     4
+#define RESOURCE_LOAD5     5
+#define RESOURCE_LOAD15    6
+#define RESOURCE_INODE     7
+#define RESOURCE_SPACE     8
+
+#define UNIT_BYTE          1
+#define UNIT_KILOBYTE      1024
+#define UNIT_MEGABYTE      1048580
+#define UNIT_GIGABYTE      1073740000
+
 #define MAXIMUM(x,y)       ((x) > (y) ? (x) : (y))
 #define is(a,b)                   ((a&&b)?!strcasecmp(a, b):0)
 
@@ -230,7 +248,7 @@
 /** Defines resource data */
 typedef struct myresource {
   int  resource_id;                              /**< Which value is checked */
-  long int limit;                                 /**< Limit of the resource */
+  long limit;                                     /**< Limit of the resource */
   int  operator;                                    /**< Comparison operator */
   int  cycle;                                     /**< Cycle overrun counter */
   int  max_cycle;                                   /**< Cycle overrun limit */
@@ -272,10 +290,33 @@
   int length;                         /**< The length of the arguments array */
 } *Command_T;
 
+/** Defines filesystem device data */
+typedef struct mydeviceinfo {
+  long f_bsize;                                     /**< Transfer block size */
+  long f_blocks;                        /**< Total data blocks in filesystem */
+  long f_blocksfree;             /**< Free blocks available to non-superuser */
+  long f_blocksfreetotal;                     /**< Free blocks in filesystem */
+  long f_files;                          /**< Total file nodes in filesystem */
+  long f_filesfree;                       /**< Free file nodes in filesystem */
+} *DeviceInfo_T;
+
+/** Defines filesystem device configuration */
+typedef struct mydevice {
+  int  resource;                        /**< Whether to check inode or space */
+  int  operator;                                    /**< Comparison operator */
+  long limit_absolute;                               /**< Watermark - blocks */
+  int  limit_percent;                               /**< Watermark - percent */
+  int  action;                                /**< Action in case of failure */
+
+  struct mydevice *next;
+} *Device_T;
+
 /** Defines process data */
 typedef struct myprocess {
+
+  /** Common parameters */
+  int task;                                         /**< Monitored task type */
   char *name;                                  /**< Process descriptive name */
-  char *pidfile;                            /**< The pid file of the process */
   char *group;                                       /**< Process group name */
   Command_T start;                    /**< The start command for the process */
   Command_T stop;                      /**< The stop command for the process */
@@ -301,12 +342,20 @@
   Resource_T resourcelist;                           /**< Resouce check list */
   Dependant_T dependantlist;                      /**<Dependant process list */
   Timestamp_T timestamplist;                       /**< Timestamp check list */
+  Device_T devicelist;                                /**< Device check list */
+
+  /** Runtime parameters */
+  DeviceInfo_T devinfo;                       /**< Data for the device check */
   ProcInfo_T procinfo;                        /**< Data for the procfs check */
+
+  /** Context specific parameters */
+  char *path;   /**< Path to the device, file, directory or process pid file */
   
   /** For internal use */
   pthread_mutex_t mutex;          /**< Mutex used for action synchronization */
   struct myprocess *next;                         /**< next process in chain */
   struct myprocess *next_depend;           /**< next depend process in chain */
+
 } *Process_T;
 
 
@@ -392,4 +441,6 @@
 int   state_should_update();
 void  state_update();
 void  state_finalize();
+char *get_device(char *, unsigned, char *);
+int   get_fsusage(char *, DeviceInfo_T);
 #endif
diff -Naur monit.20030423.base/monitrc monit.20030423/monitrc
--- monit.20030423.base/monitrc Fri Feb  7 13:17:24 2003
+++ monit.20030423/monitrc      Wed Apr 23 10:47:46 2003
@@ -233,4 +233,26 @@
 #    port 4001 
 #    timeout if 2 restarts within 3 cycles
 #    alert address@hidden
+#    depends on datafs
 #    group database
+#
+#
+#  check device datafs path /data
+#    start program  = "/bin/mount /data"
+#    stop program  = "/bin/umount /data"
+#    if space usage > 80 % then stop
+#    if inode usage > 80 % then stop
+#    alert address@hidden
+#    group database
+#
+#
+#  check device rootfs path /dev/sda1
+#    if space usage > 3 GB then alert
+#    if inode usage > 30000 then alert
+#    alert address@hidden
+#
+#
+#  check file su path /bin/su
+#
+#
+#  check directory bin path /bin
diff -Naur monit.20030423.base/p.y monit.20030423/p.y
--- monit.20030423.base/p.y     Fri Feb 14 09:22:33 2003
+++ monit.20030423/p.y  Wed Apr 23 10:47:46 2003
@@ -61,6 +61,10 @@
 #include <netdb.h>
 #endif
 
+#ifdef HAVE_MATH_H
+#include <math.h>
+#endif
+
 
 #include "net.h"
 #include "monitor.h"
@@ -119,6 +123,14 @@
     int  action;
   };
 
+  struct DeviceSet {
+    int  resource;
+    int  operator;
+    long limit_absolute;
+    int  limit_percent;
+    int  action;
+  };
+
   /* yacc interface */
   void  yyerror(const char *);
 
@@ -136,24 +148,26 @@
   static Process_T depend_list= NULL;
   static struct IHavePrecedence ihp= {FALSE, FALSE, FALSE};
   static struct MailFilter mtf= {NULL, NULL, NULL, FALSE, FALSE, FALSE,
-                                FALSE, FALSE, FALSE};
-  static struct PortSet portset= {-1, NULL, 0, SOCK_STREAM, AF_INET, FALSE, 
-                                  SSL_VERSION_AUTO, NULL, NULL, NULL, NULL};
+    FALSE, FALSE, FALSE};
+  static struct PortSet portset= {-1, NULL, 0, SOCK_STREAM, AF_INET, FALSE,
+    SSL_VERSION_AUTO, NULL, NULL, NULL, NULL};
   static struct ResourceSet resourceset= {0, 0, OPERATOR_EQUAL, 1,
-                                         ACTION_ALERT};
+    ACTION_ALERT};
   static struct TimestampSet timestampset= {NULL, OPERATOR_EQUAL, 0,
-                                           ACTION_ALERT};
+    ACTION_ALERT};
+  static struct DeviceSet deviceset= {0, OPERATOR_EQUAL, -1, -1, ACTION_ALERT};
 
   /* Private prototypes */
   static void initialize();
   static void addprocess(Process_T);
   static void addmail(char *, struct MailFilter *);
-  static void createprocess(char *, char *);
+  static void createprocess(int, char *, char *);
   static void adddependant(char *);
   static void addchecksum(char *, char *);
   static void addport(struct PortSet *);
   static void addresource(struct ResourceSet *);
   static void addtimestamp(struct TimestampSet *);
+  static void adddevice(struct DeviceSet *);
   static void *addprotocol(int);
   static void addcommand(int);
   static void addargument(char *);
@@ -167,11 +181,12 @@
   static void reset_portset();
   static void reset_resourceset();
   static void reset_timestampset();
+  static void reset_deviceset();
   static void check_name(char *);
   static void check_timeout(int, int);
   static void check_every (int);
   static void check_hostname (char *);
-  static void createprocinfo();
+  static void createinfo();
   static char *append_hostname(char *);
   static void cleanup_md5_string(char *);
   static void check_depend();
@@ -187,7 +202,7 @@
 
 %token SET LOGFILE DAEMON SYSLOG MAILSERVER HTTPD ALLOW ADDRESS INIT
 %token PEMFILE ENABLE DISABLE HTTPDSSL CLIENTPEMFILE ALLOWSELFCERTIFICATION
-%token CHECK PIDFILE START STOP
+%token CHECK PIDFILE START STOP PATHTOK
 %token HOST PORT TYPE UDP TCP TCPSSL PROTOCOL
 %token ALERT MAILFORMAT UNIXSOCKET
 %token TIMEOUT RESTART CHECKSUM EXPECT EVERY 
@@ -201,6 +216,9 @@
 %token GROUP REQUEST DEPENDS
 %token TIMESTAMP SECOND MINUTE HOUR DAY
 %token SSLAUTO SSLV2 SSLV3 TLSV1
+%token PERCENT BYTE KILOBYTE MEGABYTE GIGABYTE
+%token DIRECTORY FILETOK DEVICE PROCESS
+%token INODE SPACE
 
 %left GREATER LESS EQUAL NOTEQUAL
 
@@ -250,6 +268,12 @@
                    resourceset.action= $<number>3;
                   addresource(&resourceset);
                  }
+                | inode {
+                   adddevice(&deviceset);
+                  }
+                | space {
+                   adddevice(&deviceset);
+                  }
                 ;
 
 setdaemon       : SET DAEMON NUMBER  {
@@ -401,9 +425,21 @@
                 }
                 ;
 
-check           : CHECK STRING PIDFILE PATH {
-                   createprocess($2,$4);
-                  check_name($2);
+check           : CHECK PROCESS STRING PIDFILE PATH {
+                   createprocess(TASK_PROCESS, $3,$5);
+                  check_name($3);
+                  }
+                | CHECK FILETOK STRING PATHTOK PATH {
+                   createprocess(TASK_FILE, $3,$5);
+                  check_name($3);
+                  }
+                | CHECK DEVICE STRING PATHTOK PATH {
+                   createprocess(TASK_DEVICE, $3,$5);
+                  check_name($3);
+                  }
+                | CHECK DIRECTORY STRING PATHTOK PATH {
+                   createprocess(TASK_DIRECTORY, $3,$5);
+                  check_name($3);
                   }
                 ;
 
@@ -627,6 +663,48 @@
                 | STOP        { $<number>$= ACTION_STOP; }
                 ;
 
+inode           : INODE operator NUMBER action {
+                    deviceset.resource= RESOURCE_INODE;
+                    deviceset.operator= $<number>2;
+                    deviceset.limit_absolute= $3;
+                    deviceset.action= $<number>4;
+                  }
+                | INODE operator NUMBER PERCENT action {
+                    deviceset.resource= RESOURCE_INODE;
+                    deviceset.operator= $<number>2;
+                    deviceset.limit_percent= $<number>3;
+                    deviceset.action= $<number>5;
+                  }
+                ;
+
+space           : SPACE operator NUMBER unit action {
+
+                    DeviceInfo_T di= NEW(di);
+
+                    get_fsusage(current->path, di);
+
+                    deviceset.resource= RESOURCE_SPACE;
+                    deviceset.operator= $<number>2;
+                    deviceset.limit_absolute= (int)( (float)$3 / 
(float)di->f_bsize * (float)$<number>4 );
+                    deviceset.action= $<number>5;
+
+                    free(di);
+
+                  }
+                | SPACE operator NUMBER PERCENT action {
+                    deviceset.resource= RESOURCE_SPACE;
+                    deviceset.operator= $<number>2;
+                    deviceset.limit_percent= $<number>3;
+                    deviceset.action= $<number>5;
+                  }
+                ;
+
+unit            : BYTE     { $<number>$= UNIT_BYTE; }
+                | KILOBYTE { $<number>$= UNIT_KILOBYTE; }
+                | MEGABYTE { $<number>$= UNIT_MEGABYTE; }
+                | GIGABYTE { $<number>$= UNIT_GIGABYTE; }
+                ;
+
 %%
 
 
@@ -680,7 +758,7 @@
       /* If defined - add the last process to the process list */
       if(current) {
        
-       createprocinfo();
+       createinfo();
        addprocess(current);
        
       }
@@ -725,14 +803,14 @@
  * Create a new process object and add any current objects to the
  * process list.
  */
-static void createprocess(char *name, char *pidfile) {
+static void createprocess(int task, char *name, char *path) {
 
   ASSERT(name);
-  ASSERT(pidfile);
+  ASSERT(path);
 
   if(current) {
 
-    createprocinfo();
+    createinfo();
     addprocess(current);
     
   }
@@ -749,8 +827,9 @@
   current->do_validate= TRUE;
   current->mode= MODE_ACTIVE;
 
+  current->task= task;
   current->name= name;
-  current->pidfile= pidfile;
+  current->path= path;
   current->group= NULL;
   current->dependantlist= NULL;
 
@@ -768,10 +847,6 @@
 
   ASSERT(p);
  
-  /* if process is already running... set validate true  */ 
-  if (is_process_running(p))
-      p->do_validate= TRUE;
- 
   n= NEW(n);
   memcpy(n, p, sizeof(*p));
 
@@ -1026,12 +1101,37 @@
 
 
 /*
- * Adds procfs check data to current process procinfo
+ * Add a new device to the current tasks device list
  */
-static void createprocinfo() {
+static void adddevice(struct DeviceSet *ds) {
+
+  Device_T d= NEW(d);
+
+  ASSERT(ds);
+
+  d->resource= ds->resource;
+  d->operator= ds->operator;
+  d->limit_absolute= ds->limit_absolute;
+  d->limit_percent= ds->limit_percent;
+  d->action= ds->action;
+
+  d->next= current->devicelist;
+  current->devicelist= d;
+
+  reset_deviceset();
+
+}
 
+
+/*
+ * Adds runtime info to current process
+ */
+static void createinfo() {
+
+  DeviceInfo_T di= NEW(di);
   ProcInfo_T pi= NEW(pi);
 
+  current->devinfo=di;
   current->procinfo=pi;
   
 }
@@ -1130,7 +1230,7 @@
 
 
 /*
- * Reset the pidfil if changed
+ * Reset the pidfile if changed
  */
 static void setpidfile(char *pidfile) {
 
@@ -1306,6 +1406,20 @@
 
 }
 
+
+/*
+ * Reset the Device set to default values
+ */
+static void reset_deviceset() {
+
+  deviceset.resource= 0;
+  deviceset.operator= OPERATOR_EQUAL;
+  deviceset.limit_absolute= -1;
+  deviceset.limit_percent= -1;
+  deviceset.action= ACTION_ALERT;
+
+}
+
 
 /* ---------------------------------------------------------------- Checkers */
 
diff -Naur monit.20030423.base/status.c monit.20030423/status.c
--- monit.20030423.base/status.c        Fri Feb 14 10:20:05 2003
+++ monit.20030423/status.c     Wed Apr 23 10:47:46 2003
@@ -163,7 +163,7 @@
   
   if((pid= is_process_running(p))) {
 
-    char *uptime= get_process_uptime(p->pidfile);
+    char *uptime= get_process_uptime(p->path);
 
     fprintf(stdout, "Process '%s' is running with pid [%d] Uptime: %s "
             "Monitoring status: %s\n",
diff -Naur monit.20030423.base/util.c monit.20030423/util.c
--- monit.20030423.base/util.c  Fri Mar  7 15:24:42 2003
+++ monit.20030423/util.c       Wed Apr 23 10:47:46 2003
@@ -447,13 +447,17 @@
   Resource_T q;
   Checksum_T c;
   Timestamp_T t;
+  Device_T dl;
   Dependant_T d;
 
   ASSERT(p);
  
-  printf("%-21s = %s\n", "Process Name", p->name);
+  printf("%-21s = %s\n", tasknames[p->task], p->name);
   printf(" %-20s = %s\n", "Group", is_str_defined(p->group));
-  printf(" %-20s = %s\n", "Pid file", p->pidfile);
+  if(p->task == TASK_PROCESS)
+    printf(" %-20s = %s\n", "Pid file", p->path);
+  else
+    printf(" %-20s = %s\n", "Path", p->path);
   printf(" %-20s = %s\n", "Monitoring mode", modenames[p->mode]);
   if(p->start)
     printf(" %-20s = %s\n", "Start program", is_str_defined(p->start->arg[0]));
@@ -470,12 +474,8 @@
     if(d->dependant != NULL)
       printf(" %-20s = %s\n", "Depends on Process", d->dependant);
 
-  if(! p->portlist) {
+  if(p->portlist) {
     
-    printf(" %-20s = (not defined)\n", "Host:Port");
-    
-  } else {
-  
     for(n= p->portlist; n; n= n->next) {
     
       if(n->family == AF_INET) {
@@ -486,13 +486,8 @@
                 n->hostname, n->port, n->request?n->request:"",
                 n->protocol->name);
 
-         if(n->certmd5 != NULL) {
-
-           printf(" %-20s = %s\n", 
-                  "Server cert md5 sum",
-                  n->certmd5);
-
-         }
+         if(n->certmd5 != NULL)
+           printf(" %-20s = %s\n", "Server cert md5 sum", n->certmd5);
 
        } else {
 
@@ -524,12 +519,30 @@
     
   }
 
-  if(! p->resourcelist) {
+  for(dl= p->devicelist; dl; dl= dl->next) {
+    
+    if(dl->resource == RESOURCE_INODE) {
 
-    printf(" %-20s = (not defined)\n", "Resource Limits");
+      printf(" %-20s = if %s %ld %s then %s\n",
+           "Inodes usage limit",
+           operatornames[dl->operator],
+           (dl->limit_absolute > -1)?dl->limit_absolute:dl->limit_percent,
+           (dl->limit_absolute > -1)?"":"%",
+           actionnames[dl->action]);
+
+    } else if(dl->resource == RESOURCE_SPACE) {
+
+      printf(" %-20s = if %s %ld %s then %s\n",
+           "Space usage limit",
+           operatornames[dl->operator],
+           (dl->limit_absolute > -1)?dl->limit_absolute:dl->limit_percent,
+           (dl->limit_absolute > -1)?"blocks":"%",
+           actionnames[dl->action]);
 
-  } 
+    }
     
+  }
+
   for(q= p->resourcelist; q; q= q->next) {
 
     switch(q->resource_id) {
@@ -586,25 +599,12 @@
   }
 
   if(p->def_every)
-      
     printf(" %-20s = Check process every %d cycles\n", "Every", p->every);
   
-  else {
-    
-    printf(" %-20s = (not defined)\n", "Every");
-    
-  }
 
-  if(p->def_timeout) {
-    
+  if(p->def_timeout)
     printf(" %-20s = Do timeout if %d restart within %d cycles\n",
           "Timeout", p->to_start, p->to_cycle);
-    
-  } else {
-    
-    printf(" %-20s = (not defined)\n", "Timeout");
-    
-  }
 
   for(r= p->maillist; r; r= r->next) {
     
@@ -721,7 +721,7 @@
   
   errno= 0;
 
-  if((pid= get_pid(p->pidfile))) {
+  if((pid= get_pid(p->path))) {
     
     if((kill_return= getpgid(pid)) > 0 || errno == EPERM)
        
diff -Naur monit.20030423.base/validate.c monit.20030423/validate.c
--- monit.20030423.base/validate.c      Fri Mar  7 15:24:42 2003
+++ monit.20030423/validate.c   Wed Apr 23 10:47:46 2003
@@ -57,6 +57,7 @@
 static int  check_checksum(Process_T);
 static int  checksum_helper(Process_T, char *, char *);
 static int  check_timestamp(Process_T, Timestamp_T, char *);
+static int  check_device(Process_T, Device_T, char *);
 static void connection_timeout(int);
 static void reset_resource_counter(Process_T);
 static void vlog(char * report, int n, Process_T p, char *m,...);
@@ -124,6 +125,7 @@
   Port_T pp;
   Resource_T pr;
   Timestamp_T tl;
+  Device_T td;
   pid_t  pid= -1;
   sigset_t ns,os;
   char report[STRLEN];
@@ -145,82 +147,138 @@
   sigaddset(&ns, SIGTERM);
   pthread_sigmask(SIG_BLOCK, &ns, &os);
 
-  /* Test for running process */
-  if(!(pid= is_process_running(p))) {
 
-    /* Reset the proc info object to prevent false data in the first run */
-    memset(p->procinfo, 0, sizeof *(p->procinfo));
+  /** Context specific task actions */
+  switch(p->task) {
+
+  case TASK_PROCESS:
+
+    /* Test for running process */
+    if(!(pid= is_process_running(p))) {
+
+      /* Reset the proc info object to prevent false data in the first run */
+      memset(p->procinfo, 0, sizeof *(p->procinfo));
     
-    do_start(p, "Reason: Process is not running.");
-    goto reinstall;
+      do_start(p, "Reason: Process is not running.");
+      goto reinstall;
     
-  } else {
+    } else {
     
-    if(Run.debug) {
+      if(Run.debug) {
       
-      log("'%s' is running with pid %d\n", p->name, (int)pid);
+        log("'%s' is running with pid %d\n", p->name, (int)pid);
 
-    }
+      }
     
-  }
+    }
 
-  if(Run.doprocess) {
+    if(Run.doprocess) {
 
-    if(update_process_data(p, pid)) {
+      if(update_process_data(p, pid)) {
   
-      if(! check_process_state(p, report)) {
+        if(! check_process_state(p, report)) {
 
-       smtp_alert_resource(p, "Reason: %s\n", report);
+         smtp_alert_resource(p, "Reason: %s\n", report);
     
-      } else {
+        } else {
       
-       if(Run.debug) {
+         if(Run.debug) {
        
-         log("'%s' check_process_state() passed.\n", p->name);
+           log("'%s' check_process_state() passed.\n", p->name);
        
-       }
+         }
       
-      }
+        }
     
-      for(pr= p->resourcelist; pr; pr= pr->next) {
+        for(pr= p->resourcelist; pr; pr= pr->next) {
       
-       if(!check_resources(p, pr, report)) {
+         if(!check_resources(p, pr, report)) {
        
-         switch(pr->action) {
-         case ACTION_ALERT:
+           switch(pr->action) {
+           case ACTION_ALERT:
              if(p->def_timeout) p->nstart++;
              smtp_alert_resource(p, "Reason: %s\n", report);
              /* We are also interested in other alerts/stops/restarts! */
              pr->cycle=0;
              break;
 
-         case ACTION_STOP:
+           case ACTION_STOP:
              do_stop(p, "Reason: %s\n", report);
              reset_resource_counter(p);
              goto reinstall;
 
-         case ACTION_RESTART:
+           case ACTION_RESTART:
              do_restart(p, "Reason: %s\n", report);
              reset_resource_counter(p);
              goto reinstall;
 
-         default:
+           default:
              log("'%s' Unknow resource failure action.\n", p->name);
              break;
+           }
+
          }
+      
+        }
+       
+      } else {
 
-       }
+        log("'%s' failed to get process data\n", p->name);
       
       }
-       
-    } else {
 
-      log("'%s' failed to get process data\n", p->name);
+    }
+
+    /* Test each host:port and protocol in the process's portlist */
+    for(pp= p->portlist; pp; pp= pp->next) {
+    
+      if(!check_connection(p, pp, report)) {
+      
+        do_restart(p, "Reason: %s\n", report);
+        goto reinstall;
       
+      }
+    
     }
+    break;
+
+  case TASK_DEVICE:
+
+    /* Test devices */
+    if(p->devicelist && get_fsusage(p->path, p->devinfo)) {
+
+      for(td= p->devicelist; td; td= td->next) {
+
+        if(!check_device(p, td, report)) {
+
+          switch(td->action) {
+          case ACTION_ALERT:
+            smtp_alert_resource(p, "Reason: %s\n", report);
+            break;
+
+          case ACTION_STOP:
+            do_stop(p, "Reason: %s\n", report);
+            goto reinstall;
+
+          default:
+            log("'%s' Unknow device failure action.\n", p->name);
+            break;
+          }
+
+        }
+
+      }
+
+    }
+    break;
+
+  default:
+    break;
 
   }
 
+
+  /** Common task actions */
   for(tl= p->timestamplist; tl; tl= tl->next) {
       
     if(!check_timestamp(p, tl, report)) {
@@ -249,18 +307,6 @@
 
   }    
       
-  /* Test each host:port and protocol in the process's portlist */
-  for(pp= p->portlist; pp; pp= pp->next) {
-    
-    if(!check_connection(p, pp, report)) {
-      
-      do_restart(p, "Reason: %s\n", report);
-      goto reinstall;
-      
-    }
-    
-  }
-
   reinstall:
   
   /* Remove the SIGTERM block */
@@ -980,6 +1026,118 @@
 
 }
 
+
+/**
+ * Returns TRUE if the device test succeeded
+ * otherwise FALSE.
+ */
+static int check_device(Process_T t, Device_T td, char *report) {
+
+  ASSERT(t);
+  ASSERT(td);
+
+  if( (td->limit_percent < 0) && (td->limit_absolute < 0) ) {
+
+    log("'%s' error: device limit not set\n", t->name);
+    return FALSE;
+
+  }
+
+  switch(td->resource) {
+
+  case RESOURCE_INODE:
+
+    if(td->limit_percent >= 0) {
+
+      if(compare_value(td->operator, 100 * (t->devinfo->f_files - 
t->devinfo->f_filesfree) / t->devinfo->f_files, td->limit_percent)) {
+
+        vlog(report, STRLEN, t,
+          "inode usage %d%% matches resource limit [inode usage%s%d%%]",
+          100 * (t->devinfo->f_files - t->devinfo->f_filesfree) / 
t->devinfo->f_files,
+          operatorshortnames[td->operator],
+          td->limit_percent);
+
+        return FALSE;
+
+      }
+
+    } else {
+
+      if(compare_value(td->operator, t->devinfo->f_files - 
t->devinfo->f_filesfree, td->limit_absolute)) {
+
+        vlog(report, STRLEN, t,
+          "inode usage %d matches resource limit [inode usage%s%d]",
+          t->devinfo->f_files - t->devinfo->f_filesfree,
+          operatorshortnames[td->operator],
+          td->limit_absolute);
+
+        return FALSE;
+
+      }
+
+    }
+
+    if(Run.debug) {
+
+      log("'%s' inode usage check passed [current inode usage=%.1f%%]\n",
+        t->name,
+        (float) 100 * (t->devinfo->f_files - t->devinfo->f_filesfree) / 
t->devinfo->f_files);
+
+    }
+
+    return TRUE;
+
+  case RESOURCE_SPACE:
+
+      if(td->limit_percent >= 0) {
+
+        if(compare_value(td->operator, 100 * (t->devinfo->f_blocks - 
t->devinfo->f_blocksfree) / t->devinfo->f_blocks, td->limit_percent)) {
+
+          vlog(report, STRLEN, t,
+            "space usage %d%% matches resource limit [space usage%s%d%%]",
+            100 * (t->devinfo->f_blocks - t->devinfo->f_blocksfree) / 
t->devinfo->f_blocks,
+            operatorshortnames[td->operator],
+            td->limit_percent);
+
+          return FALSE;
+
+        }
+
+      } else {
+
+        if(compare_value(td->operator, t->devinfo->f_blocks - 
t->devinfo->f_blocksfree, td->limit_absolute)) {
+
+          vlog(report, STRLEN, t,
+            "space usage %d blocks matches resource limit [space usage%s%d 
blocks]",
+            t->devinfo->f_blocks - t->devinfo->f_blocksfree,
+            operatorshortnames[td->operator],
+            td->limit_absolute);
+
+          return FALSE;
+
+        }
+
+      }
+
+    if(Run.debug) {
+
+      log("'%s' space usage check passed [current space usage=%.1f%%]\n",
+        t->name,
+        (float) 100 * (t->devinfo->f_blocks - t->devinfo->f_blocksfree) / 
t->devinfo->f_blocks);
+
+    }
+
+    return TRUE;
+
+  default:
+
+    log("'%s' error: unknow resource type: [%d]\n", t->name, td->resource);
+    return FALSE;
+
+  }
+
+}
+
 
 /**
  * Signal handler for connection timeout

reply via email to

[Prev in Thread] Current Thread [Next in Thread]