Index: trunk/configure.ac
===================================================================
--- trunk/configure.ac	(revision 587)
+++ trunk/configure.ac	(revision 588)
@@ -1679,15 +1679,17 @@
         [
         if test "x${enable_logfile_monitor}" = xyes; then
-	   AC_CHECK_HEADER(pcre.h,
+	   cflags_store="$CFLAGS"
+	   CFLAGS="$CFLAGS -DPCRE2_CODE_UNIT_WIDTH=8"
+	   AC_CHECK_HEADER(pcre2.h,
                            [ 
 			   AC_DEFINE([USE_LOGFILE_MONITOR], [1], [Define if you want the logfile monitor module.])
-			   LIBS="-lpcre $LIBS"
+			   LIBS="-lpcre2-8 $LIBS"
 			   ],
 			   [
-				AC_CHECK_HEADER(pcre/pcre.h,
+				AC_CHECK_HEADER(pcre2/pcre2.h,
 			   	[
 			   	AC_DEFINE([USE_LOGFILE_MONITOR], [1], [Define if you want the logfile monitor module.])
-				AC_DEFINE([HAVE_PCRE_PCRE_H], [1], [Define if you have pcre/pcre.h.])
-			   	LIBS="-lpcre $LIBS"
+				AC_DEFINE([HAVE_PCRE2_PCRE2_H], [1], [Define if you have pcre2/pcre2.h.])
+			   	LIBS="-lpcre2-8 $LIBS"
 			   	],
 	                   	[AC_MSG_ERROR([The --enable-logfile-monitor option requires libpcre. For compiling the pcre development package is needed.])]
@@ -1695,9 +1697,5 @@
 			  ]
 	   )
-	   AC_CHECK_LIB(pcre, pcre_dfa_exec, [
-	   		      AC_DEFINE([HAVE_PCRE_DFA_EXEC], [1], [Define if you have pcre_dfa_exec])
-			      ], [
-			      AC_MSG_WARN([pcre_dfa_exec not available])
-			      ])
+	  CFLAGS="$cflags_store"
         fi
         ]
Index: trunk/docs/Changelog
===================================================================
--- trunk/docs/Changelog	(revision 587)
+++ trunk/docs/Changelog	(revision 588)
@@ -1,3 +1,12 @@
-4.5.2
+4.5.3:
+	* fix inadvertent inclusion of scripts/logrotate and init/samhain.startSystemd
+	(reported by kjd)
+	* fix annoying message from systemd about read permissions for service file
+	(reported by kjd)
+	* fix compiler warnings about unused variables
+	* move logfile monitor module from PCRE to PCRE2 (PCRE is end of life and no
+	longer actively maintained)
+
+4.5.2 (02-01-2025):
 	* fix segfault with --enable-static on unresolvable host name
 	* fix autoreconf (problem reported by Pascal de Bruijn)
Index: trunk/include/sh_string.h
===================================================================
--- trunk/include/sh_string.h	(revision 587)
+++ trunk/include/sh_string.h	(revision 588)
@@ -107,5 +107,5 @@
  */  
 sh_string * sh_string_replace(const sh_string * s, 
-                              const int * ovector, int ovecnum, 
+                              const size_t * ovector, int ovecnum, 
                               const char * replacement, size_t rlen);
 
Index: trunk/src/sh_log_check.c
===================================================================
--- trunk/src/sh_log_check.c	(revision 587)
+++ trunk/src/sh_log_check.c	(revision 588)
@@ -39,9 +39,10 @@
 #define FIL__  _("sh_log_check.c")
 
-/* Debian/Ubuntu: libpcre3-dev */
-#ifdef HAVE_PCRE_PCRE_H
-#include <pcre/pcre.h>
+/* Debian/Ubuntu: libpcre2-dev */
+#define PCRE2_CODE_UNIT_WIDTH 8
+#ifdef HAVE_PCRE2_PCRE2_H
+#include <pcre2/pcre2.h>
 #else
-#include <pcre.h>
+#include <pcre2.h>
 #endif
 
Index: trunk/src/sh_log_correlate.c
===================================================================
--- trunk/src/sh_log_correlate.c	(revision 587)
+++ trunk/src/sh_log_correlate.c	(revision 588)
@@ -9,14 +9,12 @@
 #include <time.h>
 
-/* Debian/Ubuntu: libpcre3-dev */
-#ifdef HAVE_PCRE_PCRE_H
-#include <pcre/pcre.h>
+/* Debian/Ubuntu: libpcre2-dev */
+#define PCRE2_CODE_UNIT_WIDTH 8
+#ifdef HAVE_PCRE2_PCRE2_H
+#include <pcre2/pcre2.h>
 #else
-#include <pcre.h>
+#include <pcre2.h>
 #endif
 
-#ifndef PCRE_NO_AUTO_CAPTURE
-#define PCRE_NO_AUTO_CAPTURE 0
-#endif
 
 #include "samhain.h"
@@ -173,5 +171,5 @@
 {
   sh_string       * label;           /* label of match rule     */
-  pcre            * rule;            /* compiled regex for rule */
+  pcre2_code      * rule;            /* compiled regex for rule */
   time_t            reported;        /* last reported           */
   struct sh_qeval * queue;           /* assigned queue          */
@@ -208,10 +206,10 @@
     {
       struct sh_mkeep * mkeep = SH_ALLOC(sizeof(struct sh_mkeep));
-      const char * error;
-      int          erroffset;
+      int               error;
+      size_t            erroffset;
       struct sh_qeval * rqueue = NULL;
 
-      mkeep->rule = pcre_compile(pattern, PCRE_NO_AUTO_CAPTURE, 
-			     &error, &erroffset, NULL);
+      mkeep->rule = pcre2_compile((PCRE2_SPTR8)pattern, PCRE2_ZERO_TERMINATED, PCRE2_NO_AUTO_CAPTURE, 
+				  &error, &erroffset, NULL);
       if (!(mkeep->rule))
 	{
@@ -239,5 +237,5 @@
 	  if (!rqueue)
 	    {
-	      pcre_free(mkeep->rule);
+	      pcre2_code_free(mkeep->rule);
 	      SH_FREE(splits);
 	      SH_FREE(mkeep);
@@ -264,5 +262,5 @@
       mkeep_list = mkeep->next;
       sh_string_destroy(&(mkeep->label));
-      pcre_free(mkeep->rule);
+      pcre2_code_free(mkeep->rule);
       mkeep = mkeep_list;
     }
@@ -286,31 +284,13 @@
 	  while (mkeep)
 	    {
-	      /* Use pcre_dfa_exec() to obtain number of matches. Needs ovector
-	       * array, otherwise number of matches is not returned.
-	       */
-#if defined(HAVE_PCRE_DFA_EXEC)
-	      int ovector[SH_MINIBUF];
-	      int wspace[SH_MINIBUF];
-#endif
-
-#if defined(HAVE_PCRE_DFA_EXEC)
-	      int val = pcre_dfa_exec(mkeep->rule, NULL, 
-				      sh_string_str(res), 
-				      (int)sh_string_len(res), 
-				      0, /* start at offset 0 in the subject */
-				      0, 
-				      ovector, SH_MINIBUF,
-				      wspace, SH_MINIBUF);
-#else
-	      int val = pcre_exec(mkeep->rule, NULL, 
-				  sh_string_str(res), 
-				  (int)sh_string_len(res), 
-				  0, /* start at offset 0 in the subject */
-				  0, 
-				  NULL, 0);
-	      val = (val >= 0) ? 1 : val;			      
-#endif
-
-	      if (val >= 0)
+	      pcre2_match_data * match_data = pcre2_match_data_create_from_pattern(mkeep->rule, NULL);
+	      
+	      int val = pcre2_match(mkeep->rule, 
+				    (PCRE2_SPTR8) sh_string_str(res), (int)sh_string_len(res), 0,
+				    0, match_data, NULL);
+	      
+	      pcre2_match_data_free(match_data);
+	      
+	      if (val > 0)
 		{
 		  sh_string * alias;
Index: trunk/src/sh_log_evalrule.c
===================================================================
--- trunk/src/sh_log_evalrule.c	(revision 587)
+++ trunk/src/sh_log_evalrule.c	(revision 588)
@@ -15,13 +15,14 @@
 #define FIL__  _("sh_log_evalrule.c")
 
-/* Debian/Ubuntu: libpcre3-dev */
-#ifdef HAVE_PCRE_PCRE_H
-#include <pcre/pcre.h>
+/* Debian/Ubuntu: libpcre2-dev */
+#define PCRE2_CODE_UNIT_WIDTH 8
+#ifdef HAVE_PCRE2_PCRE2_H
+#include <pcre2/pcre2.h>
 #else
-#include <pcre.h>
+#include <pcre2.h>
 #endif
 
-#ifndef PCRE_NO_AUTO_CAPTURE
-#define PCRE_NO_AUTO_CAPTURE 0
+#ifndef PCRE2_NO_AUTO_CAPTURE
+#define PCRE2_NO_AUTO_CAPTURE 0
 #endif
 
@@ -95,23 +96,22 @@
 struct sh_geval  /* Group of rules (may be a single rule) */
 {
-  sh_string       * label;           /* label for this group    */
-  pcre            * rule;            /* compiled regex for rule */
-  pcre_extra      * rule_extra;
-  int             * ovector;         /* captured substrings     */
-  int               ovecnum;         /* how many captured       */
-  int               captures;        /* (captures+1)*3 required */
-  int               flags;           /* bit flags               */
-  unsigned long     delay;           /* delay for keep rules    */
-  zAVLTree        * counterlist;     /* counters if EVAL_SUM    */
-  struct sh_qeval * queue;           /* queue for this rule     */
-  struct sh_geval * nextrule;        /* next rule in this group */
-  struct sh_geval * next;            /* next group of rules     */
-  struct sh_geval * gnext;           /* grouplist next          */
+  sh_string        * label;           /* label for this group    */
+  pcre2_code       * rule;            /* compiled regex for rule */
+
+  pcre2_match_data * match_data;      /* captured substrings     */
+  int                ovecnum;         /* how many captured       */
+  int                captures;        /* (captures+1)*3 required */
+  int                flags;           /* bit flags               */
+  unsigned long      delay;           /* delay for keep rules    */
+  zAVLTree         * counterlist;     /* counters if EVAL_SUM    */
+  struct sh_qeval  * queue;           /* queue for this rule     */
+  struct sh_geval  * nextrule;        /* next rule in this group */
+  struct sh_geval  * next;            /* next group of rules     */
+  struct sh_geval  * gnext;           /* grouplist next          */
 };
 
 struct sh_heval  /* host-specific rules */
 {
-  pcre            * hostname;        /* compiled regex for hostname */
-  pcre_extra      * hostname_extra;
+  pcre2_code      * hostname;        /* compiled regex for hostname */
   struct sh_geval * rulegroups;      /* list of group of rules      */
   struct sh_heval * next;
@@ -142,10 +142,11 @@
   struct sh_geval * ng;
   struct sh_geval * tmp;
-  pcre *  group;
-  pcre_extra * group_extra;
-  const char * error;
-  int          erroffset;
+  pcre2_code * group;
+
+  int          error;
+  PCRE2_SIZE   erroffset;
   unsigned int nfields = 2;
   size_t       lengths[2];
+  
   char *       new = sh_util_strdup(str);
   char **      splits = split_array(new, &nfields, ':', lengths);
@@ -164,5 +165,5 @@
     }
 
-  group = pcre_compile(splits[1], PCRE_NO_AUTO_CAPTURE, 
+  group = pcre2_compile((PCRE2_SPTR8)splits[1], lengths[1], PCRE2_NO_AUTO_CAPTURE, 
 		       &error, &erroffset, NULL);
   if (!group)
@@ -183,5 +184,4 @@
       return -1;
     }
-  group_extra = NULL; /* pcre_study(group, 0, &error); */
 
   ng = SH_ALLOC(sizeof(struct sh_geval));
@@ -192,6 +192,6 @@
 
   ng->rule        = group;
-  ng->rule_extra  = group_extra;
-  ng->ovector     = NULL;
+
+  ng->match_data  = pcre2_match_data_create_from_pattern(group, NULL);
   ng->ovecnum     = 0;
   ng->captures    = 0;
@@ -206,5 +206,6 @@
       if (0 != sh_eval_hadd("^.*"))
 	{
-	  pcre_free(group);
+	  pcre2_code_free(group);
+	  pcre2_match_data_free(ng->match_data);
 	  sh_string_destroy(&(ng->label));
 	  SH_FREE(splits);
@@ -266,14 +267,14 @@
   struct sh_heval * nh;
   struct sh_heval * tmp;
-  pcre *  host;
-  pcre_extra * host_extra;
-  const char * error;
-  int          erroffset;
+  pcre2_code     *  host;
+
+  int               error;
+  PCRE2_SIZE        erroffset;
 
   if (host_open)
     host_open = NULL;
 
-  host = pcre_compile(str, PCRE_NO_AUTO_CAPTURE, 
-		      &error, &erroffset, NULL);
+  host = pcre2_compile((PCRE2_SPTR8)str, PCRE2_ZERO_TERMINATED, PCRE2_NO_AUTO_CAPTURE, 
+		       &error, &erroffset, NULL);
   if (!host)
     {
@@ -291,5 +292,4 @@
       return -1;
     }
-  host_extra = NULL; /* pcre_study(host, 0, &error); */
 
   nh = SH_ALLOC(sizeof(struct sh_heval));
@@ -297,5 +297,4 @@
 
   nh->hostname = host;
-  nh->hostname_extra = host_extra;
   nh->rulegroups = NULL;
 
@@ -478,9 +477,9 @@
   struct sh_geval * tmp;
   struct sh_qeval * queue;
-  pcre *  rule;
-  pcre_extra * rule_extra;
-  const char * error;
-  int          erroffset;
-  int          captures = 0;
+  pcre2_code    *  rule;
+
+  int          error;
+  PCRE2_SIZE   erroffset;
+  unsigned int captures = 0;
   unsigned int nfields = 2; /* queue:regex */
   size_t       lengths[3];
@@ -576,6 +575,6 @@
     }
 
-  rule = pcre_compile(splits[rpos], 0, 
-		      &error, &erroffset, NULL);
+  rule = pcre2_compile((PCRE2_SPTR8)splits[rpos], lengths[rpos], 0, 
+		       &error, &erroffset, NULL);
   if (!rule)
     {
@@ -595,6 +594,6 @@
       return -1;
     }
-  rule_extra = NULL; /* pcre_study(rule, 0, &error); */
-  pcre_fullinfo(rule, rule_extra, PCRE_INFO_CAPTURECOUNT, &captures);
+
+  pcre2_pattern_info(rule, PCRE2_INFO_CAPTURECOUNT, &captures);
 
   if (flag_err_debug == S_TRUE)
@@ -602,8 +601,8 @@
       char * emsg = SH_ALLOC(SH_ERRBUF_SIZE);
       if (dstr)
-	sl_snprintf(emsg,  SH_ERRBUF_SIZE, _("Adding rule: |%s| with %d captures, keep(%lu,%s)"), 
+	sl_snprintf(emsg,  SH_ERRBUF_SIZE, _("Adding rule: |%s| with %u captures, keep(%lu,%s)"), 
 		    splits[rpos], captures, dsec, dstr);
       else
-	sl_snprintf(emsg,  SH_ERRBUF_SIZE, _("Adding rule: |%s| with %d captures"), 
+	sl_snprintf(emsg,  SH_ERRBUF_SIZE, _("Adding rule: |%s| with %u captures"), 
 		    splits[rpos], captures);
       SH_MUTEX_LOCK(mutex_thread_nolog);
@@ -614,5 +613,5 @@
     }
 
-  DEBUG("adding rule: |%s| with %d captures\n", splits[rpos], captures);
+  DEBUG("adding rule: |%s| with %u captures\n", splits[rpos], captures);
 
   SH_FREE(splits);
@@ -627,7 +626,7 @@
 
   nr->rule        = rule;
-  nr->rule_extra  = rule_extra;
+
   nr->captures    = captures;
-  nr->ovector     = SH_ALLOC(sizeof(int) * (captures+1) * 3);
+  nr->match_data  = pcre2_match_data_create_from_pattern(rule, NULL);
   nr->ovecnum     = 0;
   nr->counterlist = NULL;
@@ -695,5 +694,8 @@
 	      if (nr->label)
 		sh_string_destroy(&(nr->label));
-	      SH_FREE(nr->ovector);
+	      if (nr->rule)
+		pcre2_code_free(nr->rule);
+	      if (nr->match_data)
+		pcre2_match_data_free(nr->match_data);
 	      SH_FREE(nr);
 	      return -1;
@@ -743,5 +745,8 @@
 	  if (nr->label)
 	    sh_string_destroy(&(nr->label));
-	  SH_FREE(nr->ovector);
+	  if (nr->rule)
+	    pcre2_code_free(nr->rule);
+	  if (nr->match_data)
+	    pcre2_match_data_free(nr->match_data);
 	  SH_FREE(nr);
 	  return -1;
@@ -763,11 +768,13 @@
       grouplist = gtmp->gnext;
 
-      if (gtmp->label)      sh_string_destroy(&(gtmp->label));
-      if (gtmp->rule_extra) (*pcre_free)(gtmp->rule_extra);
-      if (gtmp->rule)       (*pcre_free)(gtmp->rule);
+      if (gtmp->label)
+	sh_string_destroy(&(gtmp->label));
+      if (gtmp->rule)
+	pcre2_code_free(gtmp->rule);
+      if (gtmp->match_data)
+	pcre2_match_data_free(gtmp->match_data);
       if (gtmp->counterlist)
 	zAVLFreeTree(gtmp->counterlist, sh_ceval_free);
-      if (gtmp->ovector)
-	SH_FREE(gtmp->ovector);
+
 #if 0
       while (gtmp->nextrule)
@@ -776,6 +783,6 @@
 	  gtmp->nextrule = tmp->nextrule;
 
-	  if (tmp->rule_extra) (*pcre_free)(tmp->rule_extra);
-	  if (tmp->rule)       (*pcre_free)(tmp->rule);
+	  if (tmp->rule)
+	    pcre2_code_free(tmp->rule);
 	  if (tmp->counterlist)
 	    zAVLFreeTree(tmp->counterlist, sh_ceval_free);
@@ -800,7 +807,8 @@
   while (htmp)
     {
-      if (htmp->hostname_extra) (*pcre_free)(htmp->hostname_extra);
-      if (htmp->hostname)       (*pcre_free)(htmp->hostname);
-      if (htmp->rulegroups)     htmp->rulegroups = NULL;
+      if (htmp->hostname)
+	pcre2_code_free(htmp->hostname);
+      if (htmp->rulegroups)
+	htmp->rulegroups = NULL;
       hostlist = htmp->next;
       htmp->next = NULL;
@@ -862,10 +870,12 @@
 
 	DEBUG("debug: check rule %d for <%s>\n", count, msg->str);
-	res = pcre_exec(rule->rule, rule->rule_extra, 
-			sh_string_str(msg), (int)sh_string_len(msg), 0,
-			0, rule->ovector, (3*(1+rule->captures)));
-	if (res >= 0)
+	
+	res = pcre2_match(rule->rule, 
+			  (PCRE2_SPTR8)sh_string_str(msg), (int)sh_string_len(msg), 0,
+			  0,   rule->match_data, NULL);
+
+	if (res > 0)
 	  {
-	    rule->ovecnum = res;
+	    rule->ovecnum = pcre2_get_ovector_count(rule->match_data);
 
 	    if (flag_err_debug == S_TRUE)
@@ -965,7 +975,8 @@
 
 	    DEBUG("debug: if group->label %s\n", sh_string_str(group->label));
-	    if (pcre_exec(group->rule, group->rule_extra,
-			  sh_string_str(msg), (int) sh_string_len(msg),
-			  0, 0, NULL, 0) >= 0)
+	    
+	    if (pcre2_match(group->rule,
+			    (PCRE2_SPTR8)sh_string_str(msg), (int) sh_string_len(msg), 0,
+			    0, NULL, NULL) > 0)
 	      {
 		result = test_rule(group->nextrule, msg, timestamp);
@@ -1017,7 +1028,7 @@
     {
       do {
-	if (pcre_exec(hlist->hostname, hlist->hostname_extra, 
-		      sh_string_str(host), (int) sh_string_len(host), 
-		      0, 0, NULL, 0) >= 0)
+	if (pcre2_match(hlist->hostname, 
+			(PCRE2_SPTR8)sh_string_str(host), (int) sh_string_len(host), 0, 
+			0, NULL, NULL) > 0)
 	  {
 	    /* matching host, check rules/groups of rules */
@@ -1035,5 +1046,5 @@
  */
 static sh_string * replace_captures(const sh_string * message, 
-				    int * ovector, int ovecnum)
+				    size_t * ovector, int ovecnum)
 {
   sh_string * retval = sh_string_new_from_lchar(sh_string_str(message), 
@@ -1058,5 +1069,5 @@
   SH_MUTEX_LOCK(mutex_thread_nolog);
   if (rule) {
-    mmm = replace_captures(record->message, rule->ovector, 
+    mmm = replace_captures(record->message, pcre2_get_ovector_pointer(rule->match_data), 
 			   rule->ovecnum);
     rule->ovecnum = 0;
@@ -1170,5 +1181,5 @@
   if (!(counter->counted_str))
     {
-      counter->counted_str = replace_captures(record->message, rule->ovector, 
+      counter->counted_str = replace_captures(record->message,  pcre2_get_ovector_pointer(rule->match_data), 
 					      rule->ovecnum);
       rule->ovecnum        = 0;
Index: trunk/src/sh_log_parse_apache.c
===================================================================
--- trunk/src/sh_log_parse_apache.c	(revision 587)
+++ trunk/src/sh_log_parse_apache.c	(revision 588)
@@ -28,9 +28,10 @@
 #define FIL__  _("sh_log_parse_apache.c")
 
-/* Debian/Ubuntu: libpcre3-dev */
-#ifdef HAVE_PCRE_PCRE_H
-#include <pcre/pcre.h>
+/* Debian/Ubuntu: libpcre2-dev */
+#define PCRE2_CODE_UNIT_WIDTH 8
+#ifdef HAVE_PCRE2_PCRE2_H
+#include <pcre2/pcre2.h>
 #else
-#include <pcre.h>
+#include <pcre2.h>
 #endif
 
@@ -44,7 +45,7 @@
 
 struct sh_fileinfo_apache {
-  pcre * line_regex;
-  int  * line_ovector;         /* captured substrings     */
-  int    line_ovecnum;         /* how many captured       */
+  pcre2_code * line_regex;
+  PCRE2_SIZE * line_ovector;         /* captured substrings     */
+  int          line_ovecnum;         /* how many captured       */
   
   int    pos_host;
@@ -82,6 +83,6 @@
   volatile int          p_time = -1;
   char                * f_time = NULL;
-  const char * error;
-  int          erroffset;
+  int          error;
+  size_t       erroffset;
   
   /* Take the address to keep gcc from putting them into registers. 
@@ -261,5 +262,5 @@
 
   result = SH_ALLOC(sizeof(struct sh_fileinfo_apache));
-  result->line_regex = pcre_compile(sh_string_str(re_string), 0, 
+  result->line_regex = pcre2_compile((PCRE2_SPTR8)sh_string_str(re_string), sh_string_len(re_string), 0, 
 				    &error, &erroffset, NULL);
   if (!(result->line_regex))
@@ -285,5 +286,5 @@
   sh_string_destroy(&re_string);
 
-  result->line_ovector  = SH_ALLOC(sizeof(int) * (nfields+1) * 3);
+  result->line_ovector  = NULL;
   result->line_ovecnum  = nfields;
   result->pos_host      = p_host;
@@ -304,10 +305,13 @@
   char         tstr[128];
   char         sstr[128];
-  const char * hstr;
+  char       * hstr;
   int          res;
-  const char **hstr_addr = (const char **) &hstr;
+  unsigned char **hstr_addr = (unsigned char **) &hstr;
+  size_t       hstr_len;
 
   struct sh_fileinfo_apache * info = (struct sh_fileinfo_apache *) fileinfo;
 
+  pcre2_match_data * match_data = NULL;
+  
   if (sh_string_len(logline) > 0 && flag_err_debug == S_TRUE)
     {
@@ -324,24 +328,29 @@
     }
 
-  res = pcre_exec(info->line_regex, NULL, 
-		  sh_string_str(logline), (int)sh_string_len(logline), 0,
-		  0, info->line_ovector, (3*(1+info->line_ovecnum)));
-
-  if (res == (1+info->line_ovecnum))
+  match_data = pcre2_match_data_create_from_pattern(info->line_regex, NULL);
+  
+  res = pcre2_match(info->line_regex,
+		    (PCRE2_SPTR8)sh_string_str(logline), (int)sh_string_len(logline), 0,
+		    0, match_data, NULL);
+
+  if (res == 1+info->line_ovecnum) /* successful match */
     {
       struct sh_logrecord * record;
       time_t timestamp = 0;
-
+      size_t size;
+
+      info->line_ovector = pcre2_get_ovector_pointer(match_data);
+      
       if (info->pos_time > 0)
 	{
-	  res = pcre_copy_substring(sh_string_str(logline), 
-				    info->line_ovector, res,
-				    info->pos_time, tstr, sizeof(tstr));
-	  if (res <= 0)
+	  size = sizeof(tstr);
+	  res = pcre2_substring_copy_bynumber(match_data,  info->pos_time,
+					      (PCRE2_UCHAR8 *)tstr, &size);
+	  if (res != 0)
 	    goto corrupt;
 	}
       else
 	{
-	  res = 0;
+	  res = -1;
 	  timestamp = 0;
 	  info->format_time = sh_util_strdup(_("%d/%b/%Y:%T"));
@@ -349,5 +358,5 @@
 	}
 
-      if (res > 0)
+      if (res == 0)
 	{
 	  struct tm btime;
@@ -371,8 +380,8 @@
       if (info->pos_status > 0)
 	{
-	  res = pcre_copy_substring(sh_string_str(logline), 
-				    info->line_ovector, res,
-				    info->pos_status, sstr, sizeof(sstr));
-	  if (res <= 0)
+	  size = sizeof(sstr);
+	  res = pcre2_substring_copy_bynumber(match_data,  info->pos_status,
+					      (PCRE2_UCHAR8 *)sstr, &size);
+	  if (res != 0)
 	    goto corrupt;
 	}
@@ -384,8 +393,7 @@
       if (info->pos_host > 0)
 	{
-	  res = pcre_get_substring(sh_string_str(logline), 
-				   info->line_ovector, res,
-				   info->pos_host, hstr_addr);
-	  if (res <= 0)
+	  res = pcre2_substring_get_bynumber(match_data, info->pos_host,
+					     hstr_addr, &hstr_len);
+	  if (res != 0)
 	    goto corrupt;
 	}
@@ -401,5 +409,5 @@
 
       if (hstr)
-	record->host = sh_string_new_from_lchar(hstr, strlen(hstr));
+	record->host = sh_string_new_from_lchar(hstr, hstr_len);
       else
 	record->host = sh_string_new_from_lchar(sh.host.name, strlen(sh.host.name));
@@ -409,5 +417,8 @@
       record->pid       = PID_INVALID;
 
-      pcre_free_substring(hstr); 
+      /* does nothing if hstr == NULL */
+      pcre2_substring_free((PCRE2_UCHAR8 *)hstr);
+
+      pcre2_match_data_free(match_data);
       return record;
     }
@@ -415,6 +426,5 @@
     {
       char msg[128];
-      sl_snprintf(msg, sizeof(msg), _("Incorrect number of captured subexpressions: %d vs %d"),
-		  res, info->line_ovecnum);
+      sl_snprintf(msg, sizeof(msg), _("Matching error: %d"), res);
       
       SH_MUTEX_LOCK(mutex_thread_nolog);
@@ -440,4 +450,5 @@
     sh_string_destroy(&msg);
   }
+  pcre2_match_data_free(match_data);
   return NULL;
 }
Index: trunk/src/sh_log_parse_generic.c
===================================================================
--- trunk/src/sh_log_parse_generic.c	(revision 587)
+++ trunk/src/sh_log_parse_generic.c	(revision 588)
@@ -22,9 +22,10 @@
 #include <time.h>
 
-/* Debian/Ubuntu: libpcre3-dev */
-#ifdef HAVE_PCRE_PCRE_H
-#include <pcre/pcre.h>
+/* Debian/Ubuntu: libpcre2-dev */
+#define PCRE2_CODE_UNIT_WIDTH 8
+#ifdef HAVE_PCRE2_PCRE2_H
+#include <pcre2/pcre2.h>
 #else
-#include <pcre.h>
+#include <pcre2.h>
 #endif
 
@@ -34,7 +35,7 @@
 
 struct sh_fileinfo_generic {
-  pcre * line_regex;
-  int  * line_ovector;         /* captured substrings     */
-  int    line_ovecnum;         /* how many captured       */
+  pcre2_code        * line_regex;
+  pcre2_match_data  * line_match_data;      /* captured substrings     */
+  int                 line_ovecnum;         /* how many captured       */
   
   int    pos_host;
Index: trunk/src/sh_log_parse_pacct.c
===================================================================
--- trunk/src/sh_log_parse_pacct.c	(revision 587)
+++ trunk/src/sh_log_parse_pacct.c	(revision 588)
@@ -314,4 +314,6 @@
     }
 
+  sh_dummy_294_record = NULL;
+  
   p = strchr(sh_string_str(logline), ':');
 
Index: trunk/src/sh_string.c
===================================================================
--- trunk/src/sh_string.c	(revision 587)
+++ trunk/src/sh_string.c	(revision 588)
@@ -546,7 +546,9 @@
  * of field, offset of first char after field (this is how
  * the pcre library does it).
- */  
+ */
+#define IS_PCRE2_UNSET           (~(size_t)0)
+
 sh_string * sh_string_replace(const sh_string * s, 
-                              const int * ovector, int ovecnum, 
+                              const size_t * ovector, int ovecnum, 
                               const char * replacement, size_t rlen)
 {
@@ -604,5 +606,5 @@
   for (i = 0; i < ovecnum; ++i)
     {
-      if (ovector[2*i] >= 0)
+      if (ovector[2*i] != IS_PCRE2_UNSET)
         {
           curr = 2*i;
@@ -611,5 +613,5 @@
     }
   
-  if (r && ovecnum > 0 && ovector[curr] >= 0)
+  if (r && ovecnum > 0 && ovector[curr] != IS_PCRE2_UNSET)
     {
       r->len = 0; r->str[0] = '\0'; p = r->str;
@@ -617,6 +619,6 @@
       /* First part, until start of first replacement 
        */
-      if (r->siz > (unsigned int)ovector[curr]) {
-	memcpy(p, s->str, (size_t)ovector[curr]); 
+      if (r->siz > ovector[curr]) {
+	memcpy(p, s->str, ovector[curr]); 
 	p += ovector[curr]; 
 	r->len += ovector[curr];
@@ -633,5 +635,5 @@
       for (i = 1; i < ovecnum; ++i)
         {
-          if (ovector[2*i] < 0)
+          if (ovector[2*i] == IS_PCRE2_UNSET)
             continue;
 
@@ -704,5 +706,5 @@
   size_t lengths[16];
   unsigned int iarr;
-  int ovector[16];
+  size_t ovector[16];
   int ovecnum;
 
