]>
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 debuga(_("getword loop detected after %d bytes.\n"),x
);
87 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
88 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
89 debuga(_("searching for \'x%x\'\n"),stop
);
90 //debuga(_("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 debuga(_("getword_multisep loop detected.\n"));
128 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
129 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
130 debuga(_("searching for \'x%x\'\n"),stop
);
131 //debuga(_("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 debuga(_("getword_skip loop detected after %d bytes.\n"),x
);
155 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
156 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
157 debuga(_("searching for \'x%x\'\n"),stop
);
158 //debuga(_("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
)
177 if (gwarea
->current
[0] == '-') {
180 } else if (gwarea
->current
[0] == '+') {
184 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
185 digit
=gwarea
->current
[x
]-'0';
186 if (*number
>= (LLONG_MAX
-digit
)/10) {
187 debuga(_("Integer overflow detected in getword_atoll in line %s\n"),gwarea
->beginning
);
190 *number
=(*number
* 10) + digit
;
192 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
193 debuga(_("getword_atoll loop detected after %d bytes.\n"),x
);
194 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
195 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
196 debuga(_("searching for \'x%x\'\n"),stop
);
197 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
198 #if USE_GETWORD_BACKTRACE
205 if (gwarea
->current
[x
]) ++x
;
210 int getword_atoi(int *number
, struct getwordstruct
*gwarea
, char stop
)
216 if (gwarea
->current
[0] == '-') {
219 } else if (gwarea
->current
[0] == '+') {
223 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
224 digit
=gwarea
->current
[x
]-'0';
225 if (*number
> (INT_MAX
-digit
)/10) {
226 debuga(_("Integer overflow detected in getword_atoi in line %s\n"),gwarea
->beginning
);
229 *number
=(*number
* 10) + digit
;
231 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
232 debuga(_("getword_atoi loop detected after %d bytes.\n"),x
);
233 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
234 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
235 debuga(_("searching for \'x%x\'\n"),stop
);
236 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
237 #if USE_GETWORD_BACKTRACE
244 if (gwarea
->current
[x
]) ++x
;
250 int getword_ptr(char *orig_line
,char **word
, struct getwordstruct
*gwarea
, char stop
)
253 \note Why pass the original buffer to the function ? Because we must modify it to
254 insert the terminating ASCII zero for the word we return and that's not compatible
255 with getword_restart(). Moreover, getword_start() sometime works on constant strings
256 so this function require the original buffer to detect any missuse.
262 if (orig_line
&& orig_line
!=gwarea
->beginning
) {
263 debuga(_("Invalid buffer passed to getword_ptr\n"));
267 start
=(gwarea
->current
-gwarea
->beginning
);
268 if (word
&& orig_line
) *word
=orig_line
+start
;
269 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++);
270 sep
=(gwarea
->current
[x
]!='\0');
271 if (word
&& orig_line
) orig_line
[start
+x
] = '\0';
278 #define MAXLLL 30 //!< Maximum number of digits in long long (a guess).
279 long long int my_atoll (const char *nptr
)
281 long long int returnval
=0LL;
282 int max_digits
= MAXLLL
;
284 // Soak up all the white space
285 while (isspace( *nptr
)) {
289 //For each character left to right
290 //change the character to a single digit
291 //multiply what we had before by 10 and add the new digit
293 while (--max_digits
&& isdigit( *nptr
))
295 returnval
= ( returnval
* 10 ) + ( *nptr
++ - '0' ) ;
301 int is_absolute(const char *path
)
303 if (*path
=='/') return(1);
305 if (isalpha(path
[0]) && path
[1]==':') return(1);
310 void my_mkdir(const char *name
)
316 if(!is_absolute(name
)) {
317 debuga(_("Invalid path (%s). Please, use absolute paths only.\n"),name
);
322 for (i
=0 ; name
[i
] ; i
++) {
324 debuga(_("directory name too long: %s\n"),name
);
327 if (chars
>0 && name
[i
] == '/') {
329 if (access(w0
, R_OK
) != 0) {
330 if (mkdir(w0
,0755)) {
331 debuga(_("Cannot create directory %s - %s\n"),w0
,strerror(errno
));
336 if (name
[i
] != '/') chars
++;
340 if (access(name
, R_OK
) != 0) {
341 if (mkdir(name
,0755)) {
342 debuga(_("Cannot create directory %s - %s\n"),name
,strerror(errno
));
349 void my_lltoa(unsigned long long int n
, char *s
, int ssize
, int len
)
358 debuga(_("The requested number of digits passed to my_lltoa (%d) is bigger than the output buffer size (%d)\n"),len
,ssize
);
363 s
[slen
++] = (n
% 10) + '0';
364 } while ((n
/= 10) > 0 && slen
<ssize
);
367 for (i
= 0, j
= slen
-1; i
<j
; i
++, j
--) {
375 for(j
=slen
; j
>=0; j
--)
382 int month2num(const char *month
)
386 for(m
=0 ; m
<12 && strcmp(mtab1
[m
],month
) != 0; m
++);
390 int builddia(int day
, int month
, int year
)
392 return(year
*10000+month
*100+day
);
396 void buildymd(const char *dia
, const char *mes
, const char *ano
, char *wdata
)
401 sprintf(wdata
,"%04d%02d%02d",atoi(ano
),nmes
+1,atoi(dia
));
405 int conv_month(const char *month
)
409 for(x
=0; x
<12 && strncmp(mtab1
[x
],month
,3)!=0; x
++);
414 const char *conv_month_name(int month
)
418 if (month
<1 || month
>12) {
419 snprintf(str
,sizeof(str
),"%03d",month
);
422 return(mtab1
[month
-1]);
426 void name_month(char *month
,int month_len
)
428 int x
, z
=atoi(month
)-1;
431 struct getwordstruct gwarea
;
433 strcpy(m
,_("January,February,March,April,May,June,July,August,September,October,November,December"));
434 getword_start(&gwarea
,m
);
437 if (getword_multisep(w
,sizeof(w
),&gwarea
,',')<0) {
438 debuga(_("SARG: Maybe you have a broken record or garbage in the names of the months.\n"));
441 if (getword_multisep(month
,month_len
,&gwarea
,',')<0) {
442 debuga(_("Maybe you have a broken record or garbage in the name of the months.\n"));
449 Write a debug message to stderr. The message is prefixed by "SARG:" to identify its origin.
451 \param msg The printf like message to format.
452 \param ... The arguments to format in the message.
454 void debuga(const char *msg
,...)
458 fputs(_("SARG: "),stderr
);
460 vfprintf(stderr
,msg
,ap
);
466 Write a debug message to stderr. The message is prefixed by "SARG: (info)".
468 \param msg The printf like message to format.
469 \param ... The arguments to format in the message.
471 void debugaz(const char *msg
,...)
475 fputs(_("SARG: (info) "),stderr
);
477 vfprintf(stderr
,msg
,ap
);
482 char *fixnum(long long int value
, int n
)
484 #define MAXLEN_FIXNUM 256
485 char num
[MAXLEN_FIXNUM
]="";
486 char buf
[MAXLEN_FIXNUM
* 2];
488 static char ret
[MAXLEN_FIXNUM
* 2];
490 register int i
, j
, k
;
492 static char abbrev
[30];
494 my_lltoa(value
, num
, sizeof(num
), 0);
496 if(DisplayedValues
==DISPLAY_ABBREV
) {
497 numlen
= strlen(num
);
499 sprintf(abbrev
,"%s",num
);
500 if(numlen
== 4 || numlen
== 7 || numlen
== 10 || numlen
== 13) {
501 snprintf(abbrev
,2,"%s",num
);
502 strncat(abbrev
,".",1);
503 strncat(abbrev
,num
+1,2);
504 if(!n
) return(abbrev
);
506 strncat(abbrev
,"K",1);
508 strncat(abbrev
,"M",1);
509 else if(numlen
== 10)
510 strncat(abbrev
,"G",1);
511 else if(numlen
== 13)
512 strncat(abbrev
,"T",1);
514 if(numlen
== 5 || numlen
== 8 || numlen
== 11 || numlen
== 14) {
515 snprintf(abbrev
,3,"%s",num
);
516 strncat(abbrev
,".",1);
517 strncat(abbrev
,num
+2,2);
518 if(!n
) return(abbrev
);
520 strncat(abbrev
,"K",1);
522 strncat(abbrev
,"M",1);
523 else if(numlen
== 11)
524 strncat(abbrev
,"G",1);
525 else if(numlen
== 14)
526 strncat(abbrev
,"T",1);
528 if(numlen
== 6 || numlen
== 9 || numlen
== 12 || numlen
== 15) {
529 snprintf(abbrev
,4,"%s",num
);
530 strncat(abbrev
,".",1);
531 strncat(abbrev
,num
+3,2);
532 if(!n
) return(abbrev
);
534 strncat(abbrev
,"K",1);
536 strncat(abbrev
,"M",1);
537 else if(numlen
== 12)
538 strncat(abbrev
,"G",1);
539 else if(numlen
== 15)
540 strncat(abbrev
,"T",1);
546 bzero(buf
, MAXLEN_FIXNUM
*2);
552 for ( i
= strlen(num
) - 1, j
= 0 ; i
> -1; i
--) {
553 if ( k
== 2 && i
!= 0 ) {
556 pbuf
[j
++] = (UseComma
) ? ',' : '.';
566 for ( i
= strlen(pbuf
) - 1, j
= 0 ; i
> -1; i
--, j
++)
575 char *fixnum2(long long int value
, int n
)
577 #define MAXLEN_FIXNUM2 1024
578 char num
[MAXLEN_FIXNUM2
];
579 char buf
[MAXLEN_FIXNUM2
* 2];
581 static char ret
[MAXLEN_FIXNUM2
* 2];
583 register int i
, j
, k
;
585 my_lltoa(value
, num
, sizeof(num
), 0);
586 bzero(buf
, MAXLEN_FIXNUM2
*2);
592 for ( i
= strlen(num
) - 1, j
= 0 ; i
> -1; i
--) {
593 if ( k
== 2 && i
!= 0 ) {
596 pbuf
[j
++] = (UseComma
) ? ',' : '.';
606 for ( i
= strlen(pbuf
) - 1, j
= 0 ; i
> -1; i
--, j
++)
615 char *buildtime(long long int elap
)
617 int num
= elap
/ 1000;
626 min
=(num
% 3600) / 60;
628 sprintf(buf
,"%02d:%02d:%02d",hor
,min
,sec
);
635 Get the date stored in the <tt>sarg-date</tt> file of a directory with the connection data.
637 \param dirname The directory to look for the connection directory.
638 \param name The name of the directory whose <tt>sarg-date</tt> file must be read.
639 \param data The buffer to store the content of the file. It must be more than 80
643 \retval -1 File not found.
645 int obtdate(const char *dirname
, const char *name
, char *data
)
650 sprintf(wdir
,"%s%s/sarg-date",dirname
,name
);
651 if ((fp_in
= fopen(wdir
, "rt")) == 0) {
652 sprintf(wdir
,"%s%s/date",dirname
,name
);
653 if ((fp_in
= fopen(wdir
, "rt")) == 0) {
659 if (!fgets(data
,80,fp_in
)) {
660 debuga(_("Failed to read the date in %s\n"),wdir
);
670 void formatdate(char *date
,int date_size
,int year
,int month
,int day
,int hour
,int minute
,int second
,int dst
)
676 memset(<m
,0,sizeof(ltm
));
677 if (year
>=1900) ltm
.tm_year
=year
-1900;
678 if (month
>=1 && month
<=12) ltm
.tm_mon
=month
-1;
679 if (day
>=1 && day
<=31) ltm
.tm_mday
=day
;
680 if (hour
>=0 && hour
<24) ltm
.tm_hour
=hour
;
681 if (minute
>=0 && minute
<60) ltm
.tm_min
=minute
;
682 if (second
>=0 && second
<60) ltm
.tm_sec
=second
;
684 unixtime
=mktime(<m
); //fill the missing entries
685 fulltm
=localtime(&unixtime
);
686 //strftime(date,date_size,"%a %b %d %H:%M:%S %Z %Y",fulltm);
687 strftime(date
,date_size
,"%c",fulltm
);
691 void computedate(int year
,int month
,int day
,struct tm
*t
)
693 memset(t
,0,sizeof(*t
));
694 t
->tm_year
=year
-1900;
700 int obtuser(const char *dirname
, const char *name
)
707 sprintf(wdir
,"%s%s/sarg-users",dirname
,name
);
708 if((fp_in
=fopen(wdir
,"r"))==NULL
) {
709 sprintf(wdir
,"%s%s/users",dirname
,name
);
710 if((fp_in
=fopen(wdir
,"r"))==NULL
) {
715 if (!fgets(tuser
,sizeof(tuser
),fp_in
)) {
716 debuga(_("Failed to read the number of users in %s\n"),wdir
);
726 void obttotal(const char *dirname
, const char *name
, int nuser
, long long int *tbytes
, long long int *media
)
731 char user
[MAX_USER_LEN
];
733 struct getwordstruct gwarea
;
739 sprintf(wdir
,"%s%s/sarg-general",dirname
,name
);
740 if ((fp_in
= fopen(wdir
, "r")) == 0) {
741 sprintf(wdir
,"%s%s/general",dirname
,name
);
742 if ((fp_in
= fopen(wdir
, "r")) == 0) {
747 if ((line
=longline_create())==NULL
) {
748 debuga(_("Not enough memory to read the file %s\n"),wdir
);
752 while((buf
=longline_read(fp_in
,line
))!=NULL
) {
753 if (strncmp(buf
,"TOTAL\t",6) == 0)
755 else if (strncmp(buf
,"TOTAL ",6) == 0)
759 getword_start(&gwarea
,buf
);
760 if (getword(user
,sizeof(user
),&gwarea
,sep
)<0) {
761 debuga(_("There is a invalid user in file %s\n"),wdir
);
764 if(strcmp(user
,"TOTAL") != 0)
766 if (getword_skip(MAXLEN
,&gwarea
,sep
)<0) {
767 debuga(_("There a broken total number of access in file %s\n"),wdir
);
770 if (getword_atoll(tbytes
,&gwarea
,sep
)<0) {
771 debuga(_("There is a broken number of bytes in file %s\n"),wdir
);
777 longline_destroy(&line
);
782 *media
=*tbytes
/ nuser
;
786 int getperiod_fromsarglog(const char *arqtt
,struct periodstruct
*period
)
789 int day0
, month0
, year0
, hour0
, minute0
;
790 int day1
, month1
, year1
, hour1
, minute1
;
793 memset(period
,0,sizeof(*period
));
796 while((str
=strstr(str
,"sarg-"))!=NULL
) {
798 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
799 day0
=(str
[0]-'0')*10+(str
[1]-'0');
800 if (day0
<1 || day0
>31) continue;
802 month0
=(str
[0]-'0')*10+(str
[1]-'0')-1;
803 if (month0
<0 || month0
>11) continue;
806 for (i
=0 ; isdigit(str
[i
]) && i
<4 ; i
++) year0
=year0
*10+(str
[i
]-'0');
809 if (str
[0]!='_') continue;
812 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
813 hour0
=(str
[0]-'0')*10+(str
[1]-'0');
815 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
816 minute0
=(str
[0]-'0')*10+(str
[1]-'0');
819 if (*str
!= '-') continue;
822 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
823 day1
=(str
[0]-'0')*10+(str
[1]-'0');
824 if (day1
<1 || day1
>31) continue;
826 month1
=(str
[0]-'0')*10+(str
[1]-'0')-1;
827 if (month1
<0 || month1
>11) continue;
830 for (i
=0 ; isdigit(str
[i
]) && i
<4 ; i
++) year1
=year1
*10+(str
[i
]-'0');
834 if (str
[0]!='_') continue;
837 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
838 hour1
=(str
[0]-'0')*10+(str
[1]-'0');
840 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
841 minute1
=(str
[0]-'0')*10+(str
[1]-'0');
844 period
->start
.tm_mday
=day0
;
845 period
->start
.tm_mon
=month0
;
846 period
->start
.tm_year
=year0
-1900;
847 period
->start
.tm_hour
=hour0
;
848 period
->start
.tm_min
=minute0
;
849 period
->end
.tm_mday
=day1
;
850 period
->end
.tm_mon
=month1
;
851 period
->end
.tm_year
=year1
-1900;
852 period
->end
.tm_hour
=hour1
;
853 period
->end
.tm_min
=minute1
;
859 void getperiod_fromrange(struct periodstruct
*period
,int dfrom
,int duntil
)
861 memset(&period
->start
,0,sizeof(period
->start
));
862 period
->start
.tm_mday
=dfrom
%100;
863 period
->start
.tm_mon
=(dfrom
/100)%100-1;
864 period
->start
.tm_year
=(dfrom
/10000)-1900;
866 memset(&period
->end
,0,sizeof(period
->end
));
867 period
->end
.tm_mday
=duntil
%100;
868 period
->end
.tm_mon
=(duntil
/100)%100-1;
869 period
->end
.tm_year
=(duntil
/10000)-1900;
872 int getperiod_buildtext(struct periodstruct
*period
)
876 char text1
[40], text2
[40];
879 i
=strftime(text1
, sizeof(text1
), "%Y %b %d", &period
->start
);
880 }else if(df
[0]=='e') {
881 i
=strftime(text1
, sizeof(text1
), "%d %b %Y", &period
->start
);
882 } else /*if(df[0]=='w')*/ {
883 IndexTree
=INDEX_TREE_FILE
;
884 i
=strftime(text1
, sizeof(text1
), "%Y.%U", &period
->start
);
886 if (i
== 0) return(-1);
888 range
=(period
->start
.tm_year
!=period
->end
.tm_year
||
889 period
->start
.tm_mon
!=period
->end
.tm_mon
||
890 period
->start
.tm_mday
!=period
->end
.tm_mday
);
893 i
=strftime(text2
, sizeof(text2
)-i
, "%Y %b %d", &period
->end
);
894 } else if(df
[0]=='e') {
895 i
=strftime(text2
, sizeof(text2
)-i
, "%d %b %Y", &period
->end
);
897 i
=strftime(text2
, sizeof(text2
)-i
, "%Y.%U", &period
->end
);
899 if (i
== 0) return(-1);
903 snprintf(period
->text
,sizeof(period
->text
),"%s-%s",text1
,text2
);
904 snprintf(period
->html
,sizeof(period
->html
),"%s—%s",text1
,text2
);
906 safe_strcpy(period
->text
,text1
,sizeof(period
->text
));
907 safe_strcpy(period
->html
,text1
,sizeof(period
->html
));
912 static void copy_images(void)
914 FILE *img_in
, *img_ou
;
917 char srcfile
[MAXLEN
];
918 char dstfile
[MAXLEN
];
920 struct dirent
*direntp
;
925 if (snprintf(images
,sizeof(images
),"%simages",outdir
)>=sizeof(images
)) {
926 debuga(_("Cannot copy images to target directory %simages\n"),outdir
);
929 if (access(images
,R_OK
)!=0) {
930 if (mkdir(images
,0755)) {
931 debuga(_("Cannot create directory %s - %s\n"),images
,strerror(errno
));
936 strcpy(imgdir
,IMAGEDIR
);
937 dirp
= opendir(imgdir
);
939 debuga(_("(util) Can't open directory %s: %s\n"),imgdir
,strerror(errno
));
942 while ((direntp
= readdir( dirp
)) != NULL
){
943 if(direntp
->d_name
[0]=='.')
945 sprintf(srcfile
,"%s/%s",imgdir
,direntp
->d_name
);
946 if (stat(srcfile
,&info
)) {
947 debuga(_("Cannot stat \"%s\" - %s\n"),srcfile
,strerror(errno
));
950 if (S_ISREG(info
.st_mode
)) {
951 sprintf(dstfile
,"%s/%s",images
,direntp
->d_name
);
952 img_in
= fopen(srcfile
, "rb");
954 img_ou
= fopen(dstfile
, "wb");
956 while ((nread
= fread(buffer
,1,sizeof(buffer
),img_in
))>0) {
957 if (fwrite(buffer
,1,nread
,img_ou
)!=nread
) {
958 debuga(_("Failed to copy image %s to %s\n"),srcfile
,dstfile
);
964 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open/create file", dstfile
, strerror(errno
));
967 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open file", srcfile
, strerror(errno
));
970 (void) closedir(dirp
);
975 int vrfydir(const struct periodstruct
*per1
, const char *addr
, const char *site
, const char *us
, const char *form
)
980 char dirname2
[MAXLEN
];
990 y1
=per1
->start
.tm_year
+1900;
991 y2
=per1
->end
.tm_year
+1900;
992 m1
=per1
->start
.tm_mon
+1;
993 m2
=per1
->end
.tm_mon
+1;
994 d1
=per1
->start
.tm_mday
;
995 d2
=per1
->end
.tm_mday
;
996 if(IndexTree
== INDEX_TREE_DATE
) {
997 wlen
+=sprintf(wdir
+wlen
,"%04d",y1
);
998 if(y1
!=y2
) wlen
+=sprintf(wdir
+wlen
,"-%04d",y2
);
999 if(access(wdir
, R_OK
) != 0)
1002 wlen
+=sprintf(wdir
+wlen
,"/%02d",m1
);
1003 if(m1
!= m2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",m2
);
1004 if(access(wdir
, R_OK
) != 0)
1007 wlen
+=sprintf(wdir
+wlen
,"/%02d",d1
);
1008 if(d1
!=d2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",d2
);
1011 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%04d%s%02d-%04d%s%02d",y1
,
1012 conv_month_name(m1
),d1
,y2
,conv_month_name(m2
),d2
);
1013 } else if(df
[0] == 'e') {
1014 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%02d%s%04d-%02d%s%04d",d1
,
1015 conv_month_name(m1
),y1
,d2
,conv_month_name(m2
),y2
);
1016 } else if(df
[0] == 'w') {
1017 wlen2
=strftime(wdir
+wlen
, sizeof(wdir
)-wlen
, "%Y.%U", &per1
->start
);
1018 if (wlen2
==0) return(-1);
1024 struct userinfostruct
*uinfo
=userinfo_find_from_id(us
);
1027 strcat(wdir
,uinfo
->filename
);
1030 if(addr
[0] != '\0') {
1034 if(site
[0] != '\0') {
1039 strcpy(outdirname
,wdir
);
1041 if(IndexTree
!= INDEX_TREE_DATE
) {
1042 if(!OverwriteReport
) {
1044 if(access(wdir
,R_OK
) == 0) {
1045 sprintf(wdir
,"%s.%d",outdirname
,num
);
1054 debuga(_("File %s already exists, moved to %s\n"),outdirname
,wdir
);
1055 rename(outdirname
,wdir
);
1058 if(access(outdirname
,R_OK
) == 0) {
1059 unlinkdir(outdirname
,1);
1062 my_mkdir(outdirname
);
1064 strcpy(dirname2
,wdir
);
1065 if(!OverwriteReport
) {
1067 if(access(wdir
,R_OK
) == 0) {
1068 sprintf(wdir
,"%s.%d",dirname2
,num
);
1077 debuga(_("File %s already exists, moved to %s\n"),dirname2
,wdir
);
1078 rename(dirname2
,wdir
);
1079 strcpy(dirname2
,wdir
);
1082 if(access(wdir
,R_OK
) == 0) {
1087 if(access(wdir
, R_OK
) != 0)
1091 strcpy(dirname2
,wdir
);
1093 sprintf(wdir
,"%s/sarg-date",outdirname
);
1094 if ((fp_ou
= fopen(wdir
, "wt")) == 0) {
1095 debuga(_("cannot open %s for writing\n"),wdir
);
1100 //strftime(wdir,sizeof(wdir),"%a %b %d %H:%M:%S %Z %Y",localtime(&curtime));
1101 loctm
=localtime(&curtime
);
1102 strftime(wdir
,sizeof(wdir
),"%Y-%m-%d %H:%M:%S",loctm
);
1103 if (fprintf(fp_ou
,"%s %d\n",wdir
,loctm
->tm_isdst
)<0) {
1104 debuga(_("Failed to write the date in %s\n"),wdir
);
1108 if (fclose(fp_ou
)==EOF
) {
1109 debuga(_("Failed to write the date in %s\n"),wdir
);
1119 Copy a string without overflowing the buffer. The copied string
1120 is properly terminated by an ASCII zero.
1122 \param dest The destination buffer.
1123 \param src The source buffer.
1124 \param length The size of the destination buffer. The program is aborted
1125 if the length is negative or zero.
1127 void safe_strcpy(char *dest
,const char *src
,int length
)
1130 debuga(_("Invalid buffer length passed to the function to safely copy a string\n"));
1133 strncpy(dest
,src
,length
-1);
1134 dest
[length
-1]='\0';
1137 void strip_latin(char *line
)
1144 for (i
=0;line
[i
];i
++){
1146 if (line
[i
]==';') skip
=0;
1158 void zdate(char *ftime
,int ftimesize
, const char *DateFormat
)
1164 local
= localtime(&t
);
1165 if(strcmp(DateFormat
,"u") == 0)
1166 strftime(ftime
, ftimesize
, "%b/%d/%Y %H:%M", local
);
1167 if(strcmp(DateFormat
,"e") == 0)
1168 strftime(ftime
, ftimesize
, "%d/%b/%Y-%H:%M", local
);
1169 if(strcmp(DateFormat
,"w") == 0)
1170 strftime(ftime
, ftimesize
, "%W-%H-%M", local
);
1175 char *fixtime(long long int elap
)
1177 int num
= elap
/ 1000;
1181 static char buf
[12];
1184 min
=(num
% 3600) / 60;
1187 if(hor
==0 && min
==0 && sec
==0)
1190 sprintf(buf
,"%d:%02d:%02d",hor
,min
,sec
);
1196 void date_from(char *date
, int *dfrom
, int *duntil
)
1205 if (isdigit(date
[0])) {
1208 if (sscanf(date
,"%d/%d/%d%n",&d0
,&m0
,&y0
,&next
)!=3 || y0
<100 || m0
<1 || m0
>12 || d0
<1 || d0
>31 || next
<0) {
1209 debuga(_("The date passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1212 if (date
[next
]=='-') {
1213 if (sscanf(date
+next
+1,"%d/%d/%d",&d1
,&m1
,&y1
)!=3 || y1
<100 || m1
<1 || m1
>12 || d1
<1 || d1
>31) {
1214 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1217 } else if (date
[next
]!='\0') {
1218 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1228 struct tm
*Date0
,Date1
;
1230 if (time(&Today
)==(time_t)-1) {
1231 debuga(_("Failed to get the current time\n"));
1234 if (sscanf(date
,"day-%d",&i
)==1) {
1236 debuga(_("Invalid number of days in -d parameter\n"));
1240 Date0
=localtime(&Today
);
1242 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1245 y0
=y1
=Date0
->tm_year
+1900;
1246 m0
=m1
=Date0
->tm_mon
+1;
1247 d0
=d1
=Date0
->tm_mday
;
1248 } else if (sscanf(date
,"week-%d",&i
)==1) {
1250 There is no portable way to find the first day of the week even though the
1251 information is available in the locale. nl_langinfo has the unofficial
1252 parameters _NL_TIME_FIRST_WEEKDAY and _NL_TIME_WEEK_1STDAY but they are
1253 undocumented as is their return value and it is discouraged to use them.
1254 Beside, nl_langinfo isn't available on windows and the first day of the
1255 week isn't available at all on that system.
1257 const int FirstWeekDay
=1;
1261 debuga(_("Invalid number of weeks in -d parameter\n"));
1264 Date0
=localtime(&Today
);
1266 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1269 WeekBegin
=Today
-((Date0
->tm_wday
-FirstWeekDay
+7)%7)*24*60*60;
1270 WeekBegin
-=i
*7*24*60*60;
1271 Date0
=localtime(&WeekBegin
);
1273 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1276 y0
=Date0
->tm_year
+1900;
1279 WeekBegin
+=6*24*60*60;
1280 Date0
=localtime(&WeekBegin
);
1282 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1285 y1
=Date0
->tm_year
+1900;
1288 } else if (sscanf(date
,"month-%d",&i
)==1) {
1290 debuga(_("Invalid number of months in -d parameter\n"));
1293 Date0
=localtime(&Today
);
1295 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1298 if (Date0
->tm_mon
<i
%12) {
1299 y0
=Date0
->tm_year
+1900-i
/12-1;
1300 m0
=(Date0
->tm_mon
+12-i
%12)%12+1;
1303 y0
=Date0
->tm_year
+1900-i
/12;
1304 m0
=Date0
->tm_mon
-i
%12+1;
1307 memcpy(&Date1
,Date0
,sizeof(struct tm
));
1312 Date1
.tm_year
=y0
-1900;
1315 Date1
.tm_year
=y0
-1900+1;
1319 Date0
=localtime(&t1
);
1320 y1
=Date0
->tm_year
+1900;
1324 debuga(_("Invalid date range passed on command line\n"));
1329 *dfrom
=y0
*10000+m0
*100+d0
;
1330 *duntil
=y1
*10000+m1
*100+d1
;
1331 sprintf(date
,"%02d/%02d/%04d-%02d/%02d/%04d",d0
,m0
,y0
,d1
,m1
,y1
);
1336 char *strlow(char *string
)
1342 for (s
= string
; *s
; ++s
)
1352 char *strup(char *string
)
1358 for (s
= string
; *s
; ++s
)
1366 void removetmp(const char *outdir
)
1371 if(!RemoveTempFiles
)
1375 debuga(_("Purging temporary file sarg-general\n"));
1377 if (snprintf(filename
,sizeof(filename
),"%s/sarg-general",outdir
)>=sizeof(filename
)) {
1378 debuga(_("(removetmp) directory too long to remove %s/sarg-period\n"),outdir
);
1381 if((fp_gen
=fopen(filename
,"w"))==NULL
){
1382 debuga(_("(removetmp) Cannot open file %s\n"),filename
);
1385 totalger(fp_gen
,filename
);
1386 if (fclose(fp_gen
)==EOF
) {
1387 debuga(_("Failed to close %s after writing the total line - %s\n"),filename
,strerror(errno
));
1392 void load_excludecodes(const char *ExcludeCodes
)
1400 if(ExcludeCodes
[0] == '\0')
1403 if((fp_in
=fopen(ExcludeCodes
,"r"))==NULL
) {
1404 debuga(_("(util) Cannot open file %s (exclude_codes)\n"),ExcludeCodes
);
1408 if (fseek(fp_in
, 0, SEEK_END
)==-1) {
1409 debuga(_("Failed to move till the end of the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1412 MemSize
= ftell(fp_in
);
1414 debuga(_("Cannot get the size of file %s\n"),ExcludeCodes
);
1417 if (fseek(fp_in
, 0, SEEK_SET
)==-1) {
1418 debuga(_("Failed to rewind the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1423 if((excludecode
=(char *) malloc(MemSize
))==NULL
) {
1424 debuga(_("malloc error (%ld)\n"),MemSize
);
1427 memset(excludecode
,0,MemSize
);
1430 while(fgets(data
,sizeof(data
),fp_in
)!=NULL
) {
1431 if (data
[0]=='#') continue;
1432 for (i
=strlen(data
)-1 ; i
>=0 && (unsigned char)data
[i
]<=' ' ; i
--) data
[i
]='\0';
1434 if (Stored
+i
+2>=MemSize
) {
1435 debuga(_("Too many codes to exclude in file %s\n"),ExcludeCodes
);
1438 strcat(excludecode
,data
);
1439 strcat(excludecode
,";");
1447 void free_excludecodes(void)
1455 int vercode(const char *code
)
1460 if (excludecode
&& excludecode
[0]!='\0') {
1464 if (strncmp(code
,cod
,clen
)==0 && cod
[clen
]==';')
1466 cod
=strchr(cod
,';');
1473 void fixnone(char *str
)
1477 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--);
1478 if(i
==3 && strncmp(str
,"none",4) == 0)
1484 void fixendofline(char *str
)
1488 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--) str
[i
]=0;
1491 #ifdef LEGACY_TESTVALIDUSERCHAR
1492 int testvaliduserchar(const char *user
)
1497 for (y
=0; y
<strlen(UserInvalidChar
); y
++) {
1498 for (x
=0; x
<strlen(user
); x
++) {
1499 if(user
[x
] == UserInvalidChar
[y
])
1506 int testvaliduserchar(const char *user
)
1508 char * p_UserInvalidChar
= UserInvalidChar
;
1509 const char * p_user
;
1511 while( *p_UserInvalidChar
) {
1514 if( *p_UserInvalidChar
== *p_user
)
1518 p_UserInvalidChar
++ ;
1524 int compar( const void *a
, const void *b
)
1526 if( *(int *)a
> *(int *)b
) return 1;
1527 if( *(int *)a
< *(int *)b
) return -1;
1531 int getnumlist( char *buf
, numlist
*list
, const int len
, const int maxvalue
)
1533 int i
, j
, d
, flag
, r1
, r2
;
1534 char *pbuf
, **bp
, *strbufs
[ 24 ];
1537 strtok( buf
, " \t" );
1538 for( *bp
= strtok( NULL
, "," ), list
->len
= 0; *bp
; *bp
= strtok( NULL
, "," ) ) {
1539 if( ++bp
>= &strbufs
[ 24 ] )
1546 for( i
= 0; i
< list
->len
; i
++ ) {
1547 if( strchr( strbufs
[ i
], '-' ) != 0 ) {
1548 pbuf
= strbufs
[ i
];
1549 strtok( pbuf
, "-" );
1550 pbuf
= strtok( NULL
, "\0" );
1551 r1
= atoi( strbufs
[ i
] );
1552 if( ( r2
= atoi( pbuf
) ) >= maxvalue
|| r1
>= r2
)
1554 if( i
+ d
+ ( r2
- r1
) + 1 <= len
) {
1555 for( j
= r1
; j
<= r2
; j
++ )
1556 list
->list
[ i
+ d
++ ] = j
;
1561 if( ( list
->list
[ i
+ d
] = atoi( strbufs
[ i
] ) ) >= maxvalue
)
1565 qsort( list
->list
, list
->len
, sizeof( int ), compar
);
1568 for( i
= 0; i
< list
->len
- 1; i
++ )
1569 if( list
->list
[ i
] == list
->list
[ i
+ 1 ] ) {
1570 for( j
= i
+ 1; j
< list
->len
; j
++ )
1571 list
->list
[ j
- 1 ] = list
->list
[ j
];
1581 char *get_size(const char *path
, const char *file
)
1584 static char response
[255];
1588 if (snprintf(cmd
,sizeof(cmd
),"du -skh %s%s",path
,file
)>=sizeof(cmd
)) {
1589 debuga(_("Cannot get disk space because the path %s%s is too long\n"),path
,file
);
1592 if ((fp
= popen(cmd
, "r")) == NULL
) {
1593 debuga(_("Cannot get disk space with command %s\n"),cmd
);
1596 if (!fgets(response
, sizeof(response
), fp
)) {
1597 debuga(_("Cannot get disk size with command %s\n"),cmd
);
1600 ptr
=strchr(response
,'\t');
1602 debuga(_("The command %s failed\n"),cmd
);
1611 void show_info(FILE *fp_ou
)
1615 if(!ShowSargInfo
) return;
1616 zdate(ftime
, sizeof(ftime
), DateFormat
);
1617 fprintf(fp_ou
,"<div class=\"info\">%s <a href='%s'>%s-%s</a> %s %s</div>\n",_("Generated by"),URL
,PGM
,VERSION
,_("on"),ftime
);
1620 void show_sarg(FILE *fp_ou
, int depth
)
1624 if(!ShowSargLogo
) return;
1625 fputs("<div class=\"logo\"><a href=\"http://sarg.sourceforge.net\"><img src=\"",fp_ou
);
1626 for (i
=0 ; i
<depth
; i
++)
1628 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
);
1631 void write_logo_image(FILE *fp_ou
)
1633 if(LogoImage
[0]!='\0')
1634 fprintf(fp_ou
, "<div class=\"logo\"><img src=\"%s\" width=\"%s\" height=\"%s\" alt=\"Logo\"> %s</div>\n",LogoImage
,Width
,Height
,LogoText
);
1637 void write_html_head(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1641 fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n",fp_ou
);
1642 fprintf(fp_ou
, "<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n",CharSet
);
1643 if (page_title
) fprintf(fp_ou
,"<title>%s</title>\n",page_title
);
1645 if ((javascript
& HTML_JS_SORTTABLE
)!=0 && SortTableJs
[0]) {
1646 fputs("<script type=\"text/javascript\" src=\"",fp_ou
);
1647 if (strncmp(SortTableJs
,"../",3)==0) {
1648 for (i
=0 ; i
<depth
; i
++) fputs("../",fp_ou
);
1650 fputs(SortTableJs
,fp_ou
);
1651 fputs("\"></script>\n",fp_ou
);
1653 fputs("</head>\n<body>\n",fp_ou
);
1656 void write_html_header(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1658 write_html_head(fp_ou
,depth
,page_title
,javascript
);
1659 write_logo_image(fp_ou
);
1660 show_sarg(fp_ou
, depth
);
1661 fprintf(fp_ou
,"<div class=\"title\"><table cellpadding=\"0\" cellspacing=\"0\">\n<tr><th class=\"title_c\">%s</th></tr>\n",Title
);
1664 void close_html_header(FILE *fp_ou
)
1666 fputs("</table></div>\n",fp_ou
);
1669 int write_html_trailer(FILE *fp_ou
)
1672 if (fputs("</body>\n</html>\n",fp_ou
)==EOF
) return(-1);
1676 void output_html_string(FILE *fp_ou
,const char *str
,int maxlen
)
1680 while (*str
&& (maxlen
<=0 || i
<maxlen
)) {
1683 fputs("&",fp_ou
);
1686 fputs("<",fp_ou
);
1689 fputs(">",fp_ou
);
1692 fputs(""",fp_ou
);
1695 fputs("'",fp_ou
);
1703 if (maxlen
>0 && i
>=maxlen
)
1704 fputs("…",fp_ou
);
1707 void output_html_url(FILE *fp_ou
,const char *url
)
1711 fputs("&",fp_ou
);
1719 Write a host name inside an A tag of a HTML file. If the host name starts
1720 with a star, it is assumed to be an alias that cannot be put inside a link
1721 so the A tag is not written around the host name.
1723 \param fp_ou The handle of the HTML file.
1724 \param url The host to display in the HTML file.
1725 \param maxlen The maximum number of characters to print into the host name.
1727 void output_html_link(FILE *fp_ou
,const char *url
,int maxlen
)
1729 if (url
[0]==ALIAS_PREFIX
) {
1730 // this is an alias, no need for a A tag
1731 output_html_string(fp_ou
,url
+1,100);
1733 if (skip_scheme(url
)==url
)
1734 fputs("<a href=\"http://",fp_ou
);//no scheme in the url, assume http:// to make the link clickable
1736 fputs("<a href=\"",fp_ou
);//the scheme is in the url, no need to add one
1737 output_html_url(fp_ou
,url
);
1739 output_html_string(fp_ou
,url
,100);
1740 fputs("</a>",fp_ou
);
1744 void url_module(const char *url
, char *w2
)
1750 for(x
=strlen(url
)-1; x
>=0; x
--) {
1751 if(url
[x
] == '/' || y
>=sizeof(w
)-1) break;
1760 for(y
=y
-1; y
>=0; y
--) {
1766 void url_to_file(const char *url
,char *file
,int filesize
)
1772 for(i
=0; i
<filesize
&& *url
; url
++) {
1773 if(isalnum(*url
) || *url
=='-' || *url
=='_' || *url
=='.' || *url
=='%') {
1777 if (!skip
) file
[i
++]='_';
1786 printf(_("SARG Version: %s\n"),VERSION
);
1790 char *get_param_value(const char *param
,char *line
)
1794 while (*line
==' ' || *line
=='\t') line
++;
1796 if (strncasecmp(line
,param
,plen
)) return(NULL
);
1797 if (line
[plen
]!=' ' && line
[plen
]!='\t') return(NULL
);
1799 while (*line
==' ' || *line
=='\t') line
++;
1803 void unlinkdir(const char *dir
,bool contentonly
)
1807 struct dirent
*direntp
;
1813 while ((direntp
= readdir(dirp
)) != NULL
) {
1814 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
1815 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
1817 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
1818 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
1822 err
=lstat(dname
,&st
);
1824 err
=stat(dname
,&st
);
1827 debuga(_("cannot stat %s\n"),dname
);
1830 if (S_ISREG(st
.st_mode
)) {
1831 if (unlink(dname
)) {
1832 debuga(_("Cannot delete \"%s\": %s\n"),dname
,strerror(errno
));
1835 } else if (S_ISDIR(st
.st_mode
)) {
1838 debuga(_("unknown path type %s\n"),dname
);
1845 debuga(_("Cannot delete \"%s\": %s\n"),dir
,strerror(errno
));
1852 Delete every file from the temporary directory where sarg is told to store its
1855 As any stray file left over by a previous run would be included in the report, we
1856 must delete every file from the temporary directory before we start processing the logs.
1858 But the temporary directory is given by the user either in the configuration file or
1859 on the command line. We check that the user didn't give a wrong directory by looking
1860 at the files stored in the directory. If a single file is not one of ours, we abort.
1862 \param dir The temporary directory to purge.
1864 void emptytmpdir(const char *dir
)
1868 struct dirent
*direntp
;
1874 static const char *TmpExt
[]=
1889 // make sure the temporary directory contains only our files
1890 while ((direntp
= readdir(dirp
)) != NULL
) {
1891 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
1892 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
1895 // is it one of our files
1896 dlen
=strlen(direntp
->d_name
);
1897 for (i
=sizeof(TmpExt
)/sizeof(TmpExt
[0])-1 ; i
>=0 ; i
--) {
1898 elen
=strlen(TmpExt
[i
]);
1899 if (dlen
>=elen
&& strcasecmp(direntp
->d_name
+dlen
-elen
,TmpExt
[i
])==0) break;
1902 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
1903 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
1904 "directory or manually delete the content of \"%s\"\n"),direntp
->d_name
,dir
,dir
);
1908 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
1909 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
1914 err
=lstat(dname
,&st
);
1916 err
=stat(dname
,&st
);
1919 debuga(_("cannot stat \"%s\"\n"),dname
);
1922 if (S_ISDIR(st
.st_mode
)) {
1924 } else if (!S_ISREG(st
.st_mode
)) {
1925 debuga(_("Unknown path type \"%s\". Check your temporary directory\n"),dname
);
1931 // now delete our files
1932 while ((direntp
= readdir(dirp
)) != NULL
) {
1933 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
1934 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
1937 // is it one of our files
1938 dlen
=strlen(direntp
->d_name
);
1939 for (i
=sizeof(TmpExt
)/sizeof(TmpExt
[0])-1 ; i
>=0 ; i
--) {
1940 elen
=strlen(TmpExt
[i
]);
1941 if (dlen
>=elen
&& strcasecmp(direntp
->d_name
+dlen
-elen
,TmpExt
[i
])==0) break;
1944 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
1945 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
1946 "directory or manually delete the content of \"%s\"\n"),direntp
->d_name
,dir
,dir
);
1950 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
1951 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
1955 err
=lstat(dname
,&st
);
1957 err
=stat(dname
,&st
);
1960 debuga(_("cannot stat \"%s\"\n"),dname
);
1963 if (S_ISREG(st
.st_mode
)) {
1964 if (unlink(dname
)) {
1965 debuga(_("Cannot delete \"%s\": %s\n"),dname
,strerror(errno
));
1969 debuga(_("unknown path type %s\n"),dname
);
1976 Extract an url, IPv4 or IPv6 from a buffer. The IP addresses may end with a
1979 \param buf The buffer to parse.
1980 \param text A pointer to set to the beginning of the string pattern. No terminating zero is inserted.
1981 The pointer may be NULL.
1982 \param ipv4 A 4 bytes buffer to store the bytes of the IPv4 address.
1983 \param ipv6 A 8 short integers buffer to store the values of the IPv6 address.
1984 \param nbits The number of prefix bits for an IP address.
1985 \param next The content of the line after the extracted address.
1987 \retval 3 The pattern is a IPv6 address.
1988 \retval 2 The pattern is a IPv4 address.
1989 \retval 1 The patter is a string.
1990 \retval 0 Empty pattern.
1992 int extract_address_mask(const char *buf
,const char **text
,unsigned char *ipv4
,unsigned short int *ipv6
,int *nbits
,const char **next
)
1997 unsigned int value4
, value6
;
1998 unsigned short int addr
[8];
2008 // skip leading spaces and tabs
2009 while (*buf
&& (*buf
==' ' || *buf
=='\t')) buf
++;
2011 // find out the nature of the pattern
2012 ip_size
=0x60 | 0x04;
2023 for (i
=0 ; (unsigned char)buf
[i
]>' ' && buf
[i
]!='/' && buf
[i
]!='?' && (!bracket
|| buf
[i
]!=']') && ip_size
; i
++) {
2024 if (ip_size
& 0x04) {
2025 if (isdigit(buf
[i
])) {
2027 port_num
=port_num
*10+(buf
[i
]-'0');
2028 if (port_num
>65535) ip_size
&=~0x04;
2030 value4
=value4
*10+(buf
[i
]-'0');
2031 if (value4
>0xFFU
) ip_size
&=~0x04;
2033 } else if (buf
[i
]=='.' && addr_len
<4) {
2034 addr
[addr_len
++]=(unsigned short)(value4
& 0xFFU
);
2036 } else if (!port
&& buf
[i
]==':') {
2042 if (ip_size
& 0x60) {
2043 if (isdigit(buf
[i
])) {
2044 value6
=(value6
<<4)+(buf
[i
]-'0');
2046 if (value6
>0xFFFFU
) ip_size
&=~0x60;
2047 } else if (toupper(buf
[i
])>='A' && toupper(buf
[i
])<='F') {
2048 value6
=(value6
<<4)+(toupper(buf
[i
])-'A'+10);
2050 if (value6
>0xFFFFU
) ip_size
&=~0x60;
2051 } else if (buf
[i
]==':' && addr_len
<8) {
2052 if (nibble6_len
>0) {
2053 addr
[addr_len
++]=(unsigned short)(value6
& 0xFFFFU
);
2057 if (buf
[i
+1]==':') {
2066 if (i
==0) return(0);
2067 if (ip_size
& 0x04) {
2071 addr
[addr_len
++]=(unsigned short)(value4
& 0xFFU
);
2073 if (ip_size
& 0x60) {
2074 if (pad_pos
<0 && addr_len
!=7) {
2076 } else if (pad_pos
>=0 && addr_len
>=7)
2078 else if (nibble6_len
>0)
2079 addr
[addr_len
++]=(unsigned short)(value6
& 0xFFFFU
);
2084 if (bracket
) (*text
)--;
2086 while ((unsigned char)buf
[i
]>' ') i
++;
2087 if (next
) *next
=buf
+i
;
2090 max_mask
=(ip_size
& 0x04) ? 4*8 : 8*16;
2094 while (isdigit(buf
[i
])) i
++;
2095 if (mask
<0 || mask
>max_mask
) mask
=max_mask
;
2098 if (ip_size
& 0x60 && bracket
&& buf
[i
]==']') i
++;
2099 if (next
) *next
=buf
+i
;
2100 if (ip_size
& 0x04) {
2101 if (nbits
) *nbits
=mask
;
2102 for (i
=0 ; i
<addr_len
; i
++)
2103 ipv4
[i
]=(unsigned char)addr
[i
];
2108 if (nbits
) *nbits
=mask
;
2113 ipv6
[j
++]=(unsigned short int)addr
[i
++];
2115 while (j
<pad_pos
+pad_len
)
2119 ipv6
[j
++]=(unsigned short int)addr
[i
++];