]>
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(_("End of word not found in getword 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(_("End of word not found in getword_multisep after %d bytes.\n"),x
);
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(_("End of word not found in getword_skip 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(_("End of number not found in getword_atoll 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(_("End of number not found in getword_atoi 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
;
249 int getword_atol(long int *number
, struct getwordstruct
*gwarea
, char stop
)
255 if (gwarea
->current
[0] == '-') {
258 } else if (gwarea
->current
[0] == '+') {
262 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
263 digit
=gwarea
->current
[x
]-'0';
264 if (*number
> (LONG_MAX
-digit
)/10) {
265 debuga(_("Integer overflow detected in getword_atol in line %s\n"),gwarea
->beginning
);
268 *number
=(*number
* 10) + digit
;
270 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
271 debuga(_("End of number not found in getword_atol after %ld bytes.\n"),x
);
272 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
273 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
274 debuga(_("searching for \'x%x\'\n"),stop
);
275 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
276 #if USE_GETWORD_BACKTRACE
283 if (gwarea
->current
[x
]) ++x
;
288 int getword_atolu(unsigned long int *number
, struct getwordstruct
*gwarea
, char stop
)
293 if (gwarea
->current
[0] == '-') {
294 debuga(_("getword_atolu got a negative number.\n"));
295 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
296 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
299 if (gwarea
->current
[0] == '+') {
303 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
304 digit
=gwarea
->current
[x
]-'0';
305 if (*number
> (ULONG_MAX
-digit
)/10) {
306 debuga(_("Integer overflow detected in getword_atolu in line %s\n"),gwarea
->beginning
);
309 *number
=(*number
* 10) + digit
;
311 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
312 debuga(_("End of number not found in getword_atolu after %ld bytes.\n"),x
);
313 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
314 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
315 debuga(_("searching for \'x%x\'\n"),stop
);
316 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
317 #if USE_GETWORD_BACKTRACE
323 if (gwarea
->current
[x
]) ++x
;
329 int getword_ptr(char *orig_line
,char **word
, struct getwordstruct
*gwarea
, char stop
)
332 \note Why pass the original buffer to the function ? Because we must modify it to
333 insert the terminating ASCII zero for the word we return and that's not compatible
334 with getword_restart(). Moreover, getword_start() sometime works on constant strings
335 so this function require the original buffer to detect any missuse.
341 if (orig_line
&& orig_line
!=gwarea
->beginning
) {
342 debuga(_("Invalid buffer passed to getword_ptr\n"));
346 start
=(gwarea
->current
-gwarea
->beginning
);
347 if (word
&& orig_line
) *word
=orig_line
+start
;
348 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++);
349 sep
=(gwarea
->current
[x
]!='\0');
350 if (word
&& orig_line
) orig_line
[start
+x
] = '\0';
357 #define MAXLLL 30 //!< Maximum number of digits in long long (a guess).
358 long long int my_atoll (const char *nptr
)
360 long long int returnval
=0LL;
361 int max_digits
= MAXLLL
;
363 // Soak up all the white space
364 while (isspace( *nptr
)) {
368 //For each character left to right
369 //change the character to a single digit
370 //multiply what we had before by 10 and add the new digit
372 while (--max_digits
&& isdigit( *nptr
))
374 returnval
= ( returnval
* 10 ) + ( *nptr
++ - '0' ) ;
380 int is_absolute(const char *path
)
382 if (*path
=='/') return(1);
384 if (isalpha(path
[0]) && path
[1]==':') return(1);
389 void my_mkdir(const char *name
)
395 if(!is_absolute(name
)) {
396 debuga(_("Invalid path (%s). Please, use absolute paths only.\n"),name
);
401 for (i
=0 ; name
[i
] ; i
++) {
403 debuga(_("directory name too long: %s\n"),name
);
406 if (chars
>0 && name
[i
] == '/') {
408 if (access(w0
, R_OK
) != 0) {
409 if (mkdir(w0
,0755)) {
410 debuga(_("Cannot create directory %s - %s\n"),w0
,strerror(errno
));
415 if (name
[i
] != '/') chars
++;
419 if (access(name
, R_OK
) != 0) {
420 if (mkdir(name
,0755)) {
421 debuga(_("Cannot create directory %s - %s\n"),name
,strerror(errno
));
428 void my_lltoa(unsigned long long int n
, char *s
, int ssize
, int len
)
437 debuga(_("The requested number of digits passed to my_lltoa (%d) is bigger than the output buffer size (%d)\n"),len
,ssize
);
442 s
[slen
++] = (n
% 10) + '0';
443 } while ((n
/= 10) > 0 && slen
<ssize
);
446 for (i
= 0, j
= slen
-1; i
<j
; i
++, j
--) {
454 for(j
=slen
; j
>=0; j
--)
461 int month2num(const char *month
)
465 for(m
=0 ; m
<12 && strcmp(mtab1
[m
],month
) != 0; m
++);
469 int builddia(int day
, int month
, int year
)
471 return(year
*10000+month
*100+day
);
477 \param date1 The first date to compare.
478 \param date2 The second date to compare.
480 \retval -1 If date1<date2.
481 \retval 0 If date1==date2.
482 \retval 1 if date1>date2.
484 int compare_date(struct tm
*date1
,struct tm
*date2
)
486 if (date1
->tm_year
<date2
->tm_year
) return(-1);
487 if (date1
->tm_year
>date2
->tm_year
) return(1);
488 if (date1
->tm_mon
<date2
->tm_mon
) return(-1);
489 if (date1
->tm_mon
>date2
->tm_mon
) return(1);
490 if (date1
->tm_mday
<date2
->tm_mday
) return(-1);
491 if (date1
->tm_mday
>date2
->tm_mday
) return(1);
492 if (date1
->tm_hour
<date2
->tm_hour
) return(-1);
493 if (date1
->tm_hour
>date2
->tm_hour
) return(1);
494 if (date1
->tm_min
<date2
->tm_min
) return(-1);
495 if (date1
->tm_min
>date2
->tm_min
) return(1);
496 if (date1
->tm_sec
<date2
->tm_sec
) return(-1);
497 if (date1
->tm_sec
>date2
->tm_sec
) return(1);
501 void buildymd(const char *dia
, const char *mes
, const char *ano
, char *wdata
)
506 sprintf(wdata
,"%04d%02d%02d",atoi(ano
),nmes
+1,atoi(dia
));
510 int conv_month(const char *month
)
514 for(x
=0; x
<12 && strncmp(mtab1
[x
],month
,3)!=0; x
++);
519 const char *conv_month_name(int month
)
523 if (month
<1 || month
>12) {
524 snprintf(str
,sizeof(str
),"%03d",month
);
527 return(mtab1
[month
-1]);
531 void name_month(char *month
,int month_len
)
533 int x
, z
=atoi(month
)-1;
536 struct getwordstruct gwarea
;
538 strcpy(m
,_("January,February,March,April,May,June,July,August,September,October,November,December"));
539 getword_start(&gwarea
,m
);
542 if (getword_multisep(w
,sizeof(w
),&gwarea
,',')<0) {
543 debuga(_("The internal list of month names is invalid. Please report this bug to the translator.\n"));
546 if (getword_multisep(month
,month_len
,&gwarea
,',')<0) {
547 debuga(_("The internal list of month names is invalid. Please report this bug to the translator.\n"));
554 Write a debug message to stderr. The message is prefixed by "SARG:" to identify its origin.
556 \param msg The printf like message to format.
557 \param ... The arguments to format in the message.
559 void debuga(const char *msg
,...)
563 fputs(_("SARG: "),stderr
);
565 vfprintf(stderr
,msg
,ap
);
571 Write a debug message to stderr. The message is prefixed by "SARG: (info)".
573 \param msg The printf like message to format.
574 \param ... The arguments to format in the message.
576 void debugaz(const char *msg
,...)
580 fputs(_("SARG: (info) "),stderr
);
582 vfprintf(stderr
,msg
,ap
);
587 char *fixnum(long long int value
, int n
)
589 #define MAXLEN_FIXNUM 256
590 char num
[MAXLEN_FIXNUM
]="";
591 char buf
[MAXLEN_FIXNUM
* 2];
593 static char ret
[MAXLEN_FIXNUM
* 2];
595 register int i
, j
, k
;
597 static char abbrev
[30];
599 my_lltoa(value
, num
, sizeof(num
), 0);
601 if(DisplayedValues
==DISPLAY_ABBREV
) {
602 numlen
= strlen(num
);
604 sprintf(abbrev
,"%s",num
);
605 if(numlen
== 4 || numlen
== 7 || numlen
== 10 || numlen
== 13) {
606 snprintf(abbrev
,2,"%s",num
);
607 strncat(abbrev
,".",1);
608 strncat(abbrev
,num
+1,2);
609 if(!n
) return(abbrev
);
611 strncat(abbrev
,"K",1);
613 strncat(abbrev
,"M",1);
614 else if(numlen
== 10)
615 strncat(abbrev
,"G",1);
616 else if(numlen
== 13)
617 strncat(abbrev
,"T",1);
619 if(numlen
== 5 || numlen
== 8 || numlen
== 11 || numlen
== 14) {
620 snprintf(abbrev
,3,"%s",num
);
621 strncat(abbrev
,".",1);
622 strncat(abbrev
,num
+2,2);
623 if(!n
) return(abbrev
);
625 strncat(abbrev
,"K",1);
627 strncat(abbrev
,"M",1);
628 else if(numlen
== 11)
629 strncat(abbrev
,"G",1);
630 else if(numlen
== 14)
631 strncat(abbrev
,"T",1);
633 if(numlen
== 6 || numlen
== 9 || numlen
== 12 || numlen
== 15) {
634 snprintf(abbrev
,4,"%s",num
);
635 strncat(abbrev
,".",1);
636 strncat(abbrev
,num
+3,2);
637 if(!n
) return(abbrev
);
639 strncat(abbrev
,"K",1);
641 strncat(abbrev
,"M",1);
642 else if(numlen
== 12)
643 strncat(abbrev
,"G",1);
644 else if(numlen
== 15)
645 strncat(abbrev
,"T",1);
651 bzero(buf
, MAXLEN_FIXNUM
*2);
657 for ( i
= strlen(num
) - 1, j
= 0 ; i
> -1; i
--) {
658 if ( k
== 2 && i
!= 0 ) {
661 pbuf
[j
++] = (UseComma
) ? ',' : '.';
671 for ( i
= strlen(pbuf
) - 1, j
= 0 ; i
> -1; i
--, j
++)
680 char *fixnum2(long long int value
, int n
)
682 #define MAXLEN_FIXNUM2 1024
683 char num
[MAXLEN_FIXNUM2
];
684 char buf
[MAXLEN_FIXNUM2
* 2];
686 static char ret
[MAXLEN_FIXNUM2
* 2];
688 register int i
, j
, k
;
690 my_lltoa(value
, num
, sizeof(num
), 0);
691 bzero(buf
, MAXLEN_FIXNUM2
*2);
697 for ( i
= strlen(num
) - 1, j
= 0 ; i
> -1; i
--) {
698 if ( k
== 2 && i
!= 0 ) {
701 pbuf
[j
++] = (UseComma
) ? ',' : '.';
711 for ( i
= strlen(pbuf
) - 1, j
= 0 ; i
> -1; i
--, j
++)
720 char *buildtime(long long int elap
)
722 int num
= elap
/ 1000;
731 min
=(num
% 3600) / 60;
733 sprintf(buf
,"%02d:%02d:%02d",hor
,min
,sec
);
740 Get the date stored in the <tt>sarg-date</tt> file of a directory with the connection data.
742 \param dirname The directory to look for the connection directory.
743 \param name The name of the directory whose <tt>sarg-date</tt> file must be read.
744 \param data The buffer to store the content of the file. It must be more than 80
748 \retval -1 File not found.
750 int obtdate(const char *dirname
, const char *name
, char *data
)
755 sprintf(wdir
,"%s%s/sarg-date",dirname
,name
);
756 if ((fp_in
= fopen(wdir
, "rt")) == 0) {
757 sprintf(wdir
,"%s%s/date",dirname
,name
);
758 if ((fp_in
= fopen(wdir
, "rt")) == 0) {
764 if (!fgets(data
,80,fp_in
)) {
765 debuga(_("Failed to read the date in %s\n"),wdir
);
775 void formatdate(char *date
,int date_size
,int year
,int month
,int day
,int hour
,int minute
,int second
,int dst
)
781 memset(<m
,0,sizeof(ltm
));
782 if (year
>=1900) ltm
.tm_year
=year
-1900;
783 if (month
>=1 && month
<=12) ltm
.tm_mon
=month
-1;
784 if (day
>=1 && day
<=31) ltm
.tm_mday
=day
;
785 if (hour
>=0 && hour
<24) ltm
.tm_hour
=hour
;
786 if (minute
>=0 && minute
<60) ltm
.tm_min
=minute
;
787 if (second
>=0 && second
<60) ltm
.tm_sec
=second
;
789 unixtime
=mktime(<m
); //fill the missing entries
790 fulltm
=localtime(&unixtime
);
791 //strftime(date,date_size,"%a %b %d %H:%M:%S %Z %Y",fulltm);
792 strftime(date
,date_size
,"%c",fulltm
);
796 void computedate(int year
,int month
,int day
,struct tm
*t
)
798 memset(t
,0,sizeof(*t
));
799 t
->tm_year
=year
-1900;
805 int obtuser(const char *dirname
, const char *name
)
812 sprintf(wdir
,"%s%s/sarg-users",dirname
,name
);
813 if((fp_in
=fopen(wdir
,"r"))==NULL
) {
814 sprintf(wdir
,"%s%s/users",dirname
,name
);
815 if((fp_in
=fopen(wdir
,"r"))==NULL
) {
820 if (!fgets(tuser
,sizeof(tuser
),fp_in
)) {
821 debuga(_("Failed to read the number of users in %s\n"),wdir
);
831 void obttotal(const char *dirname
, const char *name
, int nuser
, long long int *tbytes
, long long int *media
)
836 char user
[MAX_USER_LEN
];
838 struct getwordstruct gwarea
;
844 sprintf(wdir
,"%s%s/sarg-general",dirname
,name
);
845 if ((fp_in
= fopen(wdir
, "r")) == 0) {
846 sprintf(wdir
,"%s%s/general",dirname
,name
);
847 if ((fp_in
= fopen(wdir
, "r")) == 0) {
852 if ((line
=longline_create())==NULL
) {
853 debuga(_("Not enough memory to read the file %s\n"),wdir
);
857 while((buf
=longline_read(fp_in
,line
))!=NULL
) {
858 if (strncmp(buf
,"TOTAL\t",6) == 0)
860 else if (strncmp(buf
,"TOTAL ",6) == 0)
864 getword_start(&gwarea
,buf
);
865 if (getword(user
,sizeof(user
),&gwarea
,sep
)<0) {
866 debuga(_("There is a invalid user in file %s\n"),wdir
);
869 if(strcmp(user
,"TOTAL") != 0)
871 if (getword_skip(MAXLEN
,&gwarea
,sep
)<0) {
872 debuga(_("There a broken total number of access in file %s\n"),wdir
);
875 if (getword_atoll(tbytes
,&gwarea
,sep
)<0) {
876 debuga(_("There is a broken number of bytes in file %s\n"),wdir
);
882 longline_destroy(&line
);
887 *media
=*tbytes
/ nuser
;
891 int getperiod_fromsarglog(const char *arqtt
,struct periodstruct
*period
)
894 int day0
, month0
, year0
, hour0
, minute0
;
895 int day1
, month1
, year1
, hour1
, minute1
;
898 memset(period
,0,sizeof(*period
));
901 while((str
=strstr(str
,"sarg-"))!=NULL
) {
903 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
904 day0
=(str
[0]-'0')*10+(str
[1]-'0');
905 if (day0
<1 || day0
>31) continue;
907 month0
=(str
[0]-'0')*10+(str
[1]-'0')-1;
908 if (month0
<0 || month0
>11) continue;
911 for (i
=0 ; isdigit(str
[i
]) && i
<4 ; i
++) year0
=year0
*10+(str
[i
]-'0');
914 if (str
[0]!='_') continue;
917 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
918 hour0
=(str
[0]-'0')*10+(str
[1]-'0');
920 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
921 minute0
=(str
[0]-'0')*10+(str
[1]-'0');
924 if (*str
!= '-') continue;
927 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
928 day1
=(str
[0]-'0')*10+(str
[1]-'0');
929 if (day1
<1 || day1
>31) continue;
931 month1
=(str
[0]-'0')*10+(str
[1]-'0')-1;
932 if (month1
<0 || month1
>11) continue;
935 for (i
=0 ; isdigit(str
[i
]) && i
<4 ; i
++) year1
=year1
*10+(str
[i
]-'0');
939 if (str
[0]!='_') continue;
942 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
943 hour1
=(str
[0]-'0')*10+(str
[1]-'0');
945 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
946 minute1
=(str
[0]-'0')*10+(str
[1]-'0');
949 period
->start
.tm_mday
=day0
;
950 period
->start
.tm_mon
=month0
;
951 period
->start
.tm_year
=year0
-1900;
952 period
->start
.tm_hour
=hour0
;
953 period
->start
.tm_min
=minute0
;
954 period
->end
.tm_mday
=day1
;
955 period
->end
.tm_mon
=month1
;
956 period
->end
.tm_year
=year1
-1900;
957 period
->end
.tm_hour
=hour1
;
958 period
->end
.tm_min
=minute1
;
964 void getperiod_fromrange(struct periodstruct
*period
,int dfrom
,int duntil
)
966 memset(&period
->start
,0,sizeof(period
->start
));
967 period
->start
.tm_mday
=dfrom
%100;
968 period
->start
.tm_mon
=(dfrom
/100)%100-1;
969 period
->start
.tm_year
=(dfrom
/10000)-1900;
971 memset(&period
->end
,0,sizeof(period
->end
));
972 period
->end
.tm_mday
=duntil
%100;
973 period
->end
.tm_mon
=(duntil
/100)%100-1;
974 period
->end
.tm_year
=(duntil
/10000)-1900;
978 Update the \a main period to encompass the period in \a candidate.
980 void getperiod_merge(struct periodstruct
*main
,struct periodstruct
*candidate
)
985 mdate
=(main
->start
.tm_year
)*10000+(main
->start
.tm_mon
)*100+main
->start
.tm_mday
;
986 cdate
=(candidate
->start
.tm_year
)*10000+(candidate
->start
.tm_mon
)*100+candidate
->start
.tm_mday
;
987 if (cdate
<mdate
) memcpy(&main
->start
,&candidate
->start
,sizeof(struct tm
));
989 mdate
=(main
->end
.tm_year
)*10000+(main
->end
.tm_mon
)*100+main
->end
.tm_mday
;
990 cdate
=(candidate
->end
.tm_year
)*10000+(candidate
->end
.tm_mon
)*100+candidate
->end
.tm_mday
;
991 if (cdate
>mdate
) memcpy(&main
->end
,&candidate
->end
,sizeof(struct tm
));
994 int getperiod_buildtext(struct periodstruct
*period
)
998 char text1
[40], text2
[40];
1001 i
=strftime(text1
, sizeof(text1
), "%Y %b %d", &period
->start
);
1002 } else if(df
=='e') {
1003 i
=strftime(text1
, sizeof(text1
), "%d %b %Y", &period
->start
);
1004 } else /*if (df=='w')*/ {
1005 IndexTree
=INDEX_TREE_FILE
;
1006 i
=strftime(text1
, sizeof(text1
), "%Y.%U", &period
->start
);
1008 if (i
== 0) return(-1);
1010 range
=(period
->start
.tm_year
!=period
->end
.tm_year
||
1011 period
->start
.tm_mon
!=period
->end
.tm_mon
||
1012 period
->start
.tm_mday
!=period
->end
.tm_mday
);
1015 i
=strftime(text2
, sizeof(text2
)-i
, "%Y %b %d", &period
->end
);
1016 } else if (df
=='e') {
1017 i
=strftime(text2
, sizeof(text2
)-i
, "%d %b %Y", &period
->end
);
1019 i
=strftime(text2
, sizeof(text2
)-i
, "%Y.%U", &period
->end
);
1021 if (i
== 0) return(-1);
1025 snprintf(period
->text
,sizeof(period
->text
),"%s-%s",text1
,text2
);
1026 snprintf(period
->html
,sizeof(period
->html
),"%s—%s",text1
,text2
);
1028 safe_strcpy(period
->text
,text1
,sizeof(period
->text
));
1029 safe_strcpy(period
->html
,text1
,sizeof(period
->html
));
1034 static void copy_images(void)
1036 FILE *img_in
, *img_ou
;
1038 char imgdir
[MAXLEN
];
1039 char srcfile
[MAXLEN
];
1040 char dstfile
[MAXLEN
];
1042 struct dirent
*direntp
;
1043 char buffer
[MAXLEN
];
1047 if (snprintf(images
,sizeof(images
),"%simages",outdir
)>=sizeof(images
)) {
1048 debuga(_("Cannot copy images to target directory %simages\n"),outdir
);
1051 if (access(images
,R_OK
)!=0) {
1052 if (mkdir(images
,0755)) {
1053 debuga(_("Cannot create directory %s - %s\n"),images
,strerror(errno
));
1058 strcpy(imgdir
,IMAGEDIR
);
1059 dirp
= opendir(imgdir
);
1061 debuga(_("(util) Can't open directory %s: %s\n"),imgdir
,strerror(errno
));
1064 while ((direntp
= readdir( dirp
)) != NULL
){
1065 if(direntp
->d_name
[0]=='.')
1067 sprintf(srcfile
,"%s/%s",imgdir
,direntp
->d_name
);
1068 if (stat(srcfile
,&info
)) {
1069 debuga(_("Cannot stat \"%s\" - %s\n"),srcfile
,strerror(errno
));
1072 if (S_ISREG(info
.st_mode
)) {
1073 sprintf(dstfile
,"%s/%s",images
,direntp
->d_name
);
1074 img_in
= fopen(srcfile
, "rb");
1076 img_ou
= fopen(dstfile
, "wb");
1078 while ((nread
= fread(buffer
,1,sizeof(buffer
),img_in
))>0) {
1079 if (fwrite(buffer
,1,nread
,img_ou
)!=nread
) {
1080 debuga(_("Failed to copy image %s to %s\n"),srcfile
,dstfile
);
1084 if (fclose(img_ou
)==EOF
) {
1085 debuga(_("Error while copying image %s: %s\n"),dstfile
,strerror(errno
));
1089 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open/create file", dstfile
, strerror(errno
));
1092 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open file", srcfile
, strerror(errno
));
1095 (void) closedir(dirp
);
1100 int vrfydir(const struct periodstruct
*per1
, const char *addr
, const char *site
, const char *us
, const char *form
)
1105 char dirname2
[MAXLEN
];
1113 strcpy(wdir
,outdir
);
1115 y1
=per1
->start
.tm_year
+1900;
1116 y2
=per1
->end
.tm_year
+1900;
1117 m1
=per1
->start
.tm_mon
+1;
1118 m2
=per1
->end
.tm_mon
+1;
1119 d1
=per1
->start
.tm_mday
;
1120 d2
=per1
->end
.tm_mday
;
1121 if(IndexTree
== INDEX_TREE_DATE
) {
1122 wlen
+=sprintf(wdir
+wlen
,"%04d",y1
);
1123 if(y1
!=y2
) wlen
+=sprintf(wdir
+wlen
,"-%04d",y2
);
1124 if(access(wdir
, R_OK
) != 0)
1127 wlen
+=sprintf(wdir
+wlen
,"/%02d",m1
);
1128 if(m1
!= m2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",m2
);
1129 if(access(wdir
, R_OK
) != 0)
1132 wlen
+=sprintf(wdir
+wlen
,"/%02d",d1
);
1133 if(d1
!=d2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",d2
);
1136 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%04d%s%02d-%04d%s%02d",y1
,
1137 conv_month_name(m1
),d1
,y2
,conv_month_name(m2
),d2
);
1138 } else if (df
== 'e') {
1139 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%02d%s%04d-%02d%s%04d",d1
,
1140 conv_month_name(m1
),y1
,d2
,conv_month_name(m2
),y2
);
1141 } else if (df
== 'w') {
1142 wlen2
=strftime(wdir
+wlen
, sizeof(wdir
)-wlen
, "%Y.%U", &per1
->start
);
1143 if (wlen2
==0) return(-1);
1149 struct userinfostruct
*uinfo
=userinfo_find_from_id(us
);
1152 strcat(wdir
,uinfo
->filename
);
1155 if(addr
[0] != '\0') {
1159 if(site
[0] != '\0') {
1164 strcpy(outdirname
,wdir
);
1166 if(IndexTree
!= INDEX_TREE_DATE
) {
1167 if(!OverwriteReport
) {
1169 if(access(wdir
,R_OK
) == 0) {
1170 sprintf(wdir
,"%s.%d",outdirname
,num
);
1179 debuga(_("File %s already exists, moved to %s\n"),outdirname
,wdir
);
1180 rename(outdirname
,wdir
);
1183 if(access(outdirname
,R_OK
) == 0) {
1184 unlinkdir(outdirname
,1);
1187 my_mkdir(outdirname
);
1189 strcpy(dirname2
,wdir
);
1190 if(!OverwriteReport
) {
1192 if(access(wdir
,R_OK
) == 0) {
1193 sprintf(wdir
,"%s.%d",dirname2
,num
);
1202 debuga(_("File %s already exists, moved to %s\n"),dirname2
,wdir
);
1203 rename(dirname2
,wdir
);
1204 strcpy(dirname2
,wdir
);
1207 if(access(wdir
,R_OK
) == 0) {
1212 if(access(wdir
, R_OK
) != 0)
1216 strcpy(dirname2
,wdir
);
1218 sprintf(wdir
,"%s/sarg-date",outdirname
);
1219 if ((fp_ou
= fopen(wdir
, "wt")) == 0) {
1220 debuga(_("cannot open %s for writing: %s\n"),wdir
,strerror(errno
));
1225 //strftime(wdir,sizeof(wdir),"%a %b %d %H:%M:%S %Z %Y",localtime(&curtime));
1226 loctm
=localtime(&curtime
);
1227 strftime(wdir
,sizeof(wdir
),"%Y-%m-%d %H:%M:%S",loctm
);
1228 if (fprintf(fp_ou
,"%s %d\n",wdir
,loctm
->tm_isdst
)<0) {
1229 debuga(_("Failed to write the date in %s\n"),wdir
);
1233 if (fclose(fp_ou
)==EOF
) {
1234 debuga(_("Failed to write the date in %s: %s\n"),wdir
,strerror(errno
));
1243 Copy a string without overflowing the buffer. The copied string
1244 is properly terminated by an ASCII zero.
1246 \param dest The destination buffer.
1247 \param src The source buffer.
1248 \param length The size of the destination buffer. The program is aborted
1249 if the length is negative or zero.
1251 void safe_strcpy(char *dest
,const char *src
,int length
)
1254 debuga(_("Invalid buffer length passed to the function to safely copy a string\n"));
1257 strncpy(dest
,src
,length
-1);
1258 dest
[length
-1]='\0';
1261 void strip_latin(char *line
)
1268 for (i
=0;line
[i
];i
++){
1270 if (line
[i
]==';') skip
=0;
1282 void zdate(char *ftime
,int ftimesize
, char DateFormat
)
1288 local
= localtime(&t
);
1289 if (DateFormat
=='u')
1290 strftime(ftime
, ftimesize
, "%b/%d/%Y %H:%M", local
);
1291 else if (DateFormat
=='e')
1292 strftime(ftime
, ftimesize
, "%d/%b/%Y-%H:%M", local
);
1293 else if (DateFormat
=='w')
1294 strftime(ftime
, ftimesize
, "%W-%H-%M", local
);
1299 char *fixtime(long long int elap
)
1301 int num
= elap
/ 1000;
1305 static char buf
[12];
1308 min
=(num
% 3600) / 60;
1311 if(hor
==0 && min
==0 && sec
==0)
1314 sprintf(buf
,"%d:%02d:%02d",hor
,min
,sec
);
1320 void date_from(char *date
, int *dfrom
, int *duntil
)
1329 if (isdigit(date
[0])) {
1332 if (sscanf(date
,"%d/%d/%d%n",&d0
,&m0
,&y0
,&next
)!=3 || y0
<100 || m0
<1 || m0
>12 || d0
<1 || d0
>31 || next
<0) {
1333 debuga(_("The date passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1336 if (date
[next
]=='-') {
1337 if (sscanf(date
+next
+1,"%d/%d/%d",&d1
,&m1
,&y1
)!=3 || y1
<100 || m1
<1 || m1
>12 || d1
<1 || d1
>31) {
1338 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1341 } else if (date
[next
]!='\0') {
1342 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1352 struct tm
*Date0
,Date1
;
1354 if (time(&Today
)==(time_t)-1) {
1355 debuga(_("Failed to get the current time\n"));
1358 if (sscanf(date
,"day-%d",&i
)==1) {
1360 debuga(_("Invalid number of days in -d parameter\n"));
1364 Date0
=localtime(&Today
);
1366 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1369 y0
=y1
=Date0
->tm_year
+1900;
1370 m0
=m1
=Date0
->tm_mon
+1;
1371 d0
=d1
=Date0
->tm_mday
;
1372 } else if (sscanf(date
,"week-%d",&i
)==1) {
1374 There is no portable way to find the first day of the week even though the
1375 information is available in the locale. nl_langinfo has the unofficial
1376 parameters _NL_TIME_FIRST_WEEKDAY and _NL_TIME_WEEK_1STDAY but they are
1377 undocumented as is their return value and it is discouraged to use them.
1378 Beside, nl_langinfo isn't available on windows and the first day of the
1379 week isn't available at all on that system.
1381 const int FirstWeekDay
=1;
1385 debuga(_("Invalid number of weeks in -d parameter\n"));
1388 Date0
=localtime(&Today
);
1390 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1393 WeekBegin
=Today
-((Date0
->tm_wday
-FirstWeekDay
+7)%7)*24*60*60;
1394 WeekBegin
-=i
*7*24*60*60;
1395 Date0
=localtime(&WeekBegin
);
1397 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1400 y0
=Date0
->tm_year
+1900;
1403 WeekBegin
+=6*24*60*60;
1404 Date0
=localtime(&WeekBegin
);
1406 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1409 y1
=Date0
->tm_year
+1900;
1412 } else if (sscanf(date
,"month-%d",&i
)==1) {
1414 debuga(_("Invalid number of months in -d parameter\n"));
1417 Date0
=localtime(&Today
);
1419 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1422 if (Date0
->tm_mon
<i
%12) {
1423 y0
=Date0
->tm_year
+1900-i
/12-1;
1424 m0
=(Date0
->tm_mon
+12-i
%12)%12+1;
1427 y0
=Date0
->tm_year
+1900-i
/12;
1428 m0
=Date0
->tm_mon
-i
%12+1;
1431 memcpy(&Date1
,Date0
,sizeof(struct tm
));
1436 Date1
.tm_year
=y0
-1900;
1439 Date1
.tm_year
=y0
-1900+1;
1443 Date0
=localtime(&t1
);
1444 y1
=Date0
->tm_year
+1900;
1448 debuga(_("Invalid date range passed on command line\n"));
1453 *dfrom
=y0
*10000+m0
*100+d0
;
1454 *duntil
=y1
*10000+m1
*100+d1
;
1455 sprintf(date
,"%02d/%02d/%04d-%02d/%02d/%04d",d0
,m0
,y0
,d1
,m1
,y1
);
1460 char *strlow(char *string
)
1466 for (s
= string
; *s
; ++s
)
1476 char *strup(char *string
)
1482 for (s
= string
; *s
; ++s
)
1490 void removetmp(const char *outdir
)
1495 if(!RemoveTempFiles
)
1499 debuga(_("Purging temporary file sarg-general\n"));
1501 if (snprintf(filename
,sizeof(filename
),"%s/sarg-general",outdir
)>=sizeof(filename
)) {
1502 debuga(_("(removetmp) directory too long to remove %s/sarg-period\n"),outdir
);
1505 if((fp_gen
=fopen(filename
,"w"))==NULL
){
1506 debuga(_("(removetmp) Cannot open file %s: %s\n"),filename
,strerror(errno
));
1509 totalger(fp_gen
,filename
);
1510 if (fclose(fp_gen
)==EOF
) {
1511 debuga(_("Failed to close %s after writing the total line: %s\n"),filename
,strerror(errno
));
1516 void load_excludecodes(const char *ExcludeCodes
)
1524 if(ExcludeCodes
[0] == '\0')
1527 if((fp_in
=fopen(ExcludeCodes
,"r"))==NULL
) {
1528 debuga(_("(util) Cannot open file %s (exclude_codes): %s\n"),ExcludeCodes
,strerror(errno
));
1532 if (fseek(fp_in
, 0, SEEK_END
)==-1) {
1533 debuga(_("Failed to move till the end of the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1536 MemSize
= ftell(fp_in
);
1538 debuga(_("Cannot get the size of file %s\n"),ExcludeCodes
);
1541 if (fseek(fp_in
, 0, SEEK_SET
)==-1) {
1542 debuga(_("Failed to rewind the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1547 if((excludecode
=(char *) malloc(MemSize
))==NULL
) {
1548 debuga(_("malloc error (%ld)\n"),MemSize
);
1551 memset(excludecode
,0,MemSize
);
1554 while(fgets(data
,sizeof(data
),fp_in
)!=NULL
) {
1555 if (data
[0]=='#') continue;
1556 for (i
=strlen(data
)-1 ; i
>=0 && (unsigned char)data
[i
]<=' ' ; i
--) data
[i
]='\0';
1558 if (Stored
+i
+2>=MemSize
) {
1559 debuga(_("Too many codes to exclude in file %s\n"),ExcludeCodes
);
1562 strcat(excludecode
,data
);
1563 strcat(excludecode
,";");
1571 void free_excludecodes(void)
1579 int vercode(const char *code
)
1584 if (excludecode
&& excludecode
[0]!='\0') {
1588 if (strncmp(code
,cod
,clen
)==0 && cod
[clen
]==';')
1590 cod
=strchr(cod
,';');
1597 void fixnone(char *str
)
1601 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--);
1602 if(i
==3 && strncmp(str
,"none",4) == 0)
1608 void fixendofline(char *str
)
1612 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--) str
[i
]=0;
1615 #ifdef LEGACY_TESTVALIDUSERCHAR
1616 int testvaliduserchar(const char *user
)
1621 for (y
=0; y
<strlen(UserInvalidChar
); y
++) {
1622 for (x
=0; x
<strlen(user
); x
++) {
1623 if(user
[x
] == UserInvalidChar
[y
])
1630 int testvaliduserchar(const char *user
)
1632 char * p_UserInvalidChar
= UserInvalidChar
;
1633 const char * p_user
;
1635 while( *p_UserInvalidChar
) {
1638 if( *p_UserInvalidChar
== *p_user
)
1642 p_UserInvalidChar
++ ;
1648 int compar( const void *a
, const void *b
)
1650 if( *(int *)a
> *(int *)b
) return 1;
1651 if( *(int *)a
< *(int *)b
) return -1;
1655 int getnumlist( char *buf
, numlist
*list
, const int len
, const int maxvalue
)
1657 int i
, j
, d
, flag
, r1
, r2
;
1658 char *pbuf
, **bp
, *strbufs
[ 24 ];
1661 strtok( buf
, " \t" );
1662 for( *bp
= strtok( NULL
, "," ), list
->len
= 0; *bp
; *bp
= strtok( NULL
, "," ) ) {
1663 if( ++bp
>= &strbufs
[ 24 ] )
1670 for( i
= 0; i
< list
->len
; i
++ ) {
1671 if( strchr( strbufs
[ i
], '-' ) != 0 ) {
1672 pbuf
= strbufs
[ i
];
1673 strtok( pbuf
, "-" );
1674 pbuf
= strtok( NULL
, "\0" );
1675 r1
= atoi( strbufs
[ i
] );
1676 if( ( r2
= atoi( pbuf
) ) >= maxvalue
|| r1
>= r2
)
1678 if( i
+ d
+ ( r2
- r1
) + 1 <= len
) {
1679 for( j
= r1
; j
<= r2
; j
++ )
1680 list
->list
[ i
+ d
++ ] = j
;
1685 if( ( list
->list
[ i
+ d
] = atoi( strbufs
[ i
] ) ) >= maxvalue
)
1689 qsort( list
->list
, list
->len
, sizeof( int ), compar
);
1692 for( i
= 0; i
< list
->len
- 1; i
++ )
1693 if( list
->list
[ i
] == list
->list
[ i
+ 1 ] ) {
1694 for( j
= i
+ 1; j
< list
->len
; j
++ )
1695 list
->list
[ j
- 1 ] = list
->list
[ j
];
1705 char *get_size(const char *path
, const char *file
)
1708 static char response
[255];
1712 if (snprintf(cmd
,sizeof(cmd
),"du -skh %s%s",path
,file
)>=sizeof(cmd
)) {
1713 debuga(_("Cannot get disk space because the path %s%s is too long\n"),path
,file
);
1716 if ((fp
= popen(cmd
, "r")) == NULL
) {
1717 debuga(_("Cannot get disk space with command %s\n"),cmd
);
1720 if (!fgets(response
, sizeof(response
), fp
)) {
1721 debuga(_("Cannot get disk size with command %s\n"),cmd
);
1724 ptr
=strchr(response
,'\t');
1726 debuga(_("The command %s failed\n"),cmd
);
1735 void show_info(FILE *fp_ou
)
1739 if(!ShowSargInfo
) return;
1740 zdate(ftime
, sizeof(ftime
), df
);
1741 fputs("<div class=\"info\">",fp_ou
);
1742 fprintf(fp_ou
,_("Generated by <a href='%s'>%s-%s</a> on %s"),URL
,PGM
,VERSION
,ftime
);
1743 fputs("</div>\n",fp_ou
);
1746 void show_sarg(FILE *fp_ou
, int depth
)
1750 if(!ShowSargLogo
) return;
1751 fputs("<div class=\"logo\"><a href=\"http://sarg.sourceforge.net\"><img src=\"",fp_ou
);
1752 for (i
=0 ; i
<depth
; i
++)
1754 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
);
1757 void write_logo_image(FILE *fp_ou
)
1759 if(LogoImage
[0]!='\0')
1760 fprintf(fp_ou
, "<div class=\"logo\"><img src=\"%s\" width=\"%s\" height=\"%s\" alt=\"Logo\"> %s</div>\n",LogoImage
,Width
,Height
,LogoText
);
1763 void write_html_head(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1767 fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n",fp_ou
);
1768 fprintf(fp_ou
, "<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n",CharSet
);
1769 if (page_title
) fprintf(fp_ou
,"<title>%s</title>\n",page_title
);
1771 if ((javascript
& HTML_JS_SORTTABLE
)!=0 && SortTableJs
[0]) {
1772 fputs("<script type=\"text/javascript\" src=\"",fp_ou
);
1773 if (strncmp(SortTableJs
,"../",3)==0) {
1774 for (i
=0 ; i
<depth
; i
++) fputs("../",fp_ou
);
1776 fputs(SortTableJs
,fp_ou
);
1777 fputs("\"></script>\n",fp_ou
);
1779 fputs("</head>\n<body>\n",fp_ou
);
1782 void write_html_header(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1784 write_html_head(fp_ou
,depth
,page_title
,javascript
);
1785 write_logo_image(fp_ou
);
1786 show_sarg(fp_ou
, depth
);
1787 fprintf(fp_ou
,"<div class=\"title\"><table cellpadding=\"0\" cellspacing=\"0\">\n<tr><th class=\"title_c\">%s</th></tr>\n",Title
);
1790 void close_html_header(FILE *fp_ou
)
1792 fputs("</table></div>\n",fp_ou
);
1795 int write_html_trailer(FILE *fp_ou
)
1798 if (fputs("</body>\n</html>\n",fp_ou
)==EOF
) return(-1);
1802 void output_html_string(FILE *fp_ou
,const char *str
,int maxlen
)
1806 while (*str
&& (maxlen
<=0 || i
<maxlen
)) {
1809 fputs("&",fp_ou
);
1812 fputs("<",fp_ou
);
1815 fputs(">",fp_ou
);
1818 fputs(""",fp_ou
);
1821 fputs("'",fp_ou
);
1829 if (maxlen
>0 && i
>=maxlen
)
1830 fputs("…",fp_ou
);
1833 void output_html_url(FILE *fp_ou
,const char *url
)
1837 fputs("&",fp_ou
);
1845 Write a host name inside an A tag of a HTML file. If the host name starts
1846 with a star, it is assumed to be an alias that cannot be put inside a link
1847 so the A tag is not written around the host name.
1849 \param fp_ou The handle of the HTML file.
1850 \param url The host to display in the HTML file.
1851 \param maxlen The maximum number of characters to print into the host name.
1853 void output_html_link(FILE *fp_ou
,const char *url
,int maxlen
)
1855 if (url
[0]==ALIAS_PREFIX
) {
1856 // this is an alias, no need for a A tag
1857 output_html_string(fp_ou
,url
+1,100);
1859 if (skip_scheme(url
)==url
)
1860 fputs("<a href=\"http://",fp_ou
);//no scheme in the url, assume http:// to make the link clickable
1862 fputs("<a href=\"",fp_ou
);//the scheme is in the url, no need to add one
1863 output_html_url(fp_ou
,url
);
1865 output_html_string(fp_ou
,url
,100);
1866 fputs("</a>",fp_ou
);
1870 void url_module(const char *url
, char *w2
)
1876 for(x
=strlen(url
)-1; x
>=0; x
--) {
1877 if(url
[x
] == '/' || y
>=sizeof(w
)-1) break;
1886 for(y
=y
-1; y
>=0; y
--) {
1892 void url_to_file(const char *url
,char *file
,int filesize
)
1898 for(i
=0; i
<filesize
&& *url
; url
++) {
1899 if(isalnum(*url
) || *url
=='-' || *url
=='_' || *url
=='.') {
1903 if (!skip
) file
[i
++]='_';
1912 printf(_("SARG Version: %s\n"),VERSION
);
1916 char *get_param_value(const char *param
,char *line
)
1920 while (*line
==' ' || *line
=='\t') line
++;
1922 if (strncasecmp(line
,param
,plen
)) return(NULL
);
1923 if (line
[plen
]!=' ' && line
[plen
]!='\t') return(NULL
);
1925 while (*line
==' ' || *line
=='\t') line
++;
1929 void unlinkdir(const char *dir
,bool contentonly
)
1933 struct dirent
*direntp
;
1939 while ((direntp
= readdir(dirp
)) != NULL
) {
1940 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
1941 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
1943 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
1944 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
1948 err
=lstat(dname
,&st
);
1950 err
=stat(dname
,&st
);
1953 debuga(_("cannot stat %s\n"),dname
);
1956 if (S_ISREG(st
.st_mode
)) {
1957 if (unlink(dname
)) {
1958 debuga(_("Cannot delete \"%s\": %s\n"),dname
,strerror(errno
));
1961 } else if (S_ISDIR(st
.st_mode
)) {
1964 debuga(_("unknown path type %s\n"),dname
);
1971 debuga(_("Cannot delete \"%s\": %s\n"),dir
,strerror(errno
));
1978 Delete every file from the temporary directory where sarg is told to store its
1981 As any stray file left over by a previous run would be included in the report, we
1982 must delete every file from the temporary directory before we start processing the logs.
1984 But the temporary directory is given by the user either in the configuration file or
1985 on the command line. We check that the user didn't give a wrong directory by looking
1986 at the files stored in the directory. If a single file is not one of ours, we abort.
1988 \param dir The temporary directory to purge.
1990 void emptytmpdir(const char *dir
)
1994 struct dirent
*direntp
;
2000 static const char *TmpExt
[]=
2015 // make sure the temporary directory contains only our files
2016 while ((direntp
= readdir(dirp
)) != NULL
) {
2017 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
2018 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
2021 // is it one of our files
2022 dlen
=strlen(direntp
->d_name
);
2023 for (i
=sizeof(TmpExt
)/sizeof(TmpExt
[0])-1 ; i
>=0 ; i
--) {
2024 elen
=strlen(TmpExt
[i
]);
2025 if (dlen
>=elen
&& strcasecmp(direntp
->d_name
+dlen
-elen
,TmpExt
[i
])==0) break;
2028 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2029 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2030 "directory or manually delete the content of \"%s\"\n"),direntp
->d_name
,dir
,dir
);
2034 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
2035 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
2040 err
=lstat(dname
,&st
);
2042 err
=stat(dname
,&st
);
2045 debuga(_("cannot stat \"%s\"\n"),dname
);
2048 if (S_ISDIR(st
.st_mode
)) {
2050 } else if (!S_ISREG(st
.st_mode
)) {
2051 debuga(_("Unknown path type for \"%s\". Check temporary directory\n"),dname
);
2057 // now delete our files
2058 while ((direntp
= readdir(dirp
)) != NULL
) {
2059 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
2060 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
2063 // is it one of our files
2064 dlen
=strlen(direntp
->d_name
);
2065 for (i
=sizeof(TmpExt
)/sizeof(TmpExt
[0])-1 ; i
>=0 ; i
--) {
2066 elen
=strlen(TmpExt
[i
]);
2067 if (dlen
>=elen
&& strcasecmp(direntp
->d_name
+dlen
-elen
,TmpExt
[i
])==0) break;
2070 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2071 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2072 "directory or manually delete the content of \"%s\"\n"),direntp
->d_name
,dir
,dir
);
2076 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
2077 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
2081 err
=lstat(dname
,&st
);
2083 err
=stat(dname
,&st
);
2086 debuga(_("cannot stat \"%s\"\n"),dname
);
2089 if (S_ISREG(st
.st_mode
)) {
2090 if (unlink(dname
)) {
2091 debuga(_("Cannot delete \"%s\": %s\n"),dname
,strerror(errno
));
2095 debuga(_("unknown path type %s\n"),dname
);
2102 Extract an url, IPv4 or IPv6 from a buffer. The IP addresses may end with a
2105 \param buf The buffer to parse.
2106 \param text A pointer to set to the beginning of the string pattern. No terminating zero is inserted.
2107 The pointer may be NULL.
2108 \param ipv4 A 4 bytes buffer to store the bytes of the IPv4 address.
2109 \param ipv6 A 8 short integers buffer to store the values of the IPv6 address.
2110 \param nbits The number of prefix bits for an IP address.
2111 \param next The content of the line after the extracted address.
2113 \retval 3 The pattern is a IPv6 address.
2114 \retval 2 The pattern is a IPv4 address.
2115 \retval 1 The patter is a string.
2116 \retval 0 Empty pattern.
2118 int extract_address_mask(const char *buf
,const char **text
,unsigned char *ipv4
,unsigned short int *ipv6
,int *nbits
,const char **next
)
2123 unsigned int value4
, value6
;
2124 unsigned short int addr
[8];
2134 // skip leading spaces and tabs
2135 while (*buf
&& (*buf
==' ' || *buf
=='\t')) buf
++;
2137 // find out the nature of the pattern
2138 ip_size
=0x60 | 0x04;
2149 for (i
=0 ; (unsigned char)buf
[i
]>' ' && buf
[i
]!='/' && buf
[i
]!='?' && (!bracket
|| buf
[i
]!=']') && ip_size
; i
++) {
2150 if (ip_size
& 0x04) {
2151 if (isdigit(buf
[i
])) {
2153 port_num
=port_num
*10+(buf
[i
]-'0');
2154 if (port_num
>65535) ip_size
&=~0x04;
2156 value4
=value4
*10+(buf
[i
]-'0');
2157 if (value4
>0xFFU
) ip_size
&=~0x04;
2159 } else if (buf
[i
]=='.' && addr_len
<4) {
2160 addr
[addr_len
++]=(unsigned short)(value4
& 0xFFU
);
2162 } else if (!port
&& buf
[i
]==':') {
2168 if (ip_size
& 0x60) {
2169 if (isdigit(buf
[i
])) {
2170 value6
=(value6
<<4)+(buf
[i
]-'0');
2172 if (value6
>0xFFFFU
) ip_size
&=~0x60;
2173 } else if (toupper(buf
[i
])>='A' && toupper(buf
[i
])<='F') {
2174 value6
=(value6
<<4)+(toupper(buf
[i
])-'A'+10);
2176 if (value6
>0xFFFFU
) ip_size
&=~0x60;
2177 } else if (buf
[i
]==':' && addr_len
<8) {
2178 if (nibble6_len
>0) {
2179 addr
[addr_len
++]=(unsigned short)(value6
& 0xFFFFU
);
2183 if (buf
[i
+1]==':') {
2192 if (i
==0) return(0);
2193 if (ip_size
& 0x04) {
2197 addr
[addr_len
++]=(unsigned short)(value4
& 0xFFU
);
2199 if (ip_size
& 0x60) {
2200 if (pad_pos
<0 && addr_len
!=7) {
2202 } else if (pad_pos
>=0 && addr_len
>=7)
2204 else if (nibble6_len
>0)
2205 addr
[addr_len
++]=(unsigned short)(value6
& 0xFFFFU
);
2210 if (bracket
) (*text
)--;
2212 while ((unsigned char)buf
[i
]>' ') i
++;
2213 if (next
) *next
=buf
+i
;
2216 max_mask
=(ip_size
& 0x04) ? 4*8 : 8*16;
2220 while (isdigit(buf
[i
])) i
++;
2221 if (mask
<0 || mask
>max_mask
) mask
=max_mask
;
2224 if (ip_size
& 0x60 && bracket
&& buf
[i
]==']') i
++;
2225 if (next
) *next
=buf
+i
;
2226 if (ip_size
& 0x04) {
2227 if (nbits
) *nbits
=mask
;
2228 for (i
=0 ; i
<addr_len
; i
++)
2229 ipv4
[i
]=(unsigned char)addr
[i
];
2234 if (nbits
) *nbits
=mask
;
2239 ipv6
[j
++]=(unsigned short int)addr
[i
++];
2241 while (j
<pad_pos
+pad_len
)
2245 ipv6
[j
++]=(unsigned short int)addr
[i
++];