]> git.ipfire.org Git - thirdparty/sarg.git/commitdiff
Allow the use of wildcards in the access.log and useragent.log
authorFrederic Marchal <fmarchal@users.sourceforge.net>
Tue, 9 Jun 2015 18:17:08 +0000 (20:17 +0200)
committerFrederic Marchal <fmarchal@users.sourceforge.net>
Tue, 9 Jun 2015 18:17:08 +0000 (20:17 +0200)
A file name can contain * or ? if configure was not run with
--without-glob.

It is possible to see if file globbing was compiled in by running sarg with
-x -V.

CMakeLists.txt
configure.ac
filelist.c
include/config.h.in
sarg.conf
util.c

index 4006537977c00c1bd03fba6ac0758eab70c62cda..d2d99606395e1a2049f7f79f5a25a41ce2a336c0 100755 (executable)
@@ -119,6 +119,7 @@ CHECK_INCLUDE_FILE(stdbool.h HAVE_STDBOOL_H)
 CHECK_INCLUDE_FILE(getopt.h HAVE_GETOPT_H)
 CHECK_INCLUDE_FILE(fcntl.h HAVE_FCNTL_H)
 CHECK_INCLUDE_FILE(fnmatch.h HAVE_FNMATCH_H)
+CHECK_INCLUDE_FILE(glob.h HAVE_GLOB_H)
 
 IF(!HAVE_GETOPT_H)
    MESSAGE(SEND_ERROR "getopt.h is required to compile sarg")
index b51a2f9eaada17a0214a063cfc64d49b2559dd04..3be9cc691a45921ff8f09e7d0889932618b69977 100644 (file)
@@ -150,6 +150,16 @@ else
        pcre_status="disabled"
 fi
 
+# Build with file globbing
+AC_ARG_WITH([glob],
+AS_HELP_STRING([--without-glob],[Ignore wildcards in file names]),
+[with_glob=no],[with_glob=yes])
+if ( test "x$with_glob" != "xno" ) ; then
+       AC_CHECK_HEADERS(glob.h)
+else
+       glob_status="disabled"
+fi
+
 dnl Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
 AC_STRUCT_TM
