]> git.ipfire.org Git - thirdparty/sarg.git/blobdiff - readlog.c
Restore support for bzip2 files
[thirdparty/sarg.git] / readlog.c
index f71da4ac2a1393ed04574a479baca56a85ffd1d7..406f52bbca30d0cd4ae2e97507c63c192441ad72 100644 (file)
--- a/readlog.c
+++ b/readlog.c
@@ -135,6 +135,68 @@ static int LatestDate=-1;
 //! The latest date in time format.
 static struct tm LatestDateTime;
 
+/*!
+ * Read from standard input.
+ *
+ * \param Data The file object.
+ * \param Buffer The boffer to store the data read.
+ * \param Size How many bytes to read.
+ *
+ * \return The number of bytes read.
+ */
+static int Stdin_Read(void *Data,void *Buffer,int Size)
+{
+       return(fread(Buffer,1,Size,(FILE *)Data));
+}
+
+/*!
+ * Check if end of file is reached.
+ *
+ * \param Data The file object.
+ *
+ * \return \c True if end of file is reached.
+ */
+static int Stdin_Eof(void *Data)
+{
+       return(feof((FILE *)Data));
+}
+
+/*!
+ * Mimic a close of standard input but do nothing
+ *
+ * \param Data File to close.
+ *
+ * \return EOF on error.
+ */
+static int Stdin_Close(void *Data)
+{
+       return(0);
+}
+
+/*!
+ * Open a file object to read from standard input.
+ *
+ * \return The object to pass to other function in this module.
+ */
+static FileObject *Stdin_Open(void)
+{
+       FileObject *File;
+
+       FileObject_SetLastOpenError(NULL);
+       File=calloc(1,sizeof(*File));
+       if (!File)
+       {
+               FileObject_SetLastOpenError(_("Not enough memory"));
+               return(NULL);
+       }
+       File->Data=stdin;
+       File->Read=Stdin_Read;
+       File->Eof=Stdin_Eof;
+       File->Rewind=NULL;
+       File->Close=Stdin_Close;
+       return(File);
+}
+
 /*!
  * Initialize the memory structure needed by LogLine_Parse() to parse
  * a log line.
@@ -196,7 +258,7 @@ enum ReadLogReturnCodeEnum LogLine_Parse(struct LogLineStruct *log_line,struct R
                                if (debugz>=LogLevel_Process)
                                {
                                        /* TRANSLATORS: The argument is the log format name as translated by you. */
-                                       debuga(_("Log format identified as \"%s\" for %s\n"),_(log_line->current_format->Name),log_line->file_name);
+                                       debuga(__FILE__,__LINE__,_("Log format identified as \"%s\" for %s\n"),_(log_line->current_format->Name),log_line->file_name);
                                }
                                break;
                        }
