]> git.ipfire.org Git - thirdparty/sarg.git/blob - readlog.c
Report a proper message if a log file cannot be read
[thirdparty/sarg.git] / readlog.c
1 /*
2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
3 * 1998, 2013
4 *
5 * SARG donations:
6 * please look at http://sarg.sourceforge.net/donations.php
7 * Support:
8 * http://sourceforge.net/projects/sarg/forums/forum/363374
9 * ---------------------------------------------------------------------
10 *
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.
15 *
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.
20 *
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.
24 *
25 */
26
27 #include "include/conf.h"
28 #include "include/defs.h"
29 #include "include/readlog.h"
30 #include "include/filelist.h"
31
32 #define REPORT_EVERY_X_LINES 5000
33 #define MAX_OPEN_USER_FILES 10
34
35 struct userfilestruct
36 {
37 struct userfilestruct *next;
38 struct userinfostruct *user;
39 FILE *file;
40 };
41
42 enum ExcludeReasonEnum
43 {
44 //! User name too long.
45 ER_UserNameTooLong,
46 //! Squid logged an incomplete query received from the client.
47 ER_IncompleteQuery,
48 //! Log file turned over.
49 ER_LogfileTurnedOver,
50 //! Excluded by exclude_string from sarg.conf.
51 ER_ExcludeString,
52 //! Unknown input log file format.
53 ER_UnknownFormat,
54 //! Line to be ignored from the input log file.
55 ER_FormatData,
56 //! Entry not withing the requested date range.
57 ER_OutOfDateRange,
58 //! Ignored week day.
59 ER_OutOfWDayRange,
60 //! Ignored hour.
61 ER_OutOfHourRange,
62 //! User is not in the include_users list.
63 ER_User,
64 //! HTTP code excluded by exclude_code file.
65 ER_HttpCode,
66 //! Invalid character found in user name.
67 ER_InvalidUserChar,
68 //! No URL in entry.
69 ER_NoUrl,
70 //! Not the IP address requested with -a.
71 ER_UntrackedIpAddr,
72 //! URL excluded by -c or exclude_hosts.
73 ER_Url,
74 //! Entry time outside of requested hour range.
75 ER_OutOfTimeRange,
76 //! Not the URL requested by -s.
77 ER_UntrackedUrl,
78 //! No user in entry.
79 ER_NoUser,
80 //! Not the user requested by -u.
81 ER_UntrackedUser,
82 //! System user.
83 ER_SysUser,
84 //! User ignored by exclude_users
85 ER_IgnoredUser,
86
87 ER_Last //!< last entry of the list
88 };
89
90 numlist weekdays = { { 0, 1, 2, 3, 4, 5, 6 }, 7 };
91 numlist hours = { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 }, 24 };
92
93 extern char *userfile;
94 extern FileListObject AccessLog;
95
96 extern const struct ReadLogProcessStruct ReadSquidLog;
97 extern const struct ReadLogProcessStruct ReadCommonLog;
98 extern const struct ReadLogProcessStruct ReadSargLog;
99 extern const struct ReadLogProcessStruct ReadExtLog;
100
101 //! The list of the supported log formats.
102 static const struct ReadLogProcessStruct const *LogFormats[]=
103 {
104 &ReadSquidLog,
105 &ReadCommonLog,
106 &ReadSargLog,
107 &ReadExtLog
108 };
109
110 //! The path to the sarg log file.
111 static char SargLogFile[4096]="";
112 //! Handle to the sarg log file. NULL if not created.
113 static FILE *fp_log=NULL;
114 //! The number of records read from the input logs.
115 static long int totregsl=0;
116 //! The number of records kept.
117 static long int totregsg=0;
118 //! The number of records excluded.
119 static long int totregsx=0;
120 //! The beginning of a linked list of user's file.
121 static struct userfilestruct *first_user_file=NULL;
122 //! Count the number of occurence of each input log format.
123 static unsigned long int format_count[sizeof(LogFormats)/sizeof(*LogFormats)];
124 //! The minimum date found in the input logs.
125 static int mindate=0;
126 static int maxdate=0;
127 //! Count the number of excluded records.
128 static unsigned long int excluded_count[ER_Last];
129
130 /*!
131 Read a single log file.
132
133 \param arq The log file name to read.
134 */
135 static void ReadOneLogFile(struct ReadLogDataStruct *Filter,const char *arq)
136 {
137 longline line;
138 char *linebuf;
139 char *str;
140 char hora[30];
141 char dia[128]="";
142 char wuser[MAXLEN];
143 char tmp3[MAXLEN]="";
144 char download_url[MAXLEN];
145 char smartfilter[MAXLEN];
146 const char *url;
147 int current_format_idx;
148 int OutputNonZero = REPORT_EVERY_X_LINES ;
149 int idata=0;
150 int x;
151 int hmr;
152 int nopen;
153 int maxopenfiles=MAX_OPEN_USER_FILES;
154 int successive_errors=0;
155 int total_errors=0;
156 unsigned long int recs1=0UL;
157 unsigned long int recs2=0UL;
158 FILE *fp_in=NULL;
159 bool from_pipe;
160 bool from_stdin;
161 bool download_flag=false;
162 bool id_is_ip;
163 enum ReadLogReturnCodeEnum log_entry_status;
164 struct stat logstat;
165 struct getwordstruct gwarea;
166 struct userfilestruct *prev_ufile;
167 struct userinfostruct *uinfo;
168 struct userfilestruct *ufile;
169 struct userfilestruct *ufile1;
170 struct ReadLogStruct log_entry;
171 const struct ReadLogProcessStruct *current_format=NULL;
172
173 current_format=NULL;
174 current_format_idx=-1;
175 for (x=0 ; x<sizeof(LogFormats)/sizeof(*LogFormats) ; x++)
176 if (LogFormats[x]->NewFile)
177 LogFormats[x]->NewFile(arq);
178
179 if (arq[0]=='-' && arq[1]=='\0') {
180 if(debug)
181 debuga(_("Reading access log file: from stdin\n"));
182 fp_in=stdin;
183 from_stdin=true;
184 } else {
185 if (Filter->DateRange[0]!='\0') {
186 if (stat(arq,&logstat)!=0) {
187 debuga(_("Cannot get the modification time of input log file %s (%s). Processing it anyway\n"),arq,strerror(errno));
188 } else {
189 struct tm *logtime=localtime(&logstat.st_mtime);
190 if ((logtime->tm_year+1900)*10000+(logtime->tm_mon+1)*100+logtime->tm_mday<dfrom) {
191 debuga(_("Ignoring old log file %s\n"),arq);
192 return;
193 }
194 }
195 }
196 fp_in=decomp(arq,&from_pipe);
197 if(fp_in==NULL) {
198 debuga(_("Cannot open input log file \"%s\": %s\n"),arq,strerror(errno));
199 exit(EXIT_FAILURE);
200 }
201 if(debug) debuga(_("Reading access log file: %s\n"),arq);
202 from_stdin=false;
203 }
204
205 download_flag=false;
206
207 recs1=0UL;
208 recs2=0UL;
209
210 // pre-read the file only if we have to show stats
211 if (ShowReadStatistics && ShowReadPercent && !from_stdin && !from_pipe) {
212 size_t nread,i;
213 bool skipcr=false;
214 char tmp4[MAXLEN];
215
216 while ((nread=fread(tmp4,1,sizeof(tmp4),fp_in))>0) {
217 for (i=0 ; i<nread ; i++)
218 if (skipcr) {
219 if (tmp4[i]!='\n' && tmp4[i]!='\r') {
220 skipcr=false;
221 }
222 } else {
223 if (tmp4[i]=='\n' || tmp4[i]=='\r') {
224 skipcr=true;
225 recs1++;
226 }
227 }
228 }
229 rewind(fp_in);
230 printf(_("SARG: Records in file: %lu, reading: %3.2f%%"),recs1,(float) 0);
231 putchar('\r');
232 fflush( stdout ) ;
233 }
234
235 if ((line=longline_create())==NULL) {
236 debuga(_("Not enough memory to read log file %s\n"),arq);
237 exit(EXIT_FAILURE);
238 }
239
240 while ((linebuf=longline_read(fp_in,line))!=NULL) {
241 lines_read++;
242
243 recs2++;
244 if (ShowReadStatistics && --OutputNonZero<=0) {
245 if (recs1>0) {
246 double perc = recs2 * 100. / recs1 ;
247 printf(_("SARG: Records in file: %lu, reading: %3.2lf%%"),recs2,perc);
248 } else {
249 printf(_("SARG: Records in file: %lu"),recs2);
250 }
251 putchar('\r');
252 fflush (stdout);
253 OutputNonZero = REPORT_EVERY_X_LINES ;
254 }
255
256 /*
257 The following checks are retained here as I don't know to
258 what format they apply. They date back to pre 2.4 versions.
259 */
260 //if(blen < 58) continue; //this test conflict with the reading of the sarg log header line
261 if(strstr(linebuf,"HTTP/0.0") != 0) {//recorded by squid when encountering an incomplete query
262 excluded_count[ER_IncompleteQuery]++;
263 continue;
264 }
265 if(strstr(linebuf,"logfile turned over") != 0) {//reported by newsyslog
266 excluded_count[ER_LogfileTurnedOver]++;
267 continue;
268 }
269
270 // exclude_string
271 if(ExcludeString[0] != '\0') {
272 bool exstring=false;
273 getword_start(&gwarea,ExcludeString);
274 while(strchr(gwarea.current,':') != 0) {
275 if (getword_multisep(val1,sizeof(val1),&gwarea,':')<0) {
276 debuga(_("Maybe you have a broken record or garbage in your exclusion string\n"));
277 exit(EXIT_FAILURE);
278 }
279 if((str=(char *) strstr(linebuf,val1)) != (char *) NULL ) {
280 exstring=true;
281 break;
282 }
283 }
284 if(!exstring && (str=(char *) strstr(linebuf,gwarea.current)) != (char *) NULL )
285 exstring=true;
286 if(exstring) {
287 excluded_count[ER_ExcludeString]++;
288 continue;
289 }
290 }
291
292 totregsl++;
293 if(debugm)
294 printf("BUF=%s\n",linebuf);
295
296 // process the line
297 log_entry_status=RLRC_Unknown;
298 memset(&log_entry,0,sizeof(log_entry));
299 if (current_format) {
300 log_entry_status=current_format->ReadEntry(linebuf,&log_entry);
301 }
302
303 // find out what line format to use
304 if (log_entry_status==RLRC_Unknown) {
305 for (x=0 ; x<(int)(sizeof(LogFormats)/sizeof(*LogFormats)) ; x++) {
306 if (LogFormats[x]==current_format) continue;
307 memset(&log_entry,0,sizeof(log_entry));
308 log_entry_status=LogFormats[x]->ReadEntry(linebuf,&log_entry);
309 if (log_entry_status!=RLRC_Unknown) break;
310 }
311 if (x>=(int)(sizeof(LogFormats)/sizeof(*LogFormats))) {
312 if (++successive_errors>NumLogSuccessiveErrors) {
313 debuga(ngettext("%d consecutive error found in the input log file %s\n",
314 "%d consecutive errors found in the input log file %s\n",successive_errors),successive_errors,arq);
315 exit(EXIT_FAILURE);
316 }
317 if (NumLogTotalErrors>=0 && ++total_errors>NumLogTotalErrors) {
318 debuga(ngettext("%d error found in the input log file (last in %s)\n",
319 "%d errors found in the input log file (last in %s)\n",total_errors),total_errors,arq);
320 exit(EXIT_FAILURE);
321 }
322 debuga(_("The following line read from %s could not be parsed and is ignored\n%s\n"),arq,linebuf);
323 excluded_count[ER_UnknownFormat]++;
324 continue;
325 }
326 current_format=LogFormats[x];
327 current_format_idx=x;
328 if (debugz) {
329 /* TRANSLATORS: The argument is the log format name as translated by you. */
330 debuga(_("Log format identified as \"%s\" for %s\n"),_(current_format->Name),arq);
331 }
332 successive_errors=0;
333 }
334 if (log_entry_status==RLRC_Ignore) {
335 excluded_count[ER_FormatData]++;
336 continue;
337 }
338 if (current_format_idx<0 || current_format==NULL) {
339 debuga(_("Sarg failed to determine the format of the input log file %s\n"),arq);
340 exit(EXIT_FAILURE);
341 }
342 if (log_entry_status==RLRC_InternalError) {
343 debuga(_("Internal error encountered while processing %s\nSee previous message to know the reason for that error.\n"),arq);
344 exit(EXIT_FAILURE);
345 }
346 format_count[current_format_idx]++;
347
348 if (!fp_log && ParsedOutputLog[0] && current_format!=&ReadSargLog) {
349 if(access(ParsedOutputLog,R_OK) != 0) {
350 my_mkdir(ParsedOutputLog);
351 }
352 if (snprintf(SargLogFile,sizeof(SargLogFile),"%s/sarg_temp.log",ParsedOutputLog)>=sizeof(SargLogFile)) {
353 debuga(_("File name too long: %s/sarg_temp.log\n"),ParsedOutputLog);
354 exit(EXIT_FAILURE);
355 }
356 if((fp_log=MY_FOPEN(SargLogFile,"w"))==NULL) {
357 debuga(_("(log) Cannot open log file %s: %s\n"),SargLogFile,strerror(errno));
358 exit(EXIT_FAILURE);
359 }
360 fputs("*** SARG Log ***\n",fp_log);
361 }
362
363 if (log_entry.Ip==NULL) {
364 debuga(_("Unknown input log file format: no IP addresses\n"));
365 break;
366 }
367 if (log_entry.User==NULL) {
368 debuga(_("Unknown input log file format: no user\n"));
369 break;
370 }
371 if (log_entry.Url==NULL) {
372 debuga(_("Unknown input log file format: no URL\n"));
373 break;
374 }
375
376 idata=builddia(log_entry.EntryTime.tm_mday,log_entry.EntryTime.tm_mon+1,log_entry.EntryTime.tm_year+1900);
377 if(debugm)
378 printf("DATE=%s IDATA=%d DFROM=%d DUNTIL=%d\n",Filter->DateRange,idata,dfrom,duntil);
379
380 if(Filter->DateRange[0] != '\0'){
381 if(idata < dfrom || idata > duntil) {
382 excluded_count[ER_OutOfDateRange]++;
383 continue;
384 }
385 }
386
387 // Record only hours usage which is required
388 if( bsearch( &( log_entry.EntryTime.tm_wday ), weekdays.list, weekdays.len, sizeof( int ), compar ) == NULL ) {
389 excluded_count[ER_OutOfWDayRange]++;
390 continue;
391 }
392
393 if( bsearch( &( log_entry.EntryTime.tm_hour ), hours.list, hours.len, sizeof( int ), compar ) == NULL ) {
394 excluded_count[ER_OutOfHourRange]++;
395 continue;
396 }
397
398
399 if(strlen(log_entry.User) > MAX_USER_LEN) {
400 if (debugm) printf(_("User ID too long: %s\n"),log_entry.User);
401 excluded_count[ER_UserNameTooLong]++;
402 totregsx++;
403 continue;
404 }
405
406 // include_users
407 if(IncludeUsers[0] != '\0') {
408 snprintf(val1,sizeof(val1),":%s:",log_entry.User);
409 if((str=(char *) strstr(IncludeUsers,val1)) == (char *) NULL ) {
410 excluded_count[ER_User]++;
411 continue;
412 }
413 }
414
415 if(vercode(log_entry.HttpCode)) {
416 if (debugm) printf(_("Excluded code: %s\n"),log_entry.HttpCode);
417 excluded_count[ER_HttpCode]++;
418 totregsx++;
419 continue;
420 }
421
422 if(testvaliduserchar(log_entry.User)) {
423 excluded_count[ER_InvalidUserChar]++;
424 continue;
425 }
426
427 // replace any tab by a single space
428 for (str=log_entry.Url ; *str ; str++)
429 if (*str=='\t') *str=' ';
430 for (str=log_entry.HttpCode ; *str ; str++)
431 if (*str=='\t') *str=' ';
432
433 if (current_format!=&ReadSargLog) {
434 /*
435 The full URL is not saved in sarg log. There is no point in testing the URL to detect
436 a downloaded file.
437 */
438 download_flag=is_download_suffix(log_entry.Url);
439 if (download_flag) {
440 safe_strcpy(download_url,log_entry.Url,sizeof(download_url));
441 }
442 } else
443 download_flag=false;
444
445 url=process_url(log_entry.Url,LongUrl);
446 if (!url || url[0] == '\0') {
447 excluded_count[ER_NoUrl]++;
448 continue;
449 }
450
451 if(addr[0] != '\0'){
452 if(strcmp(addr,log_entry.Ip)!=0) {
453 excluded_count[ER_UntrackedIpAddr]++;
454 continue;
455 }
456 }
457 if(Filter->HostFilter) {
458 if(!vhexclude(url)) {
459 if (debugm) printf(_("Excluded site: %s\n"),url);
460 excluded_count[ER_Url]++;
461 totregsx++;
462 continue;
463 }
464 }
465
466 if(Filter->StartTime >= 0 && Filter->EndTime >= 0) {
467 hmr=log_entry.EntryTime.tm_hour*100+log_entry.EntryTime.tm_min;
468 if(hmr < Filter->StartTime || hmr > Filter->EndTime) {
469 excluded_count[ER_OutOfTimeRange]++;
470 continue;
471 }
472 }
473
474 if(site[0] != '\0'){
475 if(strstr(url,site)==0) {
476 excluded_count[ER_UntrackedUrl]++;
477 continue;
478 }
479 }
480
481 if(UserIp) {
482 log_entry.User=log_entry.Ip;
483 id_is_ip=true;
484 } else {
485 id_is_ip=false;
486 if ((log_entry.User[0]=='\0') || (log_entry.User[1]=='\0' && (log_entry.User[0]=='-' || log_entry.User[0]==' '))) {
487 if(RecordsWithoutUser == RECORDWITHOUTUSER_IP) {
488 log_entry.User=log_entry.Ip;
489 id_is_ip=true;
490 }
491 if(RecordsWithoutUser == RECORDWITHOUTUSER_IGNORE) {
492 excluded_count[ER_NoUser]++;
493 continue;
494 }
495 if(RecordsWithoutUser == RECORDWITHOUTUSER_EVERYBODY)
496 log_entry.User="everybody";
497 } else {
498 if(NtlmUserFormat == NTLMUSERFORMAT_USER) {
499 if ((str=strchr(log_entry.User,'+'))!=NULL || (str=strchr(log_entry.User,'\\'))!=NULL || (str=strchr(log_entry.User,'_'))!=NULL) {
500 log_entry.User=str+1;
501 }
502 }
503 }
504 }
505
506 if(us[0] != '\0'){
507 if(strcmp(log_entry.User,us)!=0) {
508 excluded_count[ER_UntrackedUser]++;
509 continue;
510 }
511 }
512
513 if(Filter->SysUsers) {
514 snprintf(wuser,sizeof(wuser),":%s:",log_entry.User);
515 if(strstr(userfile, wuser) == 0) {
516 excluded_count[ER_SysUser]++;
517 continue;
518 }
519 }
520
521 if(Filter->UserFilter) {
522 if(!vuexclude(log_entry.User)) {
523 if (debugm) printf(_("Excluded user: %s\n"),log_entry.User);
524 excluded_count[ER_IgnoredUser]++;
525 totregsx++;
526 continue;
527 }
528 }
529
530 log_entry.User=process_user(log_entry.User);
531 if (log_entry.User[0]=='\0' || (log_entry.User[1]=='\0' && (log_entry.User[0]=='-' ||
532 log_entry.User[0]==' ' || log_entry.User[0]==':'))) {
533 excluded_count[ER_NoUser]++;
534 continue;
535 }
536
537 if (log_entry.DataSize<0) log_entry.DataSize=0;
538
539 if (log_entry.ElapsedTime<0) log_entry.ElapsedTime=0;
540 if (Filter->max_elapsed>0 && log_entry.ElapsedTime>Filter->max_elapsed) {
541 log_entry.ElapsedTime=0;
542 }
543
544 if((str=(char *) strstr(linebuf, "[SmartFilter:")) != (char *) NULL ) {
545 fixendofline(str);
546 snprintf(smartfilter,sizeof(smartfilter),"\"%s\"",str+1);
547 } else strcpy(smartfilter,"\"\"");
548
549 nopen=0;
550 prev_ufile=NULL;
551 for (ufile=first_user_file ; ufile && strcmp(log_entry.User,ufile->user->id)!=0 ; ufile=ufile->next) {
552 prev_ufile=ufile;
553 if (ufile->file) nopen++;
554 }
555 if (!ufile) {
556 ufile=malloc(sizeof(*ufile));
557 if (!ufile) {
558 debuga(_("Not enough memory to store the user %s\n"),log_entry.User);
559 exit(EXIT_FAILURE);
560 }
561 memset(ufile,0,sizeof(*ufile));
562 ufile->next=first_user_file;
563 first_user_file=ufile;
564 uinfo=userinfo_create(log_entry.User);
565 ufile->user=uinfo;
566 uinfo->id_is_ip=id_is_ip;
567 nusers++;
568 } else {
569 if (prev_ufile) {
570 prev_ufile->next=ufile->next;
571 ufile->next=first_user_file;
572 first_user_file=ufile;
573 }
574 }
575 #ifdef ENABLE_DOUBLE_CHECK_DATA
576 ufile->user->nbytes+=log_entry.DataSize;
577 ufile->user->elap+=log_entry.ElapsedTime;
578 #endif
579
580 if (ufile->file==NULL) {
581 if (nopen>=maxopenfiles) {
582 x=0;
583 for (ufile1=first_user_file ; ufile1 ; ufile1=ufile1->next) {
584 if (ufile1->file!=NULL) {
585 if (x>=maxopenfiles) {
586 if (fclose(ufile1->file)==EOF) {
587 debuga(_("Write error in the log file of user %s: %s\n"),ufile1->user->id,strerror(errno));
588 exit(EXIT_FAILURE);
589 }
590 ufile1->file=NULL;
591 }
592 x++;
593 }
594 }
595 }
596 if (snprintf (tmp3, sizeof(tmp3), "%s/%s.user_unsort", tmp, ufile->user->filename)>=sizeof(tmp3)) {
597 debuga(_("Temporary user file name too long: %s/%s.user_unsort\n"), tmp, ufile->user->filename);
598 exit(EXIT_FAILURE);
599 }
600 if ((ufile->file = MY_FOPEN (tmp3, "a")) == NULL) {
601 debuga(_("(log) Cannot open temporary file %s: %s\n"), tmp3, strerror(errno));
602 exit (1);
603 }
604 }
605
606 strftime(dia, sizeof(dia), "%d/%m/%Y",&log_entry.EntryTime);
607 strftime(hora,sizeof(hora),"%H:%M:%S",&log_entry.EntryTime);
608
609 if (fprintf(ufile->file, "%s\t%s\t%s\t%s\t%"PRIu64"\t%s\t%ld\t%s\n",dia,hora,
610 log_entry.Ip,url,(uint64_t)log_entry.DataSize,
611 log_entry.HttpCode,log_entry.ElapsedTime,smartfilter)<=0) {
612 debuga(_("Write error in the log file of user %s\n"),log_entry.User);
613 exit(EXIT_FAILURE);
614 }
615 records_kept++;
616
617 if (fp_log && current_format!=&ReadSargLog) {
618 fprintf(fp_log, "%s\t%s\t%s\t%s\t%s\t%"PRIu64"\t%s\t%ld\t%s\n",dia,hora,
619 log_entry.User,log_entry.Ip,url,(uint64_t)log_entry.DataSize,
620 log_entry.HttpCode,log_entry.ElapsedTime,smartfilter);
621 }
622
623 totregsg++;
624
625 denied_write(&log_entry);
626 authfail_write(&log_entry);
627 download_write(&log_entry,download_url);
628
629 if (current_format!=&ReadSargLog) {
630 if (period.start.tm_year==0 || idata<mindate || compare_date(&period.start,&log_entry.EntryTime)>0){
631 mindate=idata;
632 memcpy(&period.start,&log_entry.EntryTime,sizeof(log_entry.EntryTime));
633 }
634 if (period.end.tm_year==0 || idata>maxdate || compare_date(&period.end,&log_entry.EntryTime)<0) {
635 maxdate=idata;
636 memcpy(&period.end,&log_entry.EntryTime,sizeof(log_entry.EntryTime));
637 }
638 }
639
640 if(debugm){
641 printf("IP=\t%s\n",log_entry.Ip);
642 printf("USER=\t%s\n",log_entry.User);
643 printf("ELAP=\t%ld\n",log_entry.ElapsedTime);
644 printf("DATE=\t%s\n",dia);
645 printf("TIME=\t%s\n",hora);
646 //printf("FUNC=\t%s\n",fun);
647 printf("URL=\t%s\n",url);
648 printf("CODE=\t%s\n",log_entry.HttpCode);
649 printf("LEN=\t%"PRIu64"\n",(uint64_t)log_entry.DataSize);
650 }
651 }
652 longline_destroy(&line);
653
654 if (!from_stdin) {
655 if (from_pipe)
656 pclose(fp_in);
657 else {
658 fclose(fp_in);
659 if (ShowReadStatistics) {
660 if (ShowReadPercent)
661 printf(_("SARG: Records in file: %lu, reading: %3.2f%%\n"),recs2, (float) 100 );
662 else
663 printf(_("SARG: Records in file: %lu\n"),recs2);
664 }
665 }
666 }
667 }
668
669 /*!
670 * Display a line with the excluded entries count.
671 *
672 * \param Explain A translated string explaining the exluded count.
673 * \param Reason The reason number.
674 */
675 static void DisplayExcludeCount(const char *Explain,enum ExcludeReasonEnum Reason)
676 {
677 if (excluded_count[Reason]>0) {
678 debuga(" %s: %lu\n",Explain,excluded_count[Reason]);
679 }
680 }
681
682 /*!
683 Read the log files.
684
685 \param Filter The filtering parameters for the file to load.
686
687 \retval 1 Records found.
688 \retval 0 No record found.
689 */
690 int ReadLogFile(struct ReadLogDataStruct *Filter)
691 {
692 int x;
693 int cstatus;
694 struct userfilestruct *ufile;
695 struct userfilestruct *ufile1;
696 FileListIterator FIter;
697 const char *file;
698
699 for (x=0 ; x<sizeof(format_count)/sizeof(*format_count) ; x++) format_count[x]=0;
700 for (x=0 ; x<sizeof(excluded_count)/sizeof(*excluded_count) ; x++) excluded_count[x]=0;
701 first_user_file=NULL;
702
703 if (!dataonly) {
704 denied_open();
705 authfail_open();
706 download_open();
707 }
708
709 FIter=FileListIter_Open(AccessLog);
710 while ((file=FileListIter_Next(FIter))!=NULL)
711 ReadOneLogFile(Filter,file);
712 FileListIter_Close(FIter);
713
714 if(fp_log != NULL) {
715 char val2[40];
716 char val4[4096];//val4 must not be bigger than SargLogFile without fixing the strcpy below
717
718 if (fclose(fp_log)==EOF) {
719 debuga(_("Write error in %s: %s\n"),SargLogFile,strerror(errno));
720 exit(EXIT_FAILURE);
721 }
722 strftime(val2,sizeof(val2),"%d%m%Y_%H%M",&period.start);
723 strftime(val1,sizeof(val1),"%d%m%Y_%H%M",&period.end);
724 if (snprintf(val4,sizeof(val4),"%s/sarg-%s-%s.log",ParsedOutputLog,val2,val1)>=sizeof(val4)) {
725 debuga(_("File name too long: %s/sarg-%s-%s.log\n"),ParsedOutputLog,val2,val1);
726 exit(EXIT_FAILURE);
727 }
728 if (rename(SargLogFile,val4)) {
729 debuga(_("failed to rename %s to %s - %s\n"),SargLogFile,val4,strerror(errno));
730 } else {
731 strcpy(SargLogFile,val4);
732
733 if(strcmp(ParsedOutputLogCompress,"nocompress") != 0 && ParsedOutputLogCompress[0] != '\0') {
734 /*
735 No double quotes around ParsedOutputLogCompress because it may contain command line options. If double quotes are
736 necessary around the command name, put them in the configuration file.
737 */
738 if (snprintf(val1,sizeof(val1),"%s \"%s\"",ParsedOutputLogCompress,SargLogFile)>=sizeof(val1)) {
739 debuga(_("Command too long: %s \"%s\"\n"),ParsedOutputLogCompress,SargLogFile);
740 exit(EXIT_FAILURE);
741 }
742 cstatus=system(val1);
743 if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus)) {
744 debuga(_("command return status %d\n"),WEXITSTATUS(cstatus));
745 debuga(_("command: %s\n"),val1);
746 exit(EXIT_FAILURE);
747 }
748 }
749 }
750 if(debug)
751 debuga(_("Sarg parsed log saved as %s\n"),SargLogFile);
752 }
753
754 denied_close();
755 authfail_close();
756 download_close();
757
758 for (ufile=first_user_file ; ufile ; ufile=ufile1) {
759 ufile1=ufile->next;
760 if (ufile->file!=NULL && fclose(ufile->file)==EOF) {
761 debuga(_("Write error in the log file of user %s: %s\n"),ufile->user->id,strerror(errno));
762 exit(EXIT_FAILURE);
763 }
764 free(ufile);
765 }
766
767 if (debug) {
768 unsigned long int totalcount=0;
769
770 debuga(_(" Records read: %ld, written: %ld, excluded: %ld\n"),totregsl,totregsg,totregsx);
771
772 for (x=sizeof(excluded_count)/sizeof(*excluded_count)-1 ; x>=0 && excluded_count[x]>0 ; x--);
773 if (x>=0) {
774 debuga(_("Reasons for excluded entries:\n"));
775 DisplayExcludeCount(_("User name too long"),ER_UserNameTooLong);
776 DisplayExcludeCount(_("Squid logged an incomplete query received from the client"),ER_IncompleteQuery);
777 DisplayExcludeCount(_("Log file turned over"),ER_LogfileTurnedOver);
778 DisplayExcludeCount(_("Excluded by \"exclude_string\" in sarg.conf"),ER_ExcludeString);
779 DisplayExcludeCount(_("Unknown input log file format"),ER_UnknownFormat);
780 DisplayExcludeCount(_("Line ignored by the input log format"),ER_FormatData);
781 DisplayExcludeCount(_("Time outside the requested date range (-d)"),ER_OutOfDateRange);
782 DisplayExcludeCount(_("Ignored week day (\"weekdays\" parameter in sarg.conf)"),ER_OutOfWDayRange);
783 DisplayExcludeCount(_("Ignored hour (\"hours\" parameter in sarg.conf)"),ER_OutOfHourRange);
784 DisplayExcludeCount(_("User is not in the \"include_users\" list"),ER_User);
785 DisplayExcludeCount(_("HTTP code excluded by \"exclude_code\" file"),ER_HttpCode);
786 DisplayExcludeCount(_("Invalid character found in user name"),ER_InvalidUserChar);
787 DisplayExcludeCount(_("No URL in entry"),ER_NoUrl);
788 DisplayExcludeCount(_("Not the IP address requested with -a"),ER_UntrackedIpAddr);
789 DisplayExcludeCount(_("URL excluded by -c or \"exclude_hosts\""),ER_Url);
790 DisplayExcludeCount(_("Entry time outside of requested hour range (-t)"),ER_OutOfTimeRange);
791 DisplayExcludeCount(_("Not the URL requested by -s"),ER_UntrackedUrl);
792 DisplayExcludeCount(_("No user in entry"),ER_NoUser);
793 DisplayExcludeCount(_("Not the user requested by -u"),ER_UntrackedUser);
794 DisplayExcludeCount(_("System user as defined by \"password\" in sarg.conf"),ER_SysUser);
795 DisplayExcludeCount(_("User ignored by \"exclude_users\""),ER_IgnoredUser);
796 }
797
798 for (x=0 ; x<sizeof(LogFormats)/sizeof(*LogFormats) ; x++) {
799 if (format_count[x]>0) {
800 /* TRANSLATORS: It displays the number of lines found in the input log files
801 * for each supported log format. The log format name is the %s and is a string
802 * you translate somewhere else. */
803 debuga(_("%s: %lu entries\n"),_(LogFormats[x]->Name),format_count[x]);
804 totalcount+=format_count[x];
805 }
806 }
807
808 if (totalcount==0 && totregsg)
809 debuga(_("Log with invalid format\n"));
810 }
811
812 if (debugz)
813 debugaz(_("period=%s\n"),period.text);
814
815 return((totregsg!=0) ? 1 : 0);
816 }