@@ -393,3 +403,7 @@ if ( test "x$ldap_status" = "xdisabled" ) ; then
 elif ( test "x$ldap_status" = "xnot found" ) ; then
        AC_MSG_NOTICE([ldap header files not found so LDAP is not available to resolve user's names])
 fi
+
+if ( test "x$glob_status" = "xdisabled" ) ; then
+       AC_MSG_NOTICE([Not building with file globbing as requested on the configuration command line])
+fi
index 490259077f5ad435fcdf9906f688f991d56e247d..e851a00cfafc4d22c001490120f935a7d881a1dc 100644 (file)
@@ -28,6 +28,9 @@
 #include "include/defs.h"
 #include "include/stringbuffer.h"
 #include "include/filelist.h"
+#ifdef HAVE_GLOB_H
+#include <glob.h>
+#endif
 
 struct DirEntryStruct
 {
@@ -85,6 +88,12 @@ struct _FileListIterator
        int Level;
        //! The current node at each level.
        struct DirEntryIterator *DirNodes;
+#ifdef HAVE_GLOB_H
+       //! Next globbed file to return
+       int NextGlob;
+       //! Buffer with the globbed files.
+       glob_t Glob;
+#endif
 };
 
 
@@ -417,42 +426,54 @@ static void FileListIter_GetNext(struct _FileListIterator *FIter)
  */
 const char *FileListIter_Next(struct _FileListIterator *FIter)
 {
-       int Length;
-       int Level;
-       struct DirEntryIterator *DIter;
-
-       if (!FIter) return(NULL);
-       if (!FIter->DirNodes) return(NULL);
-       if (FIter->Level<0 || FIter->Level>=FIter->TreeDepth) return(NULL);
+       const char *Path;
 
-       // how much space to store the path
-       Length=FIter->DirNodes[FIter->CurrentPathLevel].PathLength;
-       for (Level=FIter->CurrentPathLevel ; Level<=FIter->Level ; Level++)
+#ifdef HAVE_GLOB_H
+       if (FIter->NextGlob>0)
        {
-               DIter=FIter->DirNodes+Level;
-               DIter->PathLength=Length;;
-               Length+=strlen(DIter->Dir->Name)+1;
-       }
-
-       // get the memory to store the path
-       if (Length>FIter->CurrentPathSize)
-       {
-               char *temp=realloc(FIter->CurrentPath,Length);
-               if (!temp) return(NULL);
-               FIter->CurrentPath=temp;
-               FIter->CurrentPathSize=Length;
+               if (FIter->NextGlob<FIter->Glob.gl_pathc)
+               {
+                       Path=FIter->Glob.gl_pathv[FIter->NextGlob++];
+                       return(Path);
+               }
+               globfree(&FIter->Glob);
+               FIter->NextGlob=0;
        }
-
-       for (Level=FIter->CurrentPathLevel ; Level<=FIter->Level ; Level++)
+       /*
+        * Try every pattern until the list is exhausted or a real error
+        * occurs or a file is matched.
+        */
+       while ((Path=FileListIter_NextWithMask(FIter))!=NULL)
        {
-               DIter=FIter->DirNodes+Level;
-               if (Level>0) FIter->CurrentPath[DIter->PathLength-1]='/';
-               strcpy(FIter->CurrentPath+DIter->PathLength,DIter->Dir->Name);
+               int ErrCode=glob(Path,GLOB_ERR | GLOB_NOSORT,NULL,&FIter->Glob);
+               if (ErrCode==0)//success
+               {
+                       Path=FIter->Glob.gl_pathv[0];
+                       FIter->NextGlob=1;
+                       break;
+               }
+               if (ErrCode!=GLOB_NOMATCH)
+               {
+                       switch (ErrCode)
+                       {
+                       case GLOB_NOSPACE:
+                               debuga(__FILE__,__LINE__,_("Not enough memory to read the files matching \"%s\"\n"),Path);
+                               break;
+                       case GLOB_ABORTED:
+                               debuga(__FILE__,__LINE__,_("Read error while listing the files matching \"%s\"\n"),Path);
+                               break;
+                       }
+                       exit(EXIT_FAILURE);
+               }
        }
-       FIter->CurrentPathLevel=Level;
-
-       FileListIter_GetNext(FIter);
-       return(FIter->CurrentPath);
+#else
+       /*
+        * Fall back to a simple enumeration. In that case, the user cannot use
+        * wildcards as they won't be expended.
+        */
+       Path=FileListIter_NextWithMask(FIter);
+#endif
+       return(Path);
 }
 
 /*!
@@ -479,7 +500,7 @@ const char *FileListIter_NextWithMask(struct _FileListIterator *FIter)
        for (Level=FIter->CurrentPathLevel ; Level<=FIter->Level ; Level++)
        {
                DIter=FIter->DirNodes+Level;
-               DIter->PathLength=Length;;
+               DIter->PathLength=Length;
                Length+=strlen(DIter->Dir->Name)+1;
        }
 
@@ -511,6 +532,9 @@ void FileListIter_Close(struct _FileListIterator *FIter)
 {
        if (FIter)
        {
+#ifdef HAVE_GLOB_H
+               if (FIter->NextGlob>0) globfree(&FIter->Glob);
+#endif
                if (FIter->CurrentPath) free(FIter->CurrentPath);
                if (FIter->DirNodes) free(FIter->DirNodes);
                free(FIter);
index dc57c7f8ee7d41a566d4cb23fcbd38e072bf1523..e77c5daea7c2bc55108f13660317220670e11d4a 100644 (file)
@@ -53,6 +53,7 @@
 #cmakedefine HAVE_PCRE_H
 #cmakedefine HAVE_FNMATCH_H
 #cmakedefine HAVE_DIRECT_H
+#cmakedefine HAVE_GLOB_H
 
 #cmakedefine IBERTY_LIB
 
index 351b01f6ba54fff5aa6dbcc1610f71428e6d0e4b..5a32ffc99926f03ff64558b401ebc75100aa9ace 100644 (file)
--- a/sarg.conf
+++ b/sarg.conf
 #       safety against incomplete reporting due to problems occuring with the
 #       logs.
 #
+#       If the file globbing was compiled in, the file name can contain shell
+#       wildcards such as * and ?. Tilde expension and variable expension are
+#       not supported. Special characters can be escaped with a backslash.
+#
 #       If some files are passed on the command line with "sarg -l file" or
 #       "sarg file", the files listed here are ignored.
 #
 #exclude_hosts none
 
 # TAG:  useragent_log file
-#       useragent.log file patch to generate useragent report.
+#       useragent.log file to generate useragent report.
+#
+#       This option may be repeated multiple times to process several files.
+#
+#       Wildcards are allowed (see access_log).
 #
 #useragent_log none
 
diff --git a/util.c b/util.c
index d350c342c325938b27f7e5d943516f06ddc45196..8cf7aa7c65e020273ababeef2a669433f71797e0 100644 (file)
--- a/util.c
+++ b/util.c
@@ -2178,6 +2178,13 @@ void version(void)
                printf(_("If this message is in English, then your language is not supported or not correctly installed.\n"));
        }
 #endif
+       if (debug) {
+#ifdef HAVE_GLOB_H
+               printf(_("File globbing compiled in.\n"));
+#else
+               printf(_("File globbing NOT compiled in.\n"));
+#endif
+       }
        exit(EXIT_SUCCESS);
 }