]>
git.ipfire.org Git - thirdparty/sarg.git/blob - util.c
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 // #define LEGACY_MY_ATOLL
28 // #define LEGACY_TESTVALIDUSERCHAR
30 #include "include/conf.h"
31 #include "include/defs.h"
33 #if defined(HAVE_BACKTRACE)
34 #define USE_GETWORD_BACKTRACE 1
36 #define USE_GETWORD_BACKTRACE 0
39 static char mtab1
[12][4]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
41 //! The list of the HTTP codes to exclude from the report.
42 static char *excludecode
=NULL
;
44 /*void fgetword(char *word, char *line, int stop)
49 for (x=0; line[x] && (line[x] != stop); x++) word[x] = line[x];
56 tchar = strchr(line, stop);
57 if (tchar == NULL) strcpy(word, line);
60 difflen = tchar - line;
61 strncpy(word, line, difflen);
66 #if USE_GETWORD_BACKTRACE
67 static void getword_backtrace(void)
73 n
=backtrace(buffer
,sizeof(buffer
)/sizeof(buffer
[0]));
75 calls
=backtrace_symbols(buffer
,n
);
77 debuga(_("getword backtrace:\n"));
78 for (i
=0 ; i
<n
; i
++) {
79 fprintf(stderr
,"SARG: %d:%s\n",i
+1,calls
[i
]);
84 #endif //USE_GETWORD_BACKTRACE
86 void getword_start(struct getwordstruct
*gwarea
, const char *line
)
88 gwarea
->beginning
=line
;
93 void getword_restart(struct getwordstruct
*gwarea
)
95 if (gwarea
->modified
) {
96 debuga(_("Cannot parse again the line as it was modified\n"));
99 gwarea
->current
=gwarea
->beginning
;
102 int getword(char *word
, int limit
, struct getwordstruct
*gwarea
, char stop
)
106 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++) {
108 printf("SARG: getword loop detected after %d bytes.\n",x
);
109 printf("SARG: Line=\"%s\"\n",gwarea
->beginning
);
110 printf("SARG: Record=\"%s\"\n",gwarea
->current
);
111 printf("SARG: searching for \'x%x\'\n",stop
);
112 //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
113 word
[(limit
>0) ? limit
-1 : 0]='\0';
114 #if USE_GETWORD_BACKTRACE
119 word
[x
] = gwarea
->current
[x
];
123 if (gwarea
->current
[x
]) ++x
;
128 int getword_limit(char *word
, int limit
, struct getwordstruct
*gwarea
, char stop
)
133 for(x
=0; x
<limit
&& gwarea
->current
[x
] && gwarea
->current
[x
] != stop
;x
++) {
134 word
[x
] = gwarea
->current
[x
];
138 while (*gwarea
->current
&& *gwarea
->current
!= stop
) gwarea
->current
++;
139 if (*gwarea
->current
) ++gwarea
->current
;
143 int getword_multisep(char *word
, int limit
, struct getwordstruct
*gwarea
, char stop
)
147 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++) {
149 printf("SARG: getword_multisep loop detected.\n");
150 printf("SARG: Line=\"%s\"\n",gwarea
->beginning
);
151 printf("SARG: Record=\"%s\"\n",gwarea
->current
);
152 printf("SARG: searching for \'x%x\'\n",stop
);
153 //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
154 if (limit
>0) word
[limit
-1]='\0';
155 #if USE_GETWORD_BACKTRACE
158 //exit(EXIT_FAILURE);
161 word
[x
] = gwarea
->current
[x
];
165 while (gwarea
->current
[x
] && gwarea
->current
[x
]==stop
) ++x
;
170 int getword_skip(int limit
, struct getwordstruct
*gwarea
, char stop
)
174 for(x
=0;(gwarea
->current
[x
] && (gwarea
->current
[x
] != stop
));x
++) {
176 printf("SARG: getword_skip loop detected after %d bytes.\n",x
);
177 printf("SARG: Line=\"%s\"\n",gwarea
->beginning
);
178 printf("SARG: Record=\"%s\"\n",gwarea
->current
);
179 printf("SARG: searching for \'x%x\'\n",stop
);
180 //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
181 #if USE_GETWORD_BACKTRACE
188 if (gwarea
->current
[x
]) ++x
;
193 int getword_atoll(long long int *number
, struct getwordstruct
*gwarea
, char stop
)
198 if (gwarea
->current
[0] == '-') {
201 } else if (gwarea
->current
[0] == '+') {
205 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
206 *number
=(*number
* 10) + gwarea
->current
[x
]-'0';
208 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
209 printf("SARG: getword_atoll loop detected after %d bytes.\n",x
);
210 printf("SARG: Line=\"%s\"\n",gwarea
->beginning
);
211 printf("SARG: Record=\"%s\"\n",gwarea
->current
);
212 printf("SARG: searching for \'x%x\'\n",stop
);
213 //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
214 #if USE_GETWORD_BACKTRACE
221 if (gwarea
->current
[x
]) ++x
;
227 int getword_ptr(char *orig_line
,char **word
, struct getwordstruct
*gwarea
, char stop
)
230 \note Why pass the original buffer to the function ? Because we must modify it to
231 insert the terminating ASCII zero for the word we return and that's not compatible
232 with getword_restart(). Moreover, getword_start() sometime works on constant strings
233 so this function require the original buffer to detect any missuse.
239 if (orig_line
&& orig_line
!=gwarea
->beginning
) {
240 debuga(_("Invalid buffer passed to getword_ptr\n"));
244 start
=(gwarea
->current
-gwarea
->beginning
);
245 if (word
&& orig_line
) *word
=orig_line
+start
;
246 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++);
247 sep
=(gwarea
->current
[x
]!='\0');
248 if (word
&& orig_line
) orig_line
[start
+x
] = '\0';
255 #define MAXLLL 30 //!< Maximum number of digits in long long (a guess).
256 long long int my_atoll (const char *nptr
)
258 long long int returnval
=0LL;
259 int max_digits
= MAXLLL
;
261 // Soak up all the white space
262 while (isspace( *nptr
)) {
266 //For each character left to right
267 //change the character to a single digit
268 //multiply what we had before by 10 and add the new digit
270 while (--max_digits
&& isdigit( *nptr
))
272 returnval
= ( returnval
* 10 ) + ( *nptr
++ - '0' ) ;
278 int is_absolute(const char *path
)
280 if (*path
=='/') return(1);
282 if (isalpha(path
[0]) && path
[1]==':') return(1);
287 void my_mkdir(const char *name
)
293 if(!is_absolute(name
)) {
294 debuga(_("Invalid path (%s). Please, use absolute paths only.\n"),name
);
295 debuga(_("process aborted.\n"));
300 for (i
=0 ; name
[i
] ; i
++) {
302 debuga(_("directory name too long: %s\n"),name
);
305 if (chars
>0 && name
[i
] == '/') {
307 if(access(w0
, R_OK
) != 0) {
309 debuga(_("mkdir %s %s\n"),w0
,strerror(errno
));
310 debuga(_("process aborted.\n"));
315 if (name
[i
] != '/') chars
++;
319 if(access(name
, R_OK
) != 0) {
320 if(mkdir(name
,0755)) {
321 debuga(_("mkdir %s %s\n"),name
,strerror(errno
));
322 debuga(_("process aborted.\n"));
329 void my_lltoa(unsigned long long int n
, char *s
, int ssize
, int len
)
338 debuga(_("The requested number of digits passed to my_lltoa (%d) is bigger than the output buffer size (%d)\n"),len
,ssize
);
343 s
[slen
++] = (n
% 10) + '0';
344 } while ((n
/= 10) > 0 && slen
<ssize
);
347 for (i
= 0, j
= slen
-1; i
<j
; i
++, j
--) {
355 for(j
=slen
; j
>=0; j
--)
362 int month2num(const char *month
)
366 for(m
=0 ; m
<12 && strcmp(mtab1
[m
],month
) != 0; m
++);
370 int builddia(int day
, int month
, int year
)
372 return(year
*10000+month
*100+day
);
376 void buildymd(const char *dia
, const char *mes
, const char *ano
, char *wdata
)
381 sprintf(wdata
,"%04d%02d%02d",atoi(ano
),nmes
+1,atoi(dia
));
385 int conv_month(const char *month
)
389 for(x
=0; x
<12 && strncmp(mtab1
[x
],month
,3)!=0; x
++);
394 const char *conv_month_name(int month
)
398 if (month
<1 || month
>12) {
399 snprintf(str
,sizeof(str
),"%03d",month
);
402 return(mtab1
[month
-1]);
406 void name_month(char *month
,int month_len
)
408 int x
, z
=atoi(month
)-1;
411 struct getwordstruct gwarea
;
413 strcpy(m
,_("January,February,March,April,May,June,July,August,September,October,November,December"));
414 getword_start(&gwarea
,m
);
417 if (getword_multisep(w
,sizeof(w
),&gwarea
,',')<0) {
418 printf("SARG: Maybe you have a broken record or garbage in the names of the months.\n");
421 if (getword_multisep(month
,month_len
,&gwarea
,',')<0) {
422 printf("SARG: Maybe you have a broken record or garbage in the name of the months.\n");
428 void debuga(const char *msg
,...)
432 fputs(_("SARG: "),stderr
);
434 vfprintf(stderr
,msg
,ap
);
439 void debugaz(const char *head
, const char *msg
)
441 fprintf(stderr
, "SARG: (util) %s=%s\n",head
, msg
);
446 char *fixnum(long long int value
, int n
)
448 #define MAXLEN_FIXNUM 256
449 char num
[MAXLEN_FIXNUM
]="";
450 char buf
[MAXLEN_FIXNUM
* 2];
452 static char ret
[MAXLEN_FIXNUM
* 2];
454 register int i
, j
, k
;
456 static char abbrev
[30];
458 my_lltoa(value
, num
, sizeof(num
), 0);
460 if(DisplayedValues
==DISPLAY_ABBREV
) {
461 numlen
= strlen(num
);
463 sprintf(abbrev
,"%s",num
);
464 if(numlen
== 4 || numlen
== 7 || numlen
== 10 || numlen
== 13) {
465 snprintf(abbrev
,2,"%s",num
);
466 strncat(abbrev
,".",1);
467 strncat(abbrev
,num
+1,2);
468 if(!n
) return(abbrev
);
470 strncat(abbrev
,"K",1);
472 strncat(abbrev
,"M",1);
473 else if(numlen
== 10)
474 strncat(abbrev
,"G",1);
475 else if(numlen
== 13)
476 strncat(abbrev
,"T",1);
478 if(numlen
== 5 || numlen
== 8 || numlen
== 11 || numlen
== 14) {
479 snprintf(abbrev
,3,"%s",num
);
480 strncat(abbrev
,".",1);
481 strncat(abbrev
,num
+2,2);
482 if(!n
) return(abbrev
);
484 strncat(abbrev
,"K",1);
486 strncat(abbrev
,"M",1);
487 else if(numlen
== 11)
488 strncat(abbrev
,"G",1);
489 else if(numlen
== 14)
490 strncat(abbrev
,"T",1);
492 if(numlen
== 6 || numlen
== 9 || numlen
== 12 || numlen
== 15) {
493 snprintf(abbrev
,4,"%s",num
);
494 strncat(abbrev
,".",1);
495 strncat(abbrev
,num
+3,2);
496 if(!n
) return(abbrev
);
498 strncat(abbrev
,"K",1);
500 strncat(abbrev
,"M",1);
501 else if(numlen
== 12)
502 strncat(abbrev
,"G",1);
503 else if(numlen
== 15)
504 strncat(abbrev
,"T",1);
510 bzero(buf
, MAXLEN_FIXNUM
*2);
516 for ( i
= strlen(num
) - 1, j
= 0 ; i
> -1; i
--) {
517 if ( k
== 2 && i
!= 0 ) {
520 pbuf
[j
++] = (UseComma
) ? ',' : '.';
530 for ( i
= strlen(pbuf
) - 1, j
= 0 ; i
> -1; i
--, j
++)
539 char *fixnum2(long long int value
, int n
)
541 #define MAXLEN_FIXNUM2 1024
542 char num
[MAXLEN_FIXNUM2
];
543 char buf
[MAXLEN_FIXNUM2
* 2];
545 static char ret
[MAXLEN_FIXNUM2
* 2];
547 register int i
, j
, k
;
549 my_lltoa(value
, num
, sizeof(num
), 0);
550 bzero(buf
, MAXLEN_FIXNUM2
*2);
556 for ( i
= strlen(num
) - 1, j
= 0 ; i
> -1; i
--) {
557 if ( k
== 2 && i
!= 0 ) {
560 pbuf
[j
++] = (UseComma
) ? ',' : '.';
570 for ( i
= strlen(pbuf
) - 1, j
= 0 ; i
> -1; i
--, j
++)
579 char *buildtime(long long int elap
)
582 int num
= elap
/ 1000;
591 min
=(num
% 3600) / 60;
593 sprintf(buf
,"%02d:%02d:%02d",hor
,min
,sec
);
600 void obtdate(const char *dirname
, const char *name
, char *data
)
606 sprintf(wdir
,"%s%s/sarg-date",dirname
,name
);
607 if ((fp_in
= fopen(wdir
, "rt")) == 0) {
608 sprintf(wdir
,"%s%s/date",dirname
,name
);
609 if ((fp_in
= fopen(wdir
, "rt")) == 0) {
615 if (!fgets(data
,80,fp_in
)) {
616 debuga(_("Failed to read the date in %s\n"),wdir
);
627 void formatdate(char *date
,int date_size
,int year
,int month
,int day
,int hour
,int minute
,int second
,int dst
)
633 memset(<m
,0,sizeof(ltm
));
634 if (year
>=1900) ltm
.tm_year
=year
-1900;
635 if (month
>=1 && month
<=12) ltm
.tm_mon
=month
-1;
636 if (day
>=1 && day
<=31) ltm
.tm_mday
=day
;
637 if (hour
>=0 && hour
<24) ltm
.tm_hour
=hour
;
638 if (minute
>=0 && minute
<60) ltm
.tm_min
=minute
;
639 if (second
>=0 && second
<60) ltm
.tm_sec
=second
;
641 unixtime
=mktime(<m
); //fill the missing entries
642 fulltm
=localtime(&unixtime
);
643 //strftime(date,date_size,"%a %b %d %H:%M:%S %Z %Y",fulltm);
644 strftime(date
,date_size
,"%c",fulltm
);
648 void computedate(int year
,int month
,int day
,struct tm
*t
)
650 memset(t
,0,sizeof(*t
));
651 t
->tm_year
=year
-1900;
657 int obtuser(const char *dirname
, const char *name
)
665 sprintf(wdir
,"%s%s/sarg-users",dirname
,name
);
666 if((fp_in
=fopen(wdir
,"r"))==NULL
) {
667 sprintf(wdir
,"%s%s/users",dirname
,name
);
668 if((fp_in
=fopen(wdir
,"r"))==NULL
) {
673 if (!fgets(tuser
,sizeof(tuser
),fp_in
)) {
674 debuga(_("Failed to read the number of users in %s\n"),wdir
);
684 void obttotal(const char *dirname
, const char *name
, char *tbytes
, int nuser
, char *media
)
689 char user
[MAX_USER_LEN
];
692 long long int twork
=0;
693 struct getwordstruct gwarea
;
700 sprintf(wdir
,"%s%s/sarg-general",dirname
,name
);
701 if ((fp_in
= fopen(wdir
, "r")) == 0) {
702 sprintf(wdir
,"%s%s/general",dirname
,name
);
703 if ((fp_in
= fopen(wdir
, "r")) == 0) {
708 if ((line
=longline_create())==NULL
) {
709 debuga(_("Not enough memory to read the file %s\n"),wdir
);
713 while((buf
=longline_read(fp_in
,line
))!=NULL
) {
714 if (strncmp(buf
,"TOTAL\t",6) == 0)
716 else if (strncmp(buf
,"TOTAL ",6) == 0)
720 getword_start(&gwarea
,buf
);
721 if (getword(user
,sizeof(user
),&gwarea
,sep
)<0) {
722 debuga(_("There is a invalid user in file %s\n"),wdir
);
725 if(strcmp(user
,"TOTAL") != 0)
727 if (getword_skip(MAXLEN
,&gwarea
,sep
)<0) {
728 debuga(_("There a broken total number of access in file %s\n"),wdir
);
731 if (getword_atoll(&twork
,&gwarea
,sep
)<0) {
732 debuga(_("There is a broken number of bytes in file %s\n"),wdir
);
735 strcpy(tbytes
,fixnum(twork
,1));
739 longline_destroy(&line
);
747 strcpy(media
,fixnum(med
,1));
752 int getperiod_fromsarglog(const char *arqtt
,struct periodstruct
*period
)
755 int day0
, month0
, year0
, hour0
, minute0
;
756 int day1
, month1
, year1
, hour1
, minute1
;
760 memset(period
,0,sizeof(*period
));
763 while((str
=strstr(str
,"sarg-"))!=NULL
) {
765 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
766 day0
=(str
[0]-'0')*10+(str
[1]-'0');
768 strncpy(month
,str
,3);
770 month0
=month2num(month
);
771 if (month0
>=12) continue;
774 for (i
=0 ; isdigit(str
[i
]) && i
<4 ; i
++) year0
=year0
*10+(str
[i
]-'0');
777 if (str
[0]!='_') continue;
780 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
781 hour0
=(str
[0]-'0')*10+(str
[1]-'0');
783 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
784 minute0
=(str
[0]-'0')*10+(str
[1]-'0');
787 if (*str
!= '-') continue;
790 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
791 day1
=(str
[0]-'0')*10+(str
[1]-'0');
793 strncpy(month
,str
,3);
795 month1
=month2num(month
);
796 if (month1
>=12) continue;
799 for (i
=0 ; isdigit(str
[i
]) && i
<4 ; i
++) year1
=year1
*10+(str
[i
]-'0');
803 if (str
[0]!='_') continue;
806 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
807 hour1
=(str
[0]-'0')*10+(str
[1]-'0');
809 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
810 minute1
=(str
[0]-'0')*10+(str
[1]-'0');
813 period
->start
.tm_mday
=day0
;
814 period
->start
.tm_mon
=month0
;
815 period
->start
.tm_year
=year0
-1900;
816 period
->start
.tm_hour
=hour0
;
817 period
->start
.tm_min
=minute0
;
818 period
->end
.tm_mday
=day1
;
819 period
->end
.tm_mon
=month1
;
820 period
->end
.tm_year
=year1
-1900;
821 period
->end
.tm_hour
=hour1
;
822 period
->end
.tm_min
=minute1
;
828 void getperiod_fromrange(struct periodstruct
*period
,int dfrom
,int duntil
)
830 memset(&period
->start
,0,sizeof(period
->start
));
831 period
->start
.tm_mday
=dfrom
%100;
832 period
->start
.tm_mon
=(dfrom
/100)%100-1;
833 period
->start
.tm_year
=(dfrom
/10000)-1900;
835 memset(&period
->end
,0,sizeof(period
->end
));
836 period
->end
.tm_mday
=duntil
%100;
837 period
->end
.tm_mon
=(duntil
/100)%100-1;
838 period
->end
.tm_year
=(duntil
/10000)-1900;
841 int getperiod_buildtext(struct periodstruct
*period
)
845 char text1
[40], text2
[40];
848 i
=strftime(text1
, sizeof(text1
), "%Y %b %d", &period
->start
);
849 }else if(df
[0]=='e') {
850 i
=strftime(text1
, sizeof(text1
), "%d %b %Y", &period
->start
);
851 } else /*if(df[0]=='w')*/ {
852 IndexTree
=INDEX_TREE_FILE
;
853 i
=strftime(text1
, sizeof(text1
), "%Y.%U", &period
->start
);
855 if (i
== 0) return(-1);
857 range
=(period
->start
.tm_year
!=period
->end
.tm_year
||
858 period
->start
.tm_mon
!=period
->end
.tm_mon
||
859 period
->start
.tm_mday
!=period
->end
.tm_mday
);
862 i
=strftime(text2
, sizeof(text2
)-i
, "%Y %b %d", &period
->end
);
863 } else if(df
[0]=='e') {
864 i
=strftime(text2
, sizeof(text2
)-i
, "%d %b %Y", &period
->end
);
866 i
=strftime(text2
, sizeof(text2
)-i
, "%Y.%U", &period
->end
);
868 if (i
== 0) return(-1);
872 snprintf(period
->text
,sizeof(period
->text
),"%s-%s",text1
,text2
);
873 snprintf(period
->html
,sizeof(period
->html
),"%s—%s",text1
,text2
);
875 strncpy(period
->text
,text1
,sizeof(period
->text
)-1);
876 period
->text
[sizeof(period
->text
)-1]='\0';
877 strncpy(period
->html
,text1
,sizeof(period
->html
)-1);
878 period
->html
[sizeof(period
->html
)-1]='\0';
883 static void copy_images(void)
885 FILE *img_in
, *img_ou
;
888 char srcfile
[MAXLEN
];
889 char dstfile
[MAXLEN
];
891 struct dirent
*direntp
;
896 if (snprintf(images
,sizeof(images
),"%simages",outdir
)>=sizeof(images
)) {
897 debuga(_("Cannot copy images to target directory %simages\n"),outdir
);
900 if (access(images
,R_OK
)!=0) {
904 strcpy(imgdir
,IMAGEDIR
);
905 dirp
= opendir(imgdir
);
907 debuga(_("(util) Can't open directory %s: %s\n"),imgdir
,strerror(errno
));
910 while ((direntp
= readdir( dirp
)) != NULL
){
911 if(direntp
->d_name
[0]=='.')
913 sprintf(srcfile
,"%s/%s",imgdir
,direntp
->d_name
);
914 if (stat(srcfile
,&info
)) {
915 debuga(_("Cannot stat \"%s\" - %s\n"),srcfile
,strerror(errno
));
918 if (S_ISREG(info
.st_mode
)) {
919 sprintf(dstfile
,"%s/%s",images
,direntp
->d_name
);
920 img_in
= fopen(srcfile
, "rb");
922 img_ou
= fopen(dstfile
, "wb");
924 while ((nread
= fread(buffer
,1,sizeof(buffer
),img_in
))>0) {
925 if (fwrite(buffer
,1,nread
,img_ou
)!=nread
) {
926 debuga(_("Failed to copy image %s to %s\n"),srcfile
,dstfile
);
932 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open/create file", dstfile
, strerror(errno
));
935 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open file", srcfile
, strerror(errno
));
938 (void) closedir(dirp
);
943 int vrfydir(const struct periodstruct
*per1
, const char *addr
, const char *site
, const char *us
, const char *form
)
948 char dirname2
[MAXLEN
];
958 y1
=per1
->start
.tm_year
+1900;
959 y2
=per1
->end
.tm_year
+1900;
960 m1
=per1
->start
.tm_mon
+1;
961 m2
=per1
->end
.tm_mon
+1;
962 d1
=per1
->start
.tm_mday
;
963 d2
=per1
->end
.tm_mday
;
964 if(IndexTree
== INDEX_TREE_DATE
) {
965 wlen
+=sprintf(wdir
+wlen
,"%04d",y1
);
966 if(y1
!=y2
) wlen
+=sprintf(wdir
+wlen
,"-%04d",y2
);
967 if(access(wdir
, R_OK
) != 0)
970 wlen
+=sprintf(wdir
+wlen
,"/%02d",m1
);
971 if(m1
!= m2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",m2
);
972 if(access(wdir
, R_OK
) != 0)
975 wlen
+=sprintf(wdir
+wlen
,"/%02d",d1
);
976 if(d1
!=d2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",d2
);
979 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%04d%s%02d-%04d%s%02d",y1
,
980 conv_month_name(m1
),d1
,y2
,conv_month_name(m2
),d2
);
981 } else if(df
[0] == 'e') {
982 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%02d%s%04d-%02d%s%04d",d1
,
983 conv_month_name(m1
),y1
,d2
,conv_month_name(m2
),y2
);
984 } else if(df
[0] == 'w') {
985 wlen2
=strftime(wdir
+wlen
, sizeof(wdir
)-wlen
, "%Y.%U", &per1
->start
);
986 if (wlen2
==0) return(-1);
992 struct userinfostruct
*uinfo
=userinfo_find_from_id(us
);
995 strcat(wdir
,uinfo
->filename
);
998 if(addr
[0] != '\0') {
1002 if(site
[0] != '\0') {
1007 strcpy(outdirname
,wdir
);
1009 if(IndexTree
!= INDEX_TREE_DATE
) {
1010 if(!OverwriteReport
) {
1012 if(access(wdir
,R_OK
) == 0) {
1013 sprintf(wdir
,"%s.%d",outdirname
,num
);
1022 debuga(_("File %s already exists, moved to %s\n"),outdirname
,wdir
);
1023 rename(outdirname
,wdir
);
1026 if(access(outdirname
,R_OK
) == 0) {
1027 unlinkdir(outdirname
,1);
1030 my_mkdir(outdirname
);
1032 strcpy(dirname2
,wdir
);
1033 if(!OverwriteReport
) {
1035 if(access(wdir
,R_OK
) == 0) {
1036 sprintf(wdir
,"%s.%d",dirname2
,num
);
1045 debuga(_("File %s already exists, moved to %s\n"),dirname2
,wdir
);
1046 rename(dirname2
,wdir
);
1047 strcpy(dirname2
,wdir
);
1050 if(access(wdir
,R_OK
) == 0) {
1055 if(access(wdir
, R_OK
) != 0)
1059 strcpy(dirname2
,wdir
);
1061 sprintf(wdir
,"%s/sarg-date",outdirname
);
1062 if ((fp_ou
= fopen(wdir
, "wt")) == 0) {
1063 debuga(_("cannot open %s for writing\n"),wdir
);
1068 //strftime(wdir,sizeof(wdir),"%a %b %d %H:%M:%S %Z %Y",localtime(&curtime));
1069 loctm
=localtime(&curtime
);
1070 strftime(wdir
,sizeof(wdir
),"%Y-%m-%d %H:%M:%S",loctm
);
1071 if (fprintf(fp_ou
,"%s %d\n",wdir
,loctm
->tm_isdst
)<0) {
1072 debuga(_("Failed to write the date in %s\n"),wdir
);
1076 if (fclose(fp_ou
)==EOF
) {
1077 debuga(_("Failed to write the date in %s\n"),wdir
);
1086 void strip_latin(char *line
)
1093 for (i
=0;line
[i
];i
++){
1095 if (line
[i
]==';') skip
=0;
1108 void zdate(char *ftime
,int ftimesize
, const char *DateFormat
)
1115 local
= localtime(&t
);
1116 if(strcmp(DateFormat
,"u") == 0)
1117 strftime(ftime
, ftimesize
, "%b/%d/%Y %H:%M", local
);
1118 if(strcmp(DateFormat
,"e") == 0)
1119 strftime(ftime
, ftimesize
, "%d/%b/%Y-%H:%M", local
);
1120 if(strcmp(DateFormat
,"w") == 0)
1121 strftime(ftime
, ftimesize
, "%W-%H-%M", local
);
1126 char *fixtime(long long int elap
)
1128 int num
= elap
/ 1000;
1132 static char buf
[12];
1135 min
=(num
% 3600) / 60;
1138 if(hor
==0 && min
==0 && sec
==0)
1141 sprintf(buf
,"%d:%02d:%02d",hor
,min
,sec
);
1147 void date_from(char *date
, int *dfrom
, int *duntil
)
1156 if (isdigit(date
[0])) {
1159 if (sscanf(date
,"%d/%d/%d%n",&d0
,&m0
,&y0
,&next
)!=3 || y0
<100 || m0
<1 || m0
>12 || d0
<1 || d0
>31 || next
<0) {
1160 debuga(_("The date passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1163 if (date
[next
]=='-') {
1164 if (sscanf(date
+next
+1,"%d/%d/%d",&d1
,&m1
,&y1
)!=3 || y1
<100 || m1
<1 || m1
>12 || d1
<1 || d1
>31) {
1165 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1168 } else if (date
[next
]!='\0') {
1169 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1179 struct tm
*Date0
,Date1
;
1181 if (time(&Today
)==(time_t)-1) {
1182 debuga(_("Failed to get the current time\n"));
1185 if (sscanf(date
,"day-%d",&i
)==1) {
1187 debuga(_("Invalid number of days in -d parameter\n"));
1191 Date0
=localtime(&Today
);
1193 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1196 y0
=y1
=Date0
->tm_year
+1900;
1197 m0
=m1
=Date0
->tm_mon
+1;
1198 d0
=d1
=Date0
->tm_mday
;
1199 } else if (sscanf(date
,"week-%d",&i
)==1) {
1201 There is no portable way to find the first day of the week even though the
1202 information is available in the locale. nl_langinfo has the unofficial
1203 parameters _NL_TIME_FIRST_WEEKDAY and _NL_TIME_WEEK_1STDAY but they are
1204 undocumented as is their return value and it is discouraged to use them.
1205 Beside, nl_langinfo isn't available on windows and the first day of the
1206 week isn't available at all on that system.
1208 const int FirstWeekDay
=1;
1212 debuga(_("Invalid number of weeks in -d parameter\n"));
1215 Date0
=localtime(&Today
);
1217 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1220 WeekBegin
=Today
-((Date0
->tm_wday
-FirstWeekDay
+7)%7)*24*60*60;
1221 WeekBegin
-=i
*7*24*60*60;
1222 Date0
=localtime(&WeekBegin
);
1224 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1227 y0
=Date0
->tm_year
+1900;
1230 WeekBegin
+=6*24*60*60;
1231 Date0
=localtime(&WeekBegin
);
1233 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1236 y1
=Date0
->tm_year
+1900;
1239 } else if (sscanf(date
,"month-%d",&i
)==1) {
1241 debuga(_("Invalid number of months in -d parameter\n"));
1244 Date0
=localtime(&Today
);
1246 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1249 if (Date0
->tm_mon
<i
%12) {
1250 y0
=Date0
->tm_year
+1900-i
/12-1;
1251 m0
=(Date0
->tm_mon
+12-i
%12)%12+1;
1254 y0
=Date0
->tm_year
+1900-i
/12;
1255 m0
=Date0
->tm_mon
-i
%12+1;
1258 memcpy(&Date1
,Date0
,sizeof(struct tm
));
1263 Date1
.tm_year
=y0
-1900;
1266 Date1
.tm_year
=y0
-1900+1;
1270 Date0
=localtime(&t1
);
1271 y1
=Date0
->tm_year
+1900;
1275 debuga(_("Invalid date range passed on command line\n"));
1280 *dfrom
=y0
*10000+m0
*100+d0
;
1281 *duntil
=y1
*10000+m1
*100+d1
;
1282 sprintf(date
,"%02d/%02d/%04d-%02d/%02d/%04d",d0
,m0
,y0
,d1
,m1
,y1
);
1287 char *strlow(char *string
)
1293 for (s
= string
; *s
; ++s
)
1303 char *strup(char *string
)
1309 for (s
= string
; *s
; ++s
)
1317 void removetmp(const char *outdir
)
1324 if(!RemoveTempFiles
)
1328 debuga(_("Purging temporary file sarg-general\n"));
1330 if (snprintf(warea
,sizeof(warea
),"%s/sarg-general",outdir
)>=sizeof(warea
)) {
1331 debuga(_("(removetmp) directory too long to remove %s/sarg-period\n"),outdir
);
1334 if((fp_in
=fopen(warea
,"r+"))==NULL
){
1335 debuga(_("(removetmp) Cannot open file %s\n"),warea
);
1338 while(fgets(buf
,sizeof(buf
),fp_in
)!=NULL
) {
1339 if(strncmp(buf
,"TOTAL",5) == 0 && (buf
[6]=='\t' || buf
[6]==' '))
1342 if (fseek(fp_in
,0,SEEK_SET
)==-1) {
1343 debuga(_("Failed to rewind to the beginning of the file %s: %s\n"),warea
,strerror(errno
));
1347 if (fputs(buf
,fp_in
)==EOF
) {
1348 debuga(_("Failed to write the total line in %s - %s\n"),warea
,strerror(errno
));
1352 if (pos
>0 && ftruncate(fileno(fp_in
),pos
)==-1) {
1353 debuga(_("Failed to truncate %s: %s\n"),warea
,strerror(errno
));
1356 if (fclose(fp_in
)==EOF
) {
1357 debuga(_("Failed to close %s after writing the total line - %s\n"),warea
,strerror(errno
));
1364 void load_excludecodes(const char *ExcludeCodes
)
1373 if(ExcludeCodes
[0] == '\0')
1376 if((fp_in
=fopen(ExcludeCodes
,"r"))==NULL
) {
1377 debuga(_("(util) Cannot open file %s (exclude_codes)\n"),ExcludeCodes
);
1381 if (fseek(fp_in
, 0, SEEK_END
)==-1) {
1382 debuga(_("Failed to move till the end of the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1385 MemSize
= ftell(fp_in
);
1387 debuga(_("Cannot get the size of file %s\n"),ExcludeCodes
);
1390 if (fseek(fp_in
, 0, SEEK_SET
)==-1) {
1391 debuga(_("Failed to rewind the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1396 if((excludecode
=(char *) malloc(MemSize
))==NULL
) {
1397 debuga(_("malloc error (%ld)\n"),MemSize
);
1400 memset(excludecode
,0,MemSize
);
1403 while(fgets(data
,sizeof(data
),fp_in
)!=NULL
) {
1404 if (data
[0]=='#') continue;
1405 for (i
=strlen(data
)-1 ; i
>=0 && (unsigned char)data
[i
]<=' ' ; i
--) data
[i
]='\0';
1407 if (Stored
+i
+2>=MemSize
) {
1408 debuga(_("Too many codes to exclude in file %s\n"),ExcludeCodes
);
1411 strcat(excludecode
,data
);
1412 strcat(excludecode
,";");
1420 void free_excludecodes(void)
1428 int vercode(const char *code
)
1433 if (excludecode
&& excludecode
[0]!='\0') {
1437 if (strncmp(code
,cod
,clen
)==0 && cod
[clen
]==';')
1439 cod
=strchr(cod
,';');
1446 void fixnone(char *str
)
1450 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--);
1451 if(i
==3 && strncmp(str
,"none",4) == 0)
1457 void fixendofline(char *str
)
1461 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--) str
[i
]=0;
1464 #ifdef LEGACY_TESTVALIDUSERCHAR
1465 int testvaliduserchar(const char *user
)
1471 for (y
=0; y
<strlen(UserInvalidChar
); y
++) {
1472 for (x
=0; x
<strlen(user
); x
++) {
1473 if(user
[x
] == UserInvalidChar
[y
])
1480 int testvaliduserchar(const char *user
)
1483 char * p_UserInvalidChar
= UserInvalidChar
;
1484 const char * p_user
;
1486 while( *p_UserInvalidChar
) {
1489 if( *p_UserInvalidChar
== *p_user
)
1493 p_UserInvalidChar
++ ;
1499 int compar( const void *a
, const void *b
)
1500 { if( *(int *)a
> *(int *)b
) return 1;
1501 if( *(int *)a
< *(int *)b
) return -1;
1505 int getnumlist( char *buf
, numlist
*list
, const int len
, const int maxvalue
)
1507 int i
, j
, d
, flag
, r1
, r2
;
1508 char *pbuf
, **bp
, *strbufs
[ 24 ];
1511 strtok( buf
, " \t" );
1512 for( *bp
= strtok( NULL
, "," ), list
->len
= 0; *bp
; *bp
= strtok( NULL
, "," ) ) {
1513 if( ++bp
>= &strbufs
[ 24 ] )
1520 for( i
= 0; i
< list
->len
; i
++ ) {
1521 if( strchr( strbufs
[ i
], '-' ) != 0 ) {
1522 pbuf
= strbufs
[ i
];
1523 strtok( pbuf
, "-" );
1524 pbuf
= strtok( NULL
, "\0" );
1525 r1
= atoi( strbufs
[ i
] );
1526 if( ( r2
= atoi( pbuf
) ) >= maxvalue
|| r1
>= r2
)
1528 if( i
+ d
+ ( r2
- r1
) + 1 <= len
) {
1529 for( j
= r1
; j
<= r2
; j
++ )
1530 list
->list
[ i
+ d
++ ] = j
;
1535 if( ( list
->list
[ i
+ d
] = atoi( strbufs
[ i
] ) ) >= maxvalue
)
1539 qsort( list
->list
, list
->len
, sizeof( int ), compar
);
1542 for( i
= 0; i
< list
->len
- 1; i
++ )
1543 if( list
->list
[ i
] == list
->list
[ i
+ 1 ] ) {
1544 for( j
= i
+ 1; j
< list
->len
; j
++ )
1545 list
->list
[ j
- 1 ] = list
->list
[ j
];
1555 char *get_size(const char *path
, const char *file
)
1558 static char response
[255];
1562 if (snprintf(cmd
,sizeof(cmd
),"du -skh %s%s",path
,file
)>=sizeof(cmd
)) {
1563 debuga(_("Cannot get disk space because the path %s%s is too long\n"),path
,file
);
1566 if ((fp
= popen(cmd
, "r")) == NULL
) {
1567 debuga(_("Cannot get disk space with command %s\n"),cmd
);
1570 if (!fgets(response
, sizeof(response
), fp
)) {
1571 debuga(_("Cannot get disk size with command %s\n"),cmd
);
1574 ptr
=strchr(response
,'\t');
1576 debuga(_("The command %s failed\n"),cmd
);
1585 void show_info(FILE *fp_ou
)
1589 if(!ShowSargInfo
) return;
1590 zdate(ftime
, sizeof(ftime
), DateFormat
);
1591 fprintf(fp_ou
,"<div class=\"info\">%s <a href='%s'>%s-%s</a> %s %s</div>\n",_("Generated by"),URL
,PGM
,VERSION
,_("on"),ftime
);
1594 void show_sarg(FILE *fp_ou
, int depth
)
1598 if(!ShowSargLogo
) return;
1599 fputs("<div class=\"logo\"><a href=\"http://sarg.sourceforge.net\"><img src=\"",fp_ou
);
1600 for (i
=0 ; i
<depth
; i
++)
1602 fputs("images/sarg.png\" title=\"SARG, Squid Analysis Report Generator. Logo by Osamu Matsuzaki\" alt=\"Sarg\"></a> Squid Analysis Report Generator</div>\n",fp_ou
);
1605 void write_logo_image(FILE *fp_ou
)
1607 if(LogoImage
[0]!='\0')
1608 fprintf(fp_ou
, "<div class=\"logo\"><img src=\"%s\" width=\"%s\" height=\"%s\" alt=\"Logo\"> %s</div>\n",LogoImage
,Width
,Height
,LogoText
);
1611 void write_html_head(FILE *fp_ou
, const char *page_title
)
1613 fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n",fp_ou
);
1614 fprintf(fp_ou
, "<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n",CharSet
);
1615 if (page_title
) fprintf(fp_ou
,"<title>%s</title>\n",page_title
);
1617 fputs("</head>\n<body>\n",fp_ou
);
1620 void write_html_header(FILE *fp_ou
, int depth
, const char *page_title
)
1622 write_html_head(fp_ou
,page_title
);
1623 write_logo_image(fp_ou
);
1624 show_sarg(fp_ou
, depth
);
1625 fprintf(fp_ou
,"<div class=\"title\"><table cellpadding=\"0\" cellspacing=\"0\">\n<tr><th class=\"title_c\">%s</th></tr>\n",Title
);
1628 void close_html_header(FILE *fp_ou
)
1630 fputs("</table></div>\n",fp_ou
);
1633 int write_html_trailer(FILE *fp_ou
)
1636 if (fputs("</body>\n</html>\n",fp_ou
)==EOF
) return(-1);
1640 void output_html_string(FILE *fp_ou
,const char *str
,int maxlen
)
1644 while (*str
&& (maxlen
<=0 || i
<maxlen
)) {
1647 fputs("&",fp_ou
);
1650 fputs("<",fp_ou
);
1653 fputs(">",fp_ou
);
1656 fputs(""",fp_ou
);
1659 fputs("'",fp_ou
);
1667 if (maxlen
>0 && i
>=maxlen
)
1668 fputs("…",fp_ou
);
1671 void output_html_url(FILE *fp_ou
,const char *url
)
1675 fputs("&",fp_ou
);
1682 void url_hostname(const char *url
,char *hostname
,int hostsize
)
1687 for (i
=0 ; i
<hostsize
&& url
[i
] && url
[i
]!='/' ; i
++)
1692 void url_module(const char *url
, char *w2
)
1698 for(x
=strlen(url
)-1; x
>=0; x
--) {
1699 if(url
[x
] == '/' || y
>=sizeof(w
)-1) break;
1708 for(y
=y
-1; y
>=0; y
--) {
1714 void url_to_file(const char *url
,char *file
,int filesize
)
1720 for(i
=0; i
<filesize
&& *url
; url
++) {
1721 if(isalnum(*url
) || *url
=='-' || *url
=='_' || *url
=='.' || *url
=='%') {
1725 if (!skip
) file
[i
++]='_';
1734 printf(_("SARG Version: %s\n"),VERSION
);
1738 char *get_param_value(const char *param
,char *line
)
1742 while (*line
==' ' || *line
=='\t') line
++;
1744 if (strncasecmp(line
,param
,plen
)) return(NULL
);
1745 if (line
[plen
]!=' ' && line
[plen
]!='\t') return(NULL
);
1747 while (*line
==' ' || *line
=='\t') line
++;
1751 void unlinkdir(const char *dir
,int contentonly
)
1755 struct dirent
*direntp
;
1761 while ((direntp
= readdir(dirp
)) != NULL
) {
1762 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
1763 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
1765 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
1766 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
1770 err
=lstat(dname
,&st
);
1772 err
=stat(dname
,&st
);
1775 debuga(_("cannot stat %s\n"),dname
);
1778 if (S_ISREG(st
.st_mode
)) {
1779 if (unlink(dname
)) {
1780 debuga(_("cannot delete %s - %s\n"),dname
,strerror(errno
));
1783 } else if (S_ISDIR(st
.st_mode
)) {
1786 debuga(_("unknown path type %s\n"),dname
);
1793 debuga(_("cannot delete %s - %s\n"),dir
,strerror(errno
));