Index: trunk/src/sh_log_check.c
===================================================================
--- trunk/src/sh_log_check.c	(revision 275)
+++ trunk/src/sh_log_check.c	(revision 276)
@@ -8,4 +8,21 @@
 #include <sys/stat.h>
 #include <fcntl.h>
+
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#define NAMLEN(dirent) sl_strlen((dirent)->d_name)
+#else
+#define dirent direct
+#define NAMLEN(dirent) (dirent)->d_namlen
+#ifdef HAVE_SYS_NDIR_H
+#include <sys/ndir.h>
+#endif
+#ifdef HAVE_SYS_DIR_H
+#include <sys/dir.h>
+#endif
+#ifdef HAVE_NDIR_H
+#include <ndir.h>
+#endif
+#endif
 
 #if !defined(O_NONBLOCK)
@@ -58,5 +75,5 @@
     {  "PACCT",  sh_read_pacct,   sh_parse_pacct,  NULL },
 #endif
-    {  "SHELL",  sh_read_shell,   sh_parse_generic,  sh_eval_fileinfo_generic },
+    {  "SHELL",  sh_read_shell,   sh_parse_shell,  NULL },
 };
 
@@ -69,19 +86,15 @@
 };
 
+static int    do_checkpoint_cleanup = S_FALSE;
+
 static char * save_dir = NULL;
 
