]>
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 extern char *CurrentLocale
;
46 #if USE_GETWORD_BACKTRACE
47 static void getword_backtrace(void)
53 n
=backtrace(buffer
,sizeof(buffer
)/sizeof(buffer
[0]));
55 calls
=backtrace_symbols(buffer
,n
);
57 /* TRANSLATORS: "getword" is the function displaying
58 * the backtrace leading to its execution.
60 debuga(_("getword backtrace:\n"));
61 for (i
=0 ; i
<n
; i
++) {
62 fprintf(stderr
,"SARG: %d:%s\n",i
+1,calls
[i
]);
67 #endif //USE_GETWORD_BACKTRACE
69 void getword_start(struct getwordstruct
*gwarea
, const char *line
)
71 gwarea
->beginning
=line
;
76 void getword_restart(struct getwordstruct
*gwarea
)
78 if (gwarea
->modified
) {
79 debuga(_("Cannot parse again the line as it was modified\n"));
82 gwarea
->current
=gwarea
->beginning
;
85 int getword(char *word
, int limit
, struct getwordstruct
*gwarea
, char stop
)
89 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++) {
91 /* TRANSLATORS: %s is the name of the function reporting this error.
93 debuga(_("Loop detected in %s after %d bytes.\n"),__func__
,x
);
94 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
95 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
96 debuga(_("searching for \'x%x\'\n"),stop
);
97 word
[(limit
>0) ? limit
-1 : 0]='\0';
98 #if USE_GETWORD_BACKTRACE
103 word
[x
] = gwarea
->current
[x
];
107 if (gwarea
->current
[x
]) ++x
;
112 int getword_limit(char *word
, int limit
, struct getwordstruct
*gwarea
, char stop
)
117 for(x
=0; x
<limit
&& gwarea
->current
[x
] && gwarea
->current
[x
] != stop
;x
++) {
118 word
[x
] = gwarea
->current
[x
];
122 while (*gwarea
->current
&& *gwarea
->current
!= stop
) gwarea
->current
++;
123 if (*gwarea
->current
) ++gwarea
->current
;
127 int getword_multisep(char *word
, int limit
, struct getwordstruct
*gwarea
, char stop
)
131 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++) {
133 /* TRANSLATORS: %s is the name of the function reporting this error.
135 debuga(_("Loop detected in %s after %d bytes.\n"),__func__
,x
);
136 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
137 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
138 debuga(_("searching for \'x%x\'\n"),stop
);
139 if (limit
>0) word
[limit
-1]='\0';
140 #if USE_GETWORD_BACKTRACE
143 //exit(EXIT_FAILURE);
146 word
[x
] = gwarea
->current
[x
];
150 while (gwarea
->current
[x
] && gwarea
->current
[x
]==stop
) ++x
;
155 int getword_skip(int limit
, struct getwordstruct
*gwarea
, char stop
)
159 for(x
=0;(gwarea
->current
[x
] && (gwarea
->current
[x
] != stop
));x
++) {
161 /* TRANSLATORS: %s is the name of the function reporting this error.
163 debuga(_("Loop detected in %s after %d bytes.\n"),__func__
,x
);
164 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
165 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
166 debuga(_("searching for \'x%x\'\n"),stop
);
167 #if USE_GETWORD_BACKTRACE
174 if (gwarea
->current
[x
]) ++x
;
179 int getword_atoll(long long int *number
, struct getwordstruct
*gwarea
, char stop
)
185 if (gwarea
->current
[0] == '-') {
188 } else if (gwarea
->current
[0] == '+') {
192 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
193 digit
=gwarea
->current
[x
]-'0';
194 if (*number
>= (LLONG_MAX
-digit
)/10) {
195 /* TRANSLATORS: The first %s is the name of the function displaying
198 debuga(_("Integer overflow detected in %s in line \"%s\"\n"),__func__
,gwarea
->beginning
);
201 *number
=(*number
* 10) + digit
;
203 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
204 /* TRANSLATORS: %s is the name of the function reporting this error.
206 debuga(_("Loop detected in %s after %d bytes.\n"),__func__
,x
);
207 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
208 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
209 debuga(_("searching for \'x%x\'\n"),stop
);
210 #if USE_GETWORD_BACKTRACE
217 if (gwarea
->current
[x
]) ++x
;
222 int getword_atoi(int *number
, struct getwordstruct
*gwarea
, char stop
)
228 if (gwarea
->current
[0] == '-') {
231 } else if (gwarea
->current
[0] == '+') {
235 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
236 digit
=gwarea
->current
[x
]-'0';
237 if (*number
> (INT_MAX
-digit
)/10) {
238 /* TRANSLATORS: The first %s is the name of the function displaying
241 debuga(_("Integer overflow detected in %s in line \"%s\"\n"),__func__
,gwarea
->beginning
);
244 *number
=(*number
* 10) + digit
;
246 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
247 /* TRANSLATORS: %s is the name of the function reporting this error.
249 debuga(_("Loop detected in %s after %d bytes.\n"),__func__
,x
);
250 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
251 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
252 debuga(_("searching for \'x%x\'\n"),stop
);
253 #if USE_GETWORD_BACKTRACE
260 if (gwarea
->current
[x
]) ++x
;
266 int getword_ptr(char *orig_line
,char **word
, struct getwordstruct
*gwarea
, char stop
)
269 \note Why pass the original buffer to the function ? Because we must modify it to
270 insert the terminating ASCII zero for the word we return and that's not compatible
271 with getword_restart(). Moreover, getword_start() sometime works on constant strings
272 so this function require the original buffer to detect any missuse.
278 if (orig_line
&& orig_line
!=gwarea
->beginning
) {
279 debuga(_("Invalid buffer passed to getword_ptr\n"));
283 start
=(gwarea
->current
-gwarea
->beginning
);
284 if (word
&& orig_line
) *word
=orig_line
+start
;
285 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++);
286 sep
=(gwarea
->current
[x
]!='\0');
287 if (word
&& orig_line
) orig_line
[start
+x
] = '\0';
294 #define MAXLLL 30 //!< Maximum number of digits in long long (a guess).
295 long long int my_atoll (const char *nptr
)
297 long long int returnval
=0LL;
298 int max_digits
= MAXLLL
;
300 // Soak up all the white space
301 while (isspace( *nptr
)) {
305 //For each character left to right
306 //change the character to a single digit
307 //multiply what we had before by 10 and add the new digit
309 while (--max_digits
&& isdigit( *nptr
))
311 returnval
= ( returnval
* 10 ) + ( *nptr
++ - '0' ) ;
317 int is_absolute(const char *path
)
319 if (*path
=='/') return(1);
321 if (isalpha(path
[0]) && path
[1]==':') return(1);
326 void my_mkdir(const char *name
)
332 if(!is_absolute(name
)) {
333 debuga(_("Invalid path \"%s\". Please, use absolute paths only.\n"),name
);
338 for (i
=0 ; name
[i
] ; i
++) {
340 debuga(_("Path too long: "));
341 debuga_more("%s\n",name
);
344 if (chars
>0 && name
[i
] == '/') {
346 if (access(w0
, R_OK
) != 0) {
347 if (mkdir(w0
,0755)) {
348 debuga(_("Cannot create directory \"%s\": %s\n"),w0
,strerror(errno
));
353 if (name
[i
] != '/') chars
++;
357 if (access(name
, R_OK
) != 0) {
358 if (mkdir(name
,0755)) {
359 debuga(_("Cannot create directory \"%s\": %s\n"),name
,strerror(errno
));
366 void my_lltoa(unsigned long long int n
, char *s
, int ssize
, int len
)
375 debuga(_("The requested number of digits passed to my_lltoa (%d) is bigger than the output buffer size (%d)\n"),len
,ssize
);
380 s
[slen
++] = (n
% 10) + '0';
381 } while ((n
/= 10) > 0 && slen
<ssize
);
384 for (i
= 0, j
= slen
-1; i
<j
; i
++, j
--) {
392 for(j
=slen
; j
>=0; j
--)
399 int month2num(const char *month
)
403 for(m
=0 ; m
<12 && strcmp(mtab1
[m
],month
) != 0; m
++);
407 int builddia(int day
, int month
, int year
)
409 return(year
*10000+month
*100+day
);
413 void buildymd(const char *dia
, const char *mes
, const char *ano
, char *wdata
,int wdata_size
)
418 snprintf(wdata
,wdata_size
,"%04d%02d%02d",atoi(ano
),nmes
+1,atoi(dia
));
422 int conv_month(const char *month
)
426 for(x
=0; x
<12 && strncmp(mtab1
[x
],month
,3)!=0; x
++);
431 const char *conv_month_name(int month
)
435 if (month
<1 || month
>12) {
436 snprintf(str
,sizeof(str
),"%03d",month
);
439 return(mtab1
[month
-1]);
443 void name_month(char *month
,int month_len
)
445 int x
, z
=atoi(month
)-1;
448 struct getwordstruct gwarea
;
450 strcpy(m
,_("January,February,March,April,May,June,July,August,September,October,November,December"));
451 getword_start(&gwarea
,m
);
454 if (getword_multisep(w
,sizeof(w
),&gwarea
,',')<0) {
455 debuga(_("The internal list of month names is invalid. Please report this bug to the translator.\n"));
458 if (getword_multisep(month
,month_len
,&gwarea
,',')<0) {
459 debuga(_("The internal list of month names is invalid. Please report this bug to the translator.\n"));
466 Write a debug message to stderr. The message is prefixed by "SARG:" to identify its origin.
468 \param msg The printf like message to format.
469 \param ... The arguments to format in the message.
471 void debuga(const char *msg
,...)
475 fputs(_("SARG: "),stderr
);
477 vfprintf(stderr
,msg
,ap
);
482 Write a debug message to stderr. The message is supposed
483 to be displayed after a message from debuga().
485 \param msg The printf like message to format.
486 \param ... The arguments to format in the message.
488 void debuga_more(const char *msg
,...)
493 vfprintf(stderr
,msg
,ap
);
498 Write a debug message to stderr. The message is prefixed by "SARG:" to identify its origin.
500 \param pos Where, in the source code, this message comes from.
501 \param msg The printf like message to format.
502 \param ... The arguments to format in the message.
504 void debugapos(const char *pos
,const char *msg
,...)
508 /* TRANSLATORS: This text is printed on the console before any message from
509 * the debug log with level "debug".
511 fputs(_("SARG: "),stderr
);
512 fprintf(stderr
,"(%s) ",pos
);
514 vfprintf(stderr
,msg
,ap
);
519 Write a debug message to stderr. The message is prefixed by "SARG: (info)".
521 \param msg The printf like message to format.
522 \param ... The arguments to format in the message.
524 void debugaz(const char *msg
,...)
528 /* TRANSLATORS: This text is printed on the console before any message from
529 * the debug log with level "info".
531 fputs(_("SARG: (info) "),stderr
);
533 vfprintf(stderr
,msg
,ap
);
538 char *fixnum(long long int value
, int n
)
540 #define MAXLEN_FIXNUM 256
541 char num
[MAXLEN_FIXNUM
]="";
542 char buf
[MAXLEN_FIXNUM
* 2];
544 static char ret
[MAXLEN_FIXNUM
* 2];
546 register int i
, j
, k
;
548 static char abbrev
[30];
550 my_lltoa(value
, num
, sizeof(num
), 0);
552 if(DisplayedValues
==DISPLAY_ABBREV
) {
553 numlen
= strlen(num
);
555 sprintf(abbrev
,"%s",num
);
556 if(numlen
== 4 || numlen
== 7 || numlen
== 10 || numlen
== 13) {
557 snprintf(abbrev
,2,"%s",num
);
558 strncat(abbrev
,".",1);
559 strncat(abbrev
,num
+1,2);
560 if(!n
) return(abbrev
);
562 strncat(abbrev
,"K",1);
564 strncat(abbrev
,"M",1);
565 else if(numlen
== 10)
566 strncat(abbrev
,"G",1);
567 else if(numlen
== 13)
568 strncat(abbrev
,"T",1);
570 if(numlen
== 5 || numlen
== 8 || numlen
== 11 || numlen
== 14) {
571 snprintf(abbrev
,3,"%s",num
);
572 strncat(abbrev
,".",1);
573 strncat(abbrev
,num
+2,2);
574 if(!n
) return(abbrev
);
576 strncat(abbrev
,"K",1);
578 strncat(abbrev
,"M",1);
579 else if(numlen
== 11)
580 strncat(abbrev
,"G",1);
581 else if(numlen
== 14)
582 strncat(abbrev
,"T",1);
584 if(numlen
== 6 || numlen
== 9 || numlen
== 12 || numlen
== 15) {
585 snprintf(abbrev
,4,"%s",num
);
586 strncat(abbrev
,".",1);
587 strncat(abbrev
,num
+3,2);
588 if(!n
) return(abbrev
);
590 strncat(abbrev
,"K",1);
592 strncat(abbrev
,"M",1);
593 else if(numlen
== 12)
594 strncat(abbrev
,"G",1);
595 else if(numlen
== 15)
596 strncat(abbrev
,"T",1);
602 bzero(buf
, MAXLEN_FIXNUM
*2);
608 for ( i
= strlen(num
) - 1, j
= 0 ; i
> -1; i
--) {
609 if ( k
== 2 && i
!= 0 ) {
612 pbuf
[j
++] = (UseComma
) ? ',' : '.';
622 for ( i
= strlen(pbuf
) - 1, j
= 0 ; i
> -1; i
--, j
++)
631 char *fixnum2(long long int value
, int n
)
633 #define MAXLEN_FIXNUM2 1024
634 char num
[MAXLEN_FIXNUM2
];
635 char buf
[MAXLEN_FIXNUM2
* 2];
637 static char ret
[MAXLEN_FIXNUM2
* 2];
639 register int i
, j
, k
;
641 my_lltoa(value
, num
, sizeof(num
), 0);
642 bzero(buf
, MAXLEN_FIXNUM2
*2);
648 for ( i
= strlen(num
) - 1, j
= 0 ; i
> -1; i
--) {
649 if ( k
== 2 && i
!= 0 ) {
652 pbuf
[j
++] = (UseComma
) ? ',' : '.';
662 for ( i
= strlen(pbuf
) - 1, j
= 0 ; i
> -1; i
--, j
++)
671 char *buildtime(long long int elap
)
673 long int num
= elap
/ 1000LL;
680 min
=(num
% 3600L) / 60L;
682 snprintf(buf
,sizeof(buf
),"%02d:%02d:%02d",hor
,min
,sec
);
689 Get the date stored in the <tt>sarg-date</tt> file of a directory with the connection data.
691 \param dirname The directory to look for the connection directory.
692 \param name The name of the directory whose <tt>sarg-date</tt> file must be read.
693 \param data The buffer to store the content of the file. It must be more than 80
697 \retval -1 File not found.
699 int obtdate(const char *dirname
, const char *name
, char *data
)
704 if (snprintf(wdir
,sizeof(wdir
),"%s%s/sarg-date",dirname
,name
)>=sizeof(wdir
)) {
705 debuga(_("Buffer to small to store %s%s/sarg-date"),dirname
,name
);
708 if ((fp_in
= fopen(wdir
, "rt")) == 0) {
709 if (snprintf(wdir
,sizeof(wdir
),"%s%s/date",dirname
,name
)>=sizeof(wdir
)) {
710 debuga(_("Buffer to small to store %s%s/date"),dirname
,name
);
713 if ((fp_in
= fopen(wdir
, "rt")) == 0) {
719 if (!fgets(data
,80,fp_in
)) {
720 /* TRANSLATORS: %s is a file name.
722 debuga(_("Failed to read the date in \"%s\"\n"),wdir
);
732 void formatdate(char *date
,int date_size
,int year
,int month
,int day
,int hour
,int minute
,int second
,int dst
)
738 memset(<m
,0,sizeof(ltm
));
739 if (year
>=1900) ltm
.tm_year
=year
-1900;
740 if (month
>=1 && month
<=12) ltm
.tm_mon
=month
-1;
741 if (day
>=1 && day
<=31) ltm
.tm_mday
=day
;
742 if (hour
>=0 && hour
<24) ltm
.tm_hour
=hour
;
743 if (minute
>=0 && minute
<60) ltm
.tm_min
=minute
;
744 if (second
>=0 && second
<60) ltm
.tm_sec
=second
;
746 unixtime
=mktime(<m
); //fill the missing entries
747 fulltm
=localtime(&unixtime
);
748 //strftime(date,date_size,"%a %b %d %H:%M:%S %Z %Y",fulltm);
749 strftime(date
,date_size
,"%c",fulltm
);
753 void computedate(int year
,int month
,int day
,struct tm
*t
)
755 memset(t
,0,sizeof(*t
));
756 t
->tm_year
=year
-1900;
762 int obtuser(const char *dirname
, const char *name
)
769 if (snprintf(wdir
,sizeof(wdir
),"%s%s/sarg-users",dirname
,name
)>=sizeof(wdir
)) {
770 debuga(_("Buffer too small to store %s%s/sarg-users"),dirname
,name
);
773 if((fp_in
=fopen(wdir
,"r"))==NULL
) {
774 if (snprintf(wdir
,sizeof(wdir
),"%s%s/users",dirname
,name
)>=sizeof(wdir
)) {
775 debuga(_("Buffer too small to store %s%s/users"),dirname
,name
);
778 if((fp_in
=fopen(wdir
,"r"))==NULL
) {
783 if (!fgets(tuser
,sizeof(tuser
),fp_in
)) {
784 /* TRANSLATORS: %s is a file name.
786 debuga(_("Failed to read the number of users in \"%s\"\n"),wdir
);
796 void obttotal(const char *dirname
, const char *name
, int nuser
, long long int *tbytes
, long long int *media
)
801 char user
[MAX_USER_LEN
];
803 struct getwordstruct gwarea
;
809 if (snprintf(wdir
,sizeof(wdir
),"%s%s/sarg-general",dirname
,name
)>=sizeof(wdir
)) {
810 debuga(_("Buffer too small to store %s%s/sarg-general"),dirname
,name
);
813 if ((fp_in
= fopen(wdir
, "r")) == 0) {
814 if (snprintf(wdir
,sizeof(wdir
),"%s%s/general",dirname
,name
)>=sizeof(wdir
)) {
815 debuga(_("Buffer too small to store %s%s/general"),dirname
,name
);
818 if ((fp_in
= fopen(wdir
, "r")) == 0) {
823 if ((line
=longline_create())==NULL
) {
824 debuga(_("Not enough memory to read file \"%s\"\n"),wdir
);
828 while((buf
=longline_read(fp_in
,line
))!=NULL
) {
829 if (strncmp(buf
,"TOTAL\t",6) == 0)
831 else if (strncmp(buf
,"TOTAL ",6) == 0)
835 getword_start(&gwarea
,buf
);
836 if (getword(user
,sizeof(user
),&gwarea
,sep
)<0) {
837 debuga(_("Invalid user in file \"%s\"\n"),wdir
);
840 if(strcmp(user
,"TOTAL") != 0)
842 if (getword_skip(MAXLEN
,&gwarea
,sep
)<0) {
843 debuga(_("Invalid total number of accesses in file \"%s\"\n"),wdir
);
846 if (getword_atoll(tbytes
,&gwarea
,sep
)<0) {
847 debuga(_("Invalid number of bytes in file \"%s\"\n"),wdir
);
853 longline_destroy(&line
);
858 *media
=*tbytes
/ nuser
;
862 int getperiod_fromsarglog(const char *arqtt
,struct periodstruct
*period
)
865 int day0
, month0
, year0
, hour0
, minute0
;
866 int day1
, month1
, year1
, hour1
, minute1
;
869 memset(period
,0,sizeof(*period
));
872 while((str
=strstr(str
,"sarg-"))!=NULL
) {
874 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
875 day0
=(str
[0]-'0')*10+(str
[1]-'0');
876 if (day0
<1 || day0
>31) continue;
878 month0
=(str
[0]-'0')*10+(str
[1]-'0')-1;
879 if (month0
<0 || month0
>11) continue;
882 for (i
=0 ; isdigit(str
[i
]) && i
<4 ; i
++) year0
=year0
*10+(str
[i
]-'0');
885 if (str
[0]!='_') continue;
888 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
889 hour0
=(str
[0]-'0')*10+(str
[1]-'0');
891 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
892 minute0
=(str
[0]-'0')*10+(str
[1]-'0');
895 if (*str
!= '-') continue;
898 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
899 day1
=(str
[0]-'0')*10+(str
[1]-'0');
900 if (day1
<1 || day1
>31) continue;
902 month1
=(str
[0]-'0')*10+(str
[1]-'0')-1;
903 if (month1
<0 || month1
>11) continue;
906 for (i
=0 ; isdigit(str
[i
]) && i
<4 ; i
++) year1
=year1
*10+(str
[i
]-'0');
910 if (str
[0]!='_') continue;
913 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
914 hour1
=(str
[0]-'0')*10+(str
[1]-'0');
916 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
917 minute1
=(str
[0]-'0')*10+(str
[1]-'0');
920 period
->start
.tm_mday
=day0
;
921 period
->start
.tm_mon
=month0
;
922 period
->start
.tm_year
=year0
-1900;
923 period
->start
.tm_hour
=hour0
;
924 period
->start
.tm_min
=minute0
;
925 period
->end
.tm_mday
=day1
;
926 period
->end
.tm_mon
=month1
;
927 period
->end
.tm_year
=year1
-1900;
928 period
->end
.tm_hour
=hour1
;
929 period
->end
.tm_min
=minute1
;
935 void getperiod_fromrange(struct periodstruct
*period
,int dfrom
,int duntil
)
937 memset(&period
->start
,0,sizeof(period
->start
));
938 period
->start
.tm_mday
=dfrom
%100;
939 period
->start
.tm_mon
=(dfrom
/100)%100-1;
940 period
->start
.tm_year
=(dfrom
/10000)-1900;
942 memset(&period
->end
,0,sizeof(period
->end
));
943 period
->end
.tm_mday
=duntil
%100;
944 period
->end
.tm_mon
=(duntil
/100)%100-1;
945 period
->end
.tm_year
=(duntil
/10000)-1900;
948 int getperiod_buildtext(struct periodstruct
*period
)
952 char text1
[40], text2
[40];
955 i
=strftime(text1
, sizeof(text1
), "%Y %b %d", &period
->start
);
956 }else if(df
[0]=='e') {
957 i
=strftime(text1
, sizeof(text1
), "%d %b %Y", &period
->start
);
958 } else /*if(df[0]=='w')*/ {
959 IndexTree
=INDEX_TREE_FILE
;
960 i
=strftime(text1
, sizeof(text1
), "%Y.%U", &period
->start
);
962 if (i
== 0) return(-1);
964 range
=(period
->start
.tm_year
!=period
->end
.tm_year
||
965 period
->start
.tm_mon
!=period
->end
.tm_mon
||
966 period
->start
.tm_mday
!=period
->end
.tm_mday
);
969 i
=strftime(text2
, sizeof(text2
)-i
, "%Y %b %d", &period
->end
);
970 } else if(df
[0]=='e') {
971 i
=strftime(text2
, sizeof(text2
)-i
, "%d %b %Y", &period
->end
);
973 i
=strftime(text2
, sizeof(text2
)-i
, "%Y.%U", &period
->end
);
975 if (i
== 0) return(-1);
979 snprintf(period
->text
,sizeof(period
->text
),"%s-%s",text1
,text2
);
980 snprintf(period
->html
,sizeof(period
->html
),"%s—%s",text1
,text2
);
982 safe_strcpy(period
->text
,text1
,sizeof(period
->text
));
983 safe_strcpy(period
->html
,text1
,sizeof(period
->html
));
988 static void copy_images(void)
990 FILE *img_in
, *img_ou
;
993 char srcfile
[MAXLEN
];
994 char dstfile
[MAXLEN
];
996 struct dirent
*direntp
;
1001 if (snprintf(images
,sizeof(images
),"%simages",outdir
)>=sizeof(images
)) {
1002 debuga(_("Path too long: "));
1003 debuga_more("%simages\n",outdir
);
1006 if (access(images
,R_OK
)!=0) {
1007 if (mkdir(images
,0755)) {
1008 debuga(_("Cannot create directory \"%s\": %s\n"),images
,strerror(errno
));
1013 strcpy(imgdir
,IMAGEDIR
);
1014 dirp
= opendir(imgdir
);
1016 debugapos("util",_("Cannot open directory \"%s\": %s\n"),imgdir
,strerror(errno
));
1019 while ((direntp
= readdir( dirp
)) != NULL
){
1020 if(direntp
->d_name
[0]=='.')
1022 if (snprintf(srcfile
,sizeof(srcfile
),"%s/%s",imgdir
,direntp
->d_name
)>=sizeof(srcfile
)) {
1023 debuga(_("Buffer too small to store %s/%s"),imgdir
,direntp
->d_name
);
1026 if (stat(srcfile
,&info
)) {
1027 debuga(_("Cannot stat \"%s\": %s\n"),srcfile
,strerror(errno
));
1030 if (S_ISREG(info
.st_mode
)) {
1031 if (snprintf(dstfile
,sizeof(dstfile
),"%s/%s",images
,direntp
->d_name
)>=sizeof(dstfile
)) {
1032 debuga(_("Buffer too small to store %s/%s"),images
,direntp
->d_name
);
1035 img_in
= fopen(srcfile
, "rb");
1037 img_ou
= fopen(dstfile
, "wb");
1039 while ((nread
= fread(buffer
,1,sizeof(buffer
),img_in
))>0) {
1040 if (fwrite(buffer
,1,nread
,img_ou
)!=nread
) {
1041 debuga(_("Failed to copy image \"%s\" to \"%s\"\n"),srcfile
,dstfile
);
1047 debugapos("util",_("Cannot open file \"%s\": %s\n"), dstfile
, strerror(errno
));
1050 debugapos("util",_("Cannot open file \"%s\": %s\n"),srcfile
, strerror(errno
));
1053 (void) closedir(dirp
);
1058 int vrfydir(const struct periodstruct
*per1
, const char *addr
, const char *site
, const char *us
, const char *form
)
1063 char dirname2
[MAXLEN
];
1071 strcpy(wdir
,outdir
);
1073 y1
=per1
->start
.tm_year
+1900;
1074 y2
=per1
->end
.tm_year
+1900;
1075 m1
=per1
->start
.tm_mon
+1;
1076 m2
=per1
->end
.tm_mon
+1;
1077 d1
=per1
->start
.tm_mday
;
1078 d2
=per1
->end
.tm_mday
;
1079 if(IndexTree
== INDEX_TREE_DATE
) {
1080 wlen
+=sprintf(wdir
+wlen
,"%04d",y1
);
1081 if(y1
!=y2
) wlen
+=sprintf(wdir
+wlen
,"-%04d",y2
);
1082 if(access(wdir
, R_OK
) != 0)
1085 wlen
+=sprintf(wdir
+wlen
,"/%02d",m1
);
1086 if(m1
!= m2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",m2
);
1087 if(access(wdir
, R_OK
) != 0)
1090 wlen
+=sprintf(wdir
+wlen
,"/%02d",d1
);
1091 if(d1
!=d2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",d2
);
1094 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%04d%s%02d-%04d%s%02d",y1
,
1095 conv_month_name(m1
),d1
,y2
,conv_month_name(m2
),d2
);
1096 } else if(df
[0] == 'e') {
1097 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%02d%s%04d-%02d%s%04d",d1
,
1098 conv_month_name(m1
),y1
,d2
,conv_month_name(m2
),y2
);
1099 } else if(df
[0] == 'w') {
1100 wlen2
=strftime(wdir
+wlen
, sizeof(wdir
)-wlen
, "%Y.%U", &per1
->start
);
1101 if (wlen2
==0) return(-1);
1107 struct userinfostruct
*uinfo
=userinfo_find_from_id(us
);
1110 strcat(wdir
,uinfo
->filename
);
1113 if(addr
[0] != '\0') {
1117 if(site
[0] != '\0') {
1122 strcpy(outdirname
,wdir
);
1124 if(IndexTree
!= INDEX_TREE_DATE
) {
1125 if(!OverwriteReport
) {
1127 if(access(wdir
,R_OK
) == 0) {
1128 sprintf(wdir
,"%s.%d",outdirname
,num
);
1137 debuga(_("File \"%s\" already exists, moved to \"%s\"\n"),outdirname
,wdir
);
1138 rename(outdirname
,wdir
);
1141 if(access(outdirname
,R_OK
) == 0) {
1142 unlinkdir(outdirname
,1);
1145 my_mkdir(outdirname
);
1147 strcpy(dirname2
,wdir
);
1148 if(!OverwriteReport
) {
1150 if(access(wdir
,R_OK
) == 0) {
1151 sprintf(wdir
,"%s.%d",dirname2
,num
);
1160 debuga(_("File \"%s\" already exists, moved to \"%s\"\n"),dirname2
,wdir
);
1161 rename(dirname2
,wdir
);
1162 strcpy(dirname2
,wdir
);
1165 if(access(wdir
,R_OK
) == 0) {
1170 if(access(wdir
, R_OK
) != 0)
1174 strcpy(dirname2
,wdir
);
1176 if (snprintf(wdir
,sizeof(wdir
),"%s/sarg-date",outdirname
)>=sizeof(wdir
)) {
1177 debuga(_("Buffer too small to store %s/sarg-date"),outdirname
);
1180 if ((fp_ou
= fopen(wdir
, "wt")) == 0) {
1181 debuga(_("Cannot open file \"%s\": %s\n"),wdir
,strerror(errno
));
1186 //strftime(wdir,sizeof(wdir),"%a %b %d %H:%M:%S %Z %Y",localtime(&curtime));
1187 loctm
=localtime(&curtime
);
1188 strftime(wdir
,sizeof(wdir
),"%Y-%m-%d %H:%M:%S",loctm
);
1189 if (fprintf(fp_ou
,"%s %d\n",wdir
,loctm
->tm_isdst
)<0) {
1190 debuga(_("Failed to write the date in \"%s\"\n"),wdir
);
1194 if (fclose(fp_ou
)==EOF
) {
1195 debuga(_("Failed to close file \"%s\": %s\n"),wdir
,strerror(errno
));
1205 Copy a string without overflowing the buffer. The copied string
1206 is properly terminated by an ASCII zero.
1208 \param dest The destination buffer.
1209 \param src The source buffer.
1210 \param length The size of the destination buffer. The program is aborted
1211 if the length is negative or zero.
1213 void safe_strcpy(char *dest
,const char *src
,int length
)
1216 debuga(_("Invalid buffer length passed to the function to safely copy a string\n"));
1219 strncpy(dest
,src
,length
-1);
1220 dest
[length
-1]='\0';
1223 void strip_latin(char *line
)
1230 for (i
=0;line
[i
];i
++){
1232 if (line
[i
]==';') skip
=0;
1244 void zdate(char *ftime
,int ftimesize
, const char *DateFormat
)
1250 local
= localtime(&t
);
1251 if(strcmp(DateFormat
,"u") == 0)
1252 strftime(ftime
, ftimesize
, "%b/%d/%Y %H:%M", local
);
1253 if(strcmp(DateFormat
,"e") == 0)
1254 strftime(ftime
, ftimesize
, "%d/%b/%Y-%H:%M", local
);
1255 if(strcmp(DateFormat
,"w") == 0)
1256 strftime(ftime
, ftimesize
, "%W-%H-%M", local
);
1261 char *fixtime(long long int elap
)
1263 long int num
= elap
/ 1000LL;
1267 static char buf
[20];
1270 min
=(num
% 3600L) / 60L;
1273 if(hor
==0 && min
==0 && sec
==0)
1276 snprintf(buf
,sizeof(buf
),"%d:%02d:%02d",hor
,min
,sec
);
1282 void date_from(char *date
,int date_size
, int *dfrom
, int *duntil
)
1291 if (isdigit(date
[0])) {
1294 if (sscanf(date
,"%d/%d/%d%n",&d0
,&m0
,&y0
,&next
)!=3 || y0
<100 || m0
<1 || m0
>12 || d0
<1 || d0
>31 || next
<0) {
1295 debuga(_("The date passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1298 if (date
[next
]=='-') {
1299 if (sscanf(date
+next
+1,"%d/%d/%d",&d1
,&m1
,&y1
)!=3 || y1
<100 || m1
<1 || m1
>12 || d1
<1 || d1
>31) {
1300 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1303 } else if (date
[next
]!='\0') {
1304 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1314 struct tm
*Date0
,Date1
;
1316 if (time(&Today
)==(time_t)-1) {
1317 debuga(_("Failed to get the current time\n"));
1320 if (sscanf(date
,"day-%d",&i
)==1) {
1322 debuga(_("Invalid number of days in -d parameter\n"));
1326 Date0
=localtime(&Today
);
1328 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1331 y0
=y1
=Date0
->tm_year
+1900;
1332 m0
=m1
=Date0
->tm_mon
+1;
1333 d0
=d1
=Date0
->tm_mday
;
1334 } else if (sscanf(date
,"week-%d",&i
)==1) {
1336 There is no portable way to find the first day of the week even though the
1337 information is available in the locale. nl_langinfo has the unofficial
1338 parameters _NL_TIME_FIRST_WEEKDAY and _NL_TIME_WEEK_1STDAY but they are
1339 undocumented as is their return value and it is discouraged to use them.
1340 Beside, nl_langinfo isn't available on windows and the first day of the
1341 week isn't available at all on that system.
1343 const int FirstWeekDay
=1;
1347 debuga(_("Invalid number of weeks in -d parameter\n"));
1350 Date0
=localtime(&Today
);
1352 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1355 WeekBegin
=Today
-((Date0
->tm_wday
-FirstWeekDay
+7)%7)*24*60*60;
1356 WeekBegin
-=i
*7*24*60*60;
1357 Date0
=localtime(&WeekBegin
);
1359 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1362 y0
=Date0
->tm_year
+1900;
1365 WeekBegin
+=6*24*60*60;
1366 Date0
=localtime(&WeekBegin
);
1368 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1371 y1
=Date0
->tm_year
+1900;
1374 } else if (sscanf(date
,"month-%d",&i
)==1) {
1376 debuga(_("Invalid number of months in -d parameter\n"));
1379 Date0
=localtime(&Today
);
1381 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1384 if (Date0
->tm_mon
<i
%12) {
1385 y0
=Date0
->tm_year
+1900-i
/12-1;
1386 m0
=(Date0
->tm_mon
+12-i
%12)%12+1;
1389 y0
=Date0
->tm_year
+1900-i
/12;
1390 m0
=Date0
->tm_mon
-i
%12+1;
1393 memcpy(&Date1
,Date0
,sizeof(struct tm
));
1398 Date1
.tm_year
=y0
-1900;
1401 Date1
.tm_year
=y0
-1900+1;
1405 Date0
=localtime(&t1
);
1406 y1
=Date0
->tm_year
+1900;
1410 debuga(_("Invalid date range passed on command line\n"));
1415 *dfrom
=y0
*10000+m0
*100+d0
;
1416 *duntil
=y1
*10000+m1
*100+d1
;
1417 snprintf(date
,date_size
,"%02d/%02d/%04d-%02d/%02d/%04d",d0
,m0
,y0
,d1
,m1
,y1
);
1422 char *strlow(char *string
)
1428 for (s
= string
; *s
; ++s
)
1438 char *strup(char *string
)
1444 for (s
= string
; *s
; ++s
)
1452 void removetmp(const char *outdir
)
1457 if(!RemoveTempFiles
)
1461 debuga(_("Purging temporary file sarg-general\n"));
1463 if (snprintf(filename
,sizeof(filename
),"%s/sarg-general",outdir
)>=sizeof(filename
)) {
1464 debugapos("removetmp",_("Path too long: "));
1465 debuga_more("%s/sarg-period\n",outdir
);
1468 if((fp_gen
=fopen(filename
,"w"))==NULL
){
1469 debugapos("removetmp",_("Cannot open file \"%s\": %s\n"),filename
,strerror(errno
));
1472 totalger(fp_gen
,filename
);
1473 if (fclose(fp_gen
)==EOF
) {
1474 debuga(_("Failed to close file \"%s\": %s\n"),filename
,strerror(errno
));
1479 void load_excludecodes(const char *ExcludeCodes
)
1487 if(ExcludeCodes
[0] == '\0')
1490 if((fp_in
=fopen(ExcludeCodes
,"r"))==NULL
) {
1491 debugapos("util",_("Cannot open file \"%s\": %s\n"),ExcludeCodes
,strerror(errno
));
1495 if (fseek(fp_in
, 0, SEEK_END
)==-1) {
1496 debuga(_("Failed to move till the end of file \"%s\": %s\n"),ExcludeCodes
,strerror(errno
));
1499 MemSize
= ftell(fp_in
);
1501 debuga(_("Cannot get the size of file \"%s\": %s\n"),ExcludeCodes
,strerror(errno
));
1504 if (fseek(fp_in
, 0, SEEK_SET
)==-1) {
1505 debuga(_("Failed to rewind file \"%s\": %s\n"),ExcludeCodes
,strerror(errno
));
1510 if((excludecode
=(char *) malloc(MemSize
))==NULL
) {
1511 debuga(_("malloc failed to allocate %ld bytes\n"),MemSize
);
1514 memset(excludecode
,0,MemSize
);
1517 while(fgets(data
,sizeof(data
),fp_in
)!=NULL
) {
1518 if (data
[0]=='#') continue;
1519 for (i
=strlen(data
)-1 ; i
>=0 && (unsigned char)data
[i
]<=' ' ; i
--) data
[i
]='\0';
1521 if (Stored
+i
+2>=MemSize
) {
1522 debuga(_("Too many codes to exclude in file \"%s\"\n"),ExcludeCodes
);
1525 strcat(excludecode
,data
);
1526 strcat(excludecode
,";");
1534 void free_excludecodes(void)
1542 int vercode(const char *code
)
1547 if (excludecode
&& excludecode
[0]!='\0') {
1551 if (strncmp(code
,cod
,clen
)==0 && cod
[clen
]==';')
1553 cod
=strchr(cod
,';');
1560 void fixnone(char *str
)
1564 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--);
1565 if(i
==3 && strncmp(str
,"none",4) == 0)
1571 void fixendofline(char *str
)
1575 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--) str
[i
]=0;
1578 #ifdef LEGACY_TESTVALIDUSERCHAR
1579 int testvaliduserchar(const char *user
)
1584 for (y
=0; y
<strlen(UserInvalidChar
); y
++) {
1585 for (x
=0; x
<strlen(user
); x
++) {
1586 if(user
[x
] == UserInvalidChar
[y
])
1593 int testvaliduserchar(const char *user
)
1595 char * p_UserInvalidChar
= UserInvalidChar
;
1596 const char * p_user
;
1598 while( *p_UserInvalidChar
) {
1601 if( *p_UserInvalidChar
== *p_user
)
1605 p_UserInvalidChar
++ ;
1611 int compar( const void *a
, const void *b
)
1613 if( *(int *)a
> *(int *)b
) return 1;
1614 if( *(int *)a
< *(int *)b
) return -1;
1618 int getnumlist( char *buf
, numlist
*list
, const int len
, const int maxvalue
)
1620 int i
, j
, d
, flag
, r1
, r2
;
1621 char *pbuf
, **bp
, *strbufs
[ 24 ];
1624 strtok( buf
, " \t" );
1625 for( *bp
= strtok( NULL
, "," ), list
->len
= 0; *bp
; *bp
= strtok( NULL
, "," ) ) {
1626 if( ++bp
>= &strbufs
[ 24 ] )
1633 for( i
= 0; i
< list
->len
; i
++ ) {
1634 if( strchr( strbufs
[ i
], '-' ) != 0 ) {
1635 pbuf
= strbufs
[ i
];
1636 strtok( pbuf
, "-" );
1637 pbuf
= strtok( NULL
, "\0" );
1638 r1
= atoi( strbufs
[ i
] );
1639 if( ( r2
= atoi( pbuf
) ) >= maxvalue
|| r1
>= r2
)
1641 if( i
+ d
+ ( r2
- r1
) + 1 <= len
) {
1642 for( j
= r1
; j
<= r2
; j
++ )
1643 list
->list
[ i
+ d
++ ] = j
;
1648 if( ( list
->list
[ i
+ d
] = atoi( strbufs
[ i
] ) ) >= maxvalue
)
1652 qsort( list
->list
, list
->len
, sizeof( int ), compar
);
1655 for( i
= 0; i
< list
->len
- 1; i
++ )
1656 if( list
->list
[ i
] == list
->list
[ i
+ 1 ] ) {
1657 for( j
= i
+ 1; j
< list
->len
; j
++ )
1658 list
->list
[ j
- 1 ] = list
->list
[ j
];
1668 char *get_size(const char *path
, const char *file
)
1671 static char response
[255];
1675 if (snprintf(cmd
,sizeof(cmd
),"du -skh \"%s%s\"",path
,file
)>=sizeof(cmd
)) {
1676 debuga(_("Cannot get disk space because the path \"%s%s\" is too long\n"),path
,file
);
1679 if ((fp
= popen(cmd
, "r")) == NULL
) {
1680 debuga(_("Cannot get disk space with command %s\n"),cmd
);
1683 if (!fgets(response
, sizeof(response
), fp
)) {
1684 debuga(_("Cannot get disk size with command %s\n"),cmd
);
1687 ptr
=strchr(response
,'\t');
1689 /* TRANSLATORS: First %s is the command to get the occuped disk size (namely, du -skh "...").
1690 * The second %s is the string returned by the command.
1692 debuga(_("The command to compute the occupied disk size (%s) returned the unknown string %s\n"),cmd
,response
);
1701 void show_info(FILE *fp_ou
)
1706 if(!ShowSargInfo
) return;
1707 zdate(ftime
, sizeof(ftime
), DateFormat
);
1708 fputs("<div class=\"info\">",fp_ou
);
1709 snprintf(pgmurl
,sizeof(pgmurl
),"<a href='%s'>%s-%s</a>",URL
,PGM
,VERSION
);
1710 fprintf(fp_ou
,_("Generated by %s on %s"),pgmurl
,ftime
);
1711 fputs("</div>\n",fp_ou
);
1714 void show_sarg(FILE *fp_ou
, int depth
)
1718 if(!ShowSargLogo
) return;
1719 fputs("<div class=\"logo\"><a href=\"http://sarg.sourceforge.net\"><img src=\"",fp_ou
);
1720 for (i
=0 ; i
<depth
; i
++)
1722 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
);
1725 void write_logo_image(FILE *fp_ou
)
1727 if(LogoImage
[0]!='\0')
1728 fprintf(fp_ou
, "<div class=\"logo\"><img src=\"%s\" width=\"%s\" height=\"%s\" alt=\"Logo\"> %s</div>\n",LogoImage
,Width
,Height
,LogoText
);
1731 void write_html_head(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1735 fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n",fp_ou
);
1736 fprintf(fp_ou
, "<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n",CharSet
);
1737 if (page_title
) fprintf(fp_ou
,"<title>%s</title>\n",page_title
);
1739 if ((javascript
& HTML_JS_SORTTABLE
)!=0 && SortTableJs
[0]) {
1740 fputs("<script type=\"text/javascript\" src=\"",fp_ou
);
1741 if (strncmp(SortTableJs
,"../",3)==0) {
1742 for (i
=0 ; i
<depth
; i
++) fputs("../",fp_ou
);
1744 fputs(SortTableJs
,fp_ou
);
1745 fputs("\"></script>\n",fp_ou
);
1747 fputs("</head>\n<body>\n",fp_ou
);
1750 void write_html_header(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1752 write_html_head(fp_ou
,depth
,page_title
,javascript
);
1753 write_logo_image(fp_ou
);
1754 show_sarg(fp_ou
, depth
);
1755 fprintf(fp_ou
,"<div class=\"title\"><table cellpadding=\"0\" cellspacing=\"0\">\n<tr><th class=\"title_c\">%s</th></tr>\n",Title
);
1758 void close_html_header(FILE *fp_ou
)
1760 fputs("</table></div>\n",fp_ou
);
1763 int write_html_trailer(FILE *fp_ou
)
1766 if (fputs("</body>\n</html>\n",fp_ou
)==EOF
) return(-1);
1770 void output_html_string(FILE *fp_ou
,const char *str
,int maxlen
)
1774 while (*str
&& (maxlen
<=0 || i
<maxlen
)) {
1777 fputs("&",fp_ou
);
1780 fputs("<",fp_ou
);
1783 fputs(">",fp_ou
);
1786 fputs(""",fp_ou
);
1789 fputs("'",fp_ou
);
1797 if (maxlen
>0 && i
>=maxlen
)
1798 fputs("…",fp_ou
);
1801 void output_html_url(FILE *fp_ou
,const char *url
)
1805 fputs("&",fp_ou
);
1813 Write a host name inside an A tag of a HTML file. If the host name starts
1814 with a star, it is assumed to be an alias that cannot be put inside a link
1815 so the A tag is not written around the host name.
1817 \param fp_ou The handle of the HTML file.
1818 \param url The host to display in the HTML file.
1819 \param maxlen The maximum number of characters to print into the host name.
1821 void output_html_link(FILE *fp_ou
,const char *url
,int maxlen
)
1823 if (url
[0]==ALIAS_PREFIX
) {
1824 // this is an alias, no need for a A tag
1825 output_html_string(fp_ou
,url
+1,100);
1827 if (skip_scheme(url
)==url
)
1828 fputs("<a href=\"http://",fp_ou
);//no scheme in the url, assume http:// to make the link clickable
1830 fputs("<a href=\"",fp_ou
);//the scheme is in the url, no need to add one
1831 output_html_url(fp_ou
,url
);
1833 output_html_string(fp_ou
,url
,100);
1834 fputs("</a>",fp_ou
);
1838 void url_module(const char *url
, char *w2
)
1844 for(x
=strlen(url
)-1; x
>=0; x
--) {
1845 if(url
[x
] == '/' || y
>=sizeof(w
)-1) break;
1854 for(y
=y
-1; y
>=0; y
--) {
1860 void url_to_file(const char *url
,char *file
,int filesize
)
1866 for(i
=0; i
<filesize
&& *url
; url
++) {
1867 if(isalnum(*url
) || *url
=='-' || *url
=='_' || *url
=='.' || *url
=='%') {
1871 if (!skip
) file
[i
++]='_';
1880 printf(_("SARG version: %s\n"),VERSION
);
1881 #if defined(ENABLE_NLS) && defined(HAVE_LOCALE_H)
1883 printf(_("\nFor the translation to work, a valid message file should be installed as "
1884 "\"%s/<Locale>/LC_MESSAGES/%s.mo\" where <Locale> is derived from the effective locale.\n"),LOCALEDIR
,PACKAGE_NAME
);
1885 if (CurrentLocale
) {
1886 printf(_("Currently effective locale is \"%s\".\n"),CurrentLocale
);
1888 printf(_("Locale is not set in the environment variable.\n"));
1890 // TRANSLATORS: You may change this message to tell the reader that the language is correctly supported.
1891 printf(_("If this message is in English, then your language is not supported or not correctly installed.\n"));
1897 char *get_param_value(const char *param
,char *line
)
1901 while (*line
==' ' || *line
=='\t') line
++;
1903 if (strncasecmp(line
,param
,plen
)) return(NULL
);
1904 if (line
[plen
]!=' ' && line
[plen
]!='\t') return(NULL
);
1906 while (*line
==' ' || *line
=='\t') line
++;
1910 void unlinkdir(const char *dir
,bool contentonly
)
1914 struct dirent
*direntp
;
1920 while ((direntp
= readdir(dirp
)) != NULL
) {
1921 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
1922 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
1924 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
1925 debuga(_("Path too long: "));
1926 debuga_more("%s/%s\n",dir
,direntp
->d_name
);
1930 err
=lstat(dname
,&st
);
1932 err
=stat(dname
,&st
);
1935 debuga(_("Cannot stat \"%s\": %s\n"),dname
,strerror(errno
));
1938 if (S_ISREG(st
.st_mode
)) {
1939 if (unlink(dname
)) {
1940 debuga(_("Cannot delete \"%s\": %s\n"),dname
,strerror(errno
));
1943 } else if (S_ISDIR(st
.st_mode
)) {
1946 debuga(_("Unknown path type \"%s\"\n"),dname
);
1953 debuga(_("Cannot delete \"%s\": %s\n"),dir
,strerror(errno
));
1960 Delete every file from the temporary directory where sarg is told to store its
1963 As any stray file left over by a previous run would be included in the report, we
1964 must delete every file from the temporary directory before we start processing the logs.
1966 But the temporary directory is given by the user either in the configuration file or
1967 on the command line. We check that the user didn't give a wrong directory by looking
1968 at the files stored in the directory. If a single file is not one of ours, we abort.
1970 \param dir The temporary directory to purge.
1972 void emptytmpdir(const char *dir
)
1976 struct dirent
*direntp
;
1982 static const char *TmpExt
[]=
1997 // make sure the temporary directory contains only our files
1998 while ((direntp
= readdir(dirp
)) != NULL
) {
1999 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
2000 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
2003 // is it one of our files
2004 dlen
=strlen(direntp
->d_name
);
2005 for (i
=sizeof(TmpExt
)/sizeof(TmpExt
[0])-1 ; i
>=0 ; i
--) {
2006 elen
=strlen(TmpExt
[i
]);
2007 if (dlen
>=elen
&& strcasecmp(direntp
->d_name
+dlen
-elen
,TmpExt
[i
])==0) break;
2010 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2011 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2012 "directory or manually delete the content of \"%s\"\n"),direntp
->d_name
,dir
,dir
);
2016 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
2017 debuga(_("Path too long: "));
2018 debuga_more("%s/%s\n",dir
,direntp
->d_name
);
2023 err
=lstat(dname
,&st
);
2025 err
=stat(dname
,&st
);
2028 debuga(_("Cannot stat \"%s\": %s\n"),dname
,strerror(errno
));
2031 if (S_ISDIR(st
.st_mode
)) {
2033 } else if (!S_ISREG(st
.st_mode
)) {
2034 debuga(_("Unknown path type \"%s\". Check your temporary directory\n"),dname
);
2040 // now delete our files
2041 while ((direntp
= readdir(dirp
)) != NULL
) {
2042 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
2043 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
2046 // is it one of our files
2047 dlen
=strlen(direntp
->d_name
);
2048 for (i
=sizeof(TmpExt
)/sizeof(TmpExt
[0])-1 ; i
>=0 ; i
--) {
2049 elen
=strlen(TmpExt
[i
]);
2050 if (dlen
>=elen
&& strcasecmp(direntp
->d_name
+dlen
-elen
,TmpExt
[i
])==0) break;
2053 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2054 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2055 "directory or manually delete the content of \"%s\"\n"),direntp
->d_name
,dir
,dir
);
2059 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
2060 debuga(_("Path too long: "));
2061 debuga_more("%s/%s\n",dir
,direntp
->d_name
);
2065 err
=lstat(dname
,&st
);
2067 err
=stat(dname
,&st
);
2070 debuga(_("Cannot stat \"%s\": %s\n"),dname
,strerror(errno
));
2073 if (S_ISREG(st
.st_mode
)) {
2074 if (unlink(dname
)) {
2075 debuga(_("Cannot delete \"%s\": %s\n"),dname
,strerror(errno
));
2079 debuga(_("Unknown path type \"%s\"\n"),dname
);
2086 Extract an url, IPv4 or IPv6 from a buffer. The IP addresses may end with a
2089 \param buf The buffer to parse.
2090 \param text A pointer to set to the beginning of the string pattern. No terminating zero is inserted.
2091 The pointer may be NULL.
2092 \param ipv4 A 4 bytes buffer to store the bytes of the IPv4 address.
2093 \param ipv6 A 8 short integers buffer to store the values of the IPv6 address.
2094 \param nbits The number of prefix bits for an IP address.
2095 \param next The content of the line after the extracted address.
2097 \retval 3 The pattern is a IPv6 address.
2098 \retval 2 The pattern is a IPv4 address.
2099 \retval 1 The patter is a string.
2100 \retval 0 Empty pattern.
2102 int extract_address_mask(const char *buf
,const char **text
,unsigned char *ipv4
,unsigned short int *ipv6
,int *nbits
,const char **next
)
2107 unsigned int value4
, value6
;
2108 unsigned short int addr
[8];
2118 // skip leading spaces and tabs
2119 while (*buf
&& (*buf
==' ' || *buf
=='\t')) buf
++;
2121 // find out the nature of the pattern
2122 ip_size
=0x60 | 0x04;
2133 for (i
=0 ; (unsigned char)buf
[i
]>' ' && buf
[i
]!='/' && buf
[i
]!='?' && (!bracket
|| buf
[i
]!=']') && ip_size
; i
++) {
2134 if (ip_size
& 0x04) {
2135 if (isdigit(buf
[i
])) {
2137 port_num
=port_num
*10+(buf
[i
]-'0');
2138 if (port_num
>65535) ip_size
&=~0x04;
2140 value4
=value4
*10+(buf
[i
]-'0');
2141 if (value4
>0xFFU
) ip_size
&=~0x04;
2143 } else if (buf
[i
]=='.' && addr_len
<4) {
2144 addr
[addr_len
++]=(unsigned short)(value4
& 0xFFU
);
2146 } else if (!port
&& buf
[i
]==':') {
2152 if (ip_size
& 0x60) {
2153 if (isdigit(buf
[i
])) {
2154 value6
=(value6
<<4)+(buf
[i
]-'0');
2156 if (value6
>0xFFFFU
) ip_size
&=~0x60;
2157 } else if (toupper(buf
[i
])>='A' && toupper(buf
[i
])<='F') {
2158 value6
=(value6
<<4)+(toupper(buf
[i
])-'A'+10);
2160 if (value6
>0xFFFFU
) ip_size
&=~0x60;
2161 } else if (buf
[i
]==':' && addr_len
<8) {
2162 if (nibble6_len
>0) {
2163 addr
[addr_len
++]=(unsigned short)(value6
& 0xFFFFU
);
2167 if (buf
[i
+1]==':') {
2176 if (i
==0) return(0);
2177 if (ip_size
& 0x04) {
2181 addr
[addr_len
++]=(unsigned short)(value4
& 0xFFU
);
2183 if (ip_size
& 0x60) {
2184 if (pad_pos
<0 && addr_len
!=7) {
2186 } else if (pad_pos
>=0 && addr_len
>=7)
2188 else if (nibble6_len
>0)
2189 addr
[addr_len
++]=(unsigned short)(value6
& 0xFFFFU
);
2194 if (bracket
) (*text
)--;
2196 while ((unsigned char)buf
[i
]>' ') i
++;
2197 if (next
) *next
=buf
+i
;
2200 max_mask
=(ip_size
& 0x04) ? 4*8 : 8*16;
2204 while (isdigit(buf
[i
])) i
++;
2205 if (mask
<0 || mask
>max_mask
) mask
=max_mask
;
2208 if (ip_size
& 0x60 && bracket
&& buf
[i
]==']') i
++;
2209 if (next
) *next
=buf
+i
;
2210 if (ip_size
& 0x04) {
2211 if (nbits
) *nbits
=mask
;
2212 for (i
=0 ; i
<addr_len
; i
++)
2213 ipv4
[i
]=(unsigned char)addr
[i
];
2218 if (nbits
) *nbits
=mask
;
2223 ipv6
[j
++]=(unsigned short int)addr
[i
++];
2225 while (j
<pad_pos
+pad_len
)
2229 ipv6
[j
++]=(unsigned short int)addr
[i
++];