@@ -204,27 +266,27 @@ enum ReadLogReturnCodeEnum LogLine_Parse(struct LogLineStruct *log_line,struct R
                if (x>=(int)(sizeof(LogFormats)/sizeof(*LogFormats)))
                {
                        if (++log_line->successive_errors>NumLogSuccessiveErrors) {
-                               debuga(ngettext("%d consecutive error found in the input log file %s\n",
+                               debuga(__FILE__,__LINE__,ngettext("%d consecutive error found in the input log file %s\n",
                                                                                                "%d consecutive errors found in the input log file %s\n",log_line->successive_errors),log_line->successive_errors,log_line->file_name);
                                exit(EXIT_FAILURE);
                        }
                        if (NumLogTotalErrors>=0 && ++log_line->total_errors>NumLogTotalErrors) {
-                               debuga(ngettext("%d error found in the input log file (last in %s)\n",
+                               debuga(__FILE__,__LINE__,ngettext("%d error found in the input log file (last in %s)\n",
                                                                                                "%d errors found in the input log file (last in %s)\n",log_line->total_errors),log_line->total_errors,log_line->file_name);
                                exit(EXIT_FAILURE);
                        }
-                       debuga(_("The following line read from %s could not be parsed and is ignored\n%s\n"),log_line->file_name,linebuf);
+                       debuga(__FILE__,__LINE__,_("The following line read from %s could not be parsed and is ignored\n%s\n"),log_line->file_name,linebuf);
                }
                else
                        log_line->successive_errors=0;
        }
 
        if (log_line->current_format_idx<0 || log_line->current_format==NULL) {
-               debuga(_("Sarg failed to determine the format of the input log file %s\n"),log_line->file_name);
+               debuga(__FILE__,__LINE__,_("Sarg failed to determine the format of the input log file %s\n"),log_line->file_name);
                exit(EXIT_FAILURE);
        }
        if (log_entry_status==RLRC_InternalError) {
-               debuga(_("Internal error encountered while processing %s\nSee previous message to know the reason for that error.\n"),log_line->file_name);
+               debuga(__FILE__,__LINE__,_("Internal error encountered while processing %s\nSee previous message to know the reason for that error.\n"),log_line->file_name);
                exit(EXIT_FAILURE);
        }
        return(log_entry_status);
@@ -256,9 +318,7 @@ static void ReadOneLogFile(struct ReadLogDataStruct *Filter,const char *arq)
        int maxopenfiles=MAX_OPEN_USER_FILES;
        unsigned long int recs1=0UL;
        unsigned long int recs2=0UL;
-       FILE *fp_in=NULL;
-       bool from_pipe;
-       bool from_stdin;
+       FileObject *fp_in=NULL;
        bool download_flag=false;
        bool id_is_ip;
        enum ReadLogReturnCodeEnum log_entry_status;
@@ -278,29 +338,27 @@ static void ReadOneLogFile(struct ReadLogDataStruct *Filter,const char *arq)
                        LogFormats[x]->NewFile(arq);
 
        if (arq[0]=='-' && arq[1]=='\0') {
+               fp_in=Stdin_Open();
                if(debug)
-                       debuga(_("Reading access log file: from stdin\n"));
-               fp_in=stdin;
-               from_stdin=true;
+                       debuga(__FILE__,__LINE__,_("Reading access log file: from stdin\n"));
        } else {
                if (Filter->DateRange[0]!='\0') {
                        if (stat(arq,&logstat)!=0) {
-                               debuga(_("Cannot get the modification time of input log file %s (%s). Processing it anyway\n"),arq,strerror(errno));
+                               debuga(__FILE__,__LINE__,_("Cannot get the modification time of input log file %s (%s). Processing it anyway\n"),arq,strerror(errno));
                        } else {
                                struct tm *logtime=localtime(&logstat.st_mtime);
                                if ((logtime->tm_year+1900)*10000+(logtime->tm_mon+1)*100+logtime->tm_mday<dfrom) {
-                                       debuga(_("Ignoring old log file %s\n"),arq);
+                                       debuga(__FILE__,__LINE__,_("Ignoring old log file %s\n"),arq);
                                        return;
                                }
                        }
                }
-               fp_in=decomp(arq,&from_pipe);
-               if(fp_in==NULL) {
-                       debuga(_("Cannot open input log file \"%s\": %s\n"),arq,strerror(errno));
+               fp_in=decomp(arq);
+               if (fp_in==NULL) {
+                       debuga(__FILE__,__LINE__,_("Cannot open input log file \"%s\": %s\n"),arq,FileObject_GetLastOpenError());
                        exit(EXIT_FAILURE);
                }
-               if(debug) debuga(_("Reading access log file: %s\n"),arq);
-               from_stdin=false;
+               if (debug) debuga(__FILE__,__LINE__,_("Reading access log file: %s\n"),arq);
        }
 
        download_flag=false;
@@ -309,12 +367,12 @@ static void ReadOneLogFile(struct ReadLogDataStruct *Filter,const char *arq)
        recs2=0UL;
 
        // pre-read the file only if we have to show stats
-       if (ShowReadStatistics && ShowReadPercent && !from_stdin && !from_pipe) {
-               size_t nread,i;
+       if (ShowReadStatistics && ShowReadPercent && fp_in->Rewind) {
+               int nread,i;
                bool skipcr=false;
                char tmp4[MAXLEN];
 
-               while ((nread=fread(tmp4,1,sizeof(tmp4),fp_in))>0) {
+               while ((nread=FileObject_Read(fp_in,tmp4,sizeof(tmp4)))>0) {
                        for (i=0 ; i<nread ; i++)
                                if (skipcr) {
                                        if (tmp4[i]!='\n' && tmp4[i]!='\r') {
@@ -327,14 +385,14 @@ static void ReadOneLogFile(struct ReadLogDataStruct *Filter,const char *arq)
                                        }
                                }
                }
-               rewind(fp_in);
+               FileObject_Rewind(fp_in);
                printf(_("SARG: Records in file: %lu, reading: %3.2f%%"),recs1,(float) 0);
                putchar('\r');
                fflush( stdout ) ;
        }
 
        if ((line=longline_create())==NULL) {
-               debuga(_("Not enough memory to read file \"%s\"\n"),arq);
+               debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),arq);
                exit(EXIT_FAILURE);
        }
 
@@ -374,7 +432,7 @@ static void ReadOneLogFile(struct ReadLogDataStruct *Filter,const char *arq)
                        getword_start(&gwarea,ExcludeString);
                        while(strchr(gwarea.current,':') != 0) {
                                if (getword_multisep(val1,sizeof(val1),&gwarea,':')<0) {
-                                       debuga(_("Invalid record in exclusion string\n"));
+                                       debuga(__FILE__,__LINE__,_("Invalid record in exclusion string\n"));
                                        exit(EXIT_FAILURE);
                                }
                                if((str=(char *) strstr(linebuf,val1)) != (char *) NULL ) {
@@ -412,27 +470,27 @@ static void ReadOneLogFile(struct ReadLogDataStruct *Filter,const char *arq)
                                my_mkdir(ParsedOutputLog);
                        }
                        if (snprintf(SargLogFile,sizeof(SargLogFile),"%s/sarg_temp.log",ParsedOutputLog)>=sizeof(SargLogFile)) {
-                               debuga(_("Path too long: "));
+                               debuga(__FILE__,__LINE__,_("Path too long: "));
                                debuga_more("%s/sarg_temp.log\n",ParsedOutputLog);
                                exit(EXIT_FAILURE);
                        }
                        if((fp_log=MY_FOPEN(SargLogFile,"w"))==NULL) {
-                               debuga(_("Cannot open file \"%s\": %s\n"),SargLogFile,strerror(errno));
+                               debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),SargLogFile,strerror(errno));
                                exit(EXIT_FAILURE);
                        }
                        fputs("*** SARG Log ***\n",fp_log);
                }
 
                if (log_entry.Ip==NULL) {
-                       debuga(_("Unknown input log file format: no IP addresses\n"));
+                       debuga(__FILE__,__LINE__,_("Unknown input log file format: no IP addresses\n"));
                        break;
                }
                if (log_entry.User==NULL) {
-                       debuga(_("Unknown input log file format: no user\n"));
+                       debuga(__FILE__,__LINE__,_("Unknown input log file format: no user\n"));
                        break;
                }
                if (log_entry.Url==NULL) {
-                       debuga(_("Unknown input log file format: no URL\n"));
+                       debuga(__FILE__,__LINE__,_("Unknown input log file format: no URL\n"));
                        break;
                }
 
@@ -468,7 +526,7 @@ static void ReadOneLogFile(struct ReadLogDataStruct *Filter,const char *arq)
 
 
                if(strlen(log_entry.User) > MAX_USER_LEN) {
-                       if (debugz>=LogLevel_Process) debuga(_("User ID too long: %s\n"),log_entry.User);
+                       if (debugz>=LogLevel_Process) debuga(__FILE__,__LINE__,_("User ID too long: %s\n"),log_entry.User);
                        excluded_count[ER_UserNameTooLong]++;
                        totregsx++;
                        continue;
@@ -484,7 +542,7 @@ static void ReadOneLogFile(struct ReadLogDataStruct *Filter,const char *arq)
                }
 
                if(vercode(log_entry.HttpCode)) {
-                       if (debugz>=LogLevel_Process) debuga(_("Excluded code: %s\n"),log_entry.HttpCode);
+                       if (debugz>=LogLevel_Process) debuga(__FILE__,__LINE__,_("Excluded code: %s\n"),log_entry.HttpCode);
                        excluded_count[ER_HttpCode]++;
                        totregsx++;
                        continue;
@@ -527,7 +585,7 @@ static void ReadOneLogFile(struct ReadLogDataStruct *Filter,const char *arq)
                }
                if(Filter->HostFilter) {
                        if(!vhexclude(url)) {
-                               if (debugz>=LogLevel_Data) debuga(_("Excluded site: %s\n"),url);
+                               if (debugz>=LogLevel_Data) debuga(__FILE__,__LINE__,_("Excluded site: %s\n"),url);
                                excluded_count[ER_Url]++;
                                totregsx++;
                                continue;
@@ -591,7 +649,7 @@ static void ReadOneLogFile(struct ReadLogDataStruct *Filter,const char *arq)
 
                if(Filter->UserFilter) {
                        if(!vuexclude(log_entry.User)) {
-                               if (debugz>=LogLevel_Process) debuga(_("Excluded user: %s\n"),log_entry.User);
+                               if (debugz>=LogLevel_Process) debuga(__FILE__,__LINE__,_("Excluded user: %s\n"),log_entry.User);
                                excluded_count[ER_IgnoredUser]++;
                                totregsx++;
                                continue;
@@ -630,7 +688,7 @@ static void ReadOneLogFile(struct ReadLogDataStruct *Filter,const char *arq)
                if (!ufile) {
                        ufile=malloc(sizeof(*ufile));
                        if (!ufile) {
-                               debuga(_("Not enough memory to store the user %s\n"),log_entry.User);
+                               debuga(__FILE__,__LINE__,_("Not enough memory to store the user %s\n"),log_entry.User);
                                exit(EXIT_FAILURE);
                        }
                        memset(ufile,0,sizeof(*ufile));
@@ -664,7 +722,7 @@ static void ReadOneLogFile(struct ReadLogDataStruct *Filter,const char *arq)
                                        if (ufile1->file!=NULL) {
                                                if (x>=maxopenfiles) {
                                                        if (fclose(ufile1->file)==EOF) {
-                                                               debuga(_("Write error in log file of user %s: %s\n"),ufile1->user->id,strerror(errno));
+                                                               debuga(__FILE__,__LINE__,_("Write error in log file of user %s: %s\n"),ufile1->user->id,strerror(errno));
                                                                exit(EXIT_FAILURE);
                                                        }
                                                        ufile1->file=NULL;
@@ -674,11 +732,11 @@ static void ReadOneLogFile(struct ReadLogDataStruct *Filter,const char *arq)
                                }
                        }
                        if (snprintf (tmp3, sizeof(tmp3), "%s/%s.user_unsort", tmp, ufile->user->filename)>=sizeof(tmp3)) {
-                               debuga(_("Temporary user file name too long: %s/%s.user_unsort\n"), tmp, ufile->user->filename);
+                               debuga(__FILE__,__LINE__,_("Temporary user file name too long: %s/%s.user_unsort\n"), tmp, ufile->user->filename);
                                exit(EXIT_FAILURE);
                        }
                        if ((ufile->file = MY_FOPEN (tmp3, "a")) == NULL) {
-                               debuga(_("(log) Cannot open temporary file %s: %s\n"), tmp3, strerror(errno));
+                               debuga(__FILE__,__LINE__,_("(log) Cannot open temporary file %s: %s\n"), tmp3, strerror(errno));
                                exit (1);
                        }
                }
@@ -689,7 +747,7 @@ static void ReadOneLogFile(struct ReadLogDataStruct *Filter,const char *arq)
                if (fprintf(ufile->file, "%s\t%s\t%s\t%s\t%"PRIu64"\t%s\t%ld\t%s\n",dia,hora,
                                                                log_entry.Ip,url,(uint64_t)log_entry.DataSize,
                                                                log_entry.HttpCode,log_entry.ElapsedTime,smartfilter)<=0) {
-                       debuga(_("Write error in the log file of user %s\n"),log_entry.User);
+                       debuga(__FILE__,__LINE__,_("Write error in the log file of user %s\n"),log_entry.User);
                        exit(EXIT_FAILURE);
                }
                records_kept++;
@@ -731,18 +789,15 @@ static void ReadOneLogFile(struct ReadLogDataStruct *Filter,const char *arq)
        }
        longline_destroy(&line);
 
-       if (!from_stdin) {
-               if (from_pipe)
-                       pclose(fp_in);
-               else {
-                       fclose(fp_in);
-                       if (ShowReadStatistics) {
-                               if (ShowReadPercent)
-                                       printf(_("SARG: Records in file: %lu, reading: %3.2f%%\n"),recs2, (float) 100 );
-                               else
-                                       printf(_("SARG: Records in file: %lu\n"),recs2);
-                       }
-               }
+       if (FileObject_Close(fp_in)) {
+               debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),arq,FileObject_GetLastCloseError());
+               exit(EXIT_FAILURE);
+       }
+       if (ShowReadStatistics) {
+               if (ShowReadPercent)
+                       printf(_("SARG: Records in file: %lu, reading: %3.2f%%\n"),recs2, (float) 100 );
+               else
+                       printf(_("SARG: Records in file: %lu\n"),recs2);
        }
 }
 
@@ -755,7 +810,7 @@ static void ReadOneLogFile(struct ReadLogDataStruct *Filter,const char *arq)
 static void DisplayExcludeCount(const char *Explain,enum ExcludeReasonEnum Reason)
 {
        if (excluded_count[Reason]>0) {
-               debuga("   %s: %lu\n",Explain,excluded_count[Reason]);
+               debuga(__FILE__,__LINE__,"   %s: %lu\n",Explain,excluded_count[Reason]);
        }
 }
 
@@ -796,18 +851,18 @@ int ReadLogFile(struct ReadLogDataStruct *Filter)
                char val4[4096];//val4 must not be bigger than SargLogFile without fixing the strcpy below
 
                if (fclose(fp_log)==EOF) {
-                       debuga(_("Write error in \"%s\": %s\n"),SargLogFile,strerror(errno));
+                       debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),SargLogFile,strerror(errno));
                        exit(EXIT_FAILURE);
                }
                strftime(val2,sizeof(val2),"%d%m%Y_%H%M",&period.start);
                strftime(val1,sizeof(val1),"%d%m%Y_%H%M",&period.end);
                if (snprintf(val4,sizeof(val4),"%s/sarg-%s-%s.log",ParsedOutputLog,val2,val1)>=sizeof(val4)) {
-                       debuga(_("Path too long: "));
+                       debuga(__FILE__,__LINE__,_("Path too long: "));
                        debuga_more("%s/sarg-%s-%s.log\n",ParsedOutputLog,val2,val1);
                        exit(EXIT_FAILURE);
                }
                if (rename(SargLogFile,val4)) {
-                       debuga(_("failed to rename %s to %s - %s\n"),SargLogFile,val4,strerror(errno));
+                       debuga(__FILE__,__LINE__,_("failed to rename %s to %s - %s\n"),SargLogFile,val4,strerror(errno));
                } else {
                        strcpy(SargLogFile,val4);
 
@@ -817,19 +872,19 @@ int ReadLogFile(struct ReadLogDataStruct *Filter)
                                necessary around the command name, put them in the configuration file.
                                */
                                if (snprintf(val1,sizeof(val1),"%s \"%s\"",ParsedOutputLogCompress,SargLogFile)>=sizeof(val1)) {
-                                       debuga(_("Command too long: %s \"%s\"\n"),ParsedOutputLogCompress,SargLogFile);
+                                       debuga(__FILE__,__LINE__,_("Command too long: %s \"%s\"\n"),ParsedOutputLogCompress,SargLogFile);
                                        exit(EXIT_FAILURE);
                                }
                                cstatus=system(val1);
                                if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus)) {
-                                       debuga(_("command return status %d\n"),WEXITSTATUS(cstatus));
-                                       debuga(_("command: %s\n"),val1);
+                                       debuga(__FILE__,__LINE__,_("command return status %d\n"),WEXITSTATUS(cstatus));
+                                       debuga(__FILE__,__LINE__,_("command: %s\n"),val1);
                                        exit(EXIT_FAILURE);
                                }
                        }
                }
                if(debug)
