Index: trunk/src/sh_fInotify.c
===================================================================
--- trunk/src/sh_fInotify.c	(revision 370)
+++ trunk/src/sh_fInotify.c	(revision 371)
@@ -143,4 +143,10 @@
 	}
     }
+  else if (arg != NULL && arg->initval < 0 &&
+      (sh.flag.isdaemon != S_TRUE && sh.flag.loop != S_TRUE))
+    {
+      sh.flag.inotify = 0;
+      return SH_MOD_FAILED;
+    }
   else if (arg != NULL && arg->initval == SH_MOD_THREAD &&
 	   (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
@@ -162,4 +168,5 @@
   ssize_t len = -1;
   char *  buffer = SH_ALLOC(16384);
+  static int count = 0;
 
   if (ShfInotifyActive == S_FALSE)
@@ -175,5 +182,5 @@
   /* Blocking read from inotify file descriptor.
    */
-  len = sh_inotify_read(buffer, 16384);
+  len = sh_inotify_read_timeout(buffer, 16384, 1);
   
   if (len > 0)
@@ -203,4 +210,12 @@
    */ 
   sh_inotify_recheck_watches (&sh_file_watches, &sh_file_missing);
+
+  ++count;
+
+  if (count >= 10)
+    {
+      count = 0; /* Re-expand glob patterns to discover added files */
+      sh_files_check_globFilePatterns();
+    }
 
   return 0;
@@ -274,5 +289,6 @@
   SH_MUTEX_LOCK(mutex_thread_nolog);
   sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, 
-		  _("Cannot set max_user_watches"), _("sh_fInotify_set_nwatches"));
+		  _("Cannot set max_user_watches"), 
+		  _("sh_fInotify_set_nwatches"));
   SH_MUTEX_UNLOCK(mutex_thread_nolog);
   return;
@@ -353,4 +369,32 @@
   unsigned long check_mask;
   char * filename;
+  extern int flag_err_debug;
+
+  if (flag_err_debug == SL_TRUE)
+    {
+      char dbgbuf[256];
+      sl_strlcpy (dbgbuf, "inotify mask: ", sizeof(dbgbuf));
+      if (event->mask & IN_ACCESS) sl_strlcat(dbgbuf, "IN_ACCESS ", sizeof(dbgbuf));
+      if (event->mask & IN_ATTRIB) sl_strlcat(dbgbuf, "IN_ATTRIB ", sizeof(dbgbuf));
+      if (event->mask & IN_CLOSE_WRITE) sl_strlcat(dbgbuf, "IN_CLOSE_WRITE ", sizeof(dbgbuf));
+      if (event->mask & IN_CLOSE_NOWRITE) sl_strlcat(dbgbuf, "IN_CLOSE_NOWRITE ", sizeof(dbgbuf));
+      if (event->mask & IN_CREATE) sl_strlcat(dbgbuf, "IN_CREATE ", sizeof(dbgbuf));
+      if (event->mask & IN_DELETE) sl_strlcat(dbgbuf, "IN_DELETE ", sizeof(dbgbuf));
+      if (event->mask & IN_DELETE_SELF) sl_strlcat(dbgbuf, "IN_DELETE_SELF ", sizeof(dbgbuf));
+      if (event->mask & IN_MODIFY) sl_strlcat(dbgbuf, "IN_MODIFY ", sizeof(dbgbuf));
+      if (event->mask & IN_MOVE_SELF) sl_strlcat(dbgbuf, "IN_MOVE_SELF ", sizeof(dbgbuf));
+      if (event->mask & IN_MOVED_FROM) sl_strlcat(dbgbuf, "IN_MOVED_FROM ", sizeof(dbgbuf));
+      if (event->mask & IN_MOVED_TO) sl_strlcat(dbgbuf, "IN_MOVED_TO ", sizeof(dbgbuf));
+      if (event->mask & IN_OPEN) sl_strlcat(dbgbuf, "IN_OPEN ", sizeof(dbgbuf));
+      if (event->mask & IN_IGNORED) sl_strlcat(dbgbuf, "IN_IGNORED ", sizeof(dbgbuf));
+      if (event->mask & IN_ISDIR) sl_strlcat(dbgbuf, "IN_ISDIR ", sizeof(dbgbuf));
+      if (event->mask & IN_Q_OVERFLOW) sl_strlcat(dbgbuf, "IN_Q_OVERFLOW ", sizeof(dbgbuf));
+      if (event->mask & IN_UNMOUNT) sl_strlcat(dbgbuf, "IN_UNMOUNT ", sizeof(dbgbuf));
+      SH_MUTEX_LOCK(mutex_thread_nolog);
+      sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN, 
+		      dbgbuf, _("sh_fInotify_process"));
+      SH_MUTEX_UNLOCK(mutex_thread_nolog);
+    }
+
 
   if (event->wd >= 0)
