2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
6 * please look at http://sarg.sourceforge.net/donations.php
8 * http://sourceforge.net/projects/sarg/forums/forum/363374
9 * ---------------------------------------------------------------------
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
27 #include "include/conf.h"
28 #include "include/defs.h"
29 #include "include/readlog.h"
30 #include "include/filelist.h"
36 //! The log file filtering.
37 struct ReadLogDataStruct ReadFilter
;
39 //! The list of the system users.
40 /*@null@*/char *userfile
=NULL
;
42 //! List of the input log files to process.
43 FileListObject AccessLog
=NULL
;
44 //! Selected locale set through the environment variable.
45 char *CurrentLocale
=NULL
;
46 //! Set to \c true if a useragent log is provided on the command line.
47 bool UserAgentFromCmdLine
=false;
49 extern FileListObject UserAgentLog
;
51 static void getusers(const char *pwdfile
, int debug
);
53 int main(int argc
,char *argv
[])
60 char hexclude
[MAXLEN
];
61 char splitprefix
[MAXLEN
];
72 time_t read_start_time
;
74 time_t process_start_time
;
75 time_t process_end_time
;
77 double process_elapsed
;
78 FileListIterator FIter
;
81 static int output_css
=0;
82 static int show_statis
=0;
83 static int show_version
=0;
85 static struct option long_options
[]=
87 {"convert",no_argument
,&convert
,1},
88 {"css",no_argument
,&output_css
,1},
89 {"help",no_argument
,NULL
,'h'},
90 {"lastlog",required_argument
,NULL
,2},
91 {"keeplogs",no_argument
,NULL
,3},
92 {"split",no_argument
,&split
,1},
93 {"splitprefix",required_argument
,NULL
,'P'},
94 {"statistics",no_argument
,&show_statis
,1},
95 {"version",no_argument
,&show_version
,'V'},
99 start_time
=time(NULL
);
102 setlocale(LC_TIME
,"");
105 #if defined(ENABLE_NLS) && defined(HAVE_LOCALE_H)
106 CurrentLocale
=setlocale (LC_ALL
, "");
107 if (!CurrentLocale
) {
108 fprintf(stderr
,"SARG: Cannot set the locale LC_ALL to the environment variable\n");
111 if (!bindtextdomain (PACKAGE_NAME
, LOCALEDIR
)) {
112 fprintf(stderr
,"SARG: Cannot bind to text domain %s in directory %s (%s)\n",PACKAGE_NAME
,LOCALEDIR
,strerror(errno
));
115 if (!textdomain (PACKAGE_NAME
)) {
116 fprintf(stderr
,"SARG: Cannot set gettext domain for %s PACKAGE_NAME (%s)\n",PACKAGE_NAME
,strerror(errno
));
126 ExcludeHosts
[0]='\0';
127 ExcludeUsers
[0]='\0';
134 ExternalCSSFile
[0]='\0';
135 RedirectorLogFormat
[0]='\0';
138 snprintf(ExcludeCodes
,sizeof(ExcludeCodes
),"%s/exclude_codes",SYSCONFDIR
);
139 strcpy(GraphDaysBytesBarColor
,"orange");
140 strcpy(BgColor
,"#ffffff");
141 strcpy(TxColor
,"#000000");
142 strcpy(TxBgColor
,"lavender");
143 strcpy(TiColor
,"darkblue");
146 strcpy(LogoTextColor
,"#000000");
147 strcpy(HeaderColor
,"darkblue");
148 strcpy(HeaderBgColor
,"#dddddd");
149 strcpy(LogoTextColor
,"#006699");
150 strcpy(FontSize
,"9px");
151 strcpy(TempDir
,"/tmp");
152 strcpy(OutputDir
,"/var/www/html/squid-reports");
153 AnonymousOutputFiles
=false;
156 OverwriteReport
=false;
157 RemoveTempFiles
=true;
158 strcpy(ReplaceIndex
,INDEX_HTML_FILE
);
160 RecordsWithoutUser
=RECORDWITHOUTUSER_IP
;
162 strcpy(MailUtility
,"mailx");
166 TopuserSort
=TOPUSER_SORT_BYTES
| TOPUSER_SORT_REVERSE
;
167 UserSort
=USER_SORT_BYTES
| USER_SORT_REVERSE
;
168 TopsitesSort
=TOPSITE_SORT_CONNECT
| TOPSITE_SORT_REVERSE
;
170 strcpy(FontFace
,"Verdana,Tahoma,Arial");
171 datetimeby
=DATETIME_BYTE
;
172 strcpy(CharSet
,"ISO-8859-1");
174 strcpy(PrivacyString
,"***.***.***.***");
175 strcpy(PrivacyStringColor
,"blue");
177 TopUserFields
=TOPUSERFIELDS_NUM
| TOPUSERFIELDS_DATE_TIME
| TOPUSERFIELDS_USERID
| TOPUSERFIELDS_CONNECT
|
178 TOPUSERFIELDS_BYTES
| TOPUSERFIELDS_SETYB
| TOPUSERFIELDS_IN_CACHE_OUT
|
179 TOPUSERFIELDS_USED_TIME
| TOPUSERFIELDS_MILISEC
| TOPUSERFIELDS_PTIME
|
180 TOPUSERFIELDS_TOTAL
| TOPUSERFIELDS_AVERAGE
;
181 UserReportFields
=USERREPORTFIELDS_CONNECT
| USERREPORTFIELDS_BYTES
| USERREPORTFIELDS_SETYB
|
182 USERREPORTFIELDS_IN_CACHE_OUT
| USERREPORTFIELDS_USED_TIME
| USERREPORTFIELDS_MILISEC
|
183 USERREPORTFIELDS_PTIME
| USERREPORTFIELDS_TOTAL
| USERREPORTFIELDS_AVERAGE
;
184 strcpy(DataFileDelimiter
,";");
185 DataFileFields
=DATA_FIELD_USER
| DATA_FIELD_DATE
| DATA_FIELD_TIME
| DATA_FIELD_URL
| DATA_FIELD_CONNECT
|
186 DATA_FIELD_BYTES
| DATA_FIELD_IN_CACHE
| DATA_FIELD_OUT_CACHE
| DATA_FIELD_ELAPSED
;
187 ShowReadStatistics
=true;
188 ShowReadPercent
=false;
189 strcpy(IndexSortOrder
,"D");
192 ParsedOutputLog
[0]='\0';
193 strcpy(ParsedOutputLogCompress
,"/bin/gzip -f");
194 DisplayedValues
=DISPLAY_ABBREV
;
195 strcpy(HeaderFontSize
,"9px");
196 strcpy(TitleFontSize
,"11px");
197 strcpy(AuthUserTemplateFile
,"sarg_htaccess");
198 set_download_suffix("7z,ace,arj,avi,bat,bin,bz2,bzip,cab,com,cpio,dll,doc,dot,exe,gz,iso,lha,lzh,mdb,mov,mp3,mpeg,mpg,mso,nrg,ogg,ppt,rar,rtf,shs,src,sys,tar,tgz,vcd,vob,wma,wmv,zip");
201 strcpy(GraphFont
,FONTDIR
"/DejaVuSans.ttf");
205 strcpy(Ulimit
,"20000");
206 NtlmUserFormat
=NTLMUSERFORMAT_DOMAINUSER
;
207 IndexTree
=INDEX_TREE_FILE
;
208 IndexFields
=INDEXFIELDS_DIRSIZE
;
209 strcpy(RealtimeTypes
,"GET,PUT,CONNECT,POST");
210 RealtimeUnauthRec
=REALTIME_UNAUTH_REC_SHOW
;
211 RedirectorFilterOutDate
=true;
212 DansguardianFilterOutDate
=true;
213 DataFileUrl
=DATAFILEURL_IP
;
214 strcpy(MaxElapsed
,"28800000");
215 BytesInSitesUsersReport
=0;
216 UserAuthentication
=0;
217 strcpy(LDAPHost
,"127.0.0.1");
219 LDAPProtocolVersion
=3;
222 LDAPBaseSearch
[0]='\0';
223 strcpy(LDAPFilterSearch
, "(uid=%s)");
224 strcpy(LDAPTargetAttr
, "cn");
225 LDAPNativeCharset
[0]='\0';
230 ReadFilter
.DateRange
[0]='\0';
234 ReadFilter
.StartTime
=-1;
235 ReadFilter
.EndTime
=-1;
240 UserInvalidChar
[0]='\0';
242 SquidGuardConf
[0]='\0';
243 DansGuardianConf
[0]='\0';
245 HostAliasFile
[0]='\0';
246 UserAliasFile
[0]='\0';
248 dansguardian_count
=0;
251 DeniedReportLimit
=10;
252 AuthfailReportLimit
=10;
253 DansGuardianReportLimit
=10;
254 SquidGuardReportLimit
=10;
255 DownloadReportLimit
=50;
263 realtime_access_log_lines
=1000;
270 NumLogSuccessiveErrors
=3;
271 NumLogTotalErrors
=50;
276 memset(IncludeUsers
,0,sizeof(IncludeUsers
));
277 memset(ExcludeString
,0,sizeof(ExcludeString
));
278 memset(&period
,0,sizeof(period
));
280 AccessLogFromCmdLine
=0;
281 RedirectorLogFromCmdLine
=0;
283 strcpy(Title
,_("Squid User Access Report"));
285 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){
291 lastlog
=atoi(optarg
);
297 safe_strcpy(addr
,optarg
,sizeof(addr
));
299 case 'b': //unused option
300 UserAgentFromCmdLine
=true;
302 UserAgentLog
=FileList_Create();
303 if (!FileList_AddFile(UserAgentLog
,optarg
)) {
304 debuga(__FILE__
,__LINE__
,_("Not enough memory to store a user agent file name\n"));
309 safe_strcpy(hexclude
,optarg
,sizeof(hexclude
));
312 safe_strcpy(ReadFilter
.DateRange
,optarg
,sizeof(ReadFilter
.DateRange
));
313 date_from(ReadFilter
.DateRange
,sizeof(ReadFilter
.DateRange
), &dfrom
, &duntil
);
316 safe_strcpy(email
,optarg
,sizeof(email
));
319 safe_strcpy(ConfigFile
,optarg
,sizeof(ConfigFile
));
335 AccessLog
=FileList_Create();
336 if (!FileList_AddFile(AccessLog
,optarg
)) {
337 debuga(__FILE__
,__LINE__
,_("Not enough memory to store the input log file names\n"));
340 AccessLogFromCmdLine
++;
343 if (NRedirectorLogs
>MAX_REDIRECTOR_LOGS
) {
344 debuga(__FILE__
,__LINE__
,_("Too many redirector logs passed on command line with option -L.\n"));
347 if (strlen(optarg
)>=MAX_REDIRECTOR_FILELEN
) {
348 debuga(__FILE__
,__LINE__
,_("Redirector log file name too long passed on command line with opton -L: %s\n"),optarg
);
351 strcpy(RedirectorLogs
[NRedirectorLogs
],optarg
);
353 RedirectorLogFromCmdLine
++;
359 safe_strcpy(outdir
,optarg
,sizeof(outdir
));
365 safe_strcpy(splitprefix
,optarg
,sizeof(splitprefix
));
371 safe_strcpy(site
,optarg
,sizeof(site
));
377 if(strstr(optarg
,"-") == 0) {
378 if(sscanf(optarg
,"%d:%d",&h1
,&m1
)!=2) {
379 debuga(__FILE__
,__LINE__
,_("Time period passed on the command line with option -t must be HH:MM\n"));
382 ReadFilter
.StartTime
=h1
*100+m1
;
383 ReadFilter
.EndTime
=ReadFilter
.StartTime
;
384 snprintf(hm_str
,sizeof(hm_str
),"%02d:%02d",h1
,m1
);
386 if(sscanf(optarg
,"%d:%d-%d:%d",&h1
,&m1
,&h2
,&m2
)!=4) {
387 debuga(__FILE__
,__LINE__
,_("Time range passed on the command line with option -t must be HH:MM-HH:MM\n"));
390 ReadFilter
.StartTime
=h1
*100+m1
;
391 ReadFilter
.EndTime
=h2
*100+m2
;
392 snprintf(hm_str
,sizeof(hm_str
),"%02d:%02d-%02d:%02d",h1
,m1
,h2
,m2
);
397 safe_strcpy(us
,optarg
,sizeof(us
));
403 safe_strcpy(tmp
,optarg
,sizeof(tmp
));
408 case 'y': //unused option
415 debuga(__FILE__
,__LINE__
,_("Option -%c requires an argument\n"),optopt
);
440 AccessLog
=FileList_Create();
441 for (iarq
=optind
; iarq
<argc
; iarq
++) {
442 if (!FileList_AddFile(AccessLog
,argv
[iarq
])) {
443 debuga(__FILE__
,__LINE__
,_("Not enough memory to store the input log file names\n"));
446 AccessLogFromCmdLine
++;
450 if(debug
) debuga(__FILE__
,__LINE__
,_("Init\n"));
452 if(ConfigFile
[0] == '\0') snprintf(ConfigFile
,sizeof(ConfigFile
),"%s/sarg.conf",SYSCONFDIR
);
453 if(access(ConfigFile
, R_OK
) != 0) {
454 debuga(__FILE__
,__LINE__
,_("Cannot open file \"%s\": %s\n"),ConfigFile
,strerror(errno
));
458 if(access(ConfigFile
, R_OK
) == 0)
461 if(userip
) UserIp
=true;
463 if(dns
) ip2name_forcedns();
465 if (lastlog
>=0) LastLog
=lastlog
;
467 if(outdir
[0] == '\0') strcpy(outdir
,OutputDir
);
468 if(outdir
[0] != '\0') strcat(outdir
,"/");
470 if(IndexTree
== INDEX_TREE_FILE
)
471 strcpy(ImageFile
,"../images");
473 strcpy(ImageFile
,"../../../images");
475 dataonly
=(DataFile
[0] != '\0');
477 if (df
=='\0') df
=DateFormat
;
478 if (df
=='\0') df
='u';
480 IndexTree
=INDEX_TREE_FILE
;
482 if(AccessLog
==NULL
) {
483 AccessLog
=FileList_Create();
484 if (!FileList_AddFile(AccessLog
,"/var/log/squid/access.log")) {
485 debuga(__FILE__
,__LINE__
,_("Not enough memory to store the input log file names\n"));
497 FIter
=FileListIter_Open(AccessLog
);
498 while ((file
=FileListIter_Next(FIter
))!=NULL
)
499 splitlog(file
, df
, dfrom
, duntil
, convert
, splitprefix
);
500 FileListIter_Close(FIter
);
506 FIter
=FileListIter_Open(AccessLog
);
507 while ((file
=FileListIter_Next(FIter
))!=NULL
)
508 convlog(file
, df
, dfrom
, duntil
);
509 FileListIter_Close(FIter
);
513 load_excludecodes(ExcludeCodes
);
515 if(access(PasswdFile
, R_OK
) == 0) {
516 getusers(PasswdFile
,debug
);
517 ReadFilter
.SysUsers
=true;
519 ReadFilter
.SysUsers
=false;
522 if(hexclude
[0] == '\0')
523 strcpy(hexclude
,ExcludeHosts
);
524 if(hexclude
[0] != '\0') {
525 gethexclude(hexclude
,debug
);
526 ReadFilter
.HostFilter
=true;
528 ReadFilter
.HostFilter
=false;
531 if(ReportType
== 0) {
532 ReportType
=REPORT_TYPE_TOPUSERS
| REPORT_TYPE_TOPSITES
| REPORT_TYPE_USERS_SITES
|
533 REPORT_TYPE_SITES_USERS
| REPORT_TYPE_DATE_TIME
| REPORT_TYPE_DENIED
|
534 REPORT_TYPE_AUTH_FAILURES
| REPORT_TYPE_SITE_USER_TIME_DATE
| REPORT_TYPE_DOWNLOADS
;
537 if(access(ExcludeUsers
, R_OK
) == 0) {
538 getuexclude(ExcludeUsers
,debug
);
539 ReadFilter
.UserFilter
=true;
541 ReadFilter
.UserFilter
=false;
543 if (HostAliasFile
[0] != '\0')
544 read_hostalias(HostAliasFile
);
545 if (UserAliasFile
[0] != '\0')
546 read_useralias(UserAliasFile
);
549 if(ReadFilter
.UserFilter
) {
553 if(strcmp(ExcludeUsers
,"indexonly") == 0) indexonly
=true;
554 if(Index
== INDEX_ONLY
) indexonly
=true;
556 if(MaxElapsed
[0] != '\0')
557 ReadFilter
.max_elapsed
=atol(MaxElapsed
);
559 ReadFilter
.max_elapsed
=0;
561 if(tmp
[0] == '\0') strcpy(tmp
,TempDir
);
562 else strcpy(TempDir
,tmp
);
564 For historical reasons, the temporary directory is the subdirectory "sarg" of the path
565 provided by the user.
569 if (tmp
[0]!='\0' && strncmp(outdir
,tmp
,strlen(tmp
))==0) {
570 debuga(__FILE__
,__LINE__
,_("The output directory \"%s\" must be outside of the temporary directory \"%s\"\n"),outdir
,tmp
);
574 if(email
[0] == '\0' && OutputEmail
[0] != '\0') strcpy(email
,OutputEmail
);
576 if(email
[0] != '\0') {
582 if(access(tmp
, R_OK
) == 0) {
583 if (debug
) debuga(__FILE__
,__LINE__
,_("Deleting temporary directory \"%s\"\n"),tmp
);
591 debuga(__FILE__
,__LINE__
,_("Parameters:\n"));
592 debuga(__FILE__
,__LINE__
,_(" Hostname or IP address (-a) = %s\n"),addr
);
593 FIter
=FileListIter_Open(UserAgentLog
);
594 while ((file
=FileListIter_NextWithMask(FIter
))!=NULL
)
595 debuga(__FILE__
,__LINE__
,_(" Useragent log (-b) = %s\n"),file
);
596 FileListIter_Close(FIter
);
597 debuga(__FILE__
,__LINE__
,_(" Exclude file (-c) = %s\n"),hexclude
);
598 debuga(__FILE__
,__LINE__
,_(" Date from-until (-d) = %s\n"),ReadFilter
.DateRange
);
599 debuga(__FILE__
,__LINE__
,_(" Email address to send reports (-e) = %s\n"),email
);
600 debuga(__FILE__
,__LINE__
,_(" Config file (-f) = %s\n"),ConfigFile
);
602 debuga(__FILE__
,__LINE__
,_(" Date format (-g) = Europe (dd/mm/yyyy)\n"));
604 debuga(__FILE__
,__LINE__
,_(" Date format (-g) = USA (mm/dd/yyyy)\n"));
606 debuga(__FILE__
,__LINE__
,_(" Date format (-g) = Sites & Users (yyyy/ww)\n"));
607 debuga(__FILE__
,__LINE__
,_(" IP report (-i) = %s\n"),(iprel
) ? _("Yes") : _("No"));
608 debuga(__FILE__
,__LINE__
,_(" Keep temporary files (-k) = %s\n"),(KeepTempLog
) ? _("Yes") : _("No"));
609 FIter
=FileListIter_Open(AccessLog
);
610 while ((file
=FileListIter_NextWithMask(FIter
))!=NULL
)
611 debuga(__FILE__
,__LINE__
,_(" Input log (-l) = %s\n"),file
);
612 FileListIter_Close(FIter
);
613 for (iarq
=0 ; iarq
<NRedirectorLogs
; iarq
++)
614 debuga(__FILE__
,__LINE__
,_(" Redirector log (-L) = %s\n"),RedirectorLogs
[iarq
]);
615 debuga(__FILE__
,__LINE__
,_(" Resolve IP Address (-n) = %s\n"),(Ip2Name
) ? _("Yes") : _("No"));
616 debuga(__FILE__
,__LINE__
,_(" Output dir (-o) = %s\n"),outdir
);
617 debuga(__FILE__
,__LINE__
,_("Use Ip Address instead of userid (-p) = %s\n"),(UserIp
) ? _("Yes") : _("No"));
618 debuga(__FILE__
,__LINE__
,_(" Accessed site (-s) = %s\n"),site
);
619 debuga(__FILE__
,__LINE__
,_(" Time (-t) = %s\n"),hm_str
);
620 debuga(__FILE__
,__LINE__
,_(" User (-u) = %s\n"),us
);
621 debuga(__FILE__
,__LINE__
,_(" Temporary dir (-w) = %s\n"),tmp
);
622 debuga(__FILE__
,__LINE__
,_(" Debug messages (-x) = %s\n"),(debug
) ? _("Yes") : _("No"));
623 debuga(__FILE__
,__LINE__
,_(" Process messages (-z) = %d\n"),debugz
);
624 debuga(__FILE__
,__LINE__
,_(" Previous reports to keep (--lastlog) = %d\n"),LastLog
);
625 debuga(__FILE__
,__LINE__
,"\n");
629 debuga(__FILE__
,__LINE__
,_("sarg version: %s\n"),VERSION
);
631 #ifdef ENABLE_DOUBLE_CHECK_DATA
632 debuga(__FILE__
,__LINE__
,_("Sarg compiled to report warnings if the output is inconsistent\n"));
636 if (Ulimit
[0] != '\0') {
641 #if defined(RLIMIT_NOFILE)
642 getrlimit (RLIMIT_NOFILE
, &rl
);
643 #elif defined(RLIMIT_OFILE)
644 getrlimit (RLIMIT_OFILE
, &rl
);
646 #warning "No rlimit resource for the number of open files"
651 rl
.rlim_cur
= atol(Ulimit
);
652 rl
.rlim_max
= atol(Ulimit
);
653 #if defined(RLIMIT_NOFILE)
654 rc
=setrlimit (RLIMIT_NOFILE
, &rl
);
655 #elif defined(RLIMIT_OFILE)
656 rc
=setrlimit (RLIMIT_OFILE
, &rl
);
658 #warning "No rlimit resource for the number of open files"
661 debuga(_("setrlimit error: %s\n"),strerror(errno
));
665 debuga("Maximum file descriptor: cur=%ld max=%ld, changed to cur="RLIM_STRING
" max="RLIM_STRING
"\n",l1
,l2
,rl
.rlim_cur
,rl
.rlim_max
);
669 init_usertab(UserTabFile
);
671 read_start_time
=time(NULL
);
672 LogStatus
=ReadLogFile(&ReadFilter
);
673 read_end_time
=time(NULL
);
674 read_elapsed
=(double)read_end_time
-(double)read_start_time
;
676 FileList_Destroy(&AccessLog
);
682 char date0
[30], date1
[30];
685 GetLogPeriod(&Start
,&End
);
686 strftime(date0
,sizeof(date0
),"%x",&Start
);
687 strftime(date1
,sizeof(date1
),"%x",&End
);
688 // TRANSLATORS: The %s are the start and end dates in locale format.
689 debuga(__FILE__
,__LINE__
,_("Period covered by log files: %s-%s\n"),date0
,date1
);
693 debuga(__FILE__
,__LINE__
,_("No records found\n"));
694 debuga(__FILE__
,__LINE__
,_("End\n"));
696 if(userfile
) free(userfile
);
702 char date0
[30], date1
[30];
704 strftime(date0
,sizeof(date0
),"%x",&period
.start
);
705 strftime(date1
,sizeof(date1
),"%x",&period
.end
);
706 // TRANSLATORS: The %s are the start and end dates in locale format.
707 debuga(__FILE__
,__LINE__
,_("Period extracted from log files: %s-%s\n"),date0
,date1
);
709 if (ReadFilter
.DateRange
[0] != '\0') {
710 getperiod_fromrange(&period
,dfrom
,duntil
);
712 if (getperiod_buildtext(&period
)<0) {
713 debuga(__FILE__
,__LINE__
,_("Failed to build the string representation of the date range\n"));
717 process_start_time
=time(NULL
);
718 if(DataFile
[0] != '\0')
722 process_end_time
=time(NULL
);
723 process_elapsed
=(double)process_end_time
-(double)process_start_time
;
729 if(!KeepTempLog
&& strcmp(tmp
,"/tmp") != 0) {
740 FileList_Destroy(&UserAgentLog
);
745 double elapsed
=(double)end_time
-(double)start_time
;
746 debuga(__FILE__
,__LINE__
,_("Total execution time: %.0lf seconds\n"),elapsed
);
747 if (read_elapsed
>0.) {
748 debuga(__FILE__
,__LINE__
,_("Lines read: %lu lines in %.0lf seconds (%.0lf lines/s)\n"),lines_read
,read_elapsed
,(double)lines_read
/read_elapsed
);
750 if (process_elapsed
>0.) {
751 debuga(__FILE__
,__LINE__
,_("Processed records: %lu records in %.0lf seconds (%.0lf records/s)\n"),records_kept
,process_elapsed
,(double)records_kept
/process_elapsed
);
752 debuga(__FILE__
,__LINE__
,_("Users: %lu users in %.0lf seconds (%.0lf users/s)\n"),nusers
,process_elapsed
,(double)nusers
/process_elapsed
);
757 debuga(__FILE__
,__LINE__
,_("End\n"));
763 static void getusers(const char *pwdfile
, int debug
)
771 debuga(__FILE__
,__LINE__
,_("Loading password file \"%s\"\n"),pwdfile
);
773 if ((fp_usr
= fopen(pwdfile
, "r")) == NULL
) {
774 debuga(__FILE__
,__LINE__
,_("Cannot open file \"%s\": %s\n"),pwdfile
,strerror(errno
));
778 if (fseek(fp_usr
, 0, SEEK_END
)==-1) {
779 debuga(__FILE__
,__LINE__
,_("Failed to move till the end of file \"%s\": %s\n"),pwdfile
,strerror(errno
));
782 nreg
= ftell(fp_usr
);
784 debuga(__FILE__
,__LINE__
,_("Cannot get the size of file \"%s\"\n"),pwdfile
);
788 if (fseek(fp_usr
, 0, SEEK_SET
)==-1) {
789 debuga(__FILE__
,__LINE__
,_("Failed to rewind file \"%s\": %s\n"),pwdfile
,strerror(errno
));
793 if((userfile
=(char *) malloc(nreg
))==NULL
){
794 debuga(__FILE__
,__LINE__
,_("malloc error (%ld bytes required)\n"),nreg
);
798 memset(userfile
,0,nreg
);
799 strcpy(userfile
,":");
801 while(fgets(buf
,sizeof(buf
),fp_usr
)!=NULL
) {
804 debuga(__FILE__
,__LINE__
,_("Invalid user in file \"%s\"\n"),pwdfile
);
808 strcat(userfile
,buf
);
811 if (fclose(fp_usr
)==EOF
) {
812 debuga(__FILE__
,__LINE__
,_("Read error in \"%s\": %s\n"),pwdfile
,strerror(errno
));