]> git.ipfire.org Git - thirdparty/sarg.git/blobdiff - log.c
Add support to decompress xz files
[thirdparty/sarg.git] / log.c
diff --git a/log.c b/log.c
index 0bf0e56c8feca81579e3c508891f4da635602b26..0bda1f36b766295b7be484312d6e05fb24bfa858 100644 (file)
--- a/log.c
+++ b/log.c
@@ -1,6 +1,6 @@
 /*
  * SARG Squid Analysis Report Generator      http://sarg.sourceforge.net
- *                                                            1998, 2012
+ *                                                            1998, 2015
  *
  * SARG donations:
  *      please look at http://sarg.sourceforge.net/donations.php
@@ -27,6 +27,7 @@
 #include "include/conf.h"
 #include "include/defs.h"
 #include "include/readlog.h"
+#include "include/filelist.h"
 
 #ifdef HAVE_GETOPT_H
 #include <getopt.h>
@@ -38,6 +39,15 @@ struct ReadLogDataStruct ReadFilter;
 //! The list of the system users.
 /*@null@*/char *userfile=NULL;
 
+//! List of the input log files to process.
+FileListObject AccessLog=NULL;
+//! Selected locale set through the environment variable.
+char *CurrentLocale=NULL;
+//! Set to \c true if a useragent log is provided on the command line.
+bool UserAgentFromCmdLine=false;
+
+extern FileListObject UserAgentLog;
+
 static void getusers(const char *pwdfile, int debug);
 
 int main(int argc,char *argv[])
@@ -47,11 +57,9 @@ int main(int argc,char *argv[])
        extern char *optarg;
 
        char hm_str[15];
-       char uagent[MAXLEN];
        char hexclude[MAXLEN];
        char splitprefix[MAXLEN];
        int  ch;
-       int  x;
        int  errflg=0;
        bool  dns=false;
        int  iarq=0;
@@ -59,9 +67,20 @@ int main(int argc,char *argv[])
        int LogStatus;
        bool realt;
        bool userip;
+       time_t start_time;
+       time_t end_time;
+       time_t read_start_time;
+       time_t read_end_time;
+       time_t process_start_time;
+       time_t process_end_time;
+       double read_elapsed;
+       double process_elapsed;
+       FileListIterator FIter;
        static int split=0;
        static int convert=0;
        static int output_css=0;
+       static int show_statis=0;
+       static int show_version=0;
        int option_index;
        static struct option long_options[]=
        {
@@ -72,15 +91,20 @@ int main(int argc,char *argv[])
                {"keeplogs",no_argument,NULL,3},
                {"split",no_argument,&split,1},
                {"splitprefix",required_argument,NULL,'P'},
+               {"statistics",no_argument,&show_statis,1},
+               {"version",no_argument,&show_version,'V'},
                {0,0,0,0}
        };
 
+       start_time=time(NULL);
+
 #ifdef HAVE_LOCALE_H
        setlocale(LC_TIME,"");
 #endif
 
 #if defined(ENABLE_NLS) && defined(HAVE_LOCALE_H)