@@ -438,5 +482,5 @@
     }
 
-  if ( (event->mask & (IN_ACCESS|IN_MODIFY)) != 0)
+  if ( (event->mask & (IN_ATTRIB|IN_MODIFY)) != 0)
     {
       sh_files_search_file(path, &class, &check_mask, &reported);
@@ -477,7 +521,9 @@
       if (S_FALSE == sh_ignore_chk_new(path))
 	{
+	  int ret;
+
 	  sh_files_clear_file_reported(path);
 	  
-	  sh_files_search_file(path, &class, &check_mask, &reported);
+	  ret = sh_files_search_file(path, &class, &check_mask, &reported);
 	  
 	  sh_files_filecheck (class, check_mask, filename,
@@ -486,4 +532,10 @@
 	  if (SH_FFLAG_REPORTED_SET(reported))
 	    sh_files_set_file_reported(path);
+
+	  if (ret != 0)
+	    {
+	      sh_inotify_add_watch(path, &sh_file_watches, &ret,
+				   class, check_mask);
+	    }
 	}
     }
Index: trunk/src/sh_files.c
===================================================================
--- trunk/src/sh_files.c	(revision 370)
+++ trunk/src/sh_files.c	(revision 371)
@@ -56,4 +56,8 @@
 #include <glob.h>
 #endif
+#ifdef HAVE_FNMATCH_H
+#include <fnmatch.h>
+#endif
+
 
 #include "samhain.h"
@@ -281,4 +285,6 @@
 static zAVLTree * zfileList     = NULL;
 
+SH_MUTEX_STATIC(mutex_zfiles,      PTHREAD_MUTEX_INITIALIZER);
+SH_MUTEX_STATIC(mutex_zglob,       PTHREAD_MUTEX_INITIALIZER);
 
 static int        sh_files_fullpath  (char * testdir, char * d_name, 
@@ -503,6 +509,8 @@
   SL_ENTER(_("sh_files_delfilestack"));
 
+  SH_MUTEX_LOCK(mutex_zfiles);
   zAVLFreeTree (zfileList, free_dirstack);
   zfileList = NULL;
+  SH_MUTEX_UNLOCK(mutex_zfiles);
 
   SL_RETURN(0, _("sh_files_delfilestack"));
@@ -559,8 +567,9 @@
   SL_ENTER(_("sh_files_reset"));
 
+  SH_MUTEX_LOCK(mutex_zfiles);
   for (ptr = (dirstack_t *) zAVLFirst(&avlcursor, zfileList); ptr;
        ptr = (dirstack_t *) zAVLNext(&avlcursor))
     ptr->checked = 0;
-
+  SH_MUTEX_UNLOCK(mutex_zfiles);
   SL_RET0(_("sh_files_reset"));
 }
@@ -903,4 +912,5 @@
   new_item_ptr->childs_checked = S_FALSE;
 
+  SH_MUTEX_LOCK(mutex_zfiles);
   if (zfileList == NULL)
     {
@@ -914,4 +924,5 @@
 
   ret = zAVLInsert (zfileList, new_item_ptr);
+  SH_MUTEX_UNLOCK(mutex_zfiles);
 
   if (-1 == ret)
@@ -920,6 +931,5 @@
       aud__exit(FIL__, __LINE__, EXIT_FAILURE);
     }
-
-  if (3 == ret)
+  else if (3 == ret)
     { 
       if (sh.flag.started != S_TRUE)
@@ -930,8 +940,11 @@
       new_item_ptr = NULL;
     }
-
-  if (new_item_ptr && MODI_AUDIT_ENABLED(new_item_ptr->check_mask))
-    {
-      sh_audit_mark(new_item_ptr->name);
+  else
+    {
+      unsigned long mask = sh_files_maskof(class);
+      if (MODI_AUDIT_ENABLED(mask))
+	{
+	  sh_audit_mark(new_item_ptr->name);
+	}
     }
   SL_RETURN(0, _("sh_files_push_file_int"));
@@ -954,9 +967,11 @@
 
 static void sh_files_pushglob (int class, int type, const char * p, int rdepth,
-			       unsigned long check_mask, int flag)
+			       unsigned long check_mask_in, int flag)
 {
   int     globstatus = -1;
   unsigned int     gloop;
   glob_t  pglob;
+
+  volatile unsigned long check_mask = check_mask_in;
   
   SL_ENTER(_("sh_files_pushglob"));
@@ -974,4 +989,5 @@
 	  int     ret;
 	  
+	  SH_MUTEX_TRYLOCK(mutex_zfiles);
 	  fileName = sh_util_strdup (p);
 	  
@@ -1001,4 +1017,5 @@
 	      SH_FREE(new_item_ptr);
 	    }
+	  SH_MUTEX_TRYLOCK_UNLOCK(mutex_zfiles);
 	}
 