-                       debuga(_("Sarg parsed log saved as %s\n"),SargLogFile);
+                       debuga(__FILE__,__LINE__,_("Sarg parsed log saved as %s\n"),SargLogFile);
        }
 
        denied_close();
@@ -839,7 +894,7 @@ int ReadLogFile(struct ReadLogDataStruct *Filter)
        for (ufile=first_user_file ; ufile ; ufile=ufile1) {
                ufile1=ufile->next;
                if (ufile->file!=NULL && fclose(ufile->file)==EOF) {
-                       debuga(_("Write error in log file of user %s: %s\n"),ufile->user->id,strerror(errno));
+                       debuga(__FILE__,__LINE__,_("Write error in log file of user %s: %s\n"),ufile->user->id,strerror(errno));
                        exit(EXIT_FAILURE);
                }
                free(ufile);
@@ -848,11 +903,11 @@ int ReadLogFile(struct ReadLogDataStruct *Filter)
        if (debug) {
                unsigned long int totalcount=0;
 
-               debuga(_("   Records read: %ld, written: %ld, excluded: %ld\n"),totregsl,totregsg,totregsx);
+               debuga(__FILE__,__LINE__,_("   Records read: %ld, written: %ld, excluded: %ld\n"),totregsl,totregsg,totregsx);
 
                for (x=sizeof(excluded_count)/sizeof(*excluded_count)-1 ; x>=0 && excluded_count[x]>0 ; x--);
                if (x>=0) {
-                       debuga(_("Reasons for excluded entries:\n"));
+                       debuga(__FILE__,__LINE__,_("Reasons for excluded entries:\n"));
                        DisplayExcludeCount(_("User name too long"),ER_UserNameTooLong);
                        DisplayExcludeCount(_("Squid logged an incomplete query received from the client"),ER_IncompleteQuery);
                        DisplayExcludeCount(_("Log file turned over"),ER_LogfileTurnedOver);
@@ -881,13 +936,13 @@ int ReadLogFile(struct ReadLogDataStruct *Filter)
                                /* TRANSLATORS: It displays the number of lines found in the input log files
                                * for each supported log format. The log format name is the %s and is a string
                                * you translate somewhere else. */
-                               debuga(_("%s: %lu entries\n"),_(LogFormats[x]->Name),format_count[x]);
+                               debuga(__FILE__,__LINE__,_("%s: %lu entries\n"),_(LogFormats[x]->Name),format_count[x]);
                                totalcount+=format_count[x];
                        }
                }
 
                if (totalcount==0 && totregsg)
-                       debuga(_("Log with invalid format\n"));
+                       debuga(__FILE__,__LINE__,_("Log with invalid format\n"));
        }
 
        return((totregsg!=0) ? 1 : 0);
@@ -896,16 +951,21 @@ int ReadLogFile(struct ReadLogDataStruct *Filter)
 /*!
  * Get the start and end date of the period covered by the log files.
  */
-void GetLogPeriod(struct tm *Start,struct tm *End)
+bool GetLogPeriod(struct tm *Start,struct tm *End)
 {
+       bool Valid=false;
+
        if (EarliestDate>=0) {
                memcpy(Start,&EarliestDateTime,sizeof(struct tm));
+               Valid=true;
        } else {
                memset(Start,0,sizeof(struct tm));
        }
        if (LatestDate>=0) {
                memcpy(End,&LatestDateTime,sizeof(struct tm));
+               Valid=true;
        } else {
                memset(End,0,sizeof(struct tm));
        }
+       return(Valid);
 }