-       if (!setlocale (LC_ALL, "")) {
+       CurrentLocale=setlocale (LC_ALL, "");
+       if (!CurrentLocale) {
                fprintf(stderr,"SARG: Cannot set the locale LC_ALL to the environment variable\n");
                exit(EXIT_FAILURE);
        }
@@ -99,7 +123,6 @@ int main(int argc,char *argv[])
        LogoText[0]='\0';
        PasswdFile[0]='\0';
        OutputEmail[0]='\0';
-       UserAgentLog[0]='\0';
        ExcludeHosts[0]='\0';
        ExcludeUsers[0]='\0';
        ConfigFile[0]='\0';
@@ -129,10 +152,10 @@ int main(int argc,char *argv[])
        strcpy(OutputDir,"/var/www/html/squid-reports");
        AnonymousOutputFiles=false;
        Ip2Name=false;
-       strcpy(DateFormat,"u");
+       DateFormat='u';
        OverwriteReport=false;
        RemoveTempFiles=true;
-       strcpy(ReplaceIndex,"index.html");
+       strcpy(ReplaceIndex,INDEX_HTML_FILE);
        Index=INDEX_YES;
        RecordsWithoutUser=RECORDWITHOUTUSER_IP;
        UseComma=0;
@@ -162,6 +185,7 @@ int main(int argc,char *argv[])
        DataFileFields=DATA_FIELD_USER | DATA_FIELD_DATE | DATA_FIELD_TIME | DATA_FIELD_URL | DATA_FIELD_CONNECT |
              DATA_FIELD_BYTES | DATA_FIELD_IN_CACHE | DATA_FIELD_OUT_CACHE | DATA_FIELD_ELAPSED;
        ShowReadStatistics=true;
+       ShowReadPercent=false;
        strcpy(IndexSortOrder,"D");
        ShowSargInfo=true;
        ShowSargLogo=true;
@@ -182,7 +206,7 @@ int main(int argc,char *argv[])
        NtlmUserFormat=NTLMUSERFORMAT_DOMAINUSER;
        IndexTree=INDEX_TREE_FILE;
        IndexFields=INDEXFIELDS_DIRSIZE;
-       strcpy(RealtimeTypes,"GET,PUT,CONNECT");
+       strcpy(RealtimeTypes,"GET,PUT,CONNECT,POST");
        RealtimeUnauthRec=REALTIME_UNAUTH_REC_SHOW;
        RedirectorFilterOutDate=true;
        DansguardianFilterOutDate=true;
@@ -198,13 +222,13 @@ int main(int argc,char *argv[])
        LDAPBaseSearch[0]='\0';
        strcpy(LDAPFilterSearch, "(uid=%s)");
        strcpy(LDAPTargetAttr, "cn");
+       LDAPNativeCharset[0]='\0';
        SortTableJs[0]='\0';
 
        tmp[0]='\0';
        us[0]='\0';
        ReadFilter.DateRange[0]='\0';
-       df[0]='\0';
-       uagent[0]='\0';
+       df='\0';
        hexclude[0]='\0';
        addr[0]='\0';
        ReadFilter.StartTime=-1;
@@ -219,12 +243,13 @@ int main(int argc,char *argv[])
        DansGuardianConf[0]='\0';
        hm_str[0]='\0';
        HostAliasFile[0]='\0';
+       UserAliasFile[0]='\0';
 
-       download_count=0;
        dansguardian_count=0;
        redirector_count=0;
        useragent_count=0;
        DeniedReportLimit=10;
+       SiteUsersReportLimit=0;
        AuthfailReportLimit=10;
        DansGuardianReportLimit=10;
        SquidGuardReportLimit=10;
@@ -232,7 +257,6 @@ int main(int argc,char *argv[])
        UserReportLimit=0;
        debug=0;
        debugz=0;
-       debugm=0;
        iprel=false;
        userip=false;
        realt=false;
@@ -240,24 +264,26 @@ int main(int argc,char *argv[])
        realtime_access_log_lines=1000;
        cost=0.01;
        nocost=50000000;
-       ndownload=0;
        squid24=false;
        dfrom=0;
        duntil=0;
-
-       bzero(IncludeUsers, sizeof(IncludeUsers));
-       bzero(ExcludeString, sizeof(ExcludeString));
+       KeepTempLog=false;
+       NumLogSuccessiveErrors=3;
+       NumLogTotalErrors=50;
+       lines_read=0UL;
+       records_kept=0UL;
+       nusers=0UL;
+
+       memset(IncludeUsers,0,sizeof(IncludeUsers));
+       memset(ExcludeString,0,sizeof(ExcludeString));
        memset(&period,0,sizeof(period));
 
-       NAccessLog=0;
-       for(x=0; x<MAXLOGS; x++)
-               AccessLog[x][0]='\0';
        AccessLogFromCmdLine=0;
        RedirectorLogFromCmdLine=0;
 
        strcpy(Title,_("Squid User Access Report"));
 
-       while((ch = getopt_long_only(argc, argv, "a:b:c:d:e:f:g:u:l:L:o:s:t:w:P:hijmnprvxyz",long_options,&option_index)) != -1){
+       while((ch = getopt_long(argc, argv, "a:b:c:d:e:f:g:hikl:L:no:P:prs:t:u:Vw:xyz",long_options,&option_index)) != -1){
                switch(ch)
                {
                        case 0:
@@ -272,14 +298,20 @@ int main(int argc,char *argv[])
                                safe_strcpy(addr,optarg,sizeof(addr));
                                break;
                        case 'b': //unused option
-                               safe_strcpy(uagent,optarg,sizeof(uagent));
+                               UserAgentFromCmdLine=true;
+                               if (!UserAgentLog)
+                                       UserAgentLog=FileList_Create();
+                               if (!FileList_AddFile(UserAgentLog,optarg)) {
+                                       debuga(__FILE__,__LINE__,_("Not enough memory to store a user agent file name\n"));
+                                       exit(EXIT_FAILURE);
+                               }
                                break;
                        case 'c':
                                safe_strcpy(hexclude,optarg,sizeof(hexclude));
                                break;
                        case 'd':
                                safe_strcpy(ReadFilter.DateRange,optarg,sizeof(ReadFilter.DateRange));
-                               date_from(ReadFilter.DateRange, &dfrom, &duntil);
+                               date_from(ReadFilter.DateRange,sizeof(ReadFilter.DateRange), &dfrom, &duntil);
                                break;
                        case 'e':
                                safe_strcpy(email,optarg,sizeof(email));
@@ -288,7 +320,7 @@ int main(int argc,char *argv[])
                                safe_strcpy(ConfigFile,optarg,sizeof(ConfigFile));
                                break;
                        case 'g':
-                               safe_strcpy(df,optarg,sizeof(df));
+                               df=*optarg;
                                break;
                        case 'h':
                                usage(argv[0]);
@@ -296,35 +328,31 @@ int main(int argc,char *argv[])
                        case 'i':
                                iprel=true;
                                break;
+                       case 'k':
+                               KeepTempLog=true;
+                               break;
                        case 'l':
-                               if (NAccessLog>=MAXLOGS) {
-                                       debuga(_("Too many log files passed on command line with option -l.\n"));
+                               if (!AccessLog)
+                                       AccessLog=FileList_Create();
+                               if (!FileList_AddFile(AccessLog,optarg)) {
+                                       debuga(__FILE__,__LINE__,_("Not enough memory to store the input log file names\n"));
                                        exit(EXIT_FAILURE);
                                }
-                               if (strlen(optarg)>=MAX_LOG_FILELEN) {
-                                       debuga(_("Log file name too long passed on command line with option -l: %s\n"),optarg);
-                                       exit(EXIT_FAILURE);
-                               }
-                               strcpy(AccessLog[NAccessLog],optarg);
-                               NAccessLog++;
                                AccessLogFromCmdLine++;
                                break;
                        case 'L':
                                if (NRedirectorLogs>MAX_REDIRECTOR_LOGS) {
-                                       debuga(_("Too many redirector logs passed on command line with option -L.\n"));
+                                       debuga(__FILE__,__LINE__,_("Too many redirector logs passed on command line with option -L.\n"));
                                        exit(EXIT_FAILURE);
                                }
                                if (strlen(optarg)>=MAX_REDIRECTOR_FILELEN) {
-                                       debuga(_("Redirector log file name too long passed on command line with opton -L: %s\n"),optarg);
+                                       debuga(__FILE__,__LINE__,_("Redirector log file name too long passed on command line with opton -L: %s\n"),optarg);
                                        exit(EXIT_FAILURE);
                                }
                                strcpy(RedirectorLogs[NRedirectorLogs],optarg);
                                NRedirectorLogs++;
                                RedirectorLogFromCmdLine++;
                                break;
-                       case 'm':
-                               debugm++;
-                               break;
                        case 'n':
                                dns=true;
                                break;
@@ -349,7 +377,7 @@ int main(int argc,char *argv[])
 
                                if(strstr(optarg,"-") == 0) {
                                        if(sscanf(optarg,"%d:%d",&h1,&m1)!=2) {
-                                               debuga(_("Time period passed on the command line with option -t must be MM:SS\n"));
+                                               debuga(__FILE__,__LINE__,_("Time period passed on the command line with option -t must be HH:MM\n"));
                                                exit(EXIT_FAILURE);
                                        }
                                        ReadFilter.StartTime=h1*100+m1;
@@ -357,7 +385,7 @@ int main(int argc,char *argv[])
                                        snprintf(hm_str,sizeof(hm_str),"%02d:%02d",h1,m1);
                                } else {
                                        if(sscanf(optarg,"%d:%d-%d:%d",&h1,&m1,&h2,&m2)!=4) {
-                                               debuga(_("Time range passed on the command line with option -t must be MM:SS-MM:SS\n"));
+                                               debuga(__FILE__,__LINE__,_("Time range passed on the command line with option -t must be HH:MM-HH:MM\n"));
                                                exit(EXIT_FAILURE);
                                        }
                                        ReadFilter.StartTime=h1*100+m1;
@@ -369,8 +397,8 @@ int main(int argc,char *argv[])
                        case 'u':
                                safe_strcpy(us,optarg,sizeof(us));
                                break;
-                       case 'v':
-                               version();
+                       case 'V':
+                               show_version=1;
                                break;
                        case 'w':
                                safe_strcpy(tmp,optarg,sizeof(tmp));
@@ -385,7 +413,7 @@ int main(int argc,char *argv[])
                                debugz++;
                                break;
                        case ':':
-                               debuga(_("Option -%c requires an argument\n"),optopt);
+                               debuga(__FILE__,__LINE__,_("Option -%c requires an argument\n"),optopt);
                                exit(EXIT_FAILURE);
                        case '?':
                                usage(argv[0]);
@@ -399,33 +427,37 @@ int main(int argc,char *argv[])
                usage(argv[0]);
                exit(2);
        }
+       if (show_version) {
+               version();
+       }
+
+       if(output_css) {
+               css_content(stdout);
+               exit(EXIT_SUCCESS);
+       }
 
        if (optind<argc) {
+               if (!AccessLog)
+                       AccessLog=FileList_Create();
                for (iarq=optind ; iarq<argc ; iarq++) {
-                       if (NAccessLog>=MAXLOGS) {
-                               debuga(_("Too many log files passed on command line.\n"));
+                       if (!FileList_AddFile(AccessLog,argv[iarq])) {
+                               debuga(__FILE__,__LINE__,_("Not enough memory to store the input log file names\n"));
                                exit(EXIT_FAILURE);
                        }
-                       if (strlen(argv[iarq])>=MAX_LOG_FILELEN) {
-                               debuga(_("Log file name too long passed on command line: %s\n"),argv[iarq]);
-                               exit(EXIT_FAILURE);
-                       }
-                       strcpy(AccessLog[NAccessLog],argv[iarq]);
-                       NAccessLog++;
                        AccessLogFromCmdLine++;
                }
        }
 
-       if(debug) debuga(_("Init\n"));
+       if(debug) debuga(__FILE__,__LINE__,_("Init\n"));
 
        if(ConfigFile[0] == '\0') snprintf(ConfigFile,sizeof(ConfigFile),"%s/sarg.conf",SYSCONFDIR);
        if(access(ConfigFile, R_OK) != 0) {
-               debuga(_("Cannot open config file: %s - %s\n"),ConfigFile,strerror(errno));
+               debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),ConfigFile,strerror(errno));
                exit(EXIT_FAILURE);
        }
 
        if(access(ConfigFile, R_OK) == 0)
-               getconf();
+               getconf(ConfigFile);
 
        if(userip) UserIp=true;
 
@@ -436,47 +468,46 @@ int main(int argc,char *argv[])
        if(outdir[0] == '\0') strcpy(outdir,OutputDir);
        if(outdir[0] != '\0') strcat(outdir,"/");
 
-       if(realt) {
-               realtime();
-               exit(EXIT_SUCCESS);
-       }
-
        if(IndexTree == INDEX_TREE_FILE)
                strcpy(ImageFile,"../images");
        else
                strcpy(ImageFile,"../../../images");
 
-       dataonly=0;
-       if(DataFile[0] != '\0')
-               dataonly++;
-
-       if(df[0] == '\0') strcpy(df,DateFormat);
-       else strcpy(DateFormat,df);
+       dataonly=(DataFile[0] != '\0');
 
-       if(df[0] == '\0') {
-               strcpy(df,"u");
-               strcpy(DateFormat,"u");
-       }
-       if (df[0]=='w')
+       if (df=='\0') df=DateFormat;
+       if (df=='\0') df='u';
+       if (df=='w')
                IndexTree=INDEX_TREE_FILE;
 
-       if(NAccessLog == 0) {
-               strcpy(AccessLog[0],"/var/log/squid/access.log");
-               NAccessLog++;
+       if(AccessLog==NULL) {
+               AccessLog=FileList_Create();
+               if (!FileList_AddFile(AccessLog,"/var/log/squid/access.log")) {
+                       debuga(__FILE__,__LINE__,_("Not enough memory to store the input log file names\n"));
+                       exit(EXIT_FAILURE);
+               }
        }
 
-       if(output_css) {
-               css_content(stdout);
+       if(realt) {
+               realtime();
                exit(EXIT_SUCCESS);
        }
        if(split) {
-               for (iarq=0 ; iarq<NAccessLog ; iarq++)
-                       splitlog(AccessLog[iarq], df, dfrom, duntil, convert, splitprefix);
+               const char *file;
+
+               FIter=FileListIter_Open(AccessLog);
+               while ((file=FileListIter_Next(FIter))!=NULL)
+                       splitlog(file, df, dfrom, duntil, convert, splitprefix);
+               FileListIter_Close(FIter);
                exit(EXIT_SUCCESS);
        }
        if(convert) {
-               for (iarq=0 ; iarq<NAccessLog ; iarq++)
-                       convlog(AccessLog[iarq], df, dfrom, duntil);
+               const char *file;
+
+               FIter=FileListIter_Open(AccessLog);
+               while ((file=FileListIter_Next(FIter))!=NULL)
+                       convlog(file, df, dfrom, duntil);
+               FileListIter_Close(FIter);
                exit(EXIT_SUCCESS);
        }
 
@@ -501,8 +532,11 @@ int main(int argc,char *argv[])
        if(ReportType == 0) {
                ReportType=REPORT_TYPE_TOPUSERS | REPORT_TYPE_TOPSITES | REPORT_TYPE_USERS_SITES |
                           REPORT_TYPE_SITES_USERS | REPORT_TYPE_DATE_TIME | REPORT_TYPE_DENIED |
-                          REPORT_TYPE_AUTH_FAILURES | REPORT_TYPE_SITE_USER_TIME_DATE | REPORT_TYPE_DOWNLOADS;
+                                  REPORT_TYPE_AUTH_FAILURES | REPORT_TYPE_SITE_USER_TIME_DATE |
+                                  REPORT_TYPE_DOWNLOADS | REPORT_TYPE_USERAGENT;
        }
+       if (!FileList_IsEmpty(UserAgentLog))
+               ReportType|=REPORT_TYPE_USERAGENT;
 
        if(access(ExcludeUsers, R_OK) == 0) {
                getuexclude(ExcludeUsers,debug);
@@ -512,6 +546,8 @@ int main(int argc,char *argv[])
        }
        if (HostAliasFile[0] != '\0')
                read_hostalias(HostAliasFile);
+       if (UserAliasFile[0] != '\0')
+               read_useralias(UserAliasFile);
 
        indexonly=false;
        if(ReadFilter.UserFilter) {
@@ -526,8 +562,6 @@ int main(int argc,char *argv[])
        else
                ReadFilter.max_elapsed=0;
 
-       if(uagent[0] == '\0') strcpy(uagent,UserAgentLog);
-
        if(tmp[0] == '\0') strcpy(tmp,TempDir);
        else strcpy(TempDir,tmp);
        /*
@@ -537,7 +571,7 @@ int main(int argc,char *argv[])
        strcat(tmp,"/sarg");
 
        if (tmp[0]!='\0' && strncmp(outdir,tmp,strlen(tmp))==0) {
-               debuga(_("The output directory \"%s\" must be outside of the temporary directory \"%s\"\n"),outdir,tmp);
+               debuga(__FILE__,__LINE__,_("The output directory \"%s\" must be outside of the temporary directory \"%s\"\n"),outdir,tmp);
                exit(EXIT_FAILURE);
        }
 
@@ -550,80 +584,56 @@ int main(int argc,char *argv[])
        }
 
        if(access(tmp, R_OK) == 0) {
-               if (debug) debuga(_("Deleting directory %s\n"),tmp);
-               unlinkdir(tmp,1);
+               if (debug) debuga(__FILE__,__LINE__,_("Deleting temporary directory \"%s\"\n"),tmp);
+               emptytmpdir(tmp);
        }
        my_mkdir(tmp);
 
        if(debug) {
-               debuga(_("Parameters:\n"));
-               debuga(_("          Hostname or IP address (-a) = %s\n"),addr);
-               debuga(_("                   Useragent log (-b) = %s\n"),uagent);
-               debuga(_("                    Exclude file (-c) = %s\n"),hexclude);
-               debuga(_("                 Date from-until (-d) = %s\n"),ReadFilter.DateRange);
-               debuga(_("   Email address to send reports (-e) = %s\n"),email);
-               debuga(_("                     Config file (-f) = %s\n"),ConfigFile);
-               if(strcmp(df,"e") == 0)
-                       debuga(_("                     Date format (-g) = Europe (dd/mm/yyyy)\n"));
-               if(strcmp(df,"u") == 0)
-                       debuga(_("                     Date format (-g) = USA (mm/dd/yyyy)\n"));
-               if(strcmp(df,"w") == 0)
-                       debuga(_("                     Date format (-g) = Sites & Users (yyyy/ww)\n"));
-               debuga(_("                       IP report (-i) = %s\n"),(iprel) ? _("Yes") : _("No"));
-               for (iarq=0 ; iarq<NAccessLog ; iarq++)
-                       debuga(_("                       Input log (-l) = %s\n"),AccessLog[iarq]);
-               for (iarq=0 ; iarq<NRedirectorLogs ; iarq++)
-                       debuga(_("                  Redirector log (-L) = %s\n"),RedirectorLogs[iarq]);
-               debuga(_("              Resolve IP Address (-n) = %s\n"),(Ip2Name) ? _("Yes") : _("No"));
-               debuga(_("                      Output dir (-o) = %s\n"),outdir);
-               debuga(_("Use Ip Address instead of userid (-p) = %s\n"),(UserIp) ? _("Yes") : _("No"));
-               debuga(_("                   Accessed site (-s) = %s\n"),site);
-               debuga(_("                            Time (-t) = %s\n"),hm_str);
-               debuga(_("                            User (-u) = %s\n"),us);
-               debuga(_("                   Temporary dir (-w) = %s\n"),tmp);
-               debuga(_("                  Debug messages (-x) = %s\n"),(debug) ? _("Yes") : _("No"));
-               debuga(_("                Process messages (-z) = %s\n"),(debugz) ? _("Yes") : _("No"));
-               debuga(_(" Previous reports to keep (--lastlog) = %d\n"),LastLog);
-               debuga("\n");
-       }
-
-       if(debugm) {
-               printf(_("Parameters:\n"));
-               printf(_("          Hostname or IP address (-a) = %s\n"),addr);
-               printf(_("                   Useragent log (-b) = %s\n"),uagent);
-               printf(_("                    Exclude file (-c) = %s\n"),hexclude);
-               printf(_("                 Date from-until (-d) = %s\n"),ReadFilter.DateRange);
-               printf(_("   Email address to send reports (-e) = %s\n"),email);
-               printf(_("                     Config file (-f) = %s\n"),ConfigFile);
-               if(strcmp(df,"e") == 0)
-                       printf(_("                     Date format (-g) = Europe (dd/mm/yyyy)\n"));
-               if(strcmp(df,"u") == 0)
-                       printf(_("                     Date format (-g) = USA (mm/dd/yyyy)\n"));
-               if(strcmp(df,"w") == 0)
-                       printf(_("                     Date format (-g) = Sites & Users (yyyy/ww)\n"));
-               printf(_("                       IP report (-i) = %s\n"),(iprel) ? _("Yes") : _("No"));
-               for (iarq=0 ; iarq<NAccessLog ; iarq++)
-                       printf(_("                       Input log (-l) = %s\n"),AccessLog[iarq]);
+               const char *file;
+
+               debuga(__FILE__,__LINE__,_("Parameters:\n"));
+               debuga(__FILE__,__LINE__,_("          Hostname or IP address (-a) = %s\n"),addr);
+               FIter=FileListIter_Open(UserAgentLog);
+               while ((file=FileListIter_NextWithMask(FIter))!=NULL)
+                       debuga(__FILE__,__LINE__,_("                   Useragent log (-b) = %s\n"),file);
+               FileListIter_Close(FIter);
+               debuga(__FILE__,__LINE__,_("                    Exclude file (-c) = %s\n"),hexclude);
+               debuga(__FILE__,__LINE__,_("                 Date from-until (-d) = %s\n"),ReadFilter.DateRange);
+               debuga(__FILE__,__LINE__,_("   Email address to send reports (-e) = %s\n"),email);
+               debuga(__FILE__,__LINE__,_("                     Config file (-f) = %s\n"),ConfigFile);
+               if (df=='e')
+                       debuga(__FILE__,__LINE__,_("                     Date format (-g) = Europe (dd/mm/yyyy)\n"));
+               else if (df=='u')
+                       debuga(__FILE__,__LINE__,_("                     Date format (-g) = USA (mm/dd/yyyy)\n"));
+               else if (df=='w')
+                       debuga(__FILE__,__LINE__,_("                     Date format (-g) = Sites & Users (yyyy/ww)\n"));
+               debuga(__FILE__,__LINE__,_("                       IP report (-i) = %s\n"),(iprel) ? _("Yes") : _("No"));
+               debuga(__FILE__,__LINE__,_("            Keep temporary files (-k) = %s\n"),(KeepTempLog) ? _("Yes") : _("No"));
+               FIter=FileListIter_Open(AccessLog);
+               while ((file=FileListIter_NextWithMask(FIter))!=NULL)
+                       debuga(__FILE__,__LINE__,_("                       Input log (-l) = %s\n"),file);
+               FileListIter_Close(FIter);
                for (iarq=0 ; iarq<NRedirectorLogs ; iarq++)
-                       printf(_("                  Redirector log (-L) = %s\n"),RedirectorLogs[iarq]);
-               printf(_("              Resolve IP Address (-n) = %s\n"),(Ip2Name) ? _("Yes") : _("No"));
-               printf(_("                      Output dir (-o) = %s\n"),outdir);
-               printf(_("Use Ip Address instead of userid (-p) = %s\n"),(UserIp) ? _("Yes") : _("No"));
-               printf(_("                   Accessed site (-s) = %s\n"),site);
-               printf(_("                            Time (-t) = %s\n"),hm_str);
-               printf(_("                            User (-u) = %s\n"),us);
-               printf(_("                   Temporary dir (-w) = %s\n"),tmp);
-               printf(_("                  Debug messages (-x) = %s\n"),(debug) ? _("Yes") : _("No"));
-               printf(_("                Process messages (-z) = %s\n"),(debugz) ? _("Yes") : _("No"));
-               printf(_(" Previous reports to keep (--lastlog) = %d\n"),LastLog);
-               printf(_("sarg version: %s\n"),VERSION);
+                       debuga(__FILE__,__LINE__,_("                  Redirector log (-L) = %s\n"),RedirectorLogs[iarq]);
+               debuga(__FILE__,__LINE__,_("              Resolve IP Address (-n) = %s\n"),(Ip2Name) ? _("Yes") : _("No"));
+               debuga(__FILE__,__LINE__,_("                      Output dir (-o) = %s\n"),outdir);
+               debuga(__FILE__,__LINE__,_("Use Ip Address instead of userid (-p) = %s\n"),(UserIp) ? _("Yes") : _("No"));
+               debuga(__FILE__,__LINE__,_("                   Accessed site (-s) = %s\n"),site);
+               debuga(__FILE__,__LINE__,_("                            Time (-t) = %s\n"),hm_str);
+               debuga(__FILE__,__LINE__,_("                            User (-u) = %s\n"),us);
+               debuga(__FILE__,__LINE__,_("                   Temporary dir (-w) = %s\n"),tmp);
+               debuga(__FILE__,__LINE__,_("                  Debug messages (-x) = %s\n"),(debug) ? _("Yes") : _("No"));
+               debuga(__FILE__,__LINE__,_("                Process messages (-z) = %d\n"),debugz);
+               debuga(__FILE__,__LINE__,_(" Previous reports to keep (--lastlog) = %d\n"),LastLog);
+               debuga(__FILE__,__LINE__,"\n");
        }
 
        if(debug)
-               debuga(_("sarg version: %s\n"),VERSION);
+               debuga(__FILE__,__LINE__,_("sarg version: %s\n"),VERSION);
 
 #ifdef ENABLE_DOUBLE_CHECK_DATA
-       debuga(_("Sarg compiled to report warnings if the output is inconsistent\n"));
+       debuga(__FILE__,__LINE__,_("Sarg compiled to report warnings if the output is inconsistent\n"));
 #endif
 
 #ifdef HAVE_RLIM_T
@@ -652,7 +662,7 @@ int main(int argc,char *argv[])
 #warning "No rlimit resource for the number of open files"
 #endif
                if(rc == -1) {
-                       debuga(_("setrlimit error - %s\n"),strerror(errno));
+                       debuga(_("setrlimit error: %s\n"),strerror(errno));
                }
 
                if(debug)
@@ -660,60 +670,94 @@ int main(int argc,char *argv[])
        }
 #endif
 
-       init_usertab(UserTabFile);
-
+       read_start_time=time(NULL);
        LogStatus=ReadLogFile(&ReadFilter);
+       read_end_time=time(NULL);
+       read_elapsed=(double)read_end_time-(double)read_start_time;
 
+       FileList_Destroy(&AccessLog);
        free_download();
        free_excludecodes();
        free_exclude();
 
+       if (debug) {
+               char date0[30], date1[30];
+               struct tm Start,End;
+
+               if (GetLogPeriod(&Start,&End)) {
+                       strftime(date0,sizeof(date0),"%x",&Start);
+                       strftime(date1,sizeof(date1),"%x",&End);
+                       // TRANSLATORS: The %s are the start and end dates in locale format.
+                       debuga(__FILE__,__LINE__,_("Period covered by log files: %s-%s\n"),date0,date1);
+               }
+       }
+
        if (!LogStatus){
-               debuga(_("No records found\n"));
-               debuga(_("End\n"));
+               debuga(__FILE__,__LINE__,_("No records found\n"));
+               debuga(__FILE__,__LINE__,_("End\n"));
                userinfo_free();
                if(userfile) free(userfile);
                close_usertab();
                exit(EXIT_SUCCESS);
        }
 
-       if (ReadFilter.DateRange[0]!='\0') {
+       if (debug) {
                char date0[30], date1[30];
 
-               strftime(date0,sizeof(date0),"%d/%m/%Y",&period.start);
-               strftime(date1,sizeof(date1),"%d/%m/%Y",&period.end);
-               debuga(_("Period covered by log files: %s-%s\n"),date0,date1);
+               strftime(date0,sizeof(date0),"%x",&period.start);
+               strftime(date1,sizeof(date1),"%x",&period.end);
+               // TRANSLATORS: The %s are the start and end dates in locale format.
+               debuga(__FILE__,__LINE__,_("Period extracted from log files: %s-%s\n"),date0,date1);
+       }
+       if (ReadFilter.DateRange[0] != '\0') {
                getperiod_fromrange(&period,dfrom,duntil);
        }
        if (getperiod_buildtext(&period)<0) {
-               debuga(_("Failed to build the string representation of the date range\n"));
+               debuga(__FILE__,__LINE__,_("Failed to build the string representation of the date range\n"));
                exit(EXIT_FAILURE);
        }
 
-       if(debug)
-               debuga(_("Period: %s\n"),period.text);
-
+       process_start_time=time(NULL);
        if(DataFile[0] != '\0')
                data_file(tmp);
        else
                gerarel();
+       process_end_time=time(NULL);
+       process_elapsed=(double)process_end_time-(double)process_start_time;
 
        denied_cleanup();
        authfail_cleanup();
+       download_cleanup();
 
-       if(strcmp(tmp,"/tmp") != 0) {
+       if(!KeepTempLog && strcmp(tmp,"/tmp") != 0) {
                unlinkdir(tmp,0);
        }
 
        ip2name_cleanup();
        free_hostalias();
+       free_useralias();
        userinfo_free();
        if(userfile)
                free(userfile);
        close_usertab();
+       FileList_Destroy(&UserAgentLog);
+
+       end_time=time(NULL);
+
+       if (show_statis) {
+               double elapsed=(double)end_time-(double)start_time;
+               debuga(__FILE__,__LINE__,_("Total execution time: %.0lf seconds\n"),elapsed);
+               if (read_elapsed>0.) {
+                       debuga(__FILE__,__LINE__,_("Lines read: %lu lines in %.0lf seconds (%.0lf lines/s)\n"),lines_read,read_elapsed,(double)lines_read/read_elapsed);
+               }
+               if (process_elapsed>0.) {
+                       debuga(__FILE__,__LINE__,_("Processed records: %lu records in %.0lf seconds (%.0lf records/s)\n"),records_kept,process_elapsed,(double)records_kept/process_elapsed);
+                       debuga(__FILE__,__LINE__,_("Users: %lu users in %.0lf seconds (%.0lf users/s)\n"),nusers,process_elapsed,(double)nusers/process_elapsed);
+               }
+       }
 
        if(debug)
-               debuga(_("End\n"));
+               debuga(__FILE__,__LINE__,_("End\n"));
 
        exit(EXIT_SUCCESS);
 }
@@ -727,47 +771,50 @@ static void getusers(const char *pwdfile, int debug)
        long int nreg=0;
 
        if(debug)
-               debuga(_("Loading password file from %s\n"),pwdfile);
+               debuga(__FILE__,__LINE__,_("Loading password file \"%s\"\n"),pwdfile);
 
        if ((fp_usr = fopen(pwdfile, "r")) == NULL) {
-               debuga(_("(getusers) Cannot open file %s - %s\n"),pwdfile,strerror(errno));
+               debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),pwdfile,strerror(errno));
                exit(EXIT_FAILURE);
        }
 
        if (fseek(fp_usr, 0, SEEK_END)==-1) {
-               debuga(_("Failed to move till the end of the users file %s: %s\n"),pwdfile,strerror(errno));
+               debuga(__FILE__,__LINE__,_("Failed to move till the end of file \"%s\": %s\n"),pwdfile,strerror(errno));
                exit(EXIT_FAILURE);
        }
        nreg = ftell(fp_usr);
        if (nreg<0) {
-               debuga(_("Cannot get the size of file %s\n"),pwdfile);
+               debuga(__FILE__,__LINE__,_("Cannot get the size of file \"%s\"\n"),pwdfile);
                exit(EXIT_FAILURE);
        }
        nreg = nreg+5000;
        if (fseek(fp_usr, 0, SEEK_SET)==-1) {
-               debuga(_("Failed to rewind the users file %s: %s\n"),pwdfile,strerror(errno));
+               debuga(__FILE__,__LINE__,_("Failed to rewind file \"%s\": %s\n"),pwdfile,strerror(errno));
                exit(EXIT_FAILURE);
        }
 
        if((userfile=(char *) malloc(nreg))==NULL){
-               debuga(_("malloc error (%ld)\n"),nreg);
+               debuga(__FILE__,__LINE__,_("malloc error (%ld bytes required)\n"),nreg);
                exit(EXIT_FAILURE);
        }
 
-       bzero(userfile,nreg);
+       memset(userfile,0,nreg);
        strcpy(userfile,":");
 
        while(fgets(buf,sizeof(buf),fp_usr)!=NULL) {
                str=strchr(buf,':');
                if (!str) {
-                       debuga(_("You have an invalid user in your %s file\n"),pwdfile);
+                       debuga(__FILE__,__LINE__,_("Invalid user in file \"%s\"\n"),pwdfile);
                        exit(EXIT_FAILURE);
                }
                str[1]='\0';
                strcat(userfile,buf);
        }
 
-       fclose(fp_usr);
+       if (fclose(fp_usr)==EOF) {
+               debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),pwdfile,strerror(errno));
+               exit(EXIT_FAILURE);
+       }
 
        return;
 }