@@ -1058,5 +1075,5 @@
 }
 
-void sh_files_check_globPatterns()
+void sh_files_check_globFilePatterns()
 {
   sh_globstack_t * testPattern;
@@ -1065,5 +1082,30 @@
   SL_ENTER(_("sh_files_check_globPatterns"));
 
-  for (testPattern = (sh_globstack_t *) zAVLFirst (&cursor, zglobList); testPattern;
+  SH_MUTEX_LOCK(mutex_zglob);
+  for (testPattern = (sh_globstack_t *) zAVLFirst (&cursor, zglobList); 
+       testPattern;
+       testPattern = (sh_globstack_t *) zAVLNext  (&cursor))
+    {
+      if (testPattern->type == SH_LIST_FILE)
+	{
+	  sh_files_pushglob(testPattern->class, testPattern->type, 
+			    testPattern->name, testPattern->rdepth,
+			    testPattern->check_mask, 1);
+	}
+    }
+  SH_MUTEX_UNLOCK(mutex_zglob);
+  SL_RET0(_("sh_files_check_globPatterns"));
+}
+
+void sh_files_check_globPatterns()
+{
+  sh_globstack_t * testPattern;
+  zAVLCursor   cursor;
+
+  SL_ENTER(_("sh_files_check_globPatterns"));
+
+  SH_MUTEX_LOCK(mutex_zglob);
+  for (testPattern = (sh_globstack_t *) zAVLFirst (&cursor, zglobList); 
+       testPattern;
        testPattern = (sh_globstack_t *) zAVLNext  (&cursor))
     {
@@ -1072,4 +1114,5 @@
 			testPattern->check_mask, 1);
     }
+  SH_MUTEX_UNLOCK(mutex_zglob);
   SL_RET0(_("sh_files_check_globPatterns"));
 }
@@ -1097,6 +1140,8 @@
   SL_ENTER(_("sh_files_delglobstack"));
 
+  SH_MUTEX_LOCK(mutex_zglob);
   zAVLFreeTree (zglobList, free_globstack);
   zglobList = NULL;
+  SH_MUTEX_UNLOCK(mutex_zglob);
 
   SL_RETURN(0, _("sh_files_delglobstack"));
@@ -1245,4 +1290,6 @@
 }
 
+static void * sh_dummy_ptr;
+
 unsigned long sh_dirs_chk (int which)
 {
@@ -1252,9 +1299,11 @@
   dirstack_t * dst_ptr;
   int          status;
-  unsigned long dcount = 0;
+  volatile unsigned long dcount = 0;
   char       * tmp;
   
   SL_ENTER(_("sh_dirs_chk"));
 
+  sh_dummy_ptr = (void *) &ptr;
+  
   if (which == 1)
     tree = zdirListOne;
@@ -1271,4 +1320,5 @@
       if (ptr->checked == S_FALSE)
 	{
+	  SH_MUTEX_LOCK(mutex_zfiles);
 	  /* 28 Aug 2001 check the top level directory
 	   */
@@ -1290,4 +1340,5 @@
 		}
 	    }
+	  SH_MUTEX_UNLOCK(mutex_zfiles);
 
 	  if (status == S_FALSE)
@@ -1755,4 +1806,6 @@
 #endif
 
+static void * sh_dummy_dirlist;
+
 /* -- check a single directory and its content
  */
@@ -1781,10 +1834,10 @@
   int             rdepth_next;
   int             class_next;
-  int             file_class_next;
+  volatile int    file_class_next;
   unsigned long   check_mask_next;
-  unsigned long   file_check_mask_next;
-
-  int             checked_flag  = S_FALSE;
-  int             cchecked_flag = S_FALSE;
+  volatile unsigned long   file_check_mask_next;
+
+  volatile int    checked_flag  = S_FALSE;
+  volatile int    cchecked_flag = S_FALSE;
 
   dirstack_t *    dst_ptr;
@@ -1797,4 +1850,6 @@
 
   SL_ENTER(_("sh_files_checkdir"));
+
+  sh_dummy_dirlist = (void *) &dirlist;
 
   if (sig_urgent > 0) {
@@ -2045,4 +2100,5 @@
       }
 