-static void * sh_dummy_path = NULL;
-
-static char * build_path (struct sh_logfile * record)
-{
-  size_t plen;
-  int    retval;
-  char * path = NULL;
-
-  sh_dummy_path = (void *)&path;
+static const char * get_save_dir(void)
+{
+  int retval;
 
   if (!save_dir)
     {
-      save_dir = sh_util_strdup(DEFAULT_PIDDIR);
+      save_dir = sh_util_strdup(DEFAULT_DATAROOT);
 
       SH_MUTEX_LOCK(mutex_thread_nolog);
@@ -94,14 +107,85 @@
 	}
     }
-
-  plen = strlen(save_dir);
-
-  if (SL_TRUE == sl_ok_adds(plen, 130))
-    {
-      plen += 130; /* 64 + 64 + 2 */
-      path = SH_ALLOC(plen);
-      (void) sl_snprintf(path, plen, "%s/%lu_%lu", save_dir,
-			 (unsigned long) record->device_id, 
-			 (unsigned long) record->inode);
+  return save_dir;
+}
+
+static void clean_dir()
+{
+  DIR * dir;
+  struct dirent * entry;
+
+  const char * dirpath;
+
+  if (S_FALSE == do_checkpoint_cleanup)
+    return;
+
+  dirpath = get_save_dir();
+
+  if (dirpath)
+    {
+      dir = opendir(dirpath);
+      if (dir)
+	{
+	  unsigned long a, b;
+	  int retval;
+	  char c;
+	  size_t dlen = strlen(dirpath) + 1;
+	  time_t now  = time(NULL);
+
+	  while (NULL != (entry = readdir(dir)))
+	    {
+	      retval = sscanf(entry->d_name, "%lu_%lu%c", &a, &b, &c);
+
+	      if (2 == retval)
+		{
+		  struct stat buf;
+		  char * path;
+		  size_t  plen = strlen(entry->d_name) + 1;
+
+		  if (SL_TRUE == sl_ok_adds(plen, dlen))
+		    {
+		      plen += dlen;
+		      path = SH_ALLOC(plen);
+		      (void) sl_snprintf(path, plen, "%s/%s", 
+					 dirpath,entry->d_name);
+
+		      if (0 == retry_lstat(FIL__, __LINE__, path, &buf) &&
+			  S_ISREG(buf.st_mode))
+			{
+			  if (buf.st_mtime < now && 
+			      (now - buf.st_mtime) > 2592000) /* 30 days */
+			    {
+			      if (0 == tf_trust_check (path, SL_YESPRIV))
+				{
+				  unlink(path);
+				}
+			    }
+			}
+		    }
+		}
+	    }
+	  closedir(dir);
+	}
+    }
+}
+
+static char * build_path (struct sh_logfile * record)
+{
+  size_t plen;
+  char * path = NULL;
+  const char * dir = get_save_dir();
+
+  if (dir)
+    {
+      plen = strlen(dir);
+
+      if (SL_TRUE == sl_ok_adds(plen, 130))
+	{
+	  plen += 130; /* 64 + 64 + 2 */
+	  path = SH_ALLOC(plen);
+	  (void) sl_snprintf(path, plen, "%s/%lu_%lu", dir,
+			     (unsigned long) record->device_id, 
+			     (unsigned long) record->inode);
+	}
     }
 
@@ -113,4 +197,5 @@
   char * path;
   FILE * fd;
+  mode_t mask;
   struct logfile_record save_rec;
 
@@ -125,5 +210,8 @@
 	}
 
+      mask = umask(S_IWGRP | S_IWOTH);
       fd = fopen(path, "wb");
+      (void) umask(mask);
+
       if (fd)
 	{
@@ -260,5 +348,5 @@
 
   thisfile->filename     = filename;
-  if (strcmp(splits[0], _("SHELL")))
+  if (0 == strcmp(splits[0], _("SHELL")))
     thisfile->flags        = SH_LOGFILE_NOFILE;
   else
@@ -729,11 +817,67 @@
 }
 
+struct task_entry
+{
+  sh_tas_t task;
+  struct task_entry * next;
+};
+
+static struct task_entry * tasklist = NULL;
+
+static struct task_entry * task_find(FILE * fp)
+{
+  struct task_entry * entry = tasklist;
+  while (entry)
+    {
+      if (entry->task.pipe == fp)
+	return (entry);
+      entry = entry->next;
+    }
+  return NULL;
+}
+ 
+static void task_remove(struct task_entry * task)
+{
+  struct task_entry * entry = tasklist;
+  struct task_entry * prev  = tasklist;
+
+  while (entry)
+    {
+      if (entry == task)
+	{
+	  if (entry == tasklist)
+	    {
+	      tasklist = entry->next;
+	      SH_FREE(entry);
+	      return;
+	    }
+	  else
+	    {
+	      prev->next = entry->next;
+	      SH_FREE(entry);
+	      return;
+	    }
+	}
+      prev  = entry;
+      entry = entry->next;
+    }
+  return;
+}
+ 
+static void task_add(struct task_entry * entry)
+{
+  entry->next = tasklist;
+  tasklist    = entry;
+  return;
+}
+ 
 sh_string * sh_command_reader (sh_string * s, struct sh_logfile * logfile)
 {
-  sh_tas_t task;
-  struct  sigaction  new_act;
-  struct  sigaction  old_act;
-
-  volatile int         status;
+  struct task_entry * entry;
+
+  struct  sigaction   new_act;
+  struct  sigaction   old_act;
+
+  volatile int        status;
   char * tmp;
 
@@ -744,4 +888,5 @@
       /* ignore SIGPIPE (instead get EPIPE if connection is closed)
        */
+      memset(&new_act, 0, sizeof(struct  sigaction));
       new_act.sa_handler = SIG_IGN;
       (void) retry_sigaction (FIL__, __LINE__, SIGPIPE, &new_act, &old_act);
@@ -751,4 +896,6 @@
       status = (int) sh_string_read(s, logfile->fp, 8192);
 
+      fprintf(stderr, "FIXME: %s\n", sh_string_str(s));
+
       /* restore old signal handler
        */
@@ -757,5 +904,8 @@
       if (status <= 0)
 	{
-	  sh_ext_pclose (&task);
+	  entry = task_find(logfile->fp);
+	  sh_ext_pclose (&(entry->task));
+	  task_remove(entry);
+
 	  logfile->fp = NULL;
 	  sh_string_destroy(&s);
@@ -778,12 +928,16 @@
     }
 
-  status = sh_ext_popen_init (&task, logfile->filename);
+  entry = SH_ALLOC(sizeof(struct task_entry));
+
+  status = sh_ext_popen_init (&(entry->task), logfile->filename);
   if (0 == status)
     {
-      logfile->fp = task.pipe;
+      task_add(entry);
+      logfile->fp = entry->task.pipe;
       goto start_read;
     }
   else
     {
+      SH_FREE(entry);
       SH_MUTEX_LOCK(mutex_thread_nolog);
       sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN, 
@@ -1050,4 +1204,5 @@
       sh_keep_match();
       sh_log_mark_check();
+      clean_dir();
     }
   SH_MUTEX_UNLOCK(mutex_logmon_check);
@@ -1083,4 +1238,5 @@
 
 static int sh_logmon_set_active  (const char *str);
+static int sh_logmon_set_clean  (const char *str);
 static int sh_logmon_set_interval(const char *str);
 static int sh_logmon_add_watch (const char * str);
@@ -1104,4 +1260,8 @@
     },
     {
+        N_("logmonclean"),
+        sh_logmon_set_clean,
+    },
+    {
         N_("logmonwatch"),
         sh_logmon_add_watch,
@@ -1170,4 +1330,17 @@
 
   value = sh_util_flagval(str, &ShLogmonActive);
+
+  SL_RETURN((value), _("sh_logmon_set_active"));
+}
+
+/* Decide if we're active.
+ */
+static int sh_logmon_set_clean(const char *str) 
+{
+  int value;
+    
+  SL_ENTER(_("sh_logmon_set_active"));
+
+  value = sh_util_flagval(str, &do_checkpoint_cleanup);
 
   SL_RETURN((value), _("sh_logmon_set_active"));
Index: trunk/src/sh_log_evalrule.c
===================================================================
--- trunk/src/sh_log_evalrule.c	(revision 275)
+++ trunk/src/sh_log_evalrule.c	(revision 276)
@@ -1039,5 +1039,5 @@
     msg = sh_util_safe_name_keepspace (sh_string_str(record->message));
   }
-  tmp = sh_util_safe_name (record->filename);
+  tmp = sh_util_safe_name_keepspace (record->filename);
   ttt = sh_util_safe_name_keepspace (sh_string_str(record->timestr));
   sh_error_handle (severity, FIL__, __LINE__, 0, MSG_LOGMON_REP,
@@ -1070,5 +1070,5 @@
 
   SH_MUTEX_LOCK(mutex_thread_nolog);
-  tmp = sh_util_safe_name (sh_string_str(path));
+  tmp = sh_util_safe_name_keepspace (sh_string_str(path));
   msg = sh_util_safe_name_keepspace (sh_string_str(message));
   sh_error_handle (severity, FIL__, __LINE__, 0, MSG_LOGMON_SUM,
Index: trunk/src/sh_log_parse_apache.c
===================================================================
--- trunk/src/sh_log_parse_apache.c	(revision 275)
+++ trunk/src/sh_log_parse_apache.c	(revision 276)
@@ -390,5 +390,5 @@
       record->message   = sh_string_new_from_lchar(sh_string_str(logline), 
 						   sh_string_len(logline));
-      record->pid       = 0;
+      record->pid       = PID_INVALID;
 
       pcre_free(hstr); 
Index: trunk/src/sh_nmail.c
===================================================================
--- trunk/src/sh_nmail.c	(revision 275)
+++ trunk/src/sh_nmail.c	(revision 276)
@@ -966,4 +966,5 @@
 {
   struct alias * new;
+  sh_filter_type * p = NULL;
 
   while (list)
@@ -976,5 +977,9 @@
 	{
 	  sh_filter_free(new->mail_filter);
-	  SH_FREE(new->mail_filter);
+	  if (!p || p != new->mail_filter)
+	    {
+	      p = new->mail_filter;
+	      SH_FREE(new->mail_filter);
+	    }
 	}
       sh_string_destroy(&(new->recipient));
@@ -1007,5 +1012,5 @@
 	{
 	  sh_filter_free(item->mail_filter);
-	  SH_FREE(item->mail_filter);
+	  /* SH_FREE(item->mail_filter); */
 	}
       SH_FREE(item);
Index: trunk/src/sh_string.c
===================================================================
--- trunk/src/sh_string.c	(revision 275)
+++ trunk/src/sh_string.c	(revision 276)
@@ -17,4 +17,6 @@
 
 #include <ctype.h>
+#include <errno.h>
+
 /* Split array at delim in at most nfields fields. 
  * Empty fields are returned as empty (zero-length) strings. 
@@ -286,4 +288,15 @@
 }
 
+static char * sh_str_fgets (char *s, int size, FILE *fp)
+{
+  char * ret;
+  do {
+    clearerr(fp);
+    ret = fgets(s, size, fp);
+  } while (ret == NULL && ferror(fp) && errno == EAGAIN);
+
+  return ret;
+}
+
 size_t sh_string_read_int(sh_string * s, FILE * fp, size_t maxlen, char *start)
 {
@@ -293,5 +306,10 @@
   if (start)
     {
-      int first = fgetc(fp);
+      int first;
+
+      do {
+	clearerr(fp);
+	first = fgetc(fp);
+      } while (first == EOF && ferror(fp) && errno == EAGAIN);
 
       if (first == EOF)
@@ -313,5 +331,5 @@
   /* case 1) EOF or error 
    */
-  if (fgets(s->str, s->siz, fp) == NULL)
+  if (sh_str_fgets(s->str, s->siz, fp) == NULL)
     {
       sh_string_truncate(s, 0);
@@ -348,5 +366,5 @@
       }
     
-    if (fgets(&(s->str[s->len]), (s->siz - s->len), fp) == NULL) 
+    if (sh_str_fgets(&(s->str[s->len]), (s->siz - s->len), fp) == NULL) 
       {
         if (ferror(fp))
@@ -542,5 +560,4 @@
   int    i, curr, last;
 
-
   for (i = 0; i < ovecnum; ++i)
     {
@@ -588,5 +605,5 @@
       if (ovector[2*i] >= 0)
         {
-          curr = i;
+          curr = 2*i;
           break;
         }
@@ -599,7 +616,15 @@
       /* First part, until start of first replacement 
        */
-      memcpy(p, s->str, (size_t)ovector[curr]); p += ovector[curr];
-      memcpy(p, replacement,    rlen);       p += rlen;
-      *p = '\0'; r->len += (ovector[curr] + rlen);
+      if (r->siz > (unsigned int)ovector[curr]) {
+	memcpy(p, s->str, (size_t)ovector[curr]); 
+	p += ovector[curr]; 
+	r->len += ovector[curr];
+      }
+      if (r->siz > (r->len + rlen)) {
+	memcpy(p, replacement,    rlen); 
+	p += rlen;
+	r->len += rlen;
+      }
+      *p = '\0';
 
       last = curr + 1;
@@ -618,16 +643,20 @@
               len = (size_t) tlen;
 
-              if (tlen > 0)
+              if (tlen > 0 && r->siz > (r->len + len))
                 {
                   memcpy(p, &(s->str[ovector[last]]), (size_t)len);
                   p += len;
+		  r->len += len; 
                 }
               
               /* The replacement */
-              memcpy(p, replacement, rlen);       
-              p += rlen;
+	      if (r->siz > (r->len + rlen)) {
+		memcpy(p, replacement, rlen);       
+		p += rlen;
+		r->len += rlen;
+	      }
               
               /* null terminate */
-              *p = '\0'; r->len += (len + rlen);
+              *p = '\0';
 
               last = curr + 1;
@@ -645,6 +674,10 @@
             {
               len = (size_t)tlen;
-              memcpy(p, &(s->str[ovector[2*i -1]]), (size_t)len);
-              p += len; *p = '\0'; r->len += (len - 1);
+	      if (r->siz >= (r->len + len)) {
+		memcpy(p, &(s->str[ovector[2*i -1]]), (size_t)len);
+		p += (len - 1); 
+		r->len += (len - 1);
+		*p = '\0'; 
+	      }
             }
         }
