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"
31 #define REPORT_EVERY_X_LINES 5000
32 #define MAX_OPEN_USER_FILES 10
36 struct userfilestruct
*next
;
37 struct userinfostruct
*user
;
41 numlist weekdays
= { { 0, 1, 2, 3, 4, 5, 6 }, 7 };
42 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 };
44 extern char *userfile
;
49 \param Filter The filtering parameters for the file to load.
51 \retval 1 Records found.
52 \retval 0 No record found.
54 int ReadLogFile(struct ReadLogDataStruct
*Filter
)
65 ISACOL_Last
//last entry of the list !
73 ILF_Last
//last entry of the list !
76 enum InputLogFormat ilf
;
77 int ilf_count
[ILF_Last
];
84 char user
[MAX_USER_LEN
];
93 char sz_Download_Unsort
[20000];
95 char authfail_unsort
[MAXLEN
];
96 char download_url
[MAXLEN
];
97 char smartfilter
[MAXLEN
];
102 int OutputNonZero
= REPORT_EVERY_X_LINES
;
104 int isa_ncols
=0,isa_cols
[ISACOL_Last
];
108 int maxopenfiles
=MAX_OPEN_USER_FILES
;
112 unsigned long int recs1
=0UL;
113 unsigned long int recs2
=0UL;
117 long long int iyear
, imonth
, iday
;
120 FILE *fp_authfail
=NULL
;
121 FILE *fp_Download_Unsort
=NULL
;
124 bool download_flag
=false;
128 struct getwordstruct gwarea
;
130 struct userfilestruct
*prev_ufile
;
131 struct userinfostruct
*uinfo
;
132 struct userfilestruct
*first_user_file
=NULL
;
133 struct userfilestruct
*ufile
;
134 struct userfilestruct
*ufile1
;
135 struct ReadLogStruct log_entry
;
138 for (ilf
=0 ; ilf
<ILF_Last
; ilf
++) ilf_count
[ilf
]=0;
141 first_user_file
=NULL
;
143 snprintf(sz_Download_Unsort
,sizeof(sz_Download_Unsort
),"%s/download.int_unsort", tmp
);
144 snprintf(authfail_unsort
,sizeof(authfail_unsort
),"%s/authfail.int_unsort",tmp
);
146 if(DataFile
[0]=='\0') {
149 if((ReportType
& REPORT_TYPE_DENIED
) != 0 || (ReportType
& REPORT_TYPE_AUTH_FAILURES
) != 0) {
150 if((fp_authfail
=MY_FOPEN(authfail_unsort
,"w"))==NULL
) {
151 debuga(_("(log) Cannot open file: %s - %s\n"),authfail_unsort
,strerror(errno
));
157 if ((line
=longline_create())==NULL
) {
158 debuga(_("Not enough memory to read a log file\n"));
162 for (iarq
=0 ; iarq
<NAccessLog
; iarq
++) {
165 if(strcmp(arq
,"-")==0) {
167 debuga(_("Reading access log file: from stdin\n"));
171 if (Filter
->DateRange
[0]!='\0') {
172 if (stat(arq
,&logstat
)!=0) {
173 debuga(_("Cannot get the modification time of input log file %s (%s). Processing it anyway\n"),arq
,strerror(errno
));
175 struct tm
*logtime
=localtime(&logstat
.st_mtime
);
176 if ((logtime
->tm_year
+1900)*10000+(logtime
->tm_mon
+1)*100+logtime
->tm_mday
<dfrom
) {
177 debuga(_("Ignoring old log file %s\n"),arq
);
182 fp_in
=decomp(arq
,&from_pipe
);
184 debuga(_("(log) Cannot open log file: %s - %s\n"),arq
,strerror(errno
));
187 if(debug
) debuga(_("Reading access log file: %s\n"),arq
);
194 // pre-read the file only if we have to show stats
195 if (ShowReadStatistics
&& !from_stdin
&& !from_pipe
) {
203 while ((nread
=fread(tmp4
,1,sizeof(tmp4
),fp_in
))>0) {
204 for (i
=0 ; i
<nread
; i
++)
206 if (tmp4
[i
]!='\n' && tmp4
[i
]!='\r') {
210 if (tmp4
[i
]=='\n' || tmp4
[i
]=='\r') {
217 printf(_("SARG: Records in file: %lu, reading: %3.2f%%"),recs1
,(float) 0);
222 longline_reset(line
);
224 while ((linebuf
=longline_read(fp_in
,line
))!=NULL
) {
225 blen
=strlen(linebuf
);
227 if (ilf
==ILF_Unknown
) {
228 if(strncmp(linebuf
,"#Software: Mic",14) == 0) {
229 fixendofline(linebuf
);
231 debuga(_("Log is from Microsoft ISA: %s\n"),linebuf
);
237 if(strncmp(linebuf
,"*** SARG Log ***",16) == 0) {
238 if (getperiod_fromsarglog(arq
,&period
)<0) {
239 debuga(_("The name of the file is invalid: %s\n"),arq
);
248 if(!fp_log
&& ParsedOutputLog
[0] && ilf
!=ILF_Sarg
) {
249 if(access(ParsedOutputLog
,R_OK
) != 0) {
250 my_mkdir(ParsedOutputLog
);
252 if (snprintf(arq_log
,sizeof(arq_log
),"%s/sarg_temp.log",ParsedOutputLog
)>=sizeof(arq_log
)) {
253 debuga(_("File name too long: %s/sarg_temp.log\n"),ParsedOutputLog
);
256 if((fp_log
=MY_FOPEN(arq_log
,"w"))==NULL
) {
257 debuga(_("(log) Cannot open log file: %s - %s\n"),arq_log
,strerror(errno
));
260 fputs("*** SARG Log ***\n",fp_log
);
264 if( ShowReadStatistics
&& !from_stdin
&& !from_pipe
&& --OutputNonZero
<=0) {
265 double perc
= recs2
* 100. / recs1
;
266 printf(_("SARG: Records in file: %lu, reading: %3.2lf%%"),recs2
,perc
);
269 OutputNonZero
= REPORT_EVERY_X_LINES
;
271 if(blen
< 58) continue;
272 if(strstr(linebuf
,"HTTP/0.0") != 0) continue;
273 if(strstr(linebuf
,"logfile turned over") != 0) continue;
274 if(linebuf
[0] == ' ') continue;
277 if(ExcludeString
[0] != '\0') {
279 getword_start(&gwarea
,ExcludeString
);
280 while(strchr(gwarea
.current
,':') != 0) {
281 if (getword_multisep(val1
,sizeof(val1
),&gwarea
,':')<0) {
282 debuga(_("Maybe you have a broken record or garbage in your exclusion string\n"));
285 if((str
=(char *) strstr(linebuf
,val1
)) != (char *) NULL
) {
290 if(!exstring
&& (str
=(char *) strstr(linebuf
,gwarea
.current
)) != (char *) NULL
)
292 if(exstring
) continue;
297 printf("BUF=%s\n",linebuf
);
299 memset(&log_entry
,0,sizeof(log_entry
));
300 if (ilf
==ILF_Squid
|| ilf
==ILF_Common
|| ilf
==ILF_Unknown
) {
301 getword_start(&gwarea
,linebuf
);
302 if (getword(data
,sizeof(data
),&gwarea
,' ')<0) {
303 debuga(_("Maybe you have a broken time in your access.log file\n"));
306 if((str
=(char *) strchr(data
, '.')) != (char *) NULL
&& (str
=(char *) strchr(str
+1, '.')) != (char *) NULL
) {
310 if (getword(user
,sizeof(user
),&gwarea
,' ')<0 || getword_skip(255,&gwarea
,' ')<0) {
311 debuga(_("Maybe you have a broken record or garbage in your %s file\n"),arq
);
315 if (getword_skip(255,&gwarea
,' ')<0 || getword(user
,sizeof(user
),&gwarea
,' ')<0) {
316 debuga(_("Maybe you have a broken record or garbage in your %s file\n"),arq
);
321 if (getword(data
,sizeof(data
),&gwarea
,']')<0 || getword_skip(MAXLEN
,&gwarea
,'"')<0 ||
322 getword(fun
,sizeof(fun
),&gwarea
,' ')<0) {
323 debuga(_("Maybe you have a broken record or garbage in your %s file\n"),arq
);
326 if (getword_ptr(linebuf
,&log_entry
.Url
,&gwarea
,' ')<0) {
327 debuga(_("Maybe you have a broken url in your %s file\n"),arq
);
330 if (getword_skip(MAXLEN
,&gwarea
,' ')<0) {
331 debuga(_("Maybe you have a broken record or garbage in your %s file\n"),arq
);
334 if (getword(code2
,sizeof(code2
),&gwarea
,' ')<0) {
335 debuga(_("Maybe you have a broken record or garbage in your %s file\n"),arq
);
338 if (getword_atoll(&log_entry
.DataSize
,&gwarea
,' ')<0) {
339 debuga(_("Maybe you have a broken record or garbage in your %s file\n"),arq
);
342 if((str
=(char *) strchr(gwarea
.current
, ' ')) != (char *) NULL
) {
343 if (getword(code
,sizeof(code
),&gwarea
,' ')<0) {
344 debuga(_("Maybe you have a broken record or garbage in your %s file\n"),arq
);
348 if (getword(code
,sizeof(code
),&gwarea
,'\0')<0) {
349 debuga(_("Maybe you have a broken record or garbage in your %s file\n"),arq
);
354 if ((str
= strchr(code
, ':')) != NULL
)
356 log_entry
.HttpCode
=code
;
361 getword_start(&gwarea
,data
+1);
362 if (getword_multisep(data
,sizeof(data
),&gwarea
,':')<0){
363 debuga(_("Maybe you have a broken date in your %s file\n"),arq
);
366 if (getword_multisep(hora
,sizeof(hora
),&gwarea
,' ')<0){
367 debuga(_("Maybe you have a broken date in your %s file\n"),arq
);
370 getword_start(&gwarea
,data
);
371 if (getword_atoll(&iday
,&gwarea
,'/')<0){
372 debuga(_("Maybe you have a broken date in your %s file\n"),arq
);
375 if (getword(mes
,sizeof(mes
),&gwarea
,'/')<0){
376 debuga(_("Maybe you have a broken date in your %s file\n"),arq
);
379 if (getword_atoll(&iyear
,&gwarea
,'/')<0){
380 debuga(_("Maybe you have a broken date in your %s file\n"),arq
);
384 imonth
=month2num(mes
)+1;
385 idata
=builddia(iday
,imonth
,iyear
);
386 computedate(iyear
,imonth
,iday
,&tt
);
387 if (sscanf(hora
,"%d:%d:%d",&tt
.tm_hour
,&tt
.tm_min
,&tt
.tm_sec
)!=3 || tt
.tm_hour
<0 || tt
.tm_hour
>=24 ||
388 tt
.tm_min
<0 || tt
.tm_min
>=60 || tt
.tm_sec
<0 || tt
.tm_sec
>=60) {
389 debuga(_("Invalid time found in %s\n"),arq
);
392 log_entry
.EntryTime
=&tt
;
395 if(ilf
==ILF_Unknown
|| ilf
==ILF_Squid
) {
396 if (getword(elap
,sizeof(elap
),&gwarea
,' ')<0) {
397 debuga(_("Maybe you have a broken elapsed time in your %s file\n"),arq
);
400 while(strcmp(elap
,"") == 0 && gwarea
.current
[0] != '\0')
401 if (getword(elap
,sizeof(elap
),&gwarea
,' ')<0) {
402 debuga(_("Maybe you have a broken elapsed time in your %s file\n"),arq
);
405 if(strlen(elap
) < 1) continue;
406 log_entry
.ElapsedTime
=atol(elap
);
407 if (getword(ip
,sizeof(ip
),&gwarea
,' ')<0){
408 debuga(_("Maybe you have a broken client IP address in your %s file\n"),arq
);
412 if (getword(code
,sizeof(code
),&gwarea
,' ')<0){
413 debuga(_("Maybe you have a broken result code in your %s file\n"),arq
);
416 log_entry
.HttpCode
=code
;
417 if (getword_atoll(&log_entry
.DataSize
,&gwarea
,' ')<0){
418 debuga(_("Maybe you have a broken amount of data in your %s file\n"),arq
);
421 if (getword(fun
,sizeof(fun
),&gwarea
,' ')<0){
422 debuga(_("Maybe you have a broken request method in your %s file\n"),arq
);
425 if (getword_ptr(linebuf
,&log_entry
.Url
,&gwarea
,' ')<0){
426 debuga(_("Maybe you have a broken url in your %s file\n"),arq
);
429 if (getword(user
,sizeof(user
),&gwarea
,' ')<0){
430 debuga(_("Maybe you have a broken user ID in your %s file\n"),arq
);
438 log_entry
.EntryTime
=localtime(&tnum
);
439 if (log_entry
.EntryTime
== NULL
) {
440 debuga(_("Cannot convert the timestamp from the squid log file\n"));
444 strftime(tbuf2
, sizeof(tbuf2
), "%H%M", log_entry
.EntryTime
);
446 idata
=(log_entry
.EntryTime
->tm_year
+1900)*10000+(log_entry
.EntryTime
->tm_mon
+1)*100+log_entry
.EntryTime
->tm_mday
;
450 getword_start(&gwarea
,linebuf
);
451 if (getword(data
,sizeof(data
),&gwarea
,'\t')<0){
452 debuga(_("Maybe you have a broken record or garbage in your %s file\n"),arq
);
455 if (getword(hora
,sizeof(hora
),&gwarea
,'\t')<0) {
456 debuga(_("Maybe you have a broken record or garbage in your %s file\n"),arq
);
459 if (getword(user
,sizeof(user
),&gwarea
,'\t')<0) {
460 debuga(_("Maybe you have a broken record or garbage in your %s file\n"),arq
);
464 if (getword(ip
,sizeof(ip
),&gwarea
,'\t')<0) {
465 debuga(_("Maybe you have a broken record or garbage in your %s file\n"),arq
);
469 if (getword_ptr(linebuf
,&log_entry
.Url
,&gwarea
,'\t')<0){
470 debuga(_("Maybe you have a broken record or garbage in your %s file\n"),arq
);
473 if (getword_atoll(&log_entry
.DataSize
,&gwarea
,'\t')<0){
474 debuga(_("Maybe you have a broken record or garbage in your %s file\n"),arq
);
477 if (getword(code
,sizeof(code
),&gwarea
,'\t')<0){
478 debuga(_("Maybe you have a broken record or garbage in your %s file\n"),arq
);
481 log_entry
.HttpCode
=code
;
482 if (getword_atol(&log_entry
.ElapsedTime
,&gwarea
,'\t')<0){
483 debuga(_("Maybe you have a broken record or garbage in your %s file\n"),arq
);
486 if (getword(smartfilter
,sizeof(smartfilter
),&gwarea
,'\0')<0){
487 debuga(_("Maybe you have a broken record or garbage in your %s file\n"),arq
);
490 getword_start(&gwarea
,data
);
491 if (getword_atoll(&iday
,&gwarea
,'/')<0 || iday
<1 || iday
>31){
492 debuga(_("Maybe you have a broken date in your %s file\n"),arq
);
495 if (getword_atoll(&imonth
,&gwarea
,'/')<0 || imonth
<1 || imonth
>12){
496 debuga(_("Maybe you have a broken date in your %s file\n"),arq
);
499 if (getword_atoll(&iyear
,&gwarea
,'\0')<0){
500 debuga(_("Maybe you have a broken date in your %s file\n"),arq
);
503 idata
=builddia(iday
,imonth
,iyear
);
504 computedate(iyear
,imonth
,iday
,&tt
);
505 if (sscanf(hora
,"%d:%d:%d",&tt
.tm_hour
,&tt
.tm_min
,&tt
.tm_sec
)!=3 || tt
.tm_hour
<0 || tt
.tm_hour
>=24 ||
506 tt
.tm_min
<0 || tt
.tm_min
>=60 || tt
.tm_sec
<0 || tt
.tm_sec
>=60) {
507 debuga(_("Invalid time found in %s\n"),arq
);
510 log_entry
.EntryTime
=&tt
;
513 if (linebuf
[0] == '#') {
514 int ncols
,cols
[ISACOL_Last
];
516 fixendofline(linebuf
);
517 getword_start(&gwarea
,linebuf
);
518 // remove the #Fields: column at the beginning of the line
519 if (getword_skip(1000,&gwarea
,' ')<0){
520 debuga(_("Maybe you have a broken record or garbage in your %s file\n"),arq
);
523 for (ncols
=0 ; ncols
<ISACOL_Last
; ncols
++) cols
[ncols
]=-1;
525 while(gwarea
.current
[0] != '\0') {
526 if (getword(val1
,sizeof(val1
),&gwarea
,'\t')<0){
527 debuga(_("Maybe you have a broken record or garbage in your %s file\n"),arq
);
530 if(strcmp(val1
,"c-ip") == 0) cols
[ISACOL_Ip
]=ncols
;
531 if(strcmp(val1
,"cs-username") == 0) cols
[ISACOL_UserName
]=ncols
;
532 if(strcmp(val1
,"date") == 0) cols
[ISACOL_Date
]=ncols
;
533 if(strcmp(val1
,"time") == 0) cols
[ISACOL_Time
]=ncols
;
534 if(strcmp(val1
,"time-taken") == 0) cols
[ISACOL_TimeTaken
]=ncols
;
535 if(strcmp(val1
,"sc-bytes") == 0) cols
[ISACOL_Bytes
]=ncols
;
536 if(strcmp(val1
,"cs-uri") == 0) cols
[ISACOL_Uri
]=ncols
;
537 if(strcmp(val1
,"sc-status") == 0) cols
[ISACOL_Status
]=ncols
;
540 if (cols
[ISACOL_Ip
]>=0) {
542 for (ncols
=0 ; ncols
<ISACOL_Last
; ncols
++)
543 isa_cols
[ncols
]=cols
[ncols
];
547 if (!isa_ncols
) continue;
548 getword_start(&gwarea
,linebuf
);
549 for (x
=0 ; x
<isa_ncols
; x
++) {
550 if (getword_ptr(linebuf
,&str
,&gwarea
,'\t')<0) {
551 debuga(_("Maybe you have a broken record or garbage in your %s file\n"),arq
);
554 if (x
==isa_cols
[ISACOL_Ip
]) {
555 if (strlen(str
)>=sizeof(ip
)) {
556 debuga(_("Maybe you have a broken IP in your %s file\n"),arq
);
561 } else if (x
==isa_cols
[ISACOL_UserName
]) {
562 if (strlen(str
)>=sizeof(user
)) {
563 debuga(_("Maybe you have a broken user ID in your %s file\n"),arq
);
568 } else if (x
==isa_cols
[ISACOL_Date
]) {
569 if (strlen(str
)>=sizeof(data
)) {
570 debuga(_("Maybe you have a broken date in your %s file\n"),arq
);
574 } else if (x
==isa_cols
[ISACOL_Time
]) {
575 if (strlen(str
)>=sizeof(hora
)) {
576 debuga(_("Maybe you have a broken time in your %s file\n"),arq
);
580 } else if (x
==isa_cols
[ISACOL_TimeTaken
]) {
581 log_entry
.ElapsedTime
=atol(str
);
582 } else if (x
==isa_cols
[ISACOL_Bytes
]) {
583 log_entry
.DataSize
=atoll(str
);
584 } else if (x
==isa_cols
[ISACOL_Uri
]) {
586 } else if (x
==isa_cols
[ISACOL_Status
]) {
587 if (strlen(str
)>=sizeof(code
)) {
588 debuga(_("Maybe you have a broken access code in your %s file\n"),arq
);
595 if(strcmp(code
,"401") == 0 || strcmp(code
,"403") == 0 || strcmp(code
,"407") == 0) {
596 static char valcode
[12];
597 sprintf(valcode
,"DENIED/%s",code
);
598 log_entry
.HttpCode
=valcode
;
600 log_entry
.HttpCode
=code
;
602 getword_start(&gwarea
,data
);
603 if (getword_atoll(&iyear
,&gwarea
,'-')<0){
604 debuga(_("Maybe you have a broken year in your %s file\n"),arq
);
607 if (getword_atoll(&imonth
,&gwarea
,'-')<0){
608 debuga(_("Maybe you have a broken month in your %s file\n"),arq
);
611 if (getword_atoll(&iday
,&gwarea
,'\0')<0){
612 debuga(_("Maybe you have a broken day in your %s file\n"),arq
);
616 idata
=builddia(iday
,imonth
,iyear
);
617 computedate(iyear
,imonth
,iday
,&tt
);
618 if (isa_cols
[ISACOL_Time
]>=0) {
619 if (sscanf(hora
,"%d:%d:%d",&tt
.tm_hour
,&tt
.tm_min
,&tt
.tm_sec
)!=3 || tt
.tm_hour
<0 || tt
.tm_hour
>=24 ||
620 tt
.tm_min
<0 || tt
.tm_min
>=60 || tt
.tm_sec
<0 || tt
.tm_sec
>=60) {
621 debuga(_("Invalid time found in %s\n"),arq
);
625 log_entry
.EntryTime
=&tt
;
627 if (log_entry
.EntryTime
==NULL
) {
628 debuga(_("Unknown input log file format: no time\n"));
631 if (log_entry
.Ip
==NULL
) {
632 debuga(_("Unknown input log file format: no IP addresses\n"));
635 if (log_entry
.User
==NULL
) {
636 debuga(_("Unknown input log file format: no user\n"));
639 if (log_entry
.Url
==NULL
) {
640 debuga(_("Unknown input log file format: no URL\n"));
645 printf("DATE=%s IDATA=%d DFROM=%d DUNTIL=%d\n",Filter
->DateRange
,idata
,dfrom
,duntil
);
647 if(Filter
->DateRange
[0] != '\0'){
648 if(idata
< dfrom
|| idata
> duntil
) continue;
651 // Record only hours usage which is required
652 if( bsearch( &( log_entry
.EntryTime
->tm_wday
), weekdays
.list
, weekdays
.len
, sizeof( int ), compar
) == NULL
)
655 if( bsearch( &( log_entry
.EntryTime
->tm_hour
), hours
.list
, hours
.len
, sizeof( int ), compar
) == NULL
)
659 if(strlen(log_entry
.User
) > MAX_USER_LEN
) {
660 if (debugm
) printf(_("User ID too long: %s\n"),log_entry
.User
);
666 if(IncludeUsers
[0] != '\0') {
667 snprintf(val1
,sizeof(val1
),":%s:",log_entry
.User
);
668 if((str
=(char *) strstr(IncludeUsers
,val1
)) == (char *) NULL
)
672 if(vercode(log_entry
.HttpCode
)) {
673 if (debugm
) printf(_("Excluded code: %s\n"),log_entry
.HttpCode
);
678 if(testvaliduserchar(log_entry
.User
))
681 // replace any tab by a single space
682 for (str
=log_entry
.Url
; *str
; str
++)
683 if (*str
=='\t') *str
=' ';
684 for (str
=log_entry
.HttpCode
; *str
; str
++)
685 if (*str
=='\t') *str
=' ';
689 The full URL is not saved in sarg log. There is no point in testing the URL to detect
692 download_flag
=is_download_suffix(log_entry
.Url
);
694 safe_strcpy(download_url
,log_entry
.Url
,sizeof(download_url
));
700 url
=process_url(log_entry
.Url
,LongUrl
);
701 if (!url
|| url
[0] == '\0') continue;
704 if(strcmp(addr
,log_entry
.Ip
)!=0) continue;
706 if(Filter
->HostFilter
) {
707 if(!vhexclude(url
)) {
708 if (debugm
) printf(_("Excluded site: %s\n"),url
);
714 if(Filter
->StartTime
>= 0 && Filter
->EndTime
>= 0) {
715 hmr
=log_entry
.EntryTime
->tm_hour
*100+log_entry
.EntryTime
->tm_min
;
716 if(hmr
< Filter
->StartTime
|| hmr
> Filter
->EndTime
) continue;
720 if(strstr(url
,site
)==0) continue;
724 log_entry
.User
=log_entry
.Ip
;
728 if(strcmp(log_entry
.User
,"-") == 0 || strcmp(log_entry
.User
," ") == 0 || strcmp(log_entry
.User
,"") == 0) {
729 if(RecordsWithoutUser
== RECORDWITHOUTUSER_IP
) {
730 log_entry
.User
=log_entry
.Ip
;
733 if(RecordsWithoutUser
== RECORDWITHOUTUSER_IGNORE
)
735 if(RecordsWithoutUser
== RECORDWITHOUTUSER_EVERYBODY
)
736 log_entry
.User
="everybody";
738 strlow(log_entry
.User
);
739 if(NtlmUserFormat
== NTLMUSERFORMAT_USER
) {
740 if ((str
=strchr(user
,'+'))!=NULL
|| (str
=strchr(user
,'\\'))!=NULL
|| (str
=strchr(user
,'_'))!=NULL
) {
741 log_entry
.User
=str
+1;
748 if(strcmp(log_entry
.User
,us
)!=0) continue;
751 if(Filter
->SysUsers
) {
752 snprintf(wuser
,sizeof(wuser
),":%s:",log_entry
.User
);
753 if(strstr(userfile
, wuser
) == 0)
757 if(Filter
->UserFilter
) {
758 if(!vuexclude(log_entry
.User
)) {
759 if (debugm
) printf(_("Excluded user: %s\n"),log_entry
.User
);
765 if(strcmp(log_entry
.User
,"-") ==0 || strcmp(log_entry
.User
," ") ==0 ||
766 strcmp(log_entry
.User
,"") ==0 || strcmp(log_entry
.User
,":") ==0)
769 if (log_entry
.DataSize
<0) log_entry
.DataSize
=0;
771 if (log_entry
.ElapsedTime
<0) log_entry
.ElapsedTime
=0;
772 if (Filter
->max_elapsed
>0 && log_entry
.ElapsedTime
>Filter
->max_elapsed
) {
773 log_entry
.ElapsedTime
=0;
776 if((str
=(char *) strstr(linebuf
, "[SmartFilter:")) != (char *) NULL
) {
778 snprintf(smartfilter
,sizeof(smartfilter
),"\"%s\"",str
+1);
779 } else strcpy(smartfilter
,"\"\"");
783 for (ufile
=first_user_file
; ufile
&& strcmp(log_entry
.User
,ufile
->user
->id
)!=0 ; ufile
=ufile
->next
) {
785 if (ufile
->file
) nopen
++;
788 ufile
=malloc(sizeof(*ufile
));
790 debuga(_("Not enough memory to store the user %s\n"),log_entry
.User
);
793 memset(ufile
,0,sizeof(*ufile
));
794 ufile
->next
=first_user_file
;
795 first_user_file
=ufile
;
796 uinfo
=userinfo_create(log_entry
.User
);
798 uinfo
->id_is_ip
=id_is_ip
;
801 prev_ufile
->next
=ufile
->next
;
802 ufile
->next
=first_user_file
;
803 first_user_file
=ufile
;
806 #ifdef ENABLE_DOUBLE_CHECK_DATA
807 ufile
->user
->nbytes
+=log_entry
.DataSize
;
808 ufile
->user
->elap
+=log_entry
.ElapsedTime
;
811 if (ufile
->file
==NULL
) {
812 if (nopen
>=maxopenfiles
) {
814 for (ufile1
=first_user_file
; ufile1
; ufile1
=ufile1
->next
) {
815 if (ufile1
->file
!=NULL
) {
816 if (x
>=maxopenfiles
) {
817 if (fclose(ufile1
->file
)==EOF
) {
818 debuga(_("Failed to close the log file of user %s - %s\n"),ufile1
->user
->id
,strerror(errno
));
827 if (snprintf (tmp3
, sizeof(tmp3
), "%s/%s.unsort", tmp
, ufile
->user
->filename
)>=sizeof(tmp3
)) {
828 debuga(_("Temporary user file name too long: %s/%s.unsort\n"), tmp
, ufile
->user
->filename
);
831 if ((ufile
->file
= MY_FOPEN (tmp3
, "a")) == NULL
) {
832 debuga(_("(log) Cannot open temporary file: %s - %s\n"), tmp3
, strerror(errno
));
837 strftime(dia
, sizeof(dia
), "%d/%m/%Y", log_entry
.EntryTime
);
838 strftime(hora
,sizeof(hora
),"%H:%M:%S",log_entry
.EntryTime
);
840 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) {
841 debuga(_("Write error in the log file of user %s\n"),log_entry
.User
);
845 if(fp_log
&& ilf
!=ILF_Sarg
)
846 fprintf(fp_log
, "%s\t%s\t%s\t%s\t%s\t%"PRIu64
"\t%s\t%ld\t%s\n",dia
,hora
,log_entry
.User
,log_entry
.Ip
,url
,(uint64_t)log_entry
.DataSize
,log_entry
.HttpCode
,log_entry
.ElapsedTime
,smartfilter
);
850 if(!dataonly
&& download_flag
&& strstr(log_entry
.HttpCode
,"DENIED") == 0) {
853 if ( ! fp_Download_Unsort
) {
854 if ((fp_Download_Unsort
= MY_FOPEN ( sz_Download_Unsort
, "a")) == NULL
) {
855 debuga(_("(log) Cannot open temporary file: %s - %s\n"),sz_Download_Unsort
, strerror(errno
));
859 fprintf(fp_Download_Unsort
,"%s\t%s\t%s\t%s\t%s\n",dia
,hora
,log_entry
.User
,log_entry
.Ip
,download_url
);
862 denied_write(&log_entry
);
863 if((ReportType
& REPORT_TYPE_AUTH_FAILURES
) != 0) {
864 if(fp_authfail
&& (strstr(log_entry
.HttpCode
,"DENIED/401") != 0 || strstr(log_entry
.HttpCode
,"DENIED/407") != 0)) {
865 fprintf(fp_authfail
, "%s\t%s\t%s\t%s\t%s\n",dia
,hora
,log_entry
.User
,log_entry
.Ip
,log_entry
.Url
);
871 if(!totper
|| idata
<mindate
){
873 memcpy(&period
.start
,log_entry
.EntryTime
,sizeof(*log_entry
.EntryTime
));
874 strcpy(start_hour
,tbuf2
);
876 if (!totper
|| idata
>maxdate
) {
878 memcpy(&period
.end
,log_entry
.EntryTime
,sizeof(*log_entry
.EntryTime
));
884 printf("IP=\t%s\n",log_entry
.Ip
);
885 printf("USER=\t%s\n",log_entry
.User
);
886 printf("ELAP=\t%ld\n",log_entry
.ElapsedTime
);
887 printf("DATE=\t%s\n",dia
);
888 printf("TIME=\t%s\n",hora
);
889 printf("FUNC=\t%s\n",fun
);
890 printf("URL=\t%s\n",url
);
891 printf("CODE=\t%s\n",log_entry
.HttpCode
);
892 printf("LEN=\t%"PRIu64
"\n",(uint64_t)log_entry
.DataSize
);
901 if( ShowReadStatistics
)
902 printf(_("SARG: Records in file: %lu, reading: %3.2f%%\n"),recs1
, (float) 100 );
906 longline_destroy(&line
);
911 char val4
[255];//val4 must not be bigger than arq_log without fixing the strcpy below
914 safe_strcpy(end_hour
,tbuf2
,sizeof(end_hour
));
915 strftime(val2
,sizeof(val2
),"%d%m%Y",&period
.start
);
916 strftime(val1
,sizeof(val1
),"%d%m%Y",&period
.end
);
917 if (snprintf(val4
,sizeof(val4
),"%s/sarg-%s_%s-%s_%s.log",ParsedOutputLog
,val2
,start_hour
,val1
,end_hour
)>=sizeof(val4
)) {
918 debuga(_("File name too long: %s/sarg-%s_%s-%s_%s.log\n"),ParsedOutputLog
,val2
,start_hour
,val1
,end_hour
);
921 if (rename(arq_log
,val4
)) {
922 debuga(_("failed to rename %s to %s - %s\n"),arq_log
,val4
,strerror(errno
));
924 strcpy(arq_log
,val4
);
926 if(strcmp(ParsedOutputLogCompress
,"nocompress") != 0 && ParsedOutputLogCompress
[0] != '\0') {
928 No double quotes around ParsedOutputLogCompress because it may contain command line options. If double quotes are
929 necessary around the command name, put them in the configuration file.
931 if (snprintf(val1
,sizeof(val1
),"%s \"%s\"",ParsedOutputLogCompress
,arq_log
)>=sizeof(val1
)) {
932 debuga(_("Command too long: %s \"%s\"\n"),ParsedOutputLogCompress
,arq_log
);
935 cstatus
=system(val1
);
936 if (!WIFEXITED(cstatus
) || WEXITSTATUS(cstatus
)) {
937 debuga(_("command return status %d\n"),WEXITSTATUS(cstatus
));
938 debuga(_("command: %s\n"),val1
);
944 debuga(_("Sarg parsed log saved as %s\n"),arq_log
);
948 if (fp_authfail
) fclose(fp_authfail
);
949 if (fp_Download_Unsort
) fclose (fp_Download_Unsort
);
951 for (ufile
=first_user_file
; ufile
; ufile
=ufile1
) {
953 if (ufile
->file
!=NULL
) fclose(ufile
->file
);
960 debuga(_(" Records read: %ld, written: %ld, excluded: %ld\n"),totregsl
,totregsg
,totregsx
);
962 for (ilf
=0 ; ilf
<ILF_Last
; ilf
++) totalcount
+=ilf_count
[ilf
];
964 if(ilf_count
[ILF_Common
]>0 && ilf_count
[ILF_Squid
]>0)
965 debuga(_("Log with mixed records format (squid and common log)\n"));
967 if(ilf_count
[ILF_Common
]>0 && ilf_count
[ILF_Squid
]==0)
968 debuga(_("Common log format\n"));
970 if(ilf_count
[ILF_Common
]==0 && ilf_count
[ILF_Squid
]>0)
971 debuga(_("Squid log format\n"));
973 if(ilf_count
[ILF_Sarg
]>0)
974 debuga(_("Sarg log format\n"));
976 if(totalcount
==0 && totregsg
)
977 debuga(_("Log with invalid format\n"));
981 debugaz(_("date=%s\n"),dia
);
982 debugaz(_("period=%s\n"),period
.text
);
985 return((totregsg
!=0) ? 1 : 0);