+    SH_MUTEX_LOCK(mutex_zfiles);
     dst_ptr         = (dirstack_t *) zAVLSearch(zfileList, tmpcat);
 
@@ -2059,4 +2115,5 @@
 	/* cchecked_flag      = dst_ptr->childs_checked; */
       }
+    SH_MUTEX_UNLOCK(mutex_zfiles);
     
     /* ---- Has been checked already. ----
@@ -2518,7 +2575,16 @@
  * -----------------------------------
  */
-int sh_files_search_file(char * name, int * class, unsigned long *check_mask, int *reported)
-{
-  dirstack_t * item = zAVLSearch(zfileList, name);
+int sh_files_search_file(char * name, int * class, 
+			 unsigned long *check_mask, int *reported)
+{
+  int retval = 0;
+#if defined(HAVE_GLOB_H) && defined(HAVE_FNMATCH_H)
+  sh_globstack_t * testPattern;
+  zAVLCursor   cursor;
+#endif
+  dirstack_t * item;
+
+  SH_MUTEX_LOCK(mutex_zfiles);
+  item = zAVLSearch(zfileList, name);
 
   if (item)
@@ -2527,12 +2593,39 @@
       *class      = item->class;
       *reported   = item->is_reported;
-      return 1;
-    }
-  return 0;
+      retval = 1;
+      goto out;
+    }
+
+#if defined(HAVE_GLOB_H) && defined(HAVE_FNMATCH_H)
+  SH_MUTEX_LOCK(mutex_zglob);
+  for (testPattern = (sh_globstack_t *) zAVLFirst (&cursor, zglobList); 
+       testPattern;
+       testPattern = (sh_globstack_t *) zAVLNext  (&cursor))
+    {
+      if (testPattern->type == SH_LIST_FILE)
+	{
+	  if (0 == fnmatch(testPattern->name, name, FNM_PATHNAME|FNM_PERIOD))
+	    {
+	      *check_mask = testPattern->check_mask;
+	      *class      = testPattern->class;
+	      retval = 1;
+	      break;
+	    }
+	
+	}
+    }
+  SH_MUTEX_UNLOCK(mutex_zglob);
+#endif
+ out:
+  SH_MUTEX_UNLOCK(mutex_zfiles);
+  return retval;
 }
 
 void sh_files_set_file_reported(char * name)
 {
-  dirstack_t * item = zAVLSearch(zfileList, name);
+  dirstack_t * item;
+
+  SH_MUTEX_LOCK_UNSAFE(mutex_zfiles);
+  item = zAVLSearch(zfileList, name);
 
   if (item)
@@ -2541,4 +2634,5 @@
 	SET_SH_FFLAG_REPORTED(item->is_reported);
     }
+  SH_MUTEX_UNLOCK_UNSAFE(mutex_zfiles);
   return;
 }
@@ -2546,5 +2640,8 @@
 void sh_files_clear_file_reported(char * name)
 {
-  dirstack_t * item = zAVLSearch(zfileList, name);
+  dirstack_t * item;
+
+  SH_MUTEX_LOCK_UNSAFE(mutex_zfiles);
+  item = zAVLSearch(zfileList, name);
 
   if (item)
@@ -2552,4 +2649,5 @@
       CLEAR_SH_FFLAG_REPORTED(item->is_reported);
     }
+  SH_MUTEX_UNLOCK_UNSAFE(mutex_zfiles);
   return;
 }
@@ -2567,4 +2665,5 @@
   dirstack_t * pfilL;
   zAVLCursor   cursor;
+  volatile int retval = -1;
 
   SL_ENTER(_("check_file"));
@@ -2573,4 +2672,5 @@
     SL_RETURN(0, _("check_file"));
 
+  SH_MUTEX_LOCK(mutex_zfiles);
   for (pfilL = (dirstack_t *) zAVLFirst (&cursor, zfileList); pfilL;
        pfilL = (dirstack_t *) zAVLNext  (&cursor))
@@ -2580,9 +2680,16 @@
 	  (pfilL->check_mask & MODI_CTM) == 0 &&
 	  (pfilL->check_mask & MODI_MTM) == 0)
