]>
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 #if USE_GETWORD_BACKTRACE
45 static void getword_backtrace(void)
51 n
=backtrace(buffer
,sizeof(buffer
)/sizeof(buffer
[0]));
53 calls
=backtrace_symbols(buffer
,n
);
55 debuga(_("getword backtrace:\n"));
56 for (i
=0 ; i
<n
; i
++) {
57 fprintf(stderr
,"SARG: %d:%s\n",i
+1,calls
[i
]);
62 #endif //USE_GETWORD_BACKTRACE
64 void getword_start(struct getwordstruct
*gwarea
, const char *line
)
66 gwarea
->beginning
=line
;
71 void getword_restart(struct getwordstruct
*gwarea
)
73 if (gwarea
->modified
) {
74 debuga(_("Cannot parse again the line as it was modified\n"));
77 gwarea
->current
=gwarea
->beginning
;
80 int getword(char *word
, int limit
, struct getwordstruct
*gwarea
, char stop
)
84 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++) {
86 printf("SARG: getword loop detected after %d bytes.\n",x
);
87 printf("SARG: Line=\"%s\"\n",gwarea
->beginning
);
88 printf("SARG: Record=\"%s\"\n",gwarea
->current
);
89 printf("SARG: searching for \'x%x\'\n",stop
);
90 //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
91 word
[(limit
>0) ? limit
-1 : 0]='\0';
92 #if USE_GETWORD_BACKTRACE
97 word
[x
] = gwarea
->current
[x
];
101 if (gwarea
->current
[x
]) ++x
;
106 int getword_limit(char *word
, int limit
, struct getwordstruct
*gwarea
, char stop
)
111 for(x
=0; x
<limit
&& gwarea
->current
[x
] && gwarea
->current
[x
] != stop
;x
++) {
112 word
[x
] = gwarea
->current
[x
];
116 while (*gwarea
->current
&& *gwarea
->current
!= stop
) gwarea
->current
++;
117 if (*gwarea
->current
) ++gwarea
->current
;
121 int getword_multisep(char *word
, int limit
, struct getwordstruct
*gwarea
, char stop
)
125 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++) {
127 printf("SARG: getword_multisep loop detected.\n");
128 printf("SARG: Line=\"%s\"\n",gwarea
->beginning
);
129 printf("SARG: Record=\"%s\"\n",gwarea
->current
);
130 printf("SARG: searching for \'x%x\'\n",stop
);
131 //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
132 if (limit
>0) word
[limit
-1]='\0';
133 #if USE_GETWORD_BACKTRACE
136 //exit(EXIT_FAILURE);
139 word
[x
] = gwarea
->current
[x
];
143 while (gwarea
->current
[x
] && gwarea
->current
[x
]==stop
) ++x
;
148 int getword_skip(int limit
, struct getwordstruct
*gwarea
, char stop
)
152 for(x
=0;(gwarea
->current
[x
] && (gwarea
->current
[x
] != stop
));x
++) {
154 printf("SARG: getword_skip loop detected after %d bytes.\n",x
);
155 printf("SARG: Line=\"%s\"\n",gwarea
->beginning
);
156 printf("SARG: Record=\"%s\"\n",gwarea
->current
);
157 printf("SARG: searching for \'x%x\'\n",stop
);
158 //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
159 #if USE_GETWORD_BACKTRACE
166 if (gwarea
->current
[x
]) ++x
;
171 int getword_atoll(long long int *number
, struct getwordstruct
*gwarea
, char stop
)
176 if (gwarea
->current
[0] == '-') {
179 } else if (gwarea
->current
[0] == '+') {
183 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
184 *number
=(*number
* 10) + gwarea
->current
[x
]-'0';
186 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
187 printf("SARG: getword_atoll loop detected after %d bytes.\n",x
);
188 printf("SARG: Line=\"%s\"\n",gwarea
->beginning
);
189 printf("SARG: Record=\"%s\"\n",gwarea
->current
);
190 printf("SARG: searching for \'x%x\'\n",stop
);
191 //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
192 #if USE_GETWORD_BACKTRACE
199 if (gwarea
->current
[x
]) ++x
;
205 int getword_ptr(char *orig_line
,char **word
, struct getwordstruct
*gwarea
, char stop
)
208 \note Why pass the original buffer to the function ? Because we must modify it to
209 insert the terminating ASCII zero for the word we return and that's not compatible
210 with getword_restart(). Moreover, getword_start() sometime works on constant strings
211 so this function require the original buffer to detect any missuse.
217 if (orig_line
&& orig_line
!=gwarea
->beginning
) {
218 debuga(_("Invalid buffer passed to getword_ptr\n"));
222 start
=(gwarea
->current
-gwarea
->beginning
);
223 if (word
&& orig_line
) *word
=orig_line
+start
;
224 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++);
225 sep
=(gwarea
->current
[x
]!='\0');
226 if (word
&& orig_line
) orig_line
[start
+x
] = '\0';
233 #define MAXLLL 30 //!< Maximum number of digits in long long (a guess).
234 long long int my_atoll (const char *nptr
)
236 long long int returnval
=0LL;
237 int max_digits
= MAXLLL
;
239 // Soak up all the white space
240 while (isspace( *nptr
)) {
244 //For each character left to right
245 //change the character to a single digit
246 //multiply what we had before by 10 and add the new digit
248 while (--max_digits
&& isdigit( *nptr
))
250 returnval
= ( returnval
* 10 ) + ( *nptr
++ - '0' ) ;
256 int is_absolute(const char *path
)
258 if (*path
=='/') return(1);
260 if (isalpha(path
[0]) && path
[1]==':') return(1);
265 void my_mkdir(const char *name
)
271 if(!is_absolute(name
)) {
272 debuga(_("Invalid path (%s). Please, use absolute paths only.\n"),name
);
273 debuga(_("process aborted.\n"));
278 for (i
=0 ; name
[i
] ; i
++) {
280 debuga(_("directory name too long: %s\n"),name
);
283 if (chars
>0 && name
[i
] == '/') {
285 if (access(w0
, R_OK
) != 0) {
286 if (mkdir(w0
,0755)) {
287 debuga(_("Cannot create directory %s - %s\n"),w0
,strerror(errno
));
288 debuga(_("process aborted.\n"));
293 if (name
[i
] != '/') chars
++;
297 if (access(name
, R_OK
) != 0) {
298 if (mkdir(name
,0755)) {
299 debuga(_("Cannot create directory %s - %s\n"),name
,strerror(errno
));
300 debuga(_("process aborted.\n"));
307 void my_lltoa(unsigned long long int n
, char *s
, int ssize
, int len
)
316 debuga(_("The requested number of digits passed to my_lltoa (%d) is bigger than the output buffer size (%d)\n"),len
,ssize
);
321 s
[slen
++] = (n
% 10) + '0';
322 } while ((n
/= 10) > 0 && slen
<ssize
);
325 for (i
= 0, j
= slen
-1; i
<j
; i
++, j
--) {
333 for(j
=slen
; j
>=0; j
--)
340 int month2num(const char *month
)
344 for(m
=0 ; m
<12 && strcmp(mtab1
[m
],month
) != 0; m
++);
348 int builddia(int day
, int month
, int year
)
350 return(year
*10000+month
*100+day
);
354 void buildymd(const char *dia
, const char *mes
, const char *ano
, char *wdata
)
359 sprintf(wdata
,"%04d%02d%02d",atoi(ano
),nmes
+1,atoi(dia
));
363 int conv_month(const char *month
)
367 for(x
=0; x
<12 && strncmp(mtab1
[x
],month
,3)!=0; x
++);
372 const char *conv_month_name(int month
)
376 if (month
<1 || month
>12) {
377 snprintf(str
,sizeof(str
),"%03d",month
);
380 return(mtab1
[month
-1]);
384 void name_month(char *month
,int month_len
)
386 int x
, z
=atoi(month
)-1;
389 struct getwordstruct gwarea
;
391 strcpy(m
,_("January,February,March,April,May,June,July,August,September,October,November,December"));
392 getword_start(&gwarea
,m
);
395 if (getword_multisep(w
,sizeof(w
),&gwarea
,',')<0) {
396 printf("SARG: Maybe you have a broken record or garbage in the names of the months.\n");
399 if (getword_multisep(month
,month_len
,&gwarea
,',')<0) {
400 printf("SARG: Maybe you have a broken record or garbage in the name of the months.\n");
406 void debuga(const char *msg
,...)
410 fputs(_("SARG: "),stderr
);
412 vfprintf(stderr
,msg
,ap
);
417 void debugaz(const char *head
, const char *msg
)
419 fprintf(stderr
, "SARG: (util) %s=%s\n",head
, msg
);
423 char *fixnum(long long int value
, int n
)
425 #define MAXLEN_FIXNUM 256
426 char num
[MAXLEN_FIXNUM
]="";
427 char buf
[MAXLEN_FIXNUM
* 2];
429 static char ret
[MAXLEN_FIXNUM
* 2];
431 register int i
, j
, k
;
433 static char abbrev
[30];
435 my_lltoa(value
, num
, sizeof(num
), 0);
437 if(DisplayedValues
==DISPLAY_ABBREV
) {
438 numlen
= strlen(num
);
440 sprintf(abbrev
,"%s",num
);
441 if(numlen
== 4 || numlen
== 7 || numlen
== 10 || numlen
== 13) {
442 snprintf(abbrev
,2,"%s",num
);
443 strncat(abbrev
,".",1);
444 strncat(abbrev
,num
+1,2);
445 if(!n
) return(abbrev
);
447 strncat(abbrev
,"K",1);
449 strncat(abbrev
,"M",1);
450 else if(numlen
== 10)
451 strncat(abbrev
,"G",1);
452 else if(numlen
== 13)
453 strncat(abbrev
,"T",1);
455 if(numlen
== 5 || numlen
== 8 || numlen
== 11 || numlen
== 14) {
456 snprintf(abbrev
,3,"%s",num
);
457 strncat(abbrev
,".",1);
458 strncat(abbrev
,num
+2,2);
459 if(!n
) return(abbrev
);
461 strncat(abbrev
,"K",1);
463 strncat(abbrev
,"M",1);
464 else if(numlen
== 11)
465 strncat(abbrev
,"G",1);
466 else if(numlen
== 14)
467 strncat(abbrev
,"T",1);
469 if(numlen
== 6 || numlen
== 9 || numlen
== 12 || numlen
== 15) {
470 snprintf(abbrev
,4,"%s",num
);
471 strncat(abbrev
,".",1);
472 strncat(abbrev
,num
+3,2);
473 if(!n
) return(abbrev
);
475 strncat(abbrev
,"K",1);
477 strncat(abbrev
,"M",1);
478 else if(numlen
== 12)
479 strncat(abbrev
,"G",1);
480 else if(numlen
== 15)
481 strncat(abbrev
,"T",1);
487 bzero(buf
, MAXLEN_FIXNUM
*2);
493 for ( i
= strlen(num
) - 1, j
= 0 ; i
> -1; i
--) {
494 if ( k
== 2 && i
!= 0 ) {
497 pbuf
[j
++] = (UseComma
) ? ',' : '.';
507 for ( i
= strlen(pbuf
) - 1, j
= 0 ; i
> -1; i
--, j
++)
516 char *fixnum2(long long int value
, int n
)
518 #define MAXLEN_FIXNUM2 1024
519 char num
[MAXLEN_FIXNUM2
];
520 char buf
[MAXLEN_FIXNUM2
* 2];
522 static char ret
[MAXLEN_FIXNUM2
* 2];
524 register int i
, j
, k
;
526 my_lltoa(value
, num
, sizeof(num
), 0);
527 bzero(buf
, MAXLEN_FIXNUM2
*2);
533 for ( i
= strlen(num
) - 1, j
= 0 ; i
> -1; i
--) {
534 if ( k
== 2 && i
!= 0 ) {
537 pbuf
[j
++] = (UseComma
) ? ',' : '.';
547 for ( i
= strlen(pbuf
) - 1, j
= 0 ; i
> -1; i
--, j
++)
556 char *buildtime(long long int elap
)
558 int num
= elap
/ 1000;
567 min
=(num
% 3600) / 60;
569 sprintf(buf
,"%02d:%02d:%02d",hor
,min
,sec
);
576 Get the date stored in the <tt>sarg-date</tt> file of a directory with the connection data.
578 \param dirname The directory to look for the connection directory.
579 \param name The name of the directory whose <tt>sarg-date</tt> file must be read.
580 \param data The buffer to store the content of the file. It must be more than 80
584 \retval -1 File not found.
586 int obtdate(const char *dirname
, const char *name
, char *data
)
591 sprintf(wdir
,"%s%s/sarg-date",dirname
,name
);
592 if ((fp_in
= fopen(wdir
, "rt")) == 0) {
593 sprintf(wdir
,"%s%s/date",dirname
,name
);
594 if ((fp_in
= fopen(wdir
, "rt")) == 0) {
600 if (!fgets(data
,80,fp_in
)) {
601 debuga(_("Failed to read the date in %s\n"),wdir
);
611 void formatdate(char *date
,int date_size
,int year
,int month
,int day
,int hour
,int minute
,int second
,int dst
)
617 memset(<m
,0,sizeof(ltm
));
618 if (year
>=1900) ltm
.tm_year
=year
-1900;
619 if (month
>=1 && month
<=12) ltm
.tm_mon
=month
-1;
620 if (day
>=1 && day
<=31) ltm
.tm_mday
=day
;
621 if (hour
>=0 && hour
<24) ltm
.tm_hour
=hour
;
622 if (minute
>=0 && minute
<60) ltm
.tm_min
=minute
;
623 if (second
>=0 && second
<60) ltm
.tm_sec
=second
;
625 unixtime
=mktime(<m
); //fill the missing entries
626 fulltm
=localtime(&unixtime
);
627 //strftime(date,date_size,"%a %b %d %H:%M:%S %Z %Y",fulltm);
628 strftime(date
,date_size
,"%c",fulltm
);
632 void computedate(int year
,int month
,int day
,struct tm
*t
)
634 memset(t
,0,sizeof(*t
));
635 t
->tm_year
=year
-1900;
641 int obtuser(const char *dirname
, const char *name
)
648 sprintf(wdir
,"%s%s/sarg-users",dirname
,name
);
649 if((fp_in
=fopen(wdir
,"r"))==NULL
) {
650 sprintf(wdir
,"%s%s/users",dirname
,name
);
651 if((fp_in
=fopen(wdir
,"r"))==NULL
) {
656 if (!fgets(tuser
,sizeof(tuser
),fp_in
)) {
657 debuga(_("Failed to read the number of users in %s\n"),wdir
);
667 void obttotal(const char *dirname
, const char *name
, int nuser
, long long int *tbytes
, long long int *media
)
672 char user
[MAX_USER_LEN
];
674 struct getwordstruct gwarea
;
680 sprintf(wdir
,"%s%s/sarg-general",dirname
,name
);
681 if ((fp_in
= fopen(wdir
, "r")) == 0) {
682 sprintf(wdir
,"%s%s/general",dirname
,name
);
683 if ((fp_in
= fopen(wdir
, "r")) == 0) {
688 if ((line
=longline_create())==NULL
) {
689 debuga(_("Not enough memory to read the file %s\n"),wdir
);
693 while((buf
=longline_read(fp_in
,line
))!=NULL
) {
694 if (strncmp(buf
,"TOTAL\t",6) == 0)
696 else if (strncmp(buf
,"TOTAL ",6) == 0)
700 getword_start(&gwarea
,buf
);
701 if (getword(user
,sizeof(user
),&gwarea
,sep
)<0) {
702 debuga(_("There is a invalid user in file %s\n"),wdir
);
705 if(strcmp(user
,"TOTAL") != 0)
707 if (getword_skip(MAXLEN
,&gwarea
,sep
)<0) {
708 debuga(_("There a broken total number of access in file %s\n"),wdir
);
711 if (getword_atoll(tbytes
,&gwarea
,sep
)<0) {
712 debuga(_("There is a broken number of bytes in file %s\n"),wdir
);
718 longline_destroy(&line
);
723 *media
=*tbytes
/ nuser
;
727 int getperiod_fromsarglog(const char *arqtt
,struct periodstruct
*period
)
730 int day0
, month0
, year0
, hour0
, minute0
;
731 int day1
, month1
, year1
, hour1
, minute1
;
734 memset(period
,0,sizeof(*period
));
737 while((str
=strstr(str
,"sarg-"))!=NULL
) {
739 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
740 day0
=(str
[0]-'0')*10+(str
[1]-'0');
741 if (day0
<1 || day0
>31) continue;
743 month0
=(str
[0]-'0')*10+(str
[1]-'0')-1;
744 if (month0
<0 || month0
>11) continue;
747 for (i
=0 ; isdigit(str
[i
]) && i
<4 ; i
++) year0
=year0
*10+(str
[i
]-'0');
750 if (str
[0]!='_') continue;
753 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
754 hour0
=(str
[0]-'0')*10+(str
[1]-'0');
756 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
757 minute0
=(str
[0]-'0')*10+(str
[1]-'0');
760 if (*str
!= '-') continue;
763 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
764 day1
=(str
[0]-'0')*10+(str
[1]-'0');
765 if (day1
<1 || day1
>31) continue;
767 month1
=(str
[0]-'0')*10+(str
[1]-'0')-1;
768 if (month1
<0 || month1
>11) continue;
771 for (i
=0 ; isdigit(str
[i
]) && i
<4 ; i
++) year1
=year1
*10+(str
[i
]-'0');
775 if (str
[0]!='_') continue;
778 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
779 hour1
=(str
[0]-'0')*10+(str
[1]-'0');
781 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
782 minute1
=(str
[0]-'0')*10+(str
[1]-'0');
785 period
->start
.tm_mday
=day0
;
786 period
->start
.tm_mon
=month0
;
787 period
->start
.tm_year
=year0
-1900;
788 period
->start
.tm_hour
=hour0
;
789 period
->start
.tm_min
=minute0
;
790 period
->end
.tm_mday
=day1
;
791 period
->end
.tm_mon
=month1
;
792 period
->end
.tm_year
=year1
-1900;
793 period
->end
.tm_hour
=hour1
;
794 period
->end
.tm_min
=minute1
;
800 void getperiod_fromrange(struct periodstruct
*period
,int dfrom
,int duntil
)
802 memset(&period
->start
,0,sizeof(period
->start
));
803 period
->start
.tm_mday
=dfrom
%100;
804 period
->start
.tm_mon
=(dfrom
/100)%100-1;
805 period
->start
.tm_year
=(dfrom
/10000)-1900;
807 memset(&period
->end
,0,sizeof(period
->end
));
808 period
->end
.tm_mday
=duntil
%100;
809 period
->end
.tm_mon
=(duntil
/100)%100-1;
810 period
->end
.tm_year
=(duntil
/10000)-1900;
813 int getperiod_buildtext(struct periodstruct
*period
)
817 char text1
[40], text2
[40];
820 i
=strftime(text1
, sizeof(text1
), "%Y %b %d", &period
->start
);
821 }else if(df
[0]=='e') {
822 i
=strftime(text1
, sizeof(text1
), "%d %b %Y", &period
->start
);
823 } else /*if(df[0]=='w')*/ {
824 IndexTree
=INDEX_TREE_FILE
;
825 i
=strftime(text1
, sizeof(text1
), "%Y.%U", &period
->start
);
827 if (i
== 0) return(-1);
829 range
=(period
->start
.tm_year
!=period
->end
.tm_year
||
830 period
->start
.tm_mon
!=period
->end
.tm_mon
||
831 period
->start
.tm_mday
!=period
->end
.tm_mday
);
834 i
=strftime(text2
, sizeof(text2
)-i
, "%Y %b %d", &period
->end
);
835 } else if(df
[0]=='e') {
836 i
=strftime(text2
, sizeof(text2
)-i
, "%d %b %Y", &period
->end
);
838 i
=strftime(text2
, sizeof(text2
)-i
, "%Y.%U", &period
->end
);
840 if (i
== 0) return(-1);
844 snprintf(period
->text
,sizeof(period
->text
),"%s-%s",text1
,text2
);
845 snprintf(period
->html
,sizeof(period
->html
),"%s—%s",text1
,text2
);
847 strncpy(period
->text
,text1
,sizeof(period
->text
)-1);
848 period
->text
[sizeof(period
->text
)-1]='\0';
849 strncpy(period
->html
,text1
,sizeof(period
->html
)-1);
850 period
->html
[sizeof(period
->html
)-1]='\0';
855 static void copy_images(void)
857 FILE *img_in
, *img_ou
;
860 char srcfile
[MAXLEN
];
861 char dstfile
[MAXLEN
];
863 struct dirent
*direntp
;
868 if (snprintf(images
,sizeof(images
),"%simages",outdir
)>=sizeof(images
)) {
869 debuga(_("Cannot copy images to target directory %simages\n"),outdir
);
872 if (access(images
,R_OK
)!=0) {
873 if (mkdir(images
,0755)) {
874 debuga(_("Cannot create directory %s - %s\n"),images
,strerror(errno
));
879 strcpy(imgdir
,IMAGEDIR
);
880 dirp
= opendir(imgdir
);
882 debuga(_("(util) Can't open directory %s: %s\n"),imgdir
,strerror(errno
));
885 while ((direntp
= readdir( dirp
)) != NULL
){
886 if(direntp
->d_name
[0]=='.')
888 sprintf(srcfile
,"%s/%s",imgdir
,direntp
->d_name
);
889 if (stat(srcfile
,&info
)) {
890 debuga(_("Cannot stat \"%s\" - %s\n"),srcfile
,strerror(errno
));
893 if (S_ISREG(info
.st_mode
)) {
894 sprintf(dstfile
,"%s/%s",images
,direntp
->d_name
);
895 img_in
= fopen(srcfile
, "rb");
897 img_ou
= fopen(dstfile
, "wb");
899 while ((nread
= fread(buffer
,1,sizeof(buffer
),img_in
))>0) {
900 if (fwrite(buffer
,1,nread
,img_ou
)!=nread
) {
901 debuga(_("Failed to copy image %s to %s\n"),srcfile
,dstfile
);
907 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open/create file", dstfile
, strerror(errno
));
910 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open file", srcfile
, strerror(errno
));
913 (void) closedir(dirp
);
918 int vrfydir(const struct periodstruct
*per1
, const char *addr
, const char *site
, const char *us
, const char *form
)
923 char dirname2
[MAXLEN
];
933 y1
=per1
->start
.tm_year
+1900;
934 y2
=per1
->end
.tm_year
+1900;
935 m1
=per1
->start
.tm_mon
+1;
936 m2
=per1
->end
.tm_mon
+1;
937 d1
=per1
->start
.tm_mday
;
938 d2
=per1
->end
.tm_mday
;
939 if(IndexTree
== INDEX_TREE_DATE
) {
940 wlen
+=sprintf(wdir
+wlen
,"%04d",y1
);
941 if(y1
!=y2
) wlen
+=sprintf(wdir
+wlen
,"-%04d",y2
);
942 if(access(wdir
, R_OK
) != 0)
945 wlen
+=sprintf(wdir
+wlen
,"/%02d",m1
);
946 if(m1
!= m2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",m2
);
947 if(access(wdir
, R_OK
) != 0)
950 wlen
+=sprintf(wdir
+wlen
,"/%02d",d1
);
951 if(d1
!=d2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",d2
);
954 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%04d%s%02d-%04d%s%02d",y1
,
955 conv_month_name(m1
),d1
,y2
,conv_month_name(m2
),d2
);
956 } else if(df
[0] == 'e') {
957 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%02d%s%04d-%02d%s%04d",d1
,
958 conv_month_name(m1
),y1
,d2
,conv_month_name(m2
),y2
);
959 } else if(df
[0] == 'w') {
960 wlen2
=strftime(wdir
+wlen
, sizeof(wdir
)-wlen
, "%Y.%U", &per1
->start
);
961 if (wlen2
==0) return(-1);
967 struct userinfostruct
*uinfo
=userinfo_find_from_id(us
);
970 strcat(wdir
,uinfo
->filename
);
973 if(addr
[0] != '\0') {
977 if(site
[0] != '\0') {
982 strcpy(outdirname
,wdir
);
984 if(IndexTree
!= INDEX_TREE_DATE
) {
985 if(!OverwriteReport
) {
987 if(access(wdir
,R_OK
) == 0) {
988 sprintf(wdir
,"%s.%d",outdirname
,num
);
997 debuga(_("File %s already exists, moved to %s\n"),outdirname
,wdir
);
998 rename(outdirname
,wdir
);
1001 if(access(outdirname
,R_OK
) == 0) {
1002 unlinkdir(outdirname
,1);
1005 my_mkdir(outdirname
);
1007 strcpy(dirname2
,wdir
);
1008 if(!OverwriteReport
) {
1010 if(access(wdir
,R_OK
) == 0) {
1011 sprintf(wdir
,"%s.%d",dirname2
,num
);
1020 debuga(_("File %s already exists, moved to %s\n"),dirname2
,wdir
);
1021 rename(dirname2
,wdir
);
1022 strcpy(dirname2
,wdir
);
1025 if(access(wdir
,R_OK
) == 0) {
1030 if(access(wdir
, R_OK
) != 0)
1034 strcpy(dirname2
,wdir
);
1036 sprintf(wdir
,"%s/sarg-date",outdirname
);
1037 if ((fp_ou
= fopen(wdir
, "wt")) == 0) {
1038 debuga(_("cannot open %s for writing\n"),wdir
);
1043 //strftime(wdir,sizeof(wdir),"%a %b %d %H:%M:%S %Z %Y",localtime(&curtime));
1044 loctm
=localtime(&curtime
);
1045 strftime(wdir
,sizeof(wdir
),"%Y-%m-%d %H:%M:%S",loctm
);
1046 if (fprintf(fp_ou
,"%s %d\n",wdir
,loctm
->tm_isdst
)<0) {
1047 debuga(_("Failed to write the date in %s\n"),wdir
);
1051 if (fclose(fp_ou
)==EOF
) {
1052 debuga(_("Failed to write the date in %s\n"),wdir
);
1061 void strip_latin(char *line
)
1068 for (i
=0;line
[i
];i
++){
1070 if (line
[i
]==';') skip
=0;
1082 void zdate(char *ftime
,int ftimesize
, const char *DateFormat
)
1088 local
= localtime(&t
);
1089 if(strcmp(DateFormat
,"u") == 0)
1090 strftime(ftime
, ftimesize
, "%b/%d/%Y %H:%M", local
);
1091 if(strcmp(DateFormat
,"e") == 0)
1092 strftime(ftime
, ftimesize
, "%d/%b/%Y-%H:%M", local
);
1093 if(strcmp(DateFormat
,"w") == 0)
1094 strftime(ftime
, ftimesize
, "%W-%H-%M", local
);
1099 char *fixtime(long long int elap
)
1101 int num
= elap
/ 1000;
1105 static char buf
[12];
1108 min
=(num
% 3600) / 60;
1111 if(hor
==0 && min
==0 && sec
==0)
1114 sprintf(buf
,"%d:%02d:%02d",hor
,min
,sec
);
1120 void date_from(char *date
, int *dfrom
, int *duntil
)
1129 if (isdigit(date
[0])) {
1132 if (sscanf(date
,"%d/%d/%d%n",&d0
,&m0
,&y0
,&next
)!=3 || y0
<100 || m0
<1 || m0
>12 || d0
<1 || d0
>31 || next
<0) {
1133 debuga(_("The date passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1136 if (date
[next
]=='-') {
1137 if (sscanf(date
+next
+1,"%d/%d/%d",&d1
,&m1
,&y1
)!=3 || y1
<100 || m1
<1 || m1
>12 || d1
<1 || d1
>31) {
1138 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1141 } else if (date
[next
]!='\0') {
1142 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1152 struct tm
*Date0
,Date1
;
1154 if (time(&Today
)==(time_t)-1) {
1155 debuga(_("Failed to get the current time\n"));
1158 if (sscanf(date
,"day-%d",&i
)==1) {
1160 debuga(_("Invalid number of days in -d parameter\n"));
1164 Date0
=localtime(&Today
);
1166 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1169 y0
=y1
=Date0
->tm_year
+1900;
1170 m0
=m1
=Date0
->tm_mon
+1;
1171 d0
=d1
=Date0
->tm_mday
;
1172 } else if (sscanf(date
,"week-%d",&i
)==1) {
1174 There is no portable way to find the first day of the week even though the
1175 information is available in the locale. nl_langinfo has the unofficial
1176 parameters _NL_TIME_FIRST_WEEKDAY and _NL_TIME_WEEK_1STDAY but they are
1177 undocumented as is their return value and it is discouraged to use them.
1178 Beside, nl_langinfo isn't available on windows and the first day of the
1179 week isn't available at all on that system.
1181 const int FirstWeekDay
=1;
1185 debuga(_("Invalid number of weeks in -d parameter\n"));
1188 Date0
=localtime(&Today
);
1190 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1193 WeekBegin
=Today
-((Date0
->tm_wday
-FirstWeekDay
+7)%7)*24*60*60;
1194 WeekBegin
-=i
*7*24*60*60;
1195 Date0
=localtime(&WeekBegin
);
1197 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1200 y0
=Date0
->tm_year
+1900;
1203 WeekBegin
+=6*24*60*60;
1204 Date0
=localtime(&WeekBegin
);
1206 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1209 y1
=Date0
->tm_year
+1900;
1212 } else if (sscanf(date
,"month-%d",&i
)==1) {
1214 debuga(_("Invalid number of months in -d parameter\n"));
1217 Date0
=localtime(&Today
);
1219 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1222 if (Date0
->tm_mon
<i
%12) {
1223 y0
=Date0
->tm_year
+1900-i
/12-1;
1224 m0
=(Date0
->tm_mon
+12-i
%12)%12+1;
1227 y0
=Date0
->tm_year
+1900-i
/12;
1228 m0
=Date0
->tm_mon
-i
%12+1;
1231 memcpy(&Date1
,Date0
,sizeof(struct tm
));
1236 Date1
.tm_year
=y0
-1900;
1239 Date1
.tm_year
=y0
-1900+1;
1243 Date0
=localtime(&t1
);
1244 y1
=Date0
->tm_year
+1900;
1248 debuga(_("Invalid date range passed on command line\n"));
1253 *dfrom
=y0
*10000+m0
*100+d0
;
1254 *duntil
=y1
*10000+m1
*100+d1
;
1255 sprintf(date
,"%02d/%02d/%04d-%02d/%02d/%04d",d0
,m0
,y0
,d1
,m1
,y1
);
1260 char *strlow(char *string
)
1266 for (s
= string
; *s
; ++s
)
1276 char *strup(char *string
)
1282 for (s
= string
; *s
; ++s
)
1290 void removetmp(const char *outdir
)
1295 if(!RemoveTempFiles
)
1299 debuga(_("Purging temporary file sarg-general\n"));
1301 if (snprintf(filename
,sizeof(filename
),"%s/sarg-general",outdir
)>=sizeof(filename
)) {
1302 debuga(_("(removetmp) directory too long to remove %s/sarg-period\n"),outdir
);
1305 if((fp_gen
=fopen(filename
,"w"))==NULL
){
1306 debuga(_("(removetmp) Cannot open file %s\n"),filename
);
1309 totalger(fp_gen
,filename
);
1310 if (fclose(fp_gen
)==EOF
) {
1311 debuga(_("Failed to close %s after writing the total line - %s\n"),filename
,strerror(errno
));
1316 void load_excludecodes(const char *ExcludeCodes
)
1324 if(ExcludeCodes
[0] == '\0')
1327 if((fp_in
=fopen(ExcludeCodes
,"r"))==NULL
) {
1328 debuga(_("(util) Cannot open file %s (exclude_codes)\n"),ExcludeCodes
);
1332 if (fseek(fp_in
, 0, SEEK_END
)==-1) {
1333 debuga(_("Failed to move till the end of the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1336 MemSize
= ftell(fp_in
);
1338 debuga(_("Cannot get the size of file %s\n"),ExcludeCodes
);
1341 if (fseek(fp_in
, 0, SEEK_SET
)==-1) {
1342 debuga(_("Failed to rewind the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1347 if((excludecode
=(char *) malloc(MemSize
))==NULL
) {
1348 debuga(_("malloc error (%ld)\n"),MemSize
);
1351 memset(excludecode
,0,MemSize
);
1354 while(fgets(data
,sizeof(data
),fp_in
)!=NULL
) {
1355 if (data
[0]=='#') continue;
1356 for (i
=strlen(data
)-1 ; i
>=0 && (unsigned char)data
[i
]<=' ' ; i
--) data
[i
]='\0';
1358 if (Stored
+i
+2>=MemSize
) {
1359 debuga(_("Too many codes to exclude in file %s\n"),ExcludeCodes
);
1362 strcat(excludecode
,data
);
1363 strcat(excludecode
,";");
1371 void free_excludecodes(void)
1379 int vercode(const char *code
)
1384 if (excludecode
&& excludecode
[0]!='\0') {
1388 if (strncmp(code
,cod
,clen
)==0 && cod
[clen
]==';')
1390 cod
=strchr(cod
,';');
1397 void fixnone(char *str
)
1401 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--);
1402 if(i
==3 && strncmp(str
,"none",4) == 0)
1408 void fixendofline(char *str
)
1412 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--) str
[i
]=0;
1415 #ifdef LEGACY_TESTVALIDUSERCHAR
1416 int testvaliduserchar(const char *user
)
1421 for (y
=0; y
<strlen(UserInvalidChar
); y
++) {
1422 for (x
=0; x
<strlen(user
); x
++) {
1423 if(user
[x
] == UserInvalidChar
[y
])
1430 int testvaliduserchar(const char *user
)
1432 char * p_UserInvalidChar
= UserInvalidChar
;
1433 const char * p_user
;
1435 while( *p_UserInvalidChar
) {
1438 if( *p_UserInvalidChar
== *p_user
)
1442 p_UserInvalidChar
++ ;
1448 int compar( const void *a
, const void *b
)
1450 if( *(int *)a
> *(int *)b
) return 1;
1451 if( *(int *)a
< *(int *)b
) return -1;
1455 int getnumlist( char *buf
, numlist
*list
, const int len
, const int maxvalue
)
1457 int i
, j
, d
, flag
, r1
, r2
;
1458 char *pbuf
, **bp
, *strbufs
[ 24 ];
1461 strtok( buf
, " \t" );
1462 for( *bp
= strtok( NULL
, "," ), list
->len
= 0; *bp
; *bp
= strtok( NULL
, "," ) ) {
1463 if( ++bp
>= &strbufs
[ 24 ] )
1470 for( i
= 0; i
< list
->len
; i
++ ) {
1471 if( strchr( strbufs
[ i
], '-' ) != 0 ) {
1472 pbuf
= strbufs
[ i
];
1473 strtok( pbuf
, "-" );
1474 pbuf
= strtok( NULL
, "\0" );
1475 r1
= atoi( strbufs
[ i
] );
1476 if( ( r2
= atoi( pbuf
) ) >= maxvalue
|| r1
>= r2
)
1478 if( i
+ d
+ ( r2
- r1
) + 1 <= len
) {
1479 for( j
= r1
; j
<= r2
; j
++ )
1480 list
->list
[ i
+ d
++ ] = j
;
1485 if( ( list
->list
[ i
+ d
] = atoi( strbufs
[ i
] ) ) >= maxvalue
)
1489 qsort( list
->list
, list
->len
, sizeof( int ), compar
);
1492 for( i
= 0; i
< list
->len
- 1; i
++ )
1493 if( list
->list
[ i
] == list
->list
[ i
+ 1 ] ) {
1494 for( j
= i
+ 1; j
< list
->len
; j
++ )
1495 list
->list
[ j
- 1 ] = list
->list
[ j
];
1505 char *get_size(const char *path
, const char *file
)
1508 static char response
[255];
1512 if (snprintf(cmd
,sizeof(cmd
),"du -skh %s%s",path
,file
)>=sizeof(cmd
)) {
1513 debuga(_("Cannot get disk space because the path %s%s is too long\n"),path
,file
);
1516 if ((fp
= popen(cmd
, "r")) == NULL
) {
1517 debuga(_("Cannot get disk space with command %s\n"),cmd
);
1520 if (!fgets(response
, sizeof(response
), fp
)) {
1521 debuga(_("Cannot get disk size with command %s\n"),cmd
);
1524 ptr
=strchr(response
,'\t');
1526 debuga(_("The command %s failed\n"),cmd
);
1535 void show_info(FILE *fp_ou
)
1539 if(!ShowSargInfo
) return;
1540 zdate(ftime
, sizeof(ftime
), DateFormat
);
1541 fprintf(fp_ou
,"<div class=\"info\">%s <a href='%s'>%s-%s</a> %s %s</div>\n",_("Generated by"),URL
,PGM
,VERSION
,_("on"),ftime
);
1544 void show_sarg(FILE *fp_ou
, int depth
)
1548 if(!ShowSargLogo
) return;
1549 fputs("<div class=\"logo\"><a href=\"http://sarg.sourceforge.net\"><img src=\"",fp_ou
);
1550 for (i
=0 ; i
<depth
; i
++)
1552 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
);
1555 void write_logo_image(FILE *fp_ou
)
1557 if(LogoImage
[0]!='\0')
1558 fprintf(fp_ou
, "<div class=\"logo\"><img src=\"%s\" width=\"%s\" height=\"%s\" alt=\"Logo\"> %s</div>\n",LogoImage
,Width
,Height
,LogoText
);
1561 void write_html_head(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1565 fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n",fp_ou
);
1566 fprintf(fp_ou
, "<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n",CharSet
);
1567 if (page_title
) fprintf(fp_ou
,"<title>%s</title>\n",page_title
);
1569 if ((javascript
& HTML_JS_SORTTABLE
)!=0 && SortTableJs
[0]) {
1570 fputs("<script type=\"text/javascript\" src=\"",fp_ou
);
1571 if (strncmp(SortTableJs
,"../",3)==0) {
1572 for (i
=0 ; i
<depth
; i
++) fputs("../",fp_ou
);
1574 fputs(SortTableJs
,fp_ou
);
1575 fputs("\"></script>\n",fp_ou
);
1577 fputs("</head>\n<body>\n",fp_ou
);
1580 void write_html_header(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1582 write_html_head(fp_ou
,depth
,page_title
,javascript
);
1583 write_logo_image(fp_ou
);
1584 show_sarg(fp_ou
, depth
);
1585 fprintf(fp_ou
,"<div class=\"title\"><table cellpadding=\"0\" cellspacing=\"0\">\n<tr><th class=\"title_c\">%s</th></tr>\n",Title
);
1588 void close_html_header(FILE *fp_ou
)
1590 fputs("</table></div>\n",fp_ou
);
1593 int write_html_trailer(FILE *fp_ou
)
1596 if (fputs("</body>\n</html>\n",fp_ou
)==EOF
) return(-1);
1600 void output_html_string(FILE *fp_ou
,const char *str
,int maxlen
)
1604 while (*str
&& (maxlen
<=0 || i
<maxlen
)) {
1607 fputs("&",fp_ou
);
1610 fputs("<",fp_ou
);
1613 fputs(">",fp_ou
);
1616 fputs(""",fp_ou
);
1619 fputs("'",fp_ou
);
1627 if (maxlen
>0 && i
>=maxlen
)
1628 fputs("…",fp_ou
);
1631 void output_html_url(FILE *fp_ou
,const char *url
)
1635 fputs("&",fp_ou
);
1643 Write a host name inside an A tag of a HTML file. If the host name starts
1644 with a star, it is assumed to be an alias that cannot be put inside a link
1645 so the A tag is not written around the host name.
1647 \param fp_ou The handle of the HTML file.
1648 \param url The host to display in the HTML file.
1649 \param maxlen The maximum number of characters to print into the host name.
1651 void output_html_link(FILE *fp_ou
,const char *url
,int maxlen
)
1653 if (url
[0]==ALIAS_PREFIX
) {
1654 // this is an alias, no need for a A tag
1655 output_html_string(fp_ou
,url
+1,100);
1657 fputs("<a href=\"http://",fp_ou
);
1658 output_html_url(fp_ou
,url
);
1660 output_html_string(fp_ou
,url
,100);
1661 fputs("</a>",fp_ou
);
1665 void url_module(const char *url
, char *w2
)
1671 for(x
=strlen(url
)-1; x
>=0; x
--) {
1672 if(url
[x
] == '/' || y
>=sizeof(w
)-1) break;
1681 for(y
=y
-1; y
>=0; y
--) {
1687 void url_to_file(const char *url
,char *file
,int filesize
)
1693 for(i
=0; i
<filesize
&& *url
; url
++) {
1694 if(isalnum(*url
) || *url
=='-' || *url
=='_' || *url
=='.' || *url
=='%') {
1698 if (!skip
) file
[i
++]='_';
1707 printf(_("SARG Version: %s\n"),VERSION
);
1711 char *get_param_value(const char *param
,char *line
)
1715 while (*line
==' ' || *line
=='\t') line
++;
1717 if (strncasecmp(line
,param
,plen
)) return(NULL
);
1718 if (line
[plen
]!=' ' && line
[plen
]!='\t') return(NULL
);
1720 while (*line
==' ' || *line
=='\t') line
++;
1724 void unlinkdir(const char *dir
,int contentonly
)
1728 struct dirent
*direntp
;
1734 while ((direntp
= readdir(dirp
)) != NULL
) {
1735 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
1736 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
1738 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
1739 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
1743 err
=lstat(dname
,&st
);
1745 err
=stat(dname
,&st
);
1748 debuga(_("cannot stat %s\n"),dname
);
1751 if (S_ISREG(st
.st_mode
)) {
1752 if (unlink(dname
)) {
1753 debuga(_("cannot delete %s - %s\n"),dname
,strerror(errno
));
1756 } else if (S_ISDIR(st
.st_mode
)) {
1759 debuga(_("unknown path type %s\n"),dname
);
1766 debuga(_("cannot delete %s - %s\n"),dir
,strerror(errno
));