]>
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
);
605 else if(numlen
== 4 || numlen
== 7 || numlen
== 10 || numlen
== 13) {
606 memcpy(abbrev
,num
,1);
608 strncpy(abbrev
+2,num
+1,2);
610 if(!n
) return(abbrev
);
615 else if(numlen
== 10)
617 else if(numlen
== 13)
620 else if(numlen
== 5 || numlen
== 8 || numlen
== 11 || numlen
== 14) {
621 memcpy(abbrev
,num
,2);
623 strncpy(abbrev
+3,num
+2,2);
625 if(!n
) return(abbrev
);
630 else if(numlen
== 11)
632 else if(numlen
== 14)
635 else if(numlen
== 6 || numlen
== 9 || numlen
== 12 || numlen
== 15) {
636 memcpy(abbrev
,num
,3);
638 strncpy(abbrev
+4,num
+3,2);
640 if(!n
) return(abbrev
);
645 else if(numlen
== 12)
647 else if(numlen
== 15)
654 bzero(buf
, MAXLEN_FIXNUM
*2);
660 for ( i
= strlen(num
) - 1, j
= 0 ; i
> -1; i
--) {
661 if ( k
== 2 && i
!= 0 ) {
664 pbuf
[j
++] = (UseComma
) ? ',' : '.';
674 for ( i
= strlen(pbuf
) - 1, j
= 0 ; i
> -1; i
--, j
++)
683 char *fixnum2(long long int value
, int n
)
685 #define MAXLEN_FIXNUM2 1024
686 char num
[MAXLEN_FIXNUM2
];
687 char buf
[MAXLEN_FIXNUM2
* 2];
689 static char ret
[MAXLEN_FIXNUM2
* 2];
691 register int i
, j
, k
;
693 my_lltoa(value
, num
, sizeof(num
), 0);
694 bzero(buf
, MAXLEN_FIXNUM2
*2);
700 for ( i
= strlen(num
) - 1, j
= 0 ; i
> -1; i
--) {
701 if ( k
== 2 && i
!= 0 ) {
704 pbuf
[j
++] = (UseComma
) ? ',' : '.';
714 for ( i
= strlen(pbuf
) - 1, j
= 0 ; i
> -1; i
--, j
++)
723 char *buildtime(long long int elap
)
725 int num
= elap
/ 1000;
734 min
=(num
% 3600) / 60;
736 sprintf(buf
,"%02d:%02d:%02d",hor
,min
,sec
);
743 Get the date stored in the <tt>sarg-date</tt> file of a directory with the connection data.
745 \param dirname The directory to look for the connection directory.
746 \param name The name of the directory whose <tt>sarg-date</tt> file must be read.
747 \param data The buffer to store the content of the file. It must be more than 80
751 \retval -1 File not found.
753 int obtdate(const char *dirname
, const char *name
, char *data
)
758 sprintf(wdir
,"%s%s/sarg-date",dirname
,name
);
759 if ((fp_in
= fopen(wdir
, "rt")) == 0) {
760 sprintf(wdir
,"%s%s/date",dirname
,name
);
761 if ((fp_in
= fopen(wdir
, "rt")) == 0) {
767 if (!fgets(data
,80,fp_in
)) {
768 debuga(_("Failed to read the date in %s\n"),wdir
);
778 void formatdate(char *date
,int date_size
,int year
,int month
,int day
,int hour
,int minute
,int second
,int dst
)
784 memset(<m
,0,sizeof(ltm
));
785 if (year
>=1900) ltm
.tm_year
=year
-1900;
786 if (month
>=1 && month
<=12) ltm
.tm_mon
=month
-1;
787 if (day
>=1 && day
<=31) ltm
.tm_mday
=day
;
788 if (hour
>=0 && hour
<24) ltm
.tm_hour
=hour
;
789 if (minute
>=0 && minute
<60) ltm
.tm_min
=minute
;
790 if (second
>=0 && second
<60) ltm
.tm_sec
=second
;
792 unixtime
=mktime(<m
); //fill the missing entries
793 fulltm
=localtime(&unixtime
);
794 //strftime(date,date_size,"%a %b %d %H:%M:%S %Z %Y",fulltm);
795 strftime(date
,date_size
,"%c",fulltm
);
799 void computedate(int year
,int month
,int day
,struct tm
*t
)
801 memset(t
,0,sizeof(*t
));
802 t
->tm_year
=year
-1900;
808 int obtuser(const char *dirname
, const char *name
)
815 sprintf(wdir
,"%s%s/sarg-users",dirname
,name
);
816 if((fp_in
=fopen(wdir
,"r"))==NULL
) {
817 sprintf(wdir
,"%s%s/users",dirname
,name
);
818 if((fp_in
=fopen(wdir
,"r"))==NULL
) {
823 if (!fgets(tuser
,sizeof(tuser
),fp_in
)) {
824 debuga(_("Failed to read the number of users in %s\n"),wdir
);
834 void obttotal(const char *dirname
, const char *name
, int nuser
, long long int *tbytes
, long long int *media
)
839 char user
[MAX_USER_LEN
];
841 struct getwordstruct gwarea
;
847 sprintf(wdir
,"%s%s/sarg-general",dirname
,name
);
848 if ((fp_in
= fopen(wdir
, "r")) == 0) {
849 sprintf(wdir
,"%s%s/general",dirname
,name
);
850 if ((fp_in
= fopen(wdir
, "r")) == 0) {
855 if ((line
=longline_create())==NULL
) {
856 debuga(_("Not enough memory to read the file %s\n"),wdir
);
860 while((buf
=longline_read(fp_in
,line
))!=NULL
) {
861 if (strncmp(buf
,"TOTAL\t",6) == 0)
863 else if (strncmp(buf
,"TOTAL ",6) == 0)
867 getword_start(&gwarea
,buf
);
868 if (getword(user
,sizeof(user
),&gwarea
,sep
)<0) {
869 debuga(_("There is a invalid user in file %s\n"),wdir
);
872 if(strcmp(user
,"TOTAL") != 0)
874 if (getword_skip(MAXLEN
,&gwarea
,sep
)<0) {
875 debuga(_("There a broken total number of access in file %s\n"),wdir
);
878 if (getword_atoll(tbytes
,&gwarea
,sep
)<0) {
879 debuga(_("There is a broken number of bytes in file %s\n"),wdir
);
885 longline_destroy(&line
);
890 *media
=*tbytes
/ nuser
;
894 int getperiod_fromsarglog(const char *arqtt
,struct periodstruct
*period
)
897 int day0
, month0
, year0
, hour0
, minute0
;
898 int day1
, month1
, year1
, hour1
, minute1
;
901 memset(period
,0,sizeof(*period
));
904 while((str
=strstr(str
,"sarg-"))!=NULL
) {
906 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
907 day0
=(str
[0]-'0')*10+(str
[1]-'0');
908 if (day0
<1 || day0
>31) continue;
910 month0
=(str
[0]-'0')*10+(str
[1]-'0')-1;
911 if (month0
<0 || month0
>11) continue;
914 for (i
=0 ; isdigit(str
[i
]) && i
<4 ; i
++) year0
=year0
*10+(str
[i
]-'0');
917 if (str
[0]!='_') continue;
920 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
921 hour0
=(str
[0]-'0')*10+(str
[1]-'0');
923 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
924 minute0
=(str
[0]-'0')*10+(str
[1]-'0');
927 if (*str
!= '-') continue;
930 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
931 day1
=(str
[0]-'0')*10+(str
[1]-'0');
932 if (day1
<1 || day1
>31) continue;
934 month1
=(str
[0]-'0')*10+(str
[1]-'0')-1;
935 if (month1
<0 || month1
>11) continue;
938 for (i
=0 ; isdigit(str
[i
]) && i
<4 ; i
++) year1
=year1
*10+(str
[i
]-'0');
942 if (str
[0]!='_') continue;
945 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
946 hour1
=(str
[0]-'0')*10+(str
[1]-'0');
948 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
949 minute1
=(str
[0]-'0')*10+(str
[1]-'0');
952 period
->start
.tm_mday
=day0
;
953 period
->start
.tm_mon
=month0
;
954 period
->start
.tm_year
=year0
-1900;
955 period
->start
.tm_hour
=hour0
;
956 period
->start
.tm_min
=minute0
;
957 period
->end
.tm_mday
=day1
;
958 period
->end
.tm_mon
=month1
;
959 period
->end
.tm_year
=year1
-1900;
960 period
->end
.tm_hour
=hour1
;
961 period
->end
.tm_min
=minute1
;
967 void getperiod_fromrange(struct periodstruct
*period
,int dfrom
,int duntil
)
969 memset(&period
->start
,0,sizeof(period
->start
));
970 period
->start
.tm_mday
=dfrom
%100;
971 period
->start
.tm_mon
=(dfrom
/100)%100-1;
972 period
->start
.tm_year
=(dfrom
/10000)-1900;
974 memset(&period
->end
,0,sizeof(period
->end
));
975 period
->end
.tm_mday
=duntil
%100;
976 period
->end
.tm_mon
=(duntil
/100)%100-1;
977 period
->end
.tm_year
=(duntil
/10000)-1900;
981 Update the \a main period to encompass the period in \a candidate.
983 void getperiod_merge(struct periodstruct
*main
,struct periodstruct
*candidate
)
988 mdate
=(main
->start
.tm_year
)*10000+(main
->start
.tm_mon
)*100+main
->start
.tm_mday
;
989 cdate
=(candidate
->start
.tm_year
)*10000+(candidate
->start
.tm_mon
)*100+candidate
->start
.tm_mday
;
990 if (cdate
<mdate
) memcpy(&main
->start
,&candidate
->start
,sizeof(struct tm
));
992 mdate
=(main
->end
.tm_year
)*10000+(main
->end
.tm_mon
)*100+main
->end
.tm_mday
;
993 cdate
=(candidate
->end
.tm_year
)*10000+(candidate
->end
.tm_mon
)*100+candidate
->end
.tm_mday
;
994 if (cdate
>mdate
) memcpy(&main
->end
,&candidate
->end
,sizeof(struct tm
));
997 int getperiod_buildtext(struct periodstruct
*period
)
1001 char text1
[40], text2
[40];
1004 i
=strftime(text1
, sizeof(text1
), "%Y %b %d", &period
->start
);
1005 } else if(df
=='e') {
1006 i
=strftime(text1
, sizeof(text1
), "%d %b %Y", &period
->start
);
1007 } else /*if (df=='w')*/ {
1008 IndexTree
=INDEX_TREE_FILE
;
1009 i
=strftime(text1
, sizeof(text1
), "%Y.%U", &period
->start
);
1011 if (i
== 0) return(-1);
1013 range
=(period
->start
.tm_year
!=period
->end
.tm_year
||
1014 period
->start
.tm_mon
!=period
->end
.tm_mon
||
1015 period
->start
.tm_mday
!=period
->end
.tm_mday
);
1018 i
=strftime(text2
, sizeof(text2
)-i
, "%Y %b %d", &period
->end
);
1019 } else if (df
=='e') {
1020 i
=strftime(text2
, sizeof(text2
)-i
, "%d %b %Y", &period
->end
);
1022 i
=strftime(text2
, sizeof(text2
)-i
, "%Y.%U", &period
->end
);
1024 if (i
== 0) return(-1);
1028 snprintf(period
->text
,sizeof(period
->text
),"%s-%s",text1
,text2
);
1029 snprintf(period
->html
,sizeof(period
->html
),"%s—%s",text1
,text2
);
1031 safe_strcpy(period
->text
,text1
,sizeof(period
->text
));
1032 safe_strcpy(period
->html
,text1
,sizeof(period
->html
));
1037 static void copy_images(void)
1039 FILE *img_in
, *img_ou
;
1041 char imgdir
[MAXLEN
];
1042 char srcfile
[MAXLEN
];
1043 char dstfile
[MAXLEN
];
1045 struct dirent
*direntp
;
1046 char buffer
[MAXLEN
];
1050 if (snprintf(images
,sizeof(images
),"%simages",outdir
)>=sizeof(images
)) {
1051 debuga(_("Cannot copy images to target directory %simages\n"),outdir
);
1054 if (access(images
,R_OK
)!=0) {
1055 if (mkdir(images
,0755)) {
1056 debuga(_("Cannot create directory %s - %s\n"),images
,strerror(errno
));
1061 strcpy(imgdir
,IMAGEDIR
);
1062 dirp
= opendir(imgdir
);
1064 debuga(_("(util) Can't open directory %s: %s\n"),imgdir
,strerror(errno
));
1067 while ((direntp
= readdir( dirp
)) != NULL
){
1068 if(direntp
->d_name
[0]=='.')
1070 sprintf(srcfile
,"%s/%s",imgdir
,direntp
->d_name
);
1071 if (stat(srcfile
,&info
)) {
1072 debuga(_("Cannot stat \"%s\" - %s\n"),srcfile
,strerror(errno
));
1075 if (S_ISREG(info
.st_mode
)) {
1076 sprintf(dstfile
,"%s/%s",images
,direntp
->d_name
);
1077 img_in
= fopen(srcfile
, "rb");
1079 img_ou
= fopen(dstfile
, "wb");
1081 while ((nread
= fread(buffer
,1,sizeof(buffer
),img_in
))>0) {
1082 if (fwrite(buffer
,1,nread
,img_ou
)!=nread
) {
1083 debuga(_("Failed to copy image %s to %s\n"),srcfile
,dstfile
);
1087 if (fclose(img_ou
)==EOF
) {
1088 debuga(_("Error while copying image %s: %s\n"),dstfile
,strerror(errno
));
1092 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open/create file", dstfile
, strerror(errno
));
1095 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open file", srcfile
, strerror(errno
));
1098 (void) closedir(dirp
);
1103 int vrfydir(const struct periodstruct
*per1
, const char *addr
, const char *site
, const char *us
, const char *form
)
1108 char dirname2
[MAXLEN
];
1116 strcpy(wdir
,outdir
);
1118 y1
=per1
->start
.tm_year
+1900;
1119 y2
=per1
->end
.tm_year
+1900;
1120 m1
=per1
->start
.tm_mon
+1;
1121 m2
=per1
->end
.tm_mon
+1;
1122 d1
=per1
->start
.tm_mday
;
1123 d2
=per1
->end
.tm_mday
;
1124 if(IndexTree
== INDEX_TREE_DATE
) {
1125 wlen
+=sprintf(wdir
+wlen
,"%04d",y1
);
1126 if(y1
!=y2
) wlen
+=sprintf(wdir
+wlen
,"-%04d",y2
);
1127 if(access(wdir
, R_OK
) != 0)
1130 wlen
+=sprintf(wdir
+wlen
,"/%02d",m1
);
1131 if(m1
!= m2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",m2
);
1132 if(access(wdir
, R_OK
) != 0)
1135 wlen
+=sprintf(wdir
+wlen
,"/%02d",d1
);
1136 if(d1
!=d2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",d2
);
1139 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%04d%s%02d-%04d%s%02d",y1
,
1140 conv_month_name(m1
),d1
,y2
,conv_month_name(m2
),d2
);
1141 } else if (df
== 'e') {
1142 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%02d%s%04d-%02d%s%04d",d1
,
1143 conv_month_name(m1
),y1
,d2
,conv_month_name(m2
),y2
);
1144 } else if (df
== 'w') {
1145 wlen2
=strftime(wdir
+wlen
, sizeof(wdir
)-wlen
, "%Y.%U", &per1
->start
);
1146 if (wlen2
==0) return(-1);
1152 struct userinfostruct
*uinfo
=userinfo_find_from_id(us
);
1155 strcat(wdir
,uinfo
->filename
);
1158 if(addr
[0] != '\0') {
1162 if(site
[0] != '\0') {
1167 strcpy(outdirname
,wdir
);
1169 if(IndexTree
!= INDEX_TREE_DATE
) {
1170 if(!OverwriteReport
) {
1172 if(access(wdir
,R_OK
) == 0) {
1173 sprintf(wdir
,"%s.%d",outdirname
,num
);
1182 debuga(_("File %s already exists, moved to %s\n"),outdirname
,wdir
);
1183 rename(outdirname
,wdir
);
1186 if(access(outdirname
,R_OK
) == 0) {
1187 unlinkdir(outdirname
,1);
1190 my_mkdir(outdirname
);
1192 strcpy(dirname2
,wdir
);
1193 if(!OverwriteReport
) {
1195 if(access(wdir
,R_OK
) == 0) {
1196 sprintf(wdir
,"%s.%d",dirname2
,num
);
1205 debuga(_("File %s already exists, moved to %s\n"),dirname2
,wdir
);
1206 rename(dirname2
,wdir
);
1207 strcpy(dirname2
,wdir
);
1210 if(access(wdir
,R_OK
) == 0) {
1215 if(access(wdir
, R_OK
) != 0)
1219 strcpy(dirname2
,wdir
);
1221 sprintf(wdir
,"%s/sarg-date",outdirname
);
1222 if ((fp_ou
= fopen(wdir
, "wt")) == 0) {
1223 debuga(_("cannot open %s for writing: %s\n"),wdir
,strerror(errno
));
1228 //strftime(wdir,sizeof(wdir),"%a %b %d %H:%M:%S %Z %Y",localtime(&curtime));
1229 loctm
=localtime(&curtime
);
1230 strftime(wdir
,sizeof(wdir
),"%Y-%m-%d %H:%M:%S",loctm
);
1231 if (fprintf(fp_ou
,"%s %d\n",wdir
,loctm
->tm_isdst
)<0) {
1232 debuga(_("Failed to write the date in %s\n"),wdir
);
1236 if (fclose(fp_ou
)==EOF
) {
1237 debuga(_("Failed to write the date in %s: %s\n"),wdir
,strerror(errno
));
1246 Copy a string without overflowing the buffer. The copied string
1247 is properly terminated by an ASCII zero.
1249 \param dest The destination buffer.
1250 \param src The source buffer.
1251 \param length The size of the destination buffer. The program is aborted
1252 if the length is negative or zero.
1254 void safe_strcpy(char *dest
,const char *src
,int length
)
1257 debuga(_("Invalid buffer length passed to the function to safely copy a string\n"));
1260 strncpy(dest
,src
,length
-1);
1261 dest
[length
-1]='\0';
1264 void strip_latin(char *line
)
1271 for (i
=0;line
[i
];i
++){
1273 if (line
[i
]==';') skip
=0;
1285 void zdate(char *ftime
,int ftimesize
, char DateFormat
)
1291 local
= localtime(&t
);
1292 if (DateFormat
=='u')
1293 strftime(ftime
, ftimesize
, "%b/%d/%Y %H:%M", local
);
1294 else if (DateFormat
=='e')
1295 strftime(ftime
, ftimesize
, "%d/%b/%Y-%H:%M", local
);
1296 else if (DateFormat
=='w')
1297 strftime(ftime
, ftimesize
, "%W-%H-%M", local
);
1302 char *fixtime(long long int elap
)
1304 int num
= elap
/ 1000;
1308 static char buf
[12];
1311 min
=(num
% 3600) / 60;
1314 if(hor
==0 && min
==0 && sec
==0)
1317 sprintf(buf
,"%d:%02d:%02d",hor
,min
,sec
);
1323 void date_from(char *date
, int *dfrom
, int *duntil
)
1332 if (isdigit(date
[0])) {
1335 if (sscanf(date
,"%d/%d/%d%n",&d0
,&m0
,&y0
,&next
)!=3 || y0
<100 || m0
<1 || m0
>12 || d0
<1 || d0
>31 || next
<0) {
1336 debuga(_("The date passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1339 if (date
[next
]=='-') {
1340 if (sscanf(date
+next
+1,"%d/%d/%d",&d1
,&m1
,&y1
)!=3 || y1
<100 || m1
<1 || m1
>12 || d1
<1 || d1
>31) {
1341 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1344 } else if (date
[next
]!='\0') {
1345 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1355 struct tm
*Date0
,Date1
;
1357 if (time(&Today
)==(time_t)-1) {
1358 debuga(_("Failed to get the current time\n"));
1361 if (sscanf(date
,"day-%d",&i
)==1) {
1363 debuga(_("Invalid number of days in -d parameter\n"));
1367 Date0
=localtime(&Today
);
1369 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1372 y0
=y1
=Date0
->tm_year
+1900;
1373 m0
=m1
=Date0
->tm_mon
+1;
1374 d0
=d1
=Date0
->tm_mday
;
1375 } else if (sscanf(date
,"week-%d",&i
)==1) {
1377 There is no portable way to find the first day of the week even though the
1378 information is available in the locale. nl_langinfo has the unofficial
1379 parameters _NL_TIME_FIRST_WEEKDAY and _NL_TIME_WEEK_1STDAY but they are
1380 undocumented as is their return value and it is discouraged to use them.
1381 Beside, nl_langinfo isn't available on windows and the first day of the
1382 week isn't available at all on that system.
1384 const int FirstWeekDay
=1;
1388 debuga(_("Invalid number of weeks in -d parameter\n"));
1391 Date0
=localtime(&Today
);
1393 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1396 WeekBegin
=Today
-((Date0
->tm_wday
-FirstWeekDay
+7)%7)*24*60*60;
1397 WeekBegin
-=i
*7*24*60*60;
1398 Date0
=localtime(&WeekBegin
);
1400 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1403 y0
=Date0
->tm_year
+1900;
1406 WeekBegin
+=6*24*60*60;
1407 Date0
=localtime(&WeekBegin
);
1409 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1412 y1
=Date0
->tm_year
+1900;
1415 } else if (sscanf(date
,"month-%d",&i
)==1) {
1417 debuga(_("Invalid number of months in -d parameter\n"));
1420 Date0
=localtime(&Today
);
1422 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1425 if (Date0
->tm_mon
<i
%12) {
1426 y0
=Date0
->tm_year
+1900-i
/12-1;
1427 m0
=(Date0
->tm_mon
+12-i
%12)%12+1;
1430 y0
=Date0
->tm_year
+1900-i
/12;
1431 m0
=Date0
->tm_mon
-i
%12+1;
1434 memcpy(&Date1
,Date0
,sizeof(struct tm
));
1439 Date1
.tm_year
=y0
-1900;
1442 Date1
.tm_year
=y0
-1900+1;
1446 Date0
=localtime(&t1
);
1447 y1
=Date0
->tm_year
+1900;
1451 debuga(_("Invalid date range passed on command line\n"));
1456 *dfrom
=y0
*10000+m0
*100+d0
;
1457 *duntil
=y1
*10000+m1
*100+d1
;
1458 sprintf(date
,"%02d/%02d/%04d-%02d/%02d/%04d",d0
,m0
,y0
,d1
,m1
,y1
);
1463 char *strlow(char *string
)
1469 for (s
= string
; *s
; ++s
)
1479 char *strup(char *string
)
1485 for (s
= string
; *s
; ++s
)
1493 void removetmp(const char *outdir
)
1498 if(!RemoveTempFiles
)
1502 debuga(_("Purging temporary file sarg-general\n"));
1504 if (snprintf(filename
,sizeof(filename
),"%s/sarg-general",outdir
)>=sizeof(filename
)) {
1505 debuga(_("(removetmp) directory too long to remove %s/sarg-period\n"),outdir
);
1508 if((fp_gen
=fopen(filename
,"w"))==NULL
){
1509 debuga(_("(removetmp) Cannot open file %s: %s\n"),filename
,strerror(errno
));
1512 totalger(fp_gen
,filename
);
1513 if (fclose(fp_gen
)==EOF
) {
1514 debuga(_("Failed to close %s after writing the total line: %s\n"),filename
,strerror(errno
));
1519 void load_excludecodes(const char *ExcludeCodes
)
1527 if(ExcludeCodes
[0] == '\0')
1530 if((fp_in
=fopen(ExcludeCodes
,"r"))==NULL
) {
1531 debuga(_("(util) Cannot open file %s (exclude_codes): %s\n"),ExcludeCodes
,strerror(errno
));
1535 if (fseek(fp_in
, 0, SEEK_END
)==-1) {
1536 debuga(_("Failed to move till the end of the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1539 MemSize
= ftell(fp_in
);
1541 debuga(_("Cannot get the size of file %s\n"),ExcludeCodes
);
1544 if (fseek(fp_in
, 0, SEEK_SET
)==-1) {
1545 debuga(_("Failed to rewind the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1550 if((excludecode
=(char *) malloc(MemSize
))==NULL
) {
1551 debuga(_("malloc error (%ld)\n"),MemSize
);
1554 memset(excludecode
,0,MemSize
);
1557 while(fgets(data
,sizeof(data
),fp_in
)!=NULL
) {
1558 if (data
[0]=='#') continue;
1559 for (i
=strlen(data
)-1 ; i
>=0 && (unsigned char)data
[i
]<=' ' ; i
--) data
[i
]='\0';
1561 if (Stored
+i
+2>=MemSize
) {
1562 debuga(_("Too many codes to exclude in file %s\n"),ExcludeCodes
);
1565 strcat(excludecode
,data
);
1566 strcat(excludecode
,";");
1574 void free_excludecodes(void)
1582 int vercode(const char *code
)
1587 if (excludecode
&& excludecode
[0]!='\0') {
1591 if (strncmp(code
,cod
,clen
)==0 && cod
[clen
]==';')
1593 cod
=strchr(cod
,';');
1600 void fixnone(char *str
)
1604 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--);
1605 if(i
==3 && strncmp(str
,"none",4) == 0)
1611 void fixendofline(char *str
)
1615 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--) str
[i
]=0;
1618 #ifdef LEGACY_TESTVALIDUSERCHAR
1619 int testvaliduserchar(const char *user
)
1624 for (y
=0; y
<strlen(UserInvalidChar
); y
++) {
1625 for (x
=0; x
<strlen(user
); x
++) {
1626 if(user
[x
] == UserInvalidChar
[y
])
1633 int testvaliduserchar(const char *user
)
1635 char * p_UserInvalidChar
= UserInvalidChar
;
1636 const char * p_user
;
1638 while( *p_UserInvalidChar
) {
1641 if( *p_UserInvalidChar
== *p_user
)
1645 p_UserInvalidChar
++ ;
1651 int compar( const void *a
, const void *b
)
1653 if( *(int *)a
> *(int *)b
) return 1;
1654 if( *(int *)a
< *(int *)b
) return -1;
1658 int getnumlist( char *buf
, numlist
*list
, const int len
, const int maxvalue
)
1660 int i
, j
, d
, flag
, r1
, r2
;
1661 char *pbuf
, **bp
, *strbufs
[ 24 ];
1664 strtok( buf
, " \t" );
1665 for( *bp
= strtok( NULL
, "," ), list
->len
= 0; *bp
; *bp
= strtok( NULL
, "," ) ) {
1666 if( ++bp
>= &strbufs
[ 24 ] )
1673 for( i
= 0; i
< list
->len
; i
++ ) {
1674 if( strchr( strbufs
[ i
], '-' ) != 0 ) {
1675 pbuf
= strbufs
[ i
];
1676 strtok( pbuf
, "-" );
1677 pbuf
= strtok( NULL
, "\0" );
1678 r1
= atoi( strbufs
[ i
] );
1679 if( ( r2
= atoi( pbuf
) ) >= maxvalue
|| r1
>= r2
)
1681 if( i
+ d
+ ( r2
- r1
) + 1 <= len
) {
1682 for( j
= r1
; j
<= r2
; j
++ )
1683 list
->list
[ i
+ d
++ ] = j
;
1688 if( ( list
->list
[ i
+ d
] = atoi( strbufs
[ i
] ) ) >= maxvalue
)
1692 qsort( list
->list
, list
->len
, sizeof( int ), compar
);
1695 for( i
= 0; i
< list
->len
- 1; i
++ )
1696 if( list
->list
[ i
] == list
->list
[ i
+ 1 ] ) {
1697 for( j
= i
+ 1; j
< list
->len
; j
++ )
1698 list
->list
[ j
- 1 ] = list
->list
[ j
];
1708 char *get_size(const char *path
, const char *file
)
1711 static char response
[255];
1715 if (snprintf(cmd
,sizeof(cmd
),"du -skh %s%s",path
,file
)>=sizeof(cmd
)) {
1716 debuga(_("Cannot get disk space because the path %s%s is too long\n"),path
,file
);
1719 if ((fp
= popen(cmd
, "r")) == NULL
) {
1720 debuga(_("Cannot get disk space with command %s\n"),cmd
);
1723 if (!fgets(response
, sizeof(response
), fp
)) {
1724 debuga(_("Cannot get disk size with command %s\n"),cmd
);
1727 ptr
=strchr(response
,'\t');
1729 debuga(_("The command %s failed\n"),cmd
);
1738 void show_info(FILE *fp_ou
)
1742 if(!ShowSargInfo
) return;
1743 zdate(ftime
, sizeof(ftime
), df
);
1744 fputs("<div class=\"info\">",fp_ou
);
1745 fprintf(fp_ou
,_("Generated by <a href='%s'>%s-%s</a> on %s"),URL
,PGM
,VERSION
,ftime
);
1746 fputs("</div>\n",fp_ou
);
1749 void show_sarg(FILE *fp_ou
, int depth
)
1753 if(!ShowSargLogo
) return;
1754 fputs("<div class=\"logo\"><a href=\"http://sarg.sourceforge.net\"><img src=\"",fp_ou
);
1755 for (i
=0 ; i
<depth
; i
++)
1757 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
);
1760 void write_logo_image(FILE *fp_ou
)
1762 if(LogoImage
[0]!='\0')
1763 fprintf(fp_ou
, "<div class=\"logo\"><img src=\"%s\" width=\"%s\" height=\"%s\" alt=\"Logo\"> %s</div>\n",LogoImage
,Width
,Height
,LogoText
);
1766 void write_html_head(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1770 fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n",fp_ou
);
1771 fprintf(fp_ou
, "<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n",CharSet
);
1772 if (page_title
) fprintf(fp_ou
,"<title>%s</title>\n",page_title
);
1774 if ((javascript
& HTML_JS_SORTTABLE
)!=0 && SortTableJs
[0]) {
1775 fputs("<script type=\"text/javascript\" src=\"",fp_ou
);
1776 if (strncmp(SortTableJs
,"../",3)==0) {
1777 for (i
=0 ; i
<depth
; i
++) fputs("../",fp_ou
);
1779 fputs(SortTableJs
,fp_ou
);
1780 fputs("\"></script>\n",fp_ou
);
1782 fputs("</head>\n<body>\n",fp_ou
);
1785 void write_html_header(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1787 write_html_head(fp_ou
,depth
,page_title
,javascript
);
1788 write_logo_image(fp_ou
);
1789 show_sarg(fp_ou
, depth
);
1790 fprintf(fp_ou
,"<div class=\"title\"><table cellpadding=\"0\" cellspacing=\"0\">\n<tr><th class=\"title_c\">%s</th></tr>\n",Title
);
1793 void close_html_header(FILE *fp_ou
)
1795 fputs("</table></div>\n",fp_ou
);
1798 int write_html_trailer(FILE *fp_ou
)
1801 if (fputs("</body>\n</html>\n",fp_ou
)==EOF
) return(-1);
1805 void output_html_string(FILE *fp_ou
,const char *str
,int maxlen
)
1809 while (*str
&& (maxlen
<=0 || i
<maxlen
)) {
1812 fputs("&",fp_ou
);
1815 fputs("<",fp_ou
);
1818 fputs(">",fp_ou
);
1821 fputs(""",fp_ou
);
1824 fputs("'",fp_ou
);
1832 if (maxlen
>0 && i
>=maxlen
)
1833 fputs("…",fp_ou
);
1836 void output_html_url(FILE *fp_ou
,const char *url
)
1840 fputs("&",fp_ou
);
1848 Write a host name inside an A tag of a HTML file. If the host name starts
1849 with a star, it is assumed to be an alias that cannot be put inside a link
1850 so the A tag is not written around the host name.
1852 \param fp_ou The handle of the HTML file.
1853 \param url The host to display in the HTML file.
1854 \param maxlen The maximum number of characters to print into the host name.
1856 void output_html_link(FILE *fp_ou
,const char *url
,int maxlen
)
1858 if (url
[0]==ALIAS_PREFIX
) {
1859 // this is an alias, no need for a A tag
1860 output_html_string(fp_ou
,url
+1,100);
1862 if (skip_scheme(url
)==url
)
1863 fputs("<a href=\"http://",fp_ou
);//no scheme in the url, assume http:// to make the link clickable
1865 fputs("<a href=\"",fp_ou
);//the scheme is in the url, no need to add one
1866 output_html_url(fp_ou
,url
);
1868 output_html_string(fp_ou
,url
,100);
1869 fputs("</a>",fp_ou
);
1873 void url_module(const char *url
, char *w2
)
1879 for(x
=strlen(url
)-1; x
>=0; x
--) {
1880 if(url
[x
] == '/' || y
>=sizeof(w
)-1) break;
1889 for(y
=y
-1; y
>=0; y
--) {
1896 Mangle an URL to produce a part that can be used as an anchor in
1897 a html <a name=""> tag.
1899 \param url The URL to mangle.
1900 \param anchor The buffer to write the mangled URL.
1901 \param size The size of the buffer.
1903 void url_to_anchor(const char *url
,char *anchor
,int size
)
1909 for (i
=0 ; url
[i
] && url
[i
]!='/' && url
[i
]!='?' ; i
++);
1916 // only keep really safe characters
1922 if(isalnum(url
[i
]) || url
[i
]=='-' || url
[i
]=='_' || url
[i
]=='.') {
1926 if (!skip
) anchor
[--j
]='_';
1944 printf(_("SARG Version: %s\n"),VERSION
);
1948 char *get_param_value(const char *param
,char *line
)
1952 while (*line
==' ' || *line
=='\t') line
++;
1954 if (strncasecmp(line
,param
,plen
)) return(NULL
);
1955 if (line
[plen
]!=' ' && line
[plen
]!='\t') return(NULL
);
1957 while (*line
==' ' || *line
=='\t') line
++;
1961 void unlinkdir(const char *dir
,bool contentonly
)
1965 struct dirent
*direntp
;
1971 while ((direntp
= readdir(dirp
)) != NULL
) {
1972 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
1973 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
1975 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
1976 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
1980 err
=lstat(dname
,&st
);
1982 err
=stat(dname
,&st
);
1985 debuga(_("cannot stat %s\n"),dname
);
1988 if (S_ISREG(st
.st_mode
)) {
1989 if (unlink(dname
)) {
1990 debuga(_("Cannot delete \"%s\": %s\n"),dname
,strerror(errno
));
1993 } else if (S_ISDIR(st
.st_mode
)) {
1996 debuga(_("unknown path type %s\n"),dname
);
2003 debuga(_("Cannot delete \"%s\": %s\n"),dir
,strerror(errno
));
2010 Delete every file from the temporary directory where sarg is told to store its
2013 As any stray file left over by a previous run would be included in the report, we
2014 must delete every file from the temporary directory before we start processing the logs.
2016 But the temporary directory is given by the user either in the configuration file or
2017 on the command line. We check that the user didn't give a wrong directory by looking
2018 at the files stored in the directory. If a single file is not one of ours, we abort.
2020 \param dir The temporary directory to purge.
2022 void emptytmpdir(const char *dir
)
2026 struct dirent
*direntp
;
2032 static const char *TmpExt
[]=
2047 // make sure the temporary directory contains only our files
2048 while ((direntp
= readdir(dirp
)) != NULL
) {
2049 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
2050 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
2053 // is it one of our files
2054 dlen
=strlen(direntp
->d_name
);
2055 for (i
=sizeof(TmpExt
)/sizeof(TmpExt
[0])-1 ; i
>=0 ; i
--) {
2056 elen
=strlen(TmpExt
[i
]);
2057 if (dlen
>=elen
&& strcasecmp(direntp
->d_name
+dlen
-elen
,TmpExt
[i
])==0) break;
2060 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2061 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2062 "directory or manually delete the content of \"%s\"\n"),direntp
->d_name
,dir
,dir
);
2066 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
2067 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
2072 err
=lstat(dname
,&st
);
2074 err
=stat(dname
,&st
);
2077 debuga(_("cannot stat \"%s\"\n"),dname
);
2080 if (S_ISDIR(st
.st_mode
)) {
2082 } else if (!S_ISREG(st
.st_mode
)) {
2083 debuga(_("Unknown path type for \"%s\". Check temporary directory\n"),dname
);
2089 // now delete our files
2090 while ((direntp
= readdir(dirp
)) != NULL
) {
2091 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
2092 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
2095 // is it one of our files
2096 dlen
=strlen(direntp
->d_name
);
2097 for (i
=sizeof(TmpExt
)/sizeof(TmpExt
[0])-1 ; i
>=0 ; i
--) {
2098 elen
=strlen(TmpExt
[i
]);
2099 if (dlen
>=elen
&& strcasecmp(direntp
->d_name
+dlen
-elen
,TmpExt
[i
])==0) break;
2102 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2103 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2104 "directory or manually delete the content of \"%s\"\n"),direntp
->d_name
,dir
,dir
);
2108 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
2109 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
2113 err
=lstat(dname
,&st
);
2115 err
=stat(dname
,&st
);
2118 debuga(_("cannot stat \"%s\"\n"),dname
);
2121 if (S_ISREG(st
.st_mode
)) {
2122 if (unlink(dname
)) {
2123 debuga(_("Cannot delete \"%s\": %s\n"),dname
,strerror(errno
));
2127 debuga(_("unknown path type %s\n"),dname
);
2134 Extract an url, IPv4 or IPv6 from a buffer. The IP addresses may end with a
2137 \param buf The buffer to parse.
2138 \param text A pointer to set to the beginning of the string pattern. No terminating zero is inserted.
2139 The pointer may be NULL.
2140 \param ipv4 A 4 bytes buffer to store the bytes of the IPv4 address.
2141 \param ipv6 A 8 short integers buffer to store the values of the IPv6 address.
2142 \param nbits The number of prefix bits for an IP address.
2143 \param next The content of the line after the extracted address.
2145 \retval 3 The pattern is a IPv6 address.
2146 \retval 2 The pattern is a IPv4 address.
2147 \retval 1 The patter is a string.
2148 \retval 0 Empty pattern.
2150 int extract_address_mask(const char *buf
,const char **text
,unsigned char *ipv4
,unsigned short int *ipv6
,int *nbits
,const char **next
)
2155 unsigned int value4
, value6
;
2156 unsigned short int addr
[8];
2166 // skip leading spaces and tabs
2167 while (*buf
&& (*buf
==' ' || *buf
=='\t')) buf
++;
2169 // find out the nature of the pattern
2170 ip_size
=0x60 | 0x04;
2181 for (i
=0 ; (unsigned char)buf
[i
]>' ' && buf
[i
]!='/' && buf
[i
]!='?' && (!bracket
|| buf
[i
]!=']') && ip_size
; i
++) {
2182 if (ip_size
& 0x04) {
2183 if (isdigit(buf
[i
])) {
2185 port_num
=port_num
*10+(buf
[i
]-'0');
2186 if (port_num
>65535) ip_size
&=~0x04;
2188 value4
=value4
*10+(buf
[i
]-'0');
2189 if (value4
>0xFFU
) ip_size
&=~0x04;
2191 } else if (buf
[i
]=='.' && addr_len
<4) {
2192 addr
[addr_len
++]=(unsigned short)(value4
& 0xFFU
);
2194 } else if (!port
&& buf
[i
]==':') {
2200 if (ip_size
& 0x60) {
2201 if (isdigit(buf
[i
])) {
2202 value6
=(value6
<<4)+(buf
[i
]-'0');
2204 if (value6
>0xFFFFU
) ip_size
&=~0x60;
2205 } else if (toupper(buf
[i
])>='A' && toupper(buf
[i
])<='F') {
2206 value6
=(value6
<<4)+(toupper(buf
[i
])-'A'+10);
2208 if (value6
>0xFFFFU
) ip_size
&=~0x60;
2209 } else if (buf
[i
]==':' && addr_len
<8) {
2210 if (nibble6_len
>0) {
2211 addr
[addr_len
++]=(unsigned short)(value6
& 0xFFFFU
);
2215 if (buf
[i
+1]==':') {
2224 if (i
==0) return(0);
2225 if (ip_size
& 0x04) {
2229 addr
[addr_len
++]=(unsigned short)(value4
& 0xFFU
);
2231 if (ip_size
& 0x60) {
2232 if (pad_pos
<0 && addr_len
!=7) {
2234 } else if (pad_pos
>=0 && addr_len
>=7)
2236 else if (nibble6_len
>0)
2237 addr
[addr_len
++]=(unsigned short)(value6
& 0xFFFFU
);
2242 if (bracket
) (*text
)--;
2244 while ((unsigned char)buf
[i
]>' ') i
++;
2245 if (next
) *next
=buf
+i
;
2248 max_mask
=(ip_size
& 0x04) ? 4*8 : 8*16;
2252 while (isdigit(buf
[i
])) i
++;
2253 if (mask
<0 || mask
>max_mask
) mask
=max_mask
;
2256 if (ip_size
& 0x60 && bracket
&& buf
[i
]==']') i
++;
2257 if (next
) *next
=buf
+i
;
2258 if (ip_size
& 0x04) {
2259 if (nbits
) *nbits
=mask
;
2260 for (i
=0 ; i
<addr_len
; i
++)
2261 ipv4
[i
]=(unsigned char)addr
[i
];
2266 if (nbits
) *nbits
=mask
;
2271 ipv6
[j
++]=(unsigned short int)addr
[i
++];
2273 while (j
<pad_pos
+pad_len
)
2277 ipv6
[j
++]=(unsigned short int)addr
[i
++];