-	SL_RETURN(0, _("check_file"));
-    }
-  SL_RETURN((-1), _("check_file"));
-}
-  
+	{
+	  retval = 0;
+	  break;
+	}
+    }
+  SH_MUTEX_UNLOCK(mutex_zfiles);
+
+  SL_RETURN(retval, _("check_file"));
+}
+
+static void * sh_dummy_pdirL;
+
 int sh_files_test_setup_int (zAVLTree * tree)
 {
@@ -2596,4 +2703,6 @@
   SL_ENTER(_("sh_files_test_setup"));
 
+  sh_dummy_pdirL = (void *) &pdirL;
+
   for (pdirL = (dirstack_t *) zAVLFirst (&cursor1, tree); pdirL;
        pdirL = (dirstack_t *) zAVLNext  (&cursor1))
@@ -2601,4 +2710,5 @@
       dlen = strlen(pdirL->name);
 
+      SH_MUTEX_LOCK(mutex_zfiles);
       for (pfilL = (dirstack_t *) zAVLFirst (&cursor2, zfileList); pfilL;
 	   pfilL = (dirstack_t *) zAVLNext  (&cursor2))
@@ -2631,4 +2741,5 @@
 	    }
 	}
+      SH_MUTEX_UNLOCK(mutex_zfiles);
     }
 
Index: trunk/src/sh_hash.c
===================================================================
--- trunk/src/sh_hash.c	(revision 370)
+++ trunk/src/sh_hash.c	(revision 371)
@@ -1510,5 +1510,5 @@
  unlock_and_exit:
   ; /* 'label at end of compound statement */
-  SH_MUTEX_UNLOCK(mutex_hash);
+  SH_MUTEX_TRYLOCK_UNLOCK(mutex_hash);
 
   SL_RET0(_("sh_hash_hashdelete"));
Index: trunk/src/sh_inotify.c
===================================================================
--- trunk/src/sh_inotify.c	(revision 370)
+++ trunk/src/sh_inotify.c	(revision 371)
@@ -213,13 +213,24 @@
 ssize_t sh_inotify_read(char * buffer, size_t count)
 {
+  ssize_t len = -1;
+  int     ifd = sh_inotify_getfd();
+
+  do {
+    len = read (ifd, buffer, count);
+  } while (len < 0 && (errno == EINTR || errno == EAGAIN));
+
+  return len;
+}
+
+ssize_t sh_inotify_read_timeout(char * buffer, size_t count, int timeout)
+{
   ssize_t len;
   int     ifd = sh_inotify_getfd();
 
-  do {
-    len = read (ifd, buffer, count);
-  } while (len < 0 || errno == EINTR);
+  len = sl_read_timeout_fd (ifd, buffer, count, timeout, SL_FALSE);
 
   return len;
 }
+
 
 static void sh_inotify_free_watch(void * item)
@@ -287,5 +298,8 @@
     {
       listcursor->curnode = listcursor->curnode->next;
-      return listcursor->curnode->watch;
+      if (listcursor->curnode)
+	return listcursor->curnode->watch;
+      else
+	return NULL;
     }
 
@@ -512,5 +526,6 @@
   int ifd = sh_get_inotify_fd();
 
-  extern void sh_fInotify_report_add(char * path, int class, unsigned long check_mask);
+  extern void sh_fInotify_report_add(char * path, 
+				     int class, unsigned long check_mask);
 
   sh_dummy_litem = (void*) &litem;
@@ -520,6 +535,7 @@
   SH_MUTEX_LOCK(mutex_list_dormant);
   
-  for (litem = sh_inotify_list_first(&listcursor, save); litem;
-       litem = sh_inotify_list_next(&listcursor, save))
+  litem = sh_inotify_list_first(&listcursor, save);
+
+  while (litem)
     {
     have_next:
@@ -545,4 +561,5 @@
 	    }
 	}
+      litem = sh_inotify_list_next(&listcursor, save);
     }
   SH_MUTEX_UNLOCK(mutex_list_dormant);
@@ -725,5 +742,5 @@
       /* -- Blocking read on inotify file descriptor
        */
-      sh_inotify_read(buffer, sizeof(buffer));
+      len = sh_inotify_read(buffer, sizeof(buffer));
 
       if (len > 0)
Index: trunk/src/slib.c
===================================================================
--- trunk/src/slib.c	(revision 370)
+++ trunk/src/slib.c	(revision 371)
@@ -2611,4 +2611,5 @@
 	  else if (byteread == 0)
 	    {
+	      /* zero indicates end of file */
 	      break;
 	    }
@@ -2646,4 +2647,6 @@
 	  TPT(( 0, FIL__, __LINE__, _("msg=<timeout>")));
 	  errno = 0;
+	  if (bytes > 0)
+	    return ((int) bytes); 
 	  return (SL_TIMEOUT);
 	}
@@ -2676,4 +2679,6 @@
 	  TPT(( 0, FIL__, __LINE__, _("msg=<timeout>")));
 	  errno = 0;
+	  if (bytes > 0)
+	    return ((int) bytes);
 	  return (SL_TIMEOUT);
 	}
