]>
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(__MINGW32__) && defined(HAVE_DIRECT_H)
38 #if defined(HAVE_BACKTRACE)
39 #define USE_GETWORD_BACKTRACE 1
41 #define USE_GETWORD_BACKTRACE 0
44 static char mtab1
[12][4]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
46 //! The list of the HTTP codes to exclude from the report.
47 static char *excludecode
=NULL
;
49 //! Directory where the images are stored.
50 char ImageDir
[MAXLEN
]=IMAGEDIR
;
52 extern char *CurrentLocale
;
54 #if USE_GETWORD_BACKTRACE
55 static void getword_backtrace(void)
61 n
=backtrace(buffer
,sizeof(buffer
)/sizeof(buffer
[0]));
63 calls
=backtrace_symbols(buffer
,n
);
65 debuga(_("getword backtrace:\n"));
66 for (i
=0 ; i
<n
; i
++) {
67 fprintf(stderr
,"SARG: %d:%s\n",i
+1,calls
[i
]);
72 #endif //USE_GETWORD_BACKTRACE
74 void getword_start(struct getwordstruct
*gwarea
, const char *line
)
76 gwarea
->beginning
=line
;
81 void getword_restart(struct getwordstruct
*gwarea
)
83 if (gwarea
->modified
) {
84 debuga(_("Cannot parse again the line as it was modified\n"));
87 gwarea
->current
=gwarea
->beginning
;
90 int getword(char *word
, int limit
, struct getwordstruct
*gwarea
, char stop
)
94 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++) {
96 debuga(_("End of word not found in getword after %d bytes.\n"),x
);
97 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
98 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
99 debuga(_("searching for \'x%x\'\n"),stop
);
100 word
[(limit
>0) ? limit
-1 : 0]='\0';
101 #if USE_GETWORD_BACKTRACE
106 word
[x
] = gwarea
->current
[x
];
110 if (gwarea
->current
[x
]) ++x
;
115 int getword_limit(char *word
, int limit
, struct getwordstruct
*gwarea
, char stop
)
120 for(x
=0; x
<limit
&& gwarea
->current
[x
] && gwarea
->current
[x
] != stop
;x
++) {
121 word
[x
] = gwarea
->current
[x
];
125 while (*gwarea
->current
&& *gwarea
->current
!= stop
) gwarea
->current
++;
126 if (*gwarea
->current
) ++gwarea
->current
;
130 int getword_multisep(char *word
, int limit
, struct getwordstruct
*gwarea
, char stop
)
134 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++) {
136 debuga(_("End of word not found in getword_multisep after %d bytes.\n"),x
);
137 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
138 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
139 debuga(_("searching for \'x%x\'\n"),stop
);
140 if (limit
>0) word
[limit
-1]='\0';
141 #if USE_GETWORD_BACKTRACE
144 //exit(EXIT_FAILURE);
147 word
[x
] = gwarea
->current
[x
];
151 while (gwarea
->current
[x
] && gwarea
->current
[x
]==stop
) ++x
;
156 int getword_skip(int limit
, struct getwordstruct
*gwarea
, char stop
)
160 for(x
=0;(gwarea
->current
[x
] && (gwarea
->current
[x
] != stop
));x
++) {
162 debuga(_("End of word not found in getword_skip after %d bytes.\n"),x
);
163 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
164 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
165 debuga(_("searching for \'x%x\'\n"),stop
);
166 #if USE_GETWORD_BACKTRACE
173 if (gwarea
->current
[x
]) ++x
;
178 int getword_atoll(long long int *number
, struct getwordstruct
*gwarea
, char stop
)
184 if (gwarea
->current
[0] == '-') {
187 } else if (gwarea
->current
[0] == '+') {
191 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
192 digit
=gwarea
->current
[x
]-'0';
193 if (*number
>= (LLONG_MAX
-digit
)/10) {
194 debuga(_("Integer overflow detected in getword_atoll in line %s\n"),gwarea
->beginning
);
197 *number
=(*number
* 10) + digit
;
199 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
200 debuga(_("End of number not found in getword_atoll after %d bytes.\n"),x
);
201 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
202 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
203 debuga(_("searching for \'x%x\'\n"),stop
);
204 #if USE_GETWORD_BACKTRACE
211 if (gwarea
->current
[x
]) ++x
;
216 int getword_atoi(int *number
, struct getwordstruct
*gwarea
, char stop
)
222 if (gwarea
->current
[0] == '-') {
225 } else if (gwarea
->current
[0] == '+') {
229 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
230 digit
=gwarea
->current
[x
]-'0';
231 if (*number
> (INT_MAX
-digit
)/10) {
232 debuga(_("Integer overflow detected in getword_atoi in line %s\n"),gwarea
->beginning
);
235 *number
=(*number
* 10) + digit
;
237 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
238 debuga(_("End of number not found in getword_atoi after %d bytes.\n"),x
);
239 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
240 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
241 debuga(_("searching for \'x%x\'\n"),stop
);
242 #if USE_GETWORD_BACKTRACE
249 if (gwarea
->current
[x
]) ++x
;
254 int getword_atol(long int *number
, struct getwordstruct
*gwarea
, char stop
)
260 if (gwarea
->current
[0] == '-') {
263 } else if (gwarea
->current
[0] == '+') {
267 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
268 digit
=gwarea
->current
[x
]-'0';
269 if (*number
> (LONG_MAX
-digit
)/10) {
270 debuga(_("Integer overflow detected in getword_atol in line %s\n"),gwarea
->beginning
);
273 *number
=(*number
* 10) + digit
;
275 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
276 debuga(_("End of number not found in getword_atol after %ld bytes.\n"),x
);
277 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
278 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
279 debuga(_("searching for \'x%x\'\n"),stop
);
280 #if USE_GETWORD_BACKTRACE
287 if (gwarea
->current
[x
]) ++x
;
292 int getword_atolu(unsigned long int *number
, struct getwordstruct
*gwarea
, char stop
)
297 if (gwarea
->current
[0] == '-') {
298 debuga(_("getword_atolu got a negative number.\n"));
299 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
300 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
303 if (gwarea
->current
[0] == '+') {
307 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
308 digit
=gwarea
->current
[x
]-'0';
309 if (*number
> (ULONG_MAX
-digit
)/10) {
310 debuga(_("Integer overflow detected in getword_atolu in line %s\n"),gwarea
->beginning
);
313 *number
=(*number
* 10) + digit
;
315 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
316 debuga(_("End of number not found in getword_atolu after %ld bytes.\n"),x
);
317 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
318 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
319 debuga(_("searching for \'x%x\'\n"),stop
);
320 #if USE_GETWORD_BACKTRACE
326 if (gwarea
->current
[x
]) ++x
;
332 int getword_ptr(char *orig_line
,char **word
, struct getwordstruct
*gwarea
, char stop
)
335 \note Why pass the original buffer to the function ? Because we must modify it to
336 insert the terminating ASCII zero for the word we return and that's not compatible
337 with getword_restart(). Moreover, getword_start() sometime works on constant strings
338 so this function require the original buffer to detect any missuse.
344 if (orig_line
&& orig_line
!=gwarea
->beginning
) {
345 debuga(_("Invalid buffer passed to getword_ptr\n"));
349 start
=(gwarea
->current
-gwarea
->beginning
);
350 if (word
&& orig_line
) *word
=orig_line
+start
;
351 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++);
352 sep
=(gwarea
->current
[x
]!='\0');
353 if (word
&& orig_line
) orig_line
[start
+x
] = '\0';
360 #define MAXLLL 30 //!< Maximum number of digits in long long (a guess).
361 long long int my_atoll (const char *nptr
)
363 long long int returnval
=0LL;
364 int max_digits
= MAXLLL
;
366 // Soak up all the white space
367 while (isspace( *nptr
)) {
371 //For each character left to right
372 //change the character to a single digit
373 //multiply what we had before by 10 and add the new digit
375 while (--max_digits
&& isdigit( *nptr
))
377 returnval
= ( returnval
* 10 ) + ( *nptr
++ - '0' ) ;
383 int is_absolute(const char *path
)
385 if (*path
=='/') return(1);
387 if (isalpha(path
[0]) && path
[1]==':') return(1);
392 int PortableMkDir(const char *path
,int mode
)
394 #if defined(__linux__)
395 int mkerror
=mkdir(path
,mode
);
398 int mkerror
=_mkdir(path
);
403 void my_mkdir(const char *name
)
409 if(!is_absolute(name
)) {
410 debuga(_("Invalid path (%s). Please, use absolute paths only.\n"),name
);
415 for (i
=0 ; name
[i
] ; i
++) {
417 debuga(_("Path too long: "));
418 debuga_more("%s\n",name
);
421 if (chars
>0 && name
[i
] == '/') {
423 if (access(w0
, R_OK
) != 0) {
424 if (PortableMkDir(w0
,0755)) {
425 debuga(_("Cannot create directory %s - %s\n"),w0
,strerror(errno
));
430 if (name
[i
] != '/') chars
++;
434 if (access(name
, R_OK
) != 0) {
435 if (PortableMkDir(name
,0755)) {
436 debuga(_("Cannot create directory %s - %s\n"),name
,strerror(errno
));
443 void my_lltoa(unsigned long long int n
, char *s
, int ssize
, int len
)
452 debuga(_("The requested number of digits passed to my_lltoa (%d) is bigger than the output buffer size (%d)\n"),len
,ssize
);
457 s
[slen
++] = (n
% 10) + '0';
458 } while ((n
/= 10) > 0 && slen
<ssize
);
461 for (i
= 0, j
= slen
-1; i
<j
; i
++, j
--) {
469 for(j
=slen
; j
>=0; j
--)
476 int month2num(const char *month
)
480 for(m
=0 ; m
<12 && strcmp(mtab1
[m
],month
) != 0; m
++);
484 int builddia(int day
, int month
, int year
)
486 return(year
*10000+month
*100+day
);
492 \param date1 The first date to compare.
493 \param date2 The second date to compare.
495 \retval -1 If date1<date2.
496 \retval 0 If date1==date2.
497 \retval 1 if date1>date2.
499 int compare_date(struct tm
*date1
,struct tm
*date2
)
501 if (date1
->tm_year
<date2
->tm_year
) return(-1);
502 if (date1
->tm_year
>date2
->tm_year
) return(1);
503 if (date1
->tm_mon
<date2
->tm_mon
) return(-1);
504 if (date1
->tm_mon
>date2
->tm_mon
) return(1);
505 if (date1
->tm_mday
<date2
->tm_mday
) return(-1);
506 if (date1
->tm_mday
>date2
->tm_mday
) return(1);
507 if (date1
->tm_hour
<date2
->tm_hour
) return(-1);
508 if (date1
->tm_hour
>date2
->tm_hour
) return(1);
509 if (date1
->tm_min
<date2
->tm_min
) return(-1);
510 if (date1
->tm_min
>date2
->tm_min
) return(1);
511 if (date1
->tm_sec
<date2
->tm_sec
) return(-1);
512 if (date1
->tm_sec
>date2
->tm_sec
) return(1);
516 void buildymd(const char *dia
, const char *mes
, const char *ano
, char *wdata
,int wdata_size
)
521 snprintf(wdata
,wdata_size
,"%04d%02d%02d",atoi(ano
),nmes
+1,atoi(dia
));
525 int conv_month(const char *month
)
529 for(x
=0; x
<12 && strncmp(mtab1
[x
],month
,3)!=0; x
++);
534 const char *conv_month_name(int month
)
538 if (month
<1 || month
>12) {
539 snprintf(str
,sizeof(str
),"%03d",month
);
542 return(mtab1
[month
-1]);
546 Write a debug message to stderr. The message is prefixed by "SARG:" to identify its origin.
548 \param msg The printf like message to format.
549 \param ... The arguments to format in the message.
551 void debuga(const char *msg
,...)
555 fputs(_("SARG: "),stderr
);
557 vfprintf(stderr
,msg
,ap
);
562 Write a debug message to stderr. The message is supposed
563 to be displayed after a message from debuga().
565 \param msg The printf like message to format.
566 \param ... The arguments to format in the message.
568 void debuga_more(const char *msg
,...)
573 vfprintf(stderr
,msg
,ap
);
578 Write a debug message to stderr. The message is prefixed by "SARG: (info)".
580 \param msg The printf like message to format.
581 \param ... The arguments to format in the message.
583 void debugaz(const char *msg
,...)
587 fputs(_("SARG: (info) "),stderr
);
589 vfprintf(stderr
,msg
,ap
);
594 char *fixnum(long long int value
, int n
)
596 #define MAXLEN_FIXNUM 256
597 char num
[MAXLEN_FIXNUM
]="";
598 char buf
[MAXLEN_FIXNUM
* 2];
600 static char ret
[MAXLEN_FIXNUM
* 2];
602 register int i
, j
, k
;
604 static char abbrev
[30]="";
606 my_lltoa(value
, num
, sizeof(num
), 0);
608 if(DisplayedValues
==DISPLAY_ABBREV
) {
609 numlen
= strlen(num
);
612 else if (numlen
%3 == 1) {
614 abbrev
[1]=(UseComma
) ? ',' : '.';
619 else if (numlen
%3 == 2) {
622 abbrev
[2]=(UseComma
) ? ',' : '.';
627 else if (numlen
%3 == 0) {
631 abbrev
[3]=(UseComma
) ? ',' : '.';
640 else if (numlen
<= 6)
642 else if (numlen
<= 9)
644 else if (numlen
<= 12)
646 else if (numlen
<= 15)
648 else if (numlen
>= 18)
650 else if (numlen
<= 21)
652 else if (numlen
<= 24)
654 else if (numlen
<= 27)
657 strcat(abbrev
,"???");
662 memset(buf
,0,MAXLEN_FIXNUM
*2);
668 for ( i
= strlen(num
) - 1, j
= 0 ; i
> -1; i
--) {
669 if ( k
== 2 && i
!= 0 ) {
672 pbuf
[j
++] = (UseComma
) ? ',' : '.';
682 for ( i
= strlen(pbuf
) - 1, j
= 0 ; i
> -1; i
--, j
++)
691 char *fixnum2(long long int value
, int n
)
693 #define MAXLEN_FIXNUM2 1024
694 char num
[MAXLEN_FIXNUM2
];
695 char buf
[MAXLEN_FIXNUM2
* 2];
697 static char ret
[MAXLEN_FIXNUM2
* 2];
699 register int i
, j
, k
;
701 my_lltoa(value
, num
, sizeof(num
), 0);
702 memset(buf
,0,MAXLEN_FIXNUM2
*2);
708 for ( i
= strlen(num
) - 1, j
= 0 ; i
> -1; i
--) {
709 if ( k
== 2 && i
!= 0 ) {
712 pbuf
[j
++] = (UseComma
) ? ',' : '.';
722 for ( i
= strlen(pbuf
) - 1, j
= 0 ; i
> -1; i
--, j
++)
731 char *buildtime(long long int elap
)
733 long int num
= elap
/ 1000LL;
740 min
=(num
% 3600L) / 60L;
742 snprintf(buf
,sizeof(buf
),"%02d:%02d:%02d",hor
,min
,sec
);
749 Get the date stored in the <tt>sarg-date</tt> file of a directory with the connection data.
751 \param dirname The directory to look for the connection directory.
752 \param name The name of the directory whose <tt>sarg-date</tt> file must be read.
753 \param data The buffer to store the content of the file. It must be more than 80
757 \retval -1 File not found.
759 int obtdate(const char *dirname
, const char *name
, char *data
)
764 if (snprintf(wdir
,sizeof(wdir
),"%s%s/sarg-date",dirname
,name
)>=sizeof(wdir
)) {
765 debuga(_("Buffer too small to store "));
766 debuga_more("%s%s/sarg-date",dirname
,name
);
769 if ((fp_in
= fopen(wdir
, "rt")) == 0) {
770 if (snprintf(wdir
,sizeof(wdir
),"%s%s/date",dirname
,name
)>=sizeof(wdir
)) {
771 debuga(_("Buffer too small to store "));
772 debuga_more("%s%s/date",dirname
,name
);
775 if ((fp_in
= fopen(wdir
, "rt")) == 0) {
781 if (!fgets(data
,80,fp_in
)) {
782 debuga(_("Failed to read the date in %s\n"),wdir
);
792 void formatdate(char *date
,int date_size
,int year
,int month
,int day
,int hour
,int minute
,int second
,int dst
)
798 memset(<m
,0,sizeof(ltm
));
799 if (year
>=1900) ltm
.tm_year
=year
-1900;
800 if (month
>=1 && month
<=12) ltm
.tm_mon
=month
-1;
801 if (day
>=1 && day
<=31) ltm
.tm_mday
=day
;
802 if (hour
>=0 && hour
<24) ltm
.tm_hour
=hour
;
803 if (minute
>=0 && minute
<60) ltm
.tm_min
=minute
;
804 if (second
>=0 && second
<60) ltm
.tm_sec
=second
;
806 unixtime
=mktime(<m
); //fill the missing entries
807 fulltm
=localtime(&unixtime
);
808 //strftime(date,date_size,"%a %b %d %H:%M:%S %Z %Y",fulltm);
809 strftime(date
,date_size
,"%c",fulltm
);
813 void computedate(int year
,int month
,int day
,struct tm
*t
)
815 memset(t
,0,sizeof(*t
));
816 t
->tm_year
=year
-1900;
822 int obtuser(const char *dirname
, const char *name
)
829 if (snprintf(wdir
,sizeof(wdir
),"%s%s/sarg-users",dirname
,name
)>=sizeof(wdir
)) {
830 debuga(_("Buffer too small to store "));
831 debuga_more("%s%s/sarg-users",dirname
,name
);
834 if((fp_in
=fopen(wdir
,"r"))==NULL
) {
835 if (snprintf(wdir
,sizeof(wdir
),"%s%s/users",dirname
,name
)>=sizeof(wdir
)) {
836 debuga(_("Buffer too small to store "));
837 debuga_more("%s%s/users",dirname
,name
);
840 if((fp_in
=fopen(wdir
,"r"))==NULL
) {
845 if (!fgets(tuser
,sizeof(tuser
),fp_in
)) {
846 debuga(_("Failed to read the number of users in %s\n"),wdir
);
856 void obttotal(const char *dirname
, const char *name
, int nuser
, long long int *tbytes
, long long int *media
)
861 char user
[MAX_USER_LEN
];
863 struct getwordstruct gwarea
;
869 if (snprintf(wdir
,sizeof(wdir
),"%s%s/sarg-general",dirname
,name
)>=sizeof(wdir
)) {
870 debuga(_("Buffer too small to store "));
871 debuga_more("%s%s/sarg-general",dirname
,name
);
874 if ((fp_in
= fopen(wdir
, "r")) == 0) {
875 if (snprintf(wdir
,sizeof(wdir
),"%s%s/general",dirname
,name
)>=sizeof(wdir
)) {
876 debuga(_("Buffer too small to store "));
877 debuga_more("%s%s/general",dirname
,name
);
880 if ((fp_in
= fopen(wdir
, "r")) == 0) {
885 if ((line
=longline_create())==NULL
) {
886 debuga(_("Not enough memory to read the file %s\n"),wdir
);
890 while((buf
=longline_read(fp_in
,line
))!=NULL
) {
891 if (strncmp(buf
,"TOTAL\t",6) == 0)
893 else if (strncmp(buf
,"TOTAL ",6) == 0)
897 getword_start(&gwarea
,buf
);
898 if (getword(user
,sizeof(user
),&gwarea
,sep
)<0) {
899 debuga(_("There is a invalid user in file %s\n"),wdir
);
902 if(strcmp(user
,"TOTAL") != 0)
904 if (getword_skip(MAXLEN
,&gwarea
,sep
)<0) {
905 debuga(_("There a broken total number of access in file %s\n"),wdir
);
908 if (getword_atoll(tbytes
,&gwarea
,sep
)<0) {
909 debuga(_("There is a broken number of bytes in file %s\n"),wdir
);
915 longline_destroy(&line
);
920 *media
=*tbytes
/ nuser
;
924 int getperiod_fromsarglog(const char *arqtt
,struct periodstruct
*period
)
927 int day0
, month0
, year0
, hour0
, minute0
;
928 int day1
, month1
, year1
, hour1
, minute1
;
931 memset(period
,0,sizeof(*period
));
934 while((str
=strstr(str
,"sarg-"))!=NULL
) {
936 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
937 day0
=(str
[0]-'0')*10+(str
[1]-'0');
938 if (day0
<1 || day0
>31) continue;
940 month0
=(str
[0]-'0')*10+(str
[1]-'0')-1;
941 if (month0
<0 || month0
>11) continue;
944 for (i
=0 ; isdigit(str
[i
]) && i
<4 ; i
++) year0
=year0
*10+(str
[i
]-'0');
947 if (str
[0]!='_') continue;
950 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
951 hour0
=(str
[0]-'0')*10+(str
[1]-'0');
953 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
954 minute0
=(str
[0]-'0')*10+(str
[1]-'0');
957 if (*str
!= '-') continue;
960 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
961 day1
=(str
[0]-'0')*10+(str
[1]-'0');
962 if (day1
<1 || day1
>31) continue;
964 month1
=(str
[0]-'0')*10+(str
[1]-'0')-1;
965 if (month1
<0 || month1
>11) continue;
968 for (i
=0 ; isdigit(str
[i
]) && i
<4 ; i
++) year1
=year1
*10+(str
[i
]-'0');
972 if (str
[0]!='_') continue;
975 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
976 hour1
=(str
[0]-'0')*10+(str
[1]-'0');
978 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
979 minute1
=(str
[0]-'0')*10+(str
[1]-'0');
982 period
->start
.tm_mday
=day0
;
983 period
->start
.tm_mon
=month0
;
984 period
->start
.tm_year
=year0
-1900;
985 period
->start
.tm_hour
=hour0
;
986 period
->start
.tm_min
=minute0
;
987 period
->end
.tm_mday
=day1
;
988 period
->end
.tm_mon
=month1
;
989 period
->end
.tm_year
=year1
-1900;
990 period
->end
.tm_hour
=hour1
;
991 period
->end
.tm_min
=minute1
;
997 void getperiod_fromrange(struct periodstruct
*period
,int dfrom
,int duntil
)
999 memset(&period
->start
,0,sizeof(period
->start
));
1000 period
->start
.tm_mday
=dfrom
%100;
1001 period
->start
.tm_mon
=(dfrom
/100)%100-1;
1002 period
->start
.tm_year
=(dfrom
/10000)-1900;
1004 memset(&period
->end
,0,sizeof(period
->end
));
1005 period
->end
.tm_mday
=duntil
%100;
1006 period
->end
.tm_mon
=(duntil
/100)%100-1;
1007 period
->end
.tm_year
=(duntil
/10000)-1900;
1011 Update the \a main period to encompass the period in \a candidate.
1013 void getperiod_merge(struct periodstruct
*main
,struct periodstruct
*candidate
)
1018 mdate
=(main
->start
.tm_year
)*10000+(main
->start
.tm_mon
)*100+main
->start
.tm_mday
;
1019 cdate
=(candidate
->start
.tm_year
)*10000+(candidate
->start
.tm_mon
)*100+candidate
->start
.tm_mday
;
1020 if (cdate
<mdate
) memcpy(&main
->start
,&candidate
->start
,sizeof(struct tm
));
1022 mdate
=(main
->end
.tm_year
)*10000+(main
->end
.tm_mon
)*100+main
->end
.tm_mday
;
1023 cdate
=(candidate
->end
.tm_year
)*10000+(candidate
->end
.tm_mon
)*100+candidate
->end
.tm_mday
;
1024 if (cdate
>mdate
) memcpy(&main
->end
,&candidate
->end
,sizeof(struct tm
));
1027 int getperiod_buildtext(struct periodstruct
*period
)
1031 char text1
[40], text2
[40];
1034 i
=strftime(text1
, sizeof(text1
), "%Y %b %d", &period
->start
);
1035 } else if(df
=='e') {
1036 i
=strftime(text1
, sizeof(text1
), "%d %b %Y", &period
->start
);
1037 } else /*if (df=='w')*/ {
1038 IndexTree
=INDEX_TREE_FILE
;
1039 i
=strftime(text1
, sizeof(text1
), "%Y.%U", &period
->start
);
1041 if (i
== 0) return(-1);
1043 range
=(period
->start
.tm_year
!=period
->end
.tm_year
||
1044 period
->start
.tm_mon
!=period
->end
.tm_mon
||
1045 period
->start
.tm_mday
!=period
->end
.tm_mday
);
1048 i
=strftime(text2
, sizeof(text2
)-i
, "%Y %b %d", &period
->end
);
1049 } else if (df
=='e') {
1050 i
=strftime(text2
, sizeof(text2
)-i
, "%d %b %Y", &period
->end
);
1052 i
=strftime(text2
, sizeof(text2
)-i
, "%Y.%U", &period
->end
);
1054 if (i
== 0) return(-1);
1058 snprintf(period
->text
,sizeof(period
->text
),"%s-%s",text1
,text2
);
1059 snprintf(period
->html
,sizeof(period
->html
),"%s—%s",text1
,text2
);
1061 safe_strcpy(period
->text
,text1
,sizeof(period
->text
));
1062 safe_strcpy(period
->html
,text1
,sizeof(period
->html
));
1067 static void copy_images(void)
1069 FILE *img_in
, *img_ou
;
1071 char srcfile
[MAXLEN
];
1072 char dstfile
[MAXLEN
];
1074 struct dirent
*direntp
;
1075 char buffer
[MAXLEN
];
1079 if (snprintf(images
,sizeof(images
),"%simages",outdir
)>=sizeof(images
)) {
1080 debuga(_("Cannot copy images to target directory %simages\n"),outdir
);
1083 if (access(images
,R_OK
)!=0) {
1084 if (PortableMkDir(images
,0755)) {
1085 debuga(_("Cannot create directory %s - %s\n"),images
,strerror(errno
));
1090 dirp
= opendir(ImageDir
);
1092 debuga(_("(util) Can't open directory %s: %s\n"),ImageDir
,strerror(errno
));
1095 while ((direntp
= readdir( dirp
)) != NULL
){
1096 if(direntp
->d_name
[0]=='.')
1098 if (snprintf(srcfile
,sizeof(srcfile
),"%s/%s",ImageDir
,direntp
->d_name
)>=sizeof(srcfile
)) {
1099 debuga(_("Buffer too small to store "));
1100 debuga_more("%s/%s",ImageDir
,direntp
->d_name
);
1103 if (stat(srcfile
,&info
)) {
1104 debuga(_("Cannot stat \"%s\" - %s\n"),srcfile
,strerror(errno
));
1107 if (S_ISREG(info
.st_mode
)) {
1108 if (snprintf(dstfile
,sizeof(dstfile
),"%s/%s",images
,direntp
->d_name
)>=sizeof(dstfile
)) {
1109 debuga(_("Buffer too small to store "));
1110 debuga_more("%s/%s",images
,direntp
->d_name
);
1113 img_in
= fopen(srcfile
, "rb");
1115 img_ou
= fopen(dstfile
, "wb");
1117 while ((nread
= fread(buffer
,1,sizeof(buffer
),img_in
))>0) {
1118 if (fwrite(buffer
,1,nread
,img_ou
)!=nread
) {
1119 debuga(_("Failed to copy image %s to %s\n"),srcfile
,dstfile
);
1123 if (fclose(img_ou
)==EOF
) {
1124 debuga(_("Error while copying image %s: %s\n"),dstfile
,strerror(errno
));
1128 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open/create file", dstfile
, strerror(errno
));
1131 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open file", srcfile
, strerror(errno
));
1134 (void) closedir(dirp
);
1140 * Check if the proposed file name conforms to the directory structure layed out
1141 * as a file tree. It is used to check if the file name enumerated while scanning
1142 * a directory content may have been created by sarg running with IndexTree set to
1145 bool IsTreeFileDirName(const char *Name
)
1150 // start year (date format u) or start day (date format e)
1151 if (!isdigit(Name
[0]) || !isdigit(Name
[1])) return(false);
1153 if (isdigit(Name
[2]) && isdigit(Name
[3]))
1155 // date format is either u or w
1159 if (!isdigit(Name
[5]) || !isdigit(Name
[6])) return(false);
1160 return(true);//date format w is confirmed
1167 if (!isalpha(Name
[0]) || !isalpha(Name
[1]) || !isalpha(Name
[2])) return(false);
1168 for (i
=11 ; i
>=0 && memcmp(mtab1
[i
],Name
,3) ; i
--);
1169 if (i
<0) return(false);
1173 if (!isdigit(Name
[0]) || !isdigit(Name
[1])) return(false);
1178 else if (isalpha(Name
[2]) && isalpha(Name
[3]) && isalpha(Name
[4]))
1184 if (!isalpha(Name
[0]) || !isalpha(Name
[1]) || !isalpha(Name
[2])) return(false);
1185 for (i
=11 ; i
>=0 && memcmp(mtab1
[i
],Name
,3) ; i
--);
1186 if (i
<0) return(false);
1190 if (!isdigit(Name
[0]) || !isdigit(Name
[1]) || !isdigit(Name
[2]) || !isdigit(Name
[3])) return(false);
1198 if (Name
[0]!='-') return(false);
1201 if (DateFormat
=='u')
1203 if (!isdigit(Name
[0]) || !isdigit(Name
[1]) || !isdigit(Name
[2]) || !isdigit(Name
[3])) return(false);
1206 if (!isalpha(Name
[0]) || !isalpha(Name
[1]) || !isalpha(Name
[2])) return(false);
1207 for (i
=11 ; i
>=0 && memcmp(mtab1
[i
],Name
,3) ; i
--);
1208 if (i
<0) return(false);
1211 if (!isdigit(Name
[0]) || !isdigit(Name
[1])) return(false);
1214 else //DateFormat=='e'
1216 if (!isdigit(Name
[0]) || !isdigit(Name
[1])) return(false);
1219 if (!isalpha(Name
[0]) || !isalpha(Name
[1]) || !isalpha(Name
[2])) return(false);
1220 for (i
=11 ; i
>=0 && memcmp(mtab1
[i
],Name
,3) ; i
--);
1221 if (i
<0) return(false);
1224 if (!isdigit(Name
[0]) || !isdigit(Name
[1]) || !isdigit(Name
[2]) || !isdigit(Name
[3])) return(false);
1228 * The directory name may contains additional characters such as a counter if
1229 * a previous report is never overwritten.
1235 * Check if the proposed file name can be the year part of a report tree build with
1236 * IndexTree set to INDEX_TREE_DATE.
1238 bool IsTreeYearFileName(const char *Name
)
1240 if (!isdigit(Name
[0]) || !isdigit(Name
[1]) || !isdigit(Name
[2]) || !isdigit(Name
[3])) return(false);
1245 if (!isdigit(Name
[0]) || !isdigit(Name
[1]) || !isdigit(Name
[2]) || !isdigit(Name
[3])) return(false);
1248 if (Name
[0]) return(false);
1253 * Check if the proposed file name can be the month part of a report tree build with
1254 * IndexTree set to INDEX_TREE_DATE.
1256 bool IsTreeMonthFileName(const char *Name
)
1260 if (!isdigit(Name
[0]) || !isdigit(Name
[1])) return(false);
1261 m
=(Name
[0]-'0')*10+(Name
[1]-'0');
1262 if (m
<1 || m
>12) return(false);
1267 if (!isdigit(Name
[0]) || !isdigit(Name
[1])) return(false);
1268 m
=(Name
[0]-'0')*10+(Name
[1]-'0');
1269 if (m
<1 || m
>12) return(false);
1272 if (Name
[0]) return(false);
1277 * Check if the proposed file name can be the day part of a report tree build with
1278 * IndexTree set to INDEX_TREE_DATE.
1280 bool IsTreeDayFileName(const char *Name
)
1284 if (!isdigit(Name
[0]) || !isdigit(Name
[1])) return(false);
1285 d
=(Name
[0]-'0')*10+(Name
[1]-'0');
1286 if (d
<1 || d
>31) return(false);
1290 if (!isdigit(Name
[0]) || !isdigit(Name
[1])) return(false);
1291 d
=(Name
[0]-'0')*10+(Name
[1]-'0');
1292 if (d
<1 || d
>31) return(false);
1295 * The directory name may contains additional characters such as a counter if
1296 * a previous report is never overwritten.
1301 int vrfydir(const struct periodstruct
*per1
, const char *addr
, const char *site
, const char *us
, const char *form
)
1306 char dirname2
[MAXLEN
];
1314 strcpy(wdir
,outdir
);
1316 y1
=per1
->start
.tm_year
+1900;
1317 y2
=per1
->end
.tm_year
+1900;
1318 m1
=per1
->start
.tm_mon
+1;
1319 m2
=per1
->end
.tm_mon
+1;
1320 d1
=per1
->start
.tm_mday
;
1321 d2
=per1
->end
.tm_mday
;
1322 if(IndexTree
== INDEX_TREE_DATE
) {
1323 wlen
+=sprintf(wdir
+wlen
,"%04d",y1
);
1324 if(y1
!=y2
) wlen
+=sprintf(wdir
+wlen
,"-%04d",y2
);
1325 if(access(wdir
, R_OK
) != 0)
1328 wlen
+=sprintf(wdir
+wlen
,"/%02d",m1
);
1329 if(m1
!= m2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",m2
);
1330 if(access(wdir
, R_OK
) != 0)
1333 wlen
+=sprintf(wdir
+wlen
,"/%02d",d1
);
1334 if(d1
!=d2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",d2
);
1337 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%04d%s%02d-%04d%s%02d",y1
,
1338 conv_month_name(m1
),d1
,y2
,conv_month_name(m2
),d2
);
1339 } else if (df
== 'e') {
1340 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%02d%s%04d-%02d%s%04d",d1
,
1341 conv_month_name(m1
),y1
,d2
,conv_month_name(m2
),y2
);
1342 } else if (df
== 'w') {
1343 wlen2
=strftime(wdir
+wlen
, sizeof(wdir
)-wlen
, "%Y.%U", &per1
->start
);
1344 if (wlen2
==0) return(-1);
1350 struct userinfostruct
*uinfo
=userinfo_find_from_id(us
);
1353 strcat(wdir
,uinfo
->filename
);
1356 if(addr
[0] != '\0') {
1360 if(site
[0] != '\0') {
1365 strcpy(outdirname
,wdir
);
1367 if(IndexTree
!= INDEX_TREE_DATE
) {
1368 if(!OverwriteReport
) {
1370 if(access(wdir
,R_OK
) == 0) {
1371 sprintf(wdir
,"%s.%d",outdirname
,num
);
1380 debuga(_("File %s already exists, moved to %s\n"),outdirname
,wdir
);
1381 rename(outdirname
,wdir
);
1384 if(access(outdirname
,R_OK
) == 0) {
1385 unlinkdir(outdirname
,1);
1388 my_mkdir(outdirname
);
1390 strcpy(dirname2
,wdir
);
1391 if(!OverwriteReport
) {
1393 if(access(wdir
,R_OK
) == 0) {
1394 sprintf(wdir
,"%s.%d",dirname2
,num
);
1403 debuga(_("File %s already exists, moved to %s\n"),dirname2
,wdir
);
1404 rename(dirname2
,wdir
);
1405 strcpy(dirname2
,wdir
);
1408 if(access(wdir
,R_OK
) == 0) {
1413 if(access(wdir
, R_OK
) != 0)
1417 strcpy(dirname2
,wdir
);
1419 if (snprintf(wdir
,sizeof(wdir
),"%s/sarg-date",outdirname
)>=sizeof(wdir
)) {
1420 debuga(_("Buffer too small to store "));
1421 debuga_more("%s/sarg-date",outdirname
);
1424 if ((fp_ou
= fopen(wdir
, "wt")) == 0) {
1425 debuga(_("cannot open %s for writing: %s\n"),wdir
,strerror(errno
));
1430 //strftime(wdir,sizeof(wdir),"%a %b %d %H:%M:%S %Z %Y",localtime(&curtime));
1431 loctm
=localtime(&curtime
);
1432 strftime(wdir
,sizeof(wdir
),"%Y-%m-%d %H:%M:%S",loctm
);
1433 if (fprintf(fp_ou
,"%s %d\n",wdir
,loctm
->tm_isdst
)<0) {
1434 debuga(_("Failed to write the date in %s\n"),wdir
);
1438 if (fclose(fp_ou
)==EOF
) {
1439 debuga(_("Failed to write the date in %s: %s\n"),wdir
,strerror(errno
));
1448 Copy a string without overflowing the buffer. The copied string
1449 is properly terminated by an ASCII zero.
1451 \param dest The destination buffer.
1452 \param src The source buffer.
1453 \param length The size of the destination buffer. The program is aborted
1454 if the length is negative or zero.
1456 void safe_strcpy(char *dest
,const char *src
,int length
)
1459 debuga(_("Invalid buffer length passed to the function to safely copy a string\n"));
1462 strncpy(dest
,src
,length
-1);
1463 dest
[length
-1]='\0';
1466 void strip_latin(char *line
)
1473 for (i
=0;line
[i
];i
++){
1475 if (line
[i
]==';') skip
=0;
1487 void zdate(char *ftime
,int ftimesize
, char DateFormat
)
1493 local
= localtime(&t
);
1494 if (DateFormat
=='u')
1495 strftime(ftime
, ftimesize
, "%b/%d/%Y %H:%M", local
);
1496 else if (DateFormat
=='e')
1497 strftime(ftime
, ftimesize
, "%d/%b/%Y-%H:%M", local
);
1498 else if (DateFormat
=='w')
1499 strftime(ftime
, ftimesize
, "%W-%H-%M", local
);
1504 char *fixtime(long long int elap
)
1506 long int num
= elap
/ 1000LL;
1510 static char buf
[20];
1513 min
=(num
% 3600L) / 60L;
1516 if(hor
==0 && min
==0 && sec
==0)
1519 snprintf(buf
,sizeof(buf
),"%d:%02d:%02d",hor
,min
,sec
);
1525 void date_from(char *date
,int date_size
, int *dfrom
, int *duntil
)
1534 if (isdigit(date
[0])) {
1537 if (sscanf(date
,"%d/%d/%d%n",&d0
,&m0
,&y0
,&next
)!=3 || y0
<100 || m0
<1 || m0
>12 || d0
<1 || d0
>31 || next
<0) {
1538 debuga(_("The date passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1541 if (date
[next
]=='-') {
1542 if (sscanf(date
+next
+1,"%d/%d/%d",&d1
,&m1
,&y1
)!=3 || y1
<100 || m1
<1 || m1
>12 || d1
<1 || d1
>31) {
1543 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1546 } else if (date
[next
]!='\0') {
1547 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1557 struct tm
*Date0
,Date1
;
1559 if (time(&Today
)==(time_t)-1) {
1560 debuga(_("Failed to get the current time\n"));
1563 if (sscanf(date
,"day-%d",&i
)==1) {
1565 debuga(_("Invalid number of days in -d parameter\n"));
1569 Date0
=localtime(&Today
);
1571 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1574 y0
=y1
=Date0
->tm_year
+1900;
1575 m0
=m1
=Date0
->tm_mon
+1;
1576 d0
=d1
=Date0
->tm_mday
;
1577 } else if (sscanf(date
,"week-%d",&i
)==1) {
1579 There is no portable way to find the first day of the week even though the
1580 information is available in the locale. nl_langinfo has the unofficial
1581 parameters _NL_TIME_FIRST_WEEKDAY and _NL_TIME_WEEK_1STDAY but they are
1582 undocumented as is their return value and it is discouraged to use them.
1583 Beside, nl_langinfo isn't available on windows and the first day of the
1584 week isn't available at all on that system.
1586 const int FirstWeekDay
=1;
1590 debuga(_("Invalid number of weeks in -d parameter\n"));
1593 Date0
=localtime(&Today
);
1595 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1598 WeekBegin
=Today
-((Date0
->tm_wday
-FirstWeekDay
+7)%7)*24*60*60;
1599 WeekBegin
-=i
*7*24*60*60;
1600 Date0
=localtime(&WeekBegin
);
1602 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1605 y0
=Date0
->tm_year
+1900;
1608 WeekBegin
+=6*24*60*60;
1609 Date0
=localtime(&WeekBegin
);
1611 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1614 y1
=Date0
->tm_year
+1900;
1617 } else if (sscanf(date
,"month-%d",&i
)==1) {
1619 debuga(_("Invalid number of months in -d parameter\n"));
1622 Date0
=localtime(&Today
);
1624 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1627 if (Date0
->tm_mon
<i
%12) {
1628 y0
=Date0
->tm_year
+1900-i
/12-1;
1629 m0
=(Date0
->tm_mon
+12-i
%12)%12+1;
1632 y0
=Date0
->tm_year
+1900-i
/12;
1633 m0
=Date0
->tm_mon
-i
%12+1;
1636 memcpy(&Date1
,Date0
,sizeof(struct tm
));
1641 Date1
.tm_year
=y0
-1900;
1644 Date1
.tm_year
=y0
-1900+1;
1648 Date0
=localtime(&t1
);
1649 y1
=Date0
->tm_year
+1900;
1653 debuga(_("Invalid date range passed on command line\n"));
1658 *dfrom
=y0
*10000+m0
*100+d0
;
1659 *duntil
=y1
*10000+m1
*100+d1
;
1660 snprintf(date
,date_size
,"%02d/%02d/%04d-%02d/%02d/%04d",d0
,m0
,y0
,d1
,m1
,y1
);
1665 char *strlow(char *string
)
1671 for (s
= string
; *s
; ++s
)
1681 char *strup(char *string
)
1687 for (s
= string
; *s
; ++s
)
1695 void removetmp(const char *outdir
)
1700 if(!RemoveTempFiles
)
1704 debuga(_("Purging temporary file sarg-general\n"));
1706 if (snprintf(filename
,sizeof(filename
),"%s/sarg-general",outdir
)>=sizeof(filename
)) {
1707 debuga(_("Path too long: "));
1708 debuga_more("%s/sarg-period\n",outdir
);
1711 if((fp_gen
=fopen(filename
,"w"))==NULL
){
1712 debuga(_("(removetmp) Cannot open file %s: %s\n"),filename
,strerror(errno
));
1715 totalger(fp_gen
,filename
);
1716 if (fclose(fp_gen
)==EOF
) {
1717 debuga(_("Failed to close %s after writing the total line: %s\n"),filename
,strerror(errno
));
1722 void load_excludecodes(const char *ExcludeCodes
)
1730 if(ExcludeCodes
[0] == '\0')
1733 if((fp_in
=fopen(ExcludeCodes
,"r"))==NULL
) {
1734 debuga(_("(util) Cannot open file %s (exclude_codes): %s\n"),ExcludeCodes
,strerror(errno
));
1738 if (fseek(fp_in
, 0, SEEK_END
)==-1) {
1739 debuga(_("Failed to move till the end of the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1742 MemSize
= ftell(fp_in
);
1744 debuga(_("Cannot get the size of file %s\n"),ExcludeCodes
);
1747 if (fseek(fp_in
, 0, SEEK_SET
)==-1) {
1748 debuga(_("Failed to rewind the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1753 if((excludecode
=(char *) malloc(MemSize
))==NULL
) {
1754 debuga(_("malloc error (%ld)\n"),MemSize
);
1757 memset(excludecode
,0,MemSize
);
1760 while(fgets(data
,sizeof(data
),fp_in
)!=NULL
) {
1761 if (data
[0]=='#') continue;
1762 for (i
=strlen(data
)-1 ; i
>=0 && (unsigned char)data
[i
]<=' ' ; i
--) data
[i
]='\0';
1764 if (Stored
+i
+2>=MemSize
) {
1765 debuga(_("Too many codes to exclude in file %s\n"),ExcludeCodes
);
1768 strcat(excludecode
,data
);
1769 strcat(excludecode
,";");
1777 void free_excludecodes(void)
1785 int vercode(const char *code
)
1790 if (excludecode
&& excludecode
[0]!='\0') {
1794 if (strncmp(code
,cod
,clen
)==0 && cod
[clen
]==';')
1796 cod
=strchr(cod
,';');
1803 void fixnone(char *str
)
1807 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--);
1808 if(i
==3 && strncmp(str
,"none",4) == 0)
1814 void fixendofline(char *str
)
1818 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--) str
[i
]=0;
1821 #ifdef LEGACY_TESTVALIDUSERCHAR
1822 int testvaliduserchar(const char *user
)
1827 for (y
=0; y
<strlen(UserInvalidChar
); y
++) {
1828 for (x
=0; x
<strlen(user
); x
++) {
1829 if(user
[x
] == UserInvalidChar
[y
])
1836 int testvaliduserchar(const char *user
)
1838 char * p_UserInvalidChar
= UserInvalidChar
;
1839 const char * p_user
;
1841 while( *p_UserInvalidChar
) {
1844 if( *p_UserInvalidChar
== *p_user
)
1848 p_UserInvalidChar
++ ;
1854 int compar( const void *a
, const void *b
)
1856 if( *(int *)a
> *(int *)b
) return 1;
1857 if( *(int *)a
< *(int *)b
) return -1;
1861 int getnumlist( char *buf
, numlist
*list
, const int len
, const int maxvalue
)
1863 int i
, j
, d
, flag
, r1
, r2
;
1864 char *pbuf
, **bp
, *strbufs
[ 24 ];
1867 strtok( buf
, " \t" );
1868 for( *bp
= strtok( NULL
, "," ), list
->len
= 0; *bp
; *bp
= strtok( NULL
, "," ) ) {
1869 if( ++bp
>= &strbufs
[ 24 ] )
1876 for( i
= 0; i
< list
->len
; i
++ ) {
1877 if( strchr( strbufs
[ i
], '-' ) != 0 ) {
1878 pbuf
= strbufs
[ i
];
1879 strtok( pbuf
, "-" );
1880 pbuf
= strtok( NULL
, "\0" );
1881 r1
= atoi( strbufs
[ i
] );
1882 if( ( r2
= atoi( pbuf
) ) >= maxvalue
|| r1
>= r2
)
1884 if( i
+ d
+ ( r2
- r1
) + 1 <= len
) {
1885 for( j
= r1
; j
<= r2
; j
++ )
1886 list
->list
[ i
+ d
++ ] = j
;
1891 if( ( list
->list
[ i
+ d
] = atoi( strbufs
[ i
] ) ) >= maxvalue
)
1895 qsort( list
->list
, list
->len
, sizeof( int ), compar
);
1898 for( i
= 0; i
< list
->len
- 1; i
++ )
1899 if( list
->list
[ i
] == list
->list
[ i
+ 1 ] ) {
1900 for( j
= i
+ 1; j
< list
->len
; j
++ )
1901 list
->list
[ j
- 1 ] = list
->list
[ j
];
1910 void show_info(FILE *fp_ou
)
1914 if(!ShowSargInfo
) return;
1915 zdate(ftime
, sizeof(ftime
), df
);
1916 fputs("<div class=\"info\">",fp_ou
);
1917 fprintf(fp_ou
,_("Generated by <a href='%s'>%s-%s</a> on %s"),URL
,PGM
,VERSION
,ftime
);
1918 fputs("</div>\n",fp_ou
);
1921 void show_sarg(FILE *fp_ou
, int depth
)
1925 if(!ShowSargLogo
) return;
1926 fputs("<div class=\"logo\"><a href=\"http://sarg.sourceforge.net\"><img src=\"",fp_ou
);
1927 for (i
=0 ; i
<depth
; i
++)
1929 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
);
1932 void write_logo_image(FILE *fp_ou
)
1934 if(LogoImage
[0]!='\0')
1935 fprintf(fp_ou
, "<div class=\"logo\"><img src=\"%s\" width=\"%s\" height=\"%s\" alt=\"Logo\"> %s</div>\n",LogoImage
,Width
,Height
,LogoText
);
1938 void write_html_head(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1942 fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n",fp_ou
);
1943 fprintf(fp_ou
, "<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n",CharSet
);
1944 if (page_title
) fprintf(fp_ou
,"<title>%s</title>\n",page_title
);
1946 if ((javascript
& HTML_JS_SORTTABLE
)!=0 && SortTableJs
[0]) {
1947 fputs("<script type=\"text/javascript\" src=\"",fp_ou
);
1948 if (strncmp(SortTableJs
,"../",3)==0) {
1949 for (i
=0 ; i
<depth
; i
++) fputs("../",fp_ou
);
1951 fputs(SortTableJs
,fp_ou
);
1952 fputs("\"></script>\n",fp_ou
);
1954 fputs("</head>\n<body>\n",fp_ou
);
1957 void write_html_header(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1959 write_html_head(fp_ou
,depth
,page_title
,javascript
);
1960 write_logo_image(fp_ou
);
1961 show_sarg(fp_ou
, depth
);
1962 fprintf(fp_ou
,"<div class=\"title\"><table cellpadding=\"0\" cellspacing=\"0\">\n<tr><th class=\"title_c\">%s</th></tr>\n",Title
);
1965 void close_html_header(FILE *fp_ou
)
1967 fputs("</table></div>\n",fp_ou
);
1970 int write_html_trailer(FILE *fp_ou
)
1973 if (fputs("</body>\n</html>\n",fp_ou
)==EOF
) return(-1);
1977 void output_html_string(FILE *fp_ou
,const char *str
,int maxlen
)
1981 while (*str
&& (maxlen
<=0 || i
<maxlen
)) {
1984 fputs("&",fp_ou
);
1987 fputs("<",fp_ou
);
1990 fputs(">",fp_ou
);
1993 fputs(""",fp_ou
);
1996 fputs("'",fp_ou
);
2004 if (maxlen
>0 && i
>=maxlen
)
2005 fputs("…",fp_ou
);
2008 void output_html_url(FILE *fp_ou
,const char *url
)
2012 fputs("&",fp_ou
);
2020 Write a host name inside an A tag of a HTML file. If the host name starts
2021 with a star, it is assumed to be an alias that cannot be put inside a link
2022 so the A tag is not written around the host name.
2024 \param fp_ou The handle of the HTML file.
2025 \param url The host to display in the HTML file.
2026 \param maxlen The maximum number of characters to print into the host name.
2028 void output_html_link(FILE *fp_ou
,const char *url
,int maxlen
)
2030 if (url
[0]==ALIAS_PREFIX
) {
2031 // this is an alias, no need for a A tag
2032 output_html_string(fp_ou
,url
+1,100);
2034 if (skip_scheme(url
)==url
)
2035 fputs("<a href=\"http://",fp_ou
);//no scheme in the url, assume http:// to make the link clickable
2037 fputs("<a href=\"",fp_ou
);//the scheme is in the url, no need to add one
2038 output_html_url(fp_ou
,url
);
2040 output_html_string(fp_ou
,url
,100);
2041 fputs("</a>",fp_ou
);
2045 void url_module(const char *url
, char *w2
)
2051 for(x
=strlen(url
)-1; x
>=0; x
--) {
2052 if(url
[x
] == '/' || y
>=sizeof(w
)-1) break;
2061 for(y
=y
-1; y
>=0; y
--) {
2068 Mangle an URL to produce a part that can be used as an anchor in
2069 a html <a name=""> tag.
2071 \param url The URL to mangle.
2072 \param anchor The buffer to write the mangled URL.
2073 \param size The size of the buffer.
2075 void url_to_anchor(const char *url
,char *anchor
,int size
)
2081 for (i
=0 ; url
[i
] && url
[i
]!='/' && url
[i
]!='?' ; i
++);
2088 // only keep really safe characters
2094 if(isalnum(url
[i
]) || url
[i
]=='-' || url
[i
]=='_' || url
[i
]=='.') {
2098 if (!skip
) anchor
[--j
]='_';
2116 printf(_("SARG Version: %s\n"),VERSION
);
2117 #if defined(ENABLE_NLS) && defined(HAVE_LOCALE_H)
2119 printf(_("\nFor the translation to work, a valid message file should be installed as "
2120 "\"%s/<Locale>/LC_MESSAGES/%s.mo\" where <Locale> is derived from the effective locale.\n"),LOCALEDIR
,PACKAGE_NAME
);
2121 if (CurrentLocale
) {
2122 printf(_("Currently effective locale is \"%s\".\n"),CurrentLocale
);
2124 printf(_("Locale is not set in the environment variable.\n"));
2126 // TRANSLATORS: You may change this message to tell the reader that the language is correctly supported.
2127 printf(_("If this message is in English, then your language is not supported or not correctly installed.\n"));
2133 char *get_param_value(const char *param
,char *line
)
2137 while (*line
==' ' || *line
=='\t') line
++;
2139 if (strncasecmp(line
,param
,plen
)) return(NULL
);
2140 if (line
[plen
]!=' ' && line
[plen
]!='\t') return(NULL
);
2142 while (*line
==' ' || *line
=='\t') line
++;
2146 void unlinkdir(const char *dir
,bool contentonly
)
2150 struct dirent
*direntp
;
2156 while ((direntp
= readdir(dirp
)) != NULL
) {
2157 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
2158 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
2160 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
2161 debuga(_("Path too long: "));
2162 debuga_more("%s/%s\n",dir
,direntp
->d_name
);
2166 err
=lstat(dname
,&st
);
2168 err
=stat(dname
,&st
);
2171 debuga(_("cannot stat %s\n"),dname
);
2174 if (S_ISREG(st
.st_mode
)) {
2175 if (unlink(dname
)) {
2176 debuga(_("Cannot delete \"%s\": %s\n"),dname
,strerror(errno
));
2179 } else if (S_ISDIR(st
.st_mode
)) {
2182 debuga(_("unknown path type %s\n"),dname
);
2189 debuga(_("Cannot delete \"%s\": %s\n"),dir
,strerror(errno
));
2196 Delete every file from the temporary directory where sarg is told to store its
2199 As any stray file left over by a previous run would be included in the report, we
2200 must delete every file from the temporary directory before we start processing the logs.
2202 But the temporary directory is given by the user either in the configuration file or
2203 on the command line. We check that the user didn't give a wrong directory by looking
2204 at the files stored in the directory. If a single file is not one of ours, we abort.
2206 \param dir The temporary directory to purge.
2208 void emptytmpdir(const char *dir
)
2212 struct dirent
*direntp
;
2218 static const char *TmpExt
[]=
2235 // make sure the temporary directory contains only our files
2236 while ((direntp
= readdir(dirp
)) != NULL
) {
2237 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
2238 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
2241 // is it one of our files
2242 dlen
=strlen(direntp
->d_name
);
2243 for (i
=sizeof(TmpExt
)/sizeof(TmpExt
[0])-1 ; i
>=0 ; i
--) {
2244 elen
=strlen(TmpExt
[i
]);
2245 if (dlen
>=elen
&& strcasecmp(direntp
->d_name
+dlen
-elen
,TmpExt
[i
])==0) break;
2248 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2249 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2250 "directory or manually delete the content of \"%s\"\n"),direntp
->d_name
,dir
,dir
);
2254 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
2255 debuga(_("Path too long: "));
2256 debuga_more("%s/%s\n",dir
,direntp
->d_name
);
2261 err
=lstat(dname
,&st
);
2263 err
=stat(dname
,&st
);
2266 debuga(_("cannot stat \"%s\"\n"),dname
);
2269 if (S_ISDIR(st
.st_mode
)) {
2271 } else if (!S_ISREG(st
.st_mode
)) {
2272 debuga(_("Unknown path type for \"%s\". Check temporary directory\n"),dname
);
2278 // now delete our files
2279 while ((direntp
= readdir(dirp
)) != NULL
) {
2280 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
2281 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
2284 // is it one of our files
2285 dlen
=strlen(direntp
->d_name
);
2286 for (i
=sizeof(TmpExt
)/sizeof(TmpExt
[0])-1 ; i
>=0 ; i
--) {
2287 elen
=strlen(TmpExt
[i
]);
2288 if (dlen
>=elen
&& strcasecmp(direntp
->d_name
+dlen
-elen
,TmpExt
[i
])==0) break;
2291 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2292 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2293 "directory or manually delete the content of \"%s\"\n"),direntp
->d_name
,dir
,dir
);
2297 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
2298 debuga(_("Path too long: "));
2299 debuga_more("%s/%s\n",dir
,direntp
->d_name
);
2303 err
=lstat(dname
,&st
);
2305 err
=stat(dname
,&st
);
2308 debuga(_("cannot stat \"%s\"\n"),dname
);
2311 if (S_ISREG(st
.st_mode
)) {
2312 if (unlink(dname
)) {
2313 debuga(_("Cannot delete \"%s\": %s\n"),dname
,strerror(errno
));
2317 debuga(_("unknown path type %s\n"),dname
);
2324 Extract an url, IPv4 or IPv6 from a buffer. The IP addresses may end with a
2327 \param buf The buffer to parse.
2328 \param text A pointer to set to the beginning of the string pattern. No terminating zero is inserted.
2329 The pointer may be NULL.
2330 \param ipv4 A 4 bytes buffer to store the bytes of the IPv4 address.
2331 \param ipv6 A 8 short integers buffer to store the values of the IPv6 address.
2332 \param nbits The number of prefix bits for an IP address.
2333 \param next The content of the line after the extracted address.
2335 \retval 3 The pattern is a IPv6 address.
2336 \retval 2 The pattern is a IPv4 address.
2337 \retval 1 The patter is a string.
2338 \retval 0 Empty pattern.
2340 int extract_address_mask(const char *buf
,const char **text
,unsigned char *ipv4
,unsigned short int *ipv6
,int *nbits
,const char **next
)
2345 unsigned int value4
, value6
;
2346 unsigned short int addr
[8];
2356 // skip leading spaces and tabs
2357 while (*buf
&& (*buf
==' ' || *buf
=='\t')) buf
++;
2359 // find out the nature of the pattern
2360 ip_size
=0x60 | 0x04;
2371 for (i
=0 ; (unsigned char)buf
[i
]>' ' && buf
[i
]!='/' && buf
[i
]!='?' && (!bracket
|| buf
[i
]!=']') && ip_size
; i
++) {
2372 if (ip_size
& 0x04) {
2373 if (isdigit(buf
[i
])) {
2375 port_num
=port_num
*10+(buf
[i
]-'0');
2376 if (port_num
>65535) ip_size
&=~0x04;
2378 value4
=value4
*10+(buf
[i
]-'0');
2379 if (value4
>0xFFU
) ip_size
&=~0x04;
2381 } else if (buf
[i
]=='.' && addr_len
<4) {
2382 addr
[addr_len
++]=(unsigned short)(value4
& 0xFFU
);
2384 } else if (!port
&& buf
[i
]==':') {
2390 if (ip_size
& 0x60) {
2391 if (isdigit(buf
[i
])) {
2392 value6
=(value6
<<4)+(buf
[i
]-'0');
2394 if (value6
>0xFFFFU
) ip_size
&=~0x60;
2395 } else if (toupper(buf
[i
])>='A' && toupper(buf
[i
])<='F') {
2396 value6
=(value6
<<4)+(toupper(buf
[i
])-'A'+10);
2398 if (value6
>0xFFFFU
) ip_size
&=~0x60;
2399 } else if (buf
[i
]==':' && addr_len
<8) {
2400 if (nibble6_len
>0) {
2401 addr
[addr_len
++]=(unsigned short)(value6
& 0xFFFFU
);
2405 if (buf
[i
+1]==':') {
2414 if (i
==0) return(0);
2415 if (ip_size
& 0x04) {
2419 addr
[addr_len
++]=(unsigned short)(value4
& 0xFFU
);
2421 if (ip_size
& 0x60) {
2422 if (pad_pos
<0 && addr_len
!=7) {
2424 } else if (pad_pos
>=0 && addr_len
>=7)
2426 else if (nibble6_len
>0)
2427 addr
[addr_len
++]=(unsigned short)(value6
& 0xFFFFU
);
2432 if (bracket
) (*text
)--;
2434 while ((unsigned char)buf
[i
]>' ') i
++;
2435 if (next
) *next
=buf
+i
;
2438 max_mask
=(ip_size
& 0x04) ? 4*8 : 8*16;
2442 while (isdigit(buf
[i
])) i
++;
2443 if (mask
<0 || mask
>max_mask
) mask
=max_mask
;
2446 if (ip_size
& 0x60 && bracket
&& buf
[i
]==']') i
++;
2447 if (next
) *next
=buf
+i
;
2448 if (ip_size
& 0x04) {
2449 if (nbits
) *nbits
=mask
;
2450 for (i
=0 ; i
<addr_len
; i
++)
2451 ipv4
[i
]=(unsigned char)addr
[i
];
2456 if (nbits
) *nbits
=mask
;
2461 ipv6
[j
++]=(unsigned short int)addr
[i
++];
2463 while (j
<pad_pos
+pad_len
)
2467 ipv6
[j
++]=(unsigned short int)addr
[i
++];