]>
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 debuga(_("getword backtrace:\n"));
58 for (i
=0 ; i
<n
; i
++) {
59 fprintf(stderr
,"SARG: %d:%s\n",i
+1,calls
[i
]);
64 #endif //USE_GETWORD_BACKTRACE
66 void getword_start(struct getwordstruct
*gwarea
, const char *line
)
68 gwarea
->beginning
=line
;
73 void getword_restart(struct getwordstruct
*gwarea
)
75 if (gwarea
->modified
) {
76 debuga(_("Cannot parse again the line as it was modified\n"));
79 gwarea
->current
=gwarea
->beginning
;
82 int getword(char *word
, int limit
, struct getwordstruct
*gwarea
, char stop
)
86 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++) {
88 debuga(_("End of word not found in getword after %d bytes.\n"),x
);
89 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
90 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
91 debuga(_("searching for \'x%x\'\n"),stop
);
92 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
93 word
[(limit
>0) ? limit
-1 : 0]='\0';
94 #if USE_GETWORD_BACKTRACE
99 word
[x
] = gwarea
->current
[x
];
103 if (gwarea
->current
[x
]) ++x
;
108 int getword_limit(char *word
, int limit
, struct getwordstruct
*gwarea
, char stop
)
113 for(x
=0; x
<limit
&& gwarea
->current
[x
] && gwarea
->current
[x
] != stop
;x
++) {
114 word
[x
] = gwarea
->current
[x
];
118 while (*gwarea
->current
&& *gwarea
->current
!= stop
) gwarea
->current
++;
119 if (*gwarea
->current
) ++gwarea
->current
;
123 int getword_multisep(char *word
, int limit
, struct getwordstruct
*gwarea
, char stop
)
127 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++) {
129 debuga(_("End of word not found in getword_multisep after %d bytes.\n"),x
);
130 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
131 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
132 debuga(_("searching for \'x%x\'\n"),stop
);
133 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
134 if (limit
>0) word
[limit
-1]='\0';
135 #if USE_GETWORD_BACKTRACE
138 //exit(EXIT_FAILURE);
141 word
[x
] = gwarea
->current
[x
];
145 while (gwarea
->current
[x
] && gwarea
->current
[x
]==stop
) ++x
;
150 int getword_skip(int limit
, struct getwordstruct
*gwarea
, char stop
)
154 for(x
=0;(gwarea
->current
[x
] && (gwarea
->current
[x
] != stop
));x
++) {
156 debuga(_("End of word not found in getword_skip after %d bytes.\n"),x
);
157 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
158 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
159 debuga(_("searching for \'x%x\'\n"),stop
);
160 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
161 #if USE_GETWORD_BACKTRACE
168 if (gwarea
->current
[x
]) ++x
;
173 int getword_atoll(long long int *number
, struct getwordstruct
*gwarea
, char stop
)
179 if (gwarea
->current
[0] == '-') {
182 } else if (gwarea
->current
[0] == '+') {
186 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
187 digit
=gwarea
->current
[x
]-'0';
188 if (*number
>= (LLONG_MAX
-digit
)/10) {
189 debuga(_("Integer overflow detected in getword_atoll in line %s\n"),gwarea
->beginning
);
192 *number
=(*number
* 10) + digit
;
194 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
195 debuga(_("End of number not found in getword_atoll after %d bytes.\n"),x
);
196 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
197 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
198 debuga(_("searching for \'x%x\'\n"),stop
);
199 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
200 #if USE_GETWORD_BACKTRACE
207 if (gwarea
->current
[x
]) ++x
;
212 int getword_atoi(int *number
, struct getwordstruct
*gwarea
, char stop
)
218 if (gwarea
->current
[0] == '-') {
221 } else if (gwarea
->current
[0] == '+') {
225 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
226 digit
=gwarea
->current
[x
]-'0';
227 if (*number
> (INT_MAX
-digit
)/10) {
228 debuga(_("Integer overflow detected in getword_atoi in line %s\n"),gwarea
->beginning
);
231 *number
=(*number
* 10) + digit
;
233 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
234 debuga(_("End of number not found in getword_atoi after %d bytes.\n"),x
);
235 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
236 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
237 debuga(_("searching for \'x%x\'\n"),stop
);
238 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
239 #if USE_GETWORD_BACKTRACE
246 if (gwarea
->current
[x
]) ++x
;
251 int getword_atol(long int *number
, struct getwordstruct
*gwarea
, char stop
)
257 if (gwarea
->current
[0] == '-') {
260 } else if (gwarea
->current
[0] == '+') {
264 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
265 digit
=gwarea
->current
[x
]-'0';
266 if (*number
> (LONG_MAX
-digit
)/10) {
267 debuga(_("Integer overflow detected in getword_atol in line %s\n"),gwarea
->beginning
);
270 *number
=(*number
* 10) + digit
;
272 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
273 debuga(_("End of number not found in getword_atol after %ld bytes.\n"),x
);
274 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
275 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
276 debuga(_("searching for \'x%x\'\n"),stop
);
277 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
278 #if USE_GETWORD_BACKTRACE
285 if (gwarea
->current
[x
]) ++x
;
290 int getword_atolu(unsigned long int *number
, struct getwordstruct
*gwarea
, char stop
)
295 if (gwarea
->current
[0] == '-') {
296 debuga(_("getword_atolu got a negative number.\n"));
297 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
298 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
301 if (gwarea
->current
[0] == '+') {
305 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
306 digit
=gwarea
->current
[x
]-'0';
307 if (*number
> (ULONG_MAX
-digit
)/10) {
308 debuga(_("Integer overflow detected in getword_atolu in line %s\n"),gwarea
->beginning
);
311 *number
=(*number
* 10) + digit
;
313 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
314 debuga(_("End of number not found in getword_atolu after %ld bytes.\n"),x
);
315 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
316 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
317 debuga(_("searching for \'x%x\'\n"),stop
);
318 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
319 #if USE_GETWORD_BACKTRACE
325 if (gwarea
->current
[x
]) ++x
;
331 int getword_ptr(char *orig_line
,char **word
, struct getwordstruct
*gwarea
, char stop
)
334 \note Why pass the original buffer to the function ? Because we must modify it to
335 insert the terminating ASCII zero for the word we return and that's not compatible
336 with getword_restart(). Moreover, getword_start() sometime works on constant strings
337 so this function require the original buffer to detect any missuse.
343 if (orig_line
&& orig_line
!=gwarea
->beginning
) {
344 debuga(_("Invalid buffer passed to getword_ptr\n"));
348 start
=(gwarea
->current
-gwarea
->beginning
);
349 if (word
&& orig_line
) *word
=orig_line
+start
;
350 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++);
351 sep
=(gwarea
->current
[x
]!='\0');
352 if (word
&& orig_line
) orig_line
[start
+x
] = '\0';
359 #define MAXLLL 30 //!< Maximum number of digits in long long (a guess).
360 long long int my_atoll (const char *nptr
)
362 long long int returnval
=0LL;
363 int max_digits
= MAXLLL
;
365 // Soak up all the white space
366 while (isspace( *nptr
)) {
370 //For each character left to right
371 //change the character to a single digit
372 //multiply what we had before by 10 and add the new digit
374 while (--max_digits
&& isdigit( *nptr
))
376 returnval
= ( returnval
* 10 ) + ( *nptr
++ - '0' ) ;
382 int is_absolute(const char *path
)
384 if (*path
=='/') return(1);
386 if (isalpha(path
[0]) && path
[1]==':') return(1);
391 void my_mkdir(const char *name
)
397 if(!is_absolute(name
)) {
398 debuga(_("Invalid path (%s). Please, use absolute paths only.\n"),name
);
403 for (i
=0 ; name
[i
] ; i
++) {
405 debuga(_("directory name too long: %s\n"),name
);
408 if (chars
>0 && name
[i
] == '/') {
410 if (access(w0
, R_OK
) != 0) {
411 if (mkdir(w0
,0755)) {
412 debuga(_("Cannot create directory %s - %s\n"),w0
,strerror(errno
));
417 if (name
[i
] != '/') chars
++;
421 if (access(name
, R_OK
) != 0) {
422 if (mkdir(name
,0755)) {
423 debuga(_("Cannot create directory %s - %s\n"),name
,strerror(errno
));
430 void my_lltoa(unsigned long long int n
, char *s
, int ssize
, int len
)
439 debuga(_("The requested number of digits passed to my_lltoa (%d) is bigger than the output buffer size (%d)\n"),len
,ssize
);
444 s
[slen
++] = (n
% 10) + '0';
445 } while ((n
/= 10) > 0 && slen
<ssize
);
448 for (i
= 0, j
= slen
-1; i
<j
; i
++, j
--) {
456 for(j
=slen
; j
>=0; j
--)
463 int month2num(const char *month
)
467 for(m
=0 ; m
<12 && strcmp(mtab1
[m
],month
) != 0; m
++);
471 int builddia(int day
, int month
, int year
)
473 return(year
*10000+month
*100+day
);
479 \param date1 The first date to compare.
480 \param date2 The second date to compare.
482 \retval -1 If date1<date2.
483 \retval 0 If date1==date2.
484 \retval 1 if date1>date2.
486 int compare_date(struct tm
*date1
,struct tm
*date2
)
488 if (date1
->tm_year
<date2
->tm_year
) return(-1);
489 if (date1
->tm_year
>date2
->tm_year
) return(1);
490 if (date1
->tm_mon
<date2
->tm_mon
) return(-1);
491 if (date1
->tm_mon
>date2
->tm_mon
) return(1);
492 if (date1
->tm_mday
<date2
->tm_mday
) return(-1);
493 if (date1
->tm_mday
>date2
->tm_mday
) return(1);
494 if (date1
->tm_hour
<date2
->tm_hour
) return(-1);
495 if (date1
->tm_hour
>date2
->tm_hour
) return(1);
496 if (date1
->tm_min
<date2
->tm_min
) return(-1);
497 if (date1
->tm_min
>date2
->tm_min
) return(1);
498 if (date1
->tm_sec
<date2
->tm_sec
) return(-1);
499 if (date1
->tm_sec
>date2
->tm_sec
) return(1);
503 void buildymd(const char *dia
, const char *mes
, const char *ano
, char *wdata
,int wdata_size
)
508 snprintf(wdata
,wdata_size
,"%04d%02d%02d",atoi(ano
),nmes
+1,atoi(dia
));
512 int conv_month(const char *month
)
516 for(x
=0; x
<12 && strncmp(mtab1
[x
],month
,3)!=0; x
++);
521 const char *conv_month_name(int month
)
525 if (month
<1 || month
>12) {
526 snprintf(str
,sizeof(str
),"%03d",month
);
529 return(mtab1
[month
-1]);
533 Write a debug message to stderr. The message is prefixed by "SARG:" to identify its origin.
535 \param msg The printf like message to format.
536 \param ... The arguments to format in the message.
538 void debuga(const char *msg
,...)
542 fputs(_("SARG: "),stderr
);
544 vfprintf(stderr
,msg
,ap
);
550 Write a debug message to stderr. The message is prefixed by "SARG: (info)".
552 \param msg The printf like message to format.
553 \param ... The arguments to format in the message.
555 void debugaz(const char *msg
,...)
559 fputs(_("SARG: (info) "),stderr
);
561 vfprintf(stderr
,msg
,ap
);
566 char *fixnum(long long int value
, int n
)
568 #define MAXLEN_FIXNUM 256
569 char num
[MAXLEN_FIXNUM
]="";
570 char buf
[MAXLEN_FIXNUM
* 2];
572 static char ret
[MAXLEN_FIXNUM
* 2];
574 register int i
, j
, k
;
576 static char abbrev
[30]="";
578 my_lltoa(value
, num
, sizeof(num
), 0);
580 if(DisplayedValues
==DISPLAY_ABBREV
) {
581 numlen
= strlen(num
);
584 else if (numlen
%3 == 1) {
586 abbrev
[1]=(UseComma
) ? ',' : '.';
591 else if (numlen
%3 == 2) {
594 abbrev
[2]=(UseComma
) ? ',' : '.';
599 else if (numlen
%3 == 0) {
603 abbrev
[3]=(UseComma
) ? ',' : '.';
612 else if (numlen
<= 6)
614 else if (numlen
<= 9)
616 else if (numlen
<= 12)
618 else if (numlen
<= 15)
620 else if (numlen
>= 18)
622 else if (numlen
<= 21)
624 else if (numlen
<= 24)
626 else if (numlen
<= 27)
629 strcat(abbrev
,"???");
634 bzero(buf
, MAXLEN_FIXNUM
*2);
640 for ( i
= strlen(num
) - 1, j
= 0 ; i
> -1; i
--) {
641 if ( k
== 2 && i
!= 0 ) {
644 pbuf
[j
++] = (UseComma
) ? ',' : '.';
654 for ( i
= strlen(pbuf
) - 1, j
= 0 ; i
> -1; i
--, j
++)
663 char *fixnum2(long long int value
, int n
)
665 #define MAXLEN_FIXNUM2 1024
666 char num
[MAXLEN_FIXNUM2
];
667 char buf
[MAXLEN_FIXNUM2
* 2];
669 static char ret
[MAXLEN_FIXNUM2
* 2];
671 register int i
, j
, k
;
673 my_lltoa(value
, num
, sizeof(num
), 0);
674 bzero(buf
, MAXLEN_FIXNUM2
*2);
680 for ( i
= strlen(num
) - 1, j
= 0 ; i
> -1; i
--) {
681 if ( k
== 2 && i
!= 0 ) {
684 pbuf
[j
++] = (UseComma
) ? ',' : '.';
694 for ( i
= strlen(pbuf
) - 1, j
= 0 ; i
> -1; i
--, j
++)
703 char *buildtime(long long int elap
)
705 long int num
= elap
/ 1000LL;
712 min
=(num
% 3600L) / 60L;
714 snprintf(buf
,sizeof(buf
),"%02d:%02d:%02d",hor
,min
,sec
);
721 Get the date stored in the <tt>sarg-date</tt> file of a directory with the connection data.
723 \param dirname The directory to look for the connection directory.
724 \param name The name of the directory whose <tt>sarg-date</tt> file must be read.
725 \param data The buffer to store the content of the file. It must be more than 80
729 \retval -1 File not found.
731 int obtdate(const char *dirname
, const char *name
, char *data
)
736 if (snprintf(wdir
,sizeof(wdir
),"%s%s/sarg-date",dirname
,name
)>=sizeof(wdir
)) {
737 debuga(_("Buffer to small to store %s%s/sarg-date"),dirname
,name
);
740 if ((fp_in
= fopen(wdir
, "rt")) == 0) {
741 if (snprintf(wdir
,sizeof(wdir
),"%s%s/date",dirname
,name
)>=sizeof(wdir
)) {
742 debuga(_("Buffer to small to store %s%s/date"),dirname
,name
);
745 if ((fp_in
= fopen(wdir
, "rt")) == 0) {
751 if (!fgets(data
,80,fp_in
)) {
752 debuga(_("Failed to read the date in %s\n"),wdir
);
762 void formatdate(char *date
,int date_size
,int year
,int month
,int day
,int hour
,int minute
,int second
,int dst
)
768 memset(<m
,0,sizeof(ltm
));
769 if (year
>=1900) ltm
.tm_year
=year
-1900;
770 if (month
>=1 && month
<=12) ltm
.tm_mon
=month
-1;
771 if (day
>=1 && day
<=31) ltm
.tm_mday
=day
;
772 if (hour
>=0 && hour
<24) ltm
.tm_hour
=hour
;
773 if (minute
>=0 && minute
<60) ltm
.tm_min
=minute
;
774 if (second
>=0 && second
<60) ltm
.tm_sec
=second
;
776 unixtime
=mktime(<m
); //fill the missing entries
777 fulltm
=localtime(&unixtime
);
778 //strftime(date,date_size,"%a %b %d %H:%M:%S %Z %Y",fulltm);
779 strftime(date
,date_size
,"%c",fulltm
);
783 void computedate(int year
,int month
,int day
,struct tm
*t
)
785 memset(t
,0,sizeof(*t
));
786 t
->tm_year
=year
-1900;
792 int obtuser(const char *dirname
, const char *name
)
799 if (snprintf(wdir
,sizeof(wdir
),"%s%s/sarg-users",dirname
,name
)>=sizeof(wdir
)) {
800 debuga(_("Buffer too small to store %s%s/sarg-users"),dirname
,name
);
803 if((fp_in
=fopen(wdir
,"r"))==NULL
) {
804 if (snprintf(wdir
,sizeof(wdir
),"%s%s/users",dirname
,name
)>=sizeof(wdir
)) {
805 debuga(_("Buffer too small to store %s%s/users"),dirname
,name
);
808 if((fp_in
=fopen(wdir
,"r"))==NULL
) {
813 if (!fgets(tuser
,sizeof(tuser
),fp_in
)) {
814 debuga(_("Failed to read the number of users in %s\n"),wdir
);
824 void obttotal(const char *dirname
, const char *name
, int nuser
, long long int *tbytes
, long long int *media
)
829 char user
[MAX_USER_LEN
];
831 struct getwordstruct gwarea
;
837 if (snprintf(wdir
,sizeof(wdir
),"%s%s/sarg-general",dirname
,name
)>=sizeof(wdir
)) {
838 debuga(_("Buffer too small to store %s%s/sarg-general"),dirname
,name
);
841 if ((fp_in
= fopen(wdir
, "r")) == 0) {
842 if (snprintf(wdir
,sizeof(wdir
),"%s%s/general",dirname
,name
)>=sizeof(wdir
)) {
843 debuga(_("Buffer too small to store %s%s/general"),dirname
,name
);
846 if ((fp_in
= fopen(wdir
, "r")) == 0) {
851 if ((line
=longline_create())==NULL
) {
852 debuga(_("Not enough memory to read the file %s\n"),wdir
);
856 while((buf
=longline_read(fp_in
,line
))!=NULL
) {
857 if (strncmp(buf
,"TOTAL\t",6) == 0)
859 else if (strncmp(buf
,"TOTAL ",6) == 0)
863 getword_start(&gwarea
,buf
);
864 if (getword(user
,sizeof(user
),&gwarea
,sep
)<0) {
865 debuga(_("There is a invalid user in file %s\n"),wdir
);
868 if(strcmp(user
,"TOTAL") != 0)
870 if (getword_skip(MAXLEN
,&gwarea
,sep
)<0) {
871 debuga(_("There a broken total number of access in file %s\n"),wdir
);
874 if (getword_atoll(tbytes
,&gwarea
,sep
)<0) {
875 debuga(_("There is a broken number of bytes in file %s\n"),wdir
);
881 longline_destroy(&line
);
886 *media
=*tbytes
/ nuser
;
890 int getperiod_fromsarglog(const char *arqtt
,struct periodstruct
*period
)
893 int day0
, month0
, year0
, hour0
, minute0
;
894 int day1
, month1
, year1
, hour1
, minute1
;
897 memset(period
,0,sizeof(*period
));
900 while((str
=strstr(str
,"sarg-"))!=NULL
) {
902 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
903 day0
=(str
[0]-'0')*10+(str
[1]-'0');
904 if (day0
<1 || day0
>31) continue;
906 month0
=(str
[0]-'0')*10+(str
[1]-'0')-1;
907 if (month0
<0 || month0
>11) continue;
910 for (i
=0 ; isdigit(str
[i
]) && i
<4 ; i
++) year0
=year0
*10+(str
[i
]-'0');
913 if (str
[0]!='_') continue;
916 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
917 hour0
=(str
[0]-'0')*10+(str
[1]-'0');
919 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
920 minute0
=(str
[0]-'0')*10+(str
[1]-'0');
923 if (*str
!= '-') continue;
926 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
927 day1
=(str
[0]-'0')*10+(str
[1]-'0');
928 if (day1
<1 || day1
>31) continue;
930 month1
=(str
[0]-'0')*10+(str
[1]-'0')-1;
931 if (month1
<0 || month1
>11) continue;
934 for (i
=0 ; isdigit(str
[i
]) && i
<4 ; i
++) year1
=year1
*10+(str
[i
]-'0');
938 if (str
[0]!='_') continue;
941 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
942 hour1
=(str
[0]-'0')*10+(str
[1]-'0');
944 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
945 minute1
=(str
[0]-'0')*10+(str
[1]-'0');
948 period
->start
.tm_mday
=day0
;
949 period
->start
.tm_mon
=month0
;
950 period
->start
.tm_year
=year0
-1900;
951 period
->start
.tm_hour
=hour0
;
952 period
->start
.tm_min
=minute0
;
953 period
->end
.tm_mday
=day1
;
954 period
->end
.tm_mon
=month1
;
955 period
->end
.tm_year
=year1
-1900;
956 period
->end
.tm_hour
=hour1
;
957 period
->end
.tm_min
=minute1
;
963 void getperiod_fromrange(struct periodstruct
*period
,int dfrom
,int duntil
)
965 memset(&period
->start
,0,sizeof(period
->start
));
966 period
->start
.tm_mday
=dfrom
%100;
967 period
->start
.tm_mon
=(dfrom
/100)%100-1;
968 period
->start
.tm_year
=(dfrom
/10000)-1900;
970 memset(&period
->end
,0,sizeof(period
->end
));
971 period
->end
.tm_mday
=duntil
%100;
972 period
->end
.tm_mon
=(duntil
/100)%100-1;
973 period
->end
.tm_year
=(duntil
/10000)-1900;
977 Update the \a main period to encompass the period in \a candidate.
979 void getperiod_merge(struct periodstruct
*main
,struct periodstruct
*candidate
)
984 mdate
=(main
->start
.tm_year
)*10000+(main
->start
.tm_mon
)*100+main
->start
.tm_mday
;
985 cdate
=(candidate
->start
.tm_year
)*10000+(candidate
->start
.tm_mon
)*100+candidate
->start
.tm_mday
;
986 if (cdate
<mdate
) memcpy(&main
->start
,&candidate
->start
,sizeof(struct tm
));
988 mdate
=(main
->end
.tm_year
)*10000+(main
->end
.tm_mon
)*100+main
->end
.tm_mday
;
989 cdate
=(candidate
->end
.tm_year
)*10000+(candidate
->end
.tm_mon
)*100+candidate
->end
.tm_mday
;
990 if (cdate
>mdate
) memcpy(&main
->end
,&candidate
->end
,sizeof(struct tm
));
993 int getperiod_buildtext(struct periodstruct
*period
)
997 char text1
[40], text2
[40];
1000 i
=strftime(text1
, sizeof(text1
), "%Y %b %d", &period
->start
);
1001 } else if(df
=='e') {
1002 i
=strftime(text1
, sizeof(text1
), "%d %b %Y", &period
->start
);
1003 } else /*if (df=='w')*/ {
1004 IndexTree
=INDEX_TREE_FILE
;
1005 i
=strftime(text1
, sizeof(text1
), "%Y.%U", &period
->start
);
1007 if (i
== 0) return(-1);
1009 range
=(period
->start
.tm_year
!=period
->end
.tm_year
||
1010 period
->start
.tm_mon
!=period
->end
.tm_mon
||
1011 period
->start
.tm_mday
!=period
->end
.tm_mday
);
1014 i
=strftime(text2
, sizeof(text2
)-i
, "%Y %b %d", &period
->end
);
1015 } else if (df
=='e') {
1016 i
=strftime(text2
, sizeof(text2
)-i
, "%d %b %Y", &period
->end
);
1018 i
=strftime(text2
, sizeof(text2
)-i
, "%Y.%U", &period
->end
);
1020 if (i
== 0) return(-1);
1024 snprintf(period
->text
,sizeof(period
->text
),"%s-%s",text1
,text2
);
1025 snprintf(period
->html
,sizeof(period
->html
),"%s—%s",text1
,text2
);
1027 safe_strcpy(period
->text
,text1
,sizeof(period
->text
));
1028 safe_strcpy(period
->html
,text1
,sizeof(period
->html
));
1033 static void copy_images(void)
1035 FILE *img_in
, *img_ou
;
1037 char imgdir
[MAXLEN
];
1038 char srcfile
[MAXLEN
];
1039 char dstfile
[MAXLEN
];
1041 struct dirent
*direntp
;
1042 char buffer
[MAXLEN
];
1046 if (snprintf(images
,sizeof(images
),"%simages",outdir
)>=sizeof(images
)) {
1047 debuga(_("Cannot copy images to target directory %simages\n"),outdir
);
1050 if (access(images
,R_OK
)!=0) {
1051 if (mkdir(images
,0755)) {
1052 debuga(_("Cannot create directory %s - %s\n"),images
,strerror(errno
));
1057 strcpy(imgdir
,IMAGEDIR
);
1058 dirp
= opendir(imgdir
);
1060 debuga(_("(util) Can't open directory %s: %s\n"),imgdir
,strerror(errno
));
1063 while ((direntp
= readdir( dirp
)) != NULL
){
1064 if(direntp
->d_name
[0]=='.')
1066 if (snprintf(srcfile
,sizeof(srcfile
),"%s/%s",imgdir
,direntp
->d_name
)>=sizeof(srcfile
)) {
1067 debuga(_("Buffer too small to store %s/%s"),imgdir
,direntp
->d_name
);
1070 if (stat(srcfile
,&info
)) {
1071 debuga(_("Cannot stat \"%s\" - %s\n"),srcfile
,strerror(errno
));
1074 if (S_ISREG(info
.st_mode
)) {
1075 if (snprintf(dstfile
,sizeof(dstfile
),"%s/%s",images
,direntp
->d_name
)>=sizeof(dstfile
)) {
1076 debuga(_("Buffer too small to store %s/%s"),images
,direntp
->d_name
);
1079 img_in
= fopen(srcfile
, "rb");
1081 img_ou
= fopen(dstfile
, "wb");
1083 while ((nread
= fread(buffer
,1,sizeof(buffer
),img_in
))>0) {
1084 if (fwrite(buffer
,1,nread
,img_ou
)!=nread
) {
1085 debuga(_("Failed to copy image %s to %s\n"),srcfile
,dstfile
);
1089 if (fclose(img_ou
)==EOF
) {
1090 debuga(_("Error while copying image %s: %s\n"),dstfile
,strerror(errno
));
1094 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open/create file", dstfile
, strerror(errno
));
1097 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open file", srcfile
, strerror(errno
));
1100 (void) closedir(dirp
);
1106 * Check if the proposed file name conforms to the directory structure layed out
1107 * as a file tree. It is used to check if the file name enumerated while scanning
1108 * a directory content may have been created by sarg running with IndexTree set to
1111 bool IsTreeFileDirName(const char *Name
)
1116 // start year (date format u) or start day (date format e)
1117 if (!isdigit(Name
[0]) || !isdigit(Name
[1])) return(false);
1119 if (isdigit(Name
[2]) && isdigit(Name
[3]))
1121 // date format is either u or w
1125 if (!isdigit(Name
[5]) || !isdigit(Name
[6])) return(false);
1126 return(true);//date format w is confirmed
1133 if (!isalpha(Name
[0]) || !isalpha(Name
[1]) || !isalpha(Name
[2])) return(false);
1134 for (i
=11 ; i
>=0 && memcmp(mtab1
[i
],Name
,3) ; i
--);
1135 if (i
<0) return(false);
1139 if (!isdigit(Name
[0]) || !isdigit(Name
[1])) return(false);
1144 else if (isalpha(Name
[2]) && isalpha(Name
[3]) && isalpha(Name
[4]))
1150 if (!isalpha(Name
[0]) || !isalpha(Name
[1]) || !isalpha(Name
[2])) return(false);
1151 for (i
=11 ; i
>=0 && memcmp(mtab1
[i
],Name
,3) ; i
--);
1152 if (i
<0) return(false);
1156 if (!isdigit(Name
[0]) || !isdigit(Name
[1]) || !isdigit(Name
[2]) || !isdigit(Name
[3])) return(false);
1164 if (Name
[0]!='-') return(false);
1167 if (DateFormat
=='u')
1169 if (!isdigit(Name
[0]) || !isdigit(Name
[1]) || !isdigit(Name
[2]) || !isdigit(Name
[3])) return(false);
1172 if (!isalpha(Name
[0]) || !isalpha(Name
[1]) || !isalpha(Name
[2])) return(false);
1173 for (i
=11 ; i
>=0 && memcmp(mtab1
[i
],Name
,3) ; i
--);
1174 if (i
<0) return(false);
1177 if (!isdigit(Name
[0]) || !isdigit(Name
[1])) return(false);
1180 else //DateFormat=='e'
1182 if (!isdigit(Name
[0]) || !isdigit(Name
[1])) return(false);
1185 if (!isalpha(Name
[0]) || !isalpha(Name
[1]) || !isalpha(Name
[2])) return(false);
1186 for (i
=11 ; i
>=0 && memcmp(mtab1
[i
],Name
,3) ; i
--);
1187 if (i
<0) return(false);
1190 if (!isdigit(Name
[0]) || !isdigit(Name
[1]) || !isdigit(Name
[2]) || !isdigit(Name
[3])) return(false);
1194 * The directory name may contains additional characters such as a counter if
1195 * a previous report is never overwritten.
1201 * Check if the proposed file name can be the year part of a report tree build with
1202 * IndexTree set to INDEX_TREE_DATE.
1204 bool IsTreeYearFileName(const char *Name
)
1206 if (!isdigit(Name
[0]) || !isdigit(Name
[1]) || !isdigit(Name
[2]) || !isdigit(Name
[3])) return(false);
1211 if (!isdigit(Name
[0]) || !isdigit(Name
[1]) || !isdigit(Name
[2]) || !isdigit(Name
[3])) return(false);
1214 if (Name
[0]) return(false);
1219 * Check if the proposed file name can be the month part of a report tree build with
1220 * IndexTree set to INDEX_TREE_DATE.
1222 bool IsTreeMonthFileName(const char *Name
)
1226 if (!isdigit(Name
[0]) || !isdigit(Name
[1])) return(false);
1227 m
=(Name
[0]-'0')*10+(Name
[1]-'0');
1228 if (m
<1 || m
>12) return(false);
1233 if (!isdigit(Name
[0]) || !isdigit(Name
[1])) return(false);
1234 m
=(Name
[0]-'0')*10+(Name
[1]-'0');
1235 if (m
<1 || m
>12) return(false);
1238 if (Name
[0]) return(false);
1243 * Check if the proposed file name can be the day part of a report tree build with
1244 * IndexTree set to INDEX_TREE_DATE.
1246 bool IsTreeDayFileName(const char *Name
)
1250 if (!isdigit(Name
[0]) || !isdigit(Name
[1])) return(false);
1251 d
=(Name
[0]-'0')*10+(Name
[1]-'0');
1252 if (d
<1 || d
>31) return(false);
1256 if (!isdigit(Name
[0]) || !isdigit(Name
[1])) return(false);
1257 d
=(Name
[0]-'0')*10+(Name
[1]-'0');
1258 if (d
<1 || d
>31) return(false);
1261 * The directory name may contains additional characters such as a counter if
1262 * a previous report is never overwritten.
1267 int vrfydir(const struct periodstruct
*per1
, const char *addr
, const char *site
, const char *us
, const char *form
)
1272 char dirname2
[MAXLEN
];
1280 strcpy(wdir
,outdir
);
1282 y1
=per1
->start
.tm_year
+1900;
1283 y2
=per1
->end
.tm_year
+1900;
1284 m1
=per1
->start
.tm_mon
+1;
1285 m2
=per1
->end
.tm_mon
+1;
1286 d1
=per1
->start
.tm_mday
;
1287 d2
=per1
->end
.tm_mday
;
1288 if(IndexTree
== INDEX_TREE_DATE
) {
1289 wlen
+=sprintf(wdir
+wlen
,"%04d",y1
);
1290 if(y1
!=y2
) wlen
+=sprintf(wdir
+wlen
,"-%04d",y2
);
1291 if(access(wdir
, R_OK
) != 0)
1294 wlen
+=sprintf(wdir
+wlen
,"/%02d",m1
);
1295 if(m1
!= m2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",m2
);
1296 if(access(wdir
, R_OK
) != 0)
1299 wlen
+=sprintf(wdir
+wlen
,"/%02d",d1
);
1300 if(d1
!=d2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",d2
);
1303 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%04d%s%02d-%04d%s%02d",y1
,
1304 conv_month_name(m1
),d1
,y2
,conv_month_name(m2
),d2
);
1305 } else if (df
== 'e') {
1306 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%02d%s%04d-%02d%s%04d",d1
,
1307 conv_month_name(m1
),y1
,d2
,conv_month_name(m2
),y2
);
1308 } else if (df
== 'w') {
1309 wlen2
=strftime(wdir
+wlen
, sizeof(wdir
)-wlen
, "%Y.%U", &per1
->start
);
1310 if (wlen2
==0) return(-1);
1316 struct userinfostruct
*uinfo
=userinfo_find_from_id(us
);
1319 strcat(wdir
,uinfo
->filename
);
1322 if(addr
[0] != '\0') {
1326 if(site
[0] != '\0') {
1331 strcpy(outdirname
,wdir
);
1333 if(IndexTree
!= INDEX_TREE_DATE
) {
1334 if(!OverwriteReport
) {
1336 if(access(wdir
,R_OK
) == 0) {
1337 sprintf(wdir
,"%s.%d",outdirname
,num
);
1346 debuga(_("File %s already exists, moved to %s\n"),outdirname
,wdir
);
1347 rename(outdirname
,wdir
);
1350 if(access(outdirname
,R_OK
) == 0) {
1351 unlinkdir(outdirname
,1);
1354 my_mkdir(outdirname
);
1356 strcpy(dirname2
,wdir
);
1357 if(!OverwriteReport
) {
1359 if(access(wdir
,R_OK
) == 0) {
1360 sprintf(wdir
,"%s.%d",dirname2
,num
);
1369 debuga(_("File %s already exists, moved to %s\n"),dirname2
,wdir
);
1370 rename(dirname2
,wdir
);
1371 strcpy(dirname2
,wdir
);
1374 if(access(wdir
,R_OK
) == 0) {
1379 if(access(wdir
, R_OK
) != 0)
1383 strcpy(dirname2
,wdir
);
1385 if (snprintf(wdir
,sizeof(wdir
),"%s/sarg-date",outdirname
)>=sizeof(wdir
)) {
1386 debuga(_("Buffer too small to store %s/sarg-date"),outdirname
);
1389 if ((fp_ou
= fopen(wdir
, "wt")) == 0) {
1390 debuga(_("cannot open %s for writing: %s\n"),wdir
,strerror(errno
));
1395 //strftime(wdir,sizeof(wdir),"%a %b %d %H:%M:%S %Z %Y",localtime(&curtime));
1396 loctm
=localtime(&curtime
);
1397 strftime(wdir
,sizeof(wdir
),"%Y-%m-%d %H:%M:%S",loctm
);
1398 if (fprintf(fp_ou
,"%s %d\n",wdir
,loctm
->tm_isdst
)<0) {
1399 debuga(_("Failed to write the date in %s\n"),wdir
);
1403 if (fclose(fp_ou
)==EOF
) {
1404 debuga(_("Failed to write the date in %s: %s\n"),wdir
,strerror(errno
));
1413 Copy a string without overflowing the buffer. The copied string
1414 is properly terminated by an ASCII zero.
1416 \param dest The destination buffer.
1417 \param src The source buffer.
1418 \param length The size of the destination buffer. The program is aborted
1419 if the length is negative or zero.
1421 void safe_strcpy(char *dest
,const char *src
,int length
)
1424 debuga(_("Invalid buffer length passed to the function to safely copy a string\n"));
1427 strncpy(dest
,src
,length
-1);
1428 dest
[length
-1]='\0';
1431 void strip_latin(char *line
)
1438 for (i
=0;line
[i
];i
++){
1440 if (line
[i
]==';') skip
=0;
1452 void zdate(char *ftime
,int ftimesize
, char DateFormat
)
1458 local
= localtime(&t
);
1459 if (DateFormat
=='u')
1460 strftime(ftime
, ftimesize
, "%b/%d/%Y %H:%M", local
);
1461 else if (DateFormat
=='e')
1462 strftime(ftime
, ftimesize
, "%d/%b/%Y-%H:%M", local
);
1463 else if (DateFormat
=='w')
1464 strftime(ftime
, ftimesize
, "%W-%H-%M", local
);
1469 char *fixtime(long long int elap
)
1471 long int num
= elap
/ 1000LL;
1475 static char buf
[20];
1478 min
=(num
% 3600L) / 60L;
1481 if(hor
==0 && min
==0 && sec
==0)
1484 snprintf(buf
,sizeof(buf
),"%d:%02d:%02d",hor
,min
,sec
);
1490 void date_from(char *date
,int date_size
, int *dfrom
, int *duntil
)
1499 if (isdigit(date
[0])) {
1502 if (sscanf(date
,"%d/%d/%d%n",&d0
,&m0
,&y0
,&next
)!=3 || y0
<100 || m0
<1 || m0
>12 || d0
<1 || d0
>31 || next
<0) {
1503 debuga(_("The date passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1506 if (date
[next
]=='-') {
1507 if (sscanf(date
+next
+1,"%d/%d/%d",&d1
,&m1
,&y1
)!=3 || y1
<100 || m1
<1 || m1
>12 || d1
<1 || d1
>31) {
1508 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1511 } else if (date
[next
]!='\0') {
1512 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1522 struct tm
*Date0
,Date1
;
1524 if (time(&Today
)==(time_t)-1) {
1525 debuga(_("Failed to get the current time\n"));
1528 if (sscanf(date
,"day-%d",&i
)==1) {
1530 debuga(_("Invalid number of days in -d parameter\n"));
1534 Date0
=localtime(&Today
);
1536 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1539 y0
=y1
=Date0
->tm_year
+1900;
1540 m0
=m1
=Date0
->tm_mon
+1;
1541 d0
=d1
=Date0
->tm_mday
;
1542 } else if (sscanf(date
,"week-%d",&i
)==1) {
1544 There is no portable way to find the first day of the week even though the
1545 information is available in the locale. nl_langinfo has the unofficial
1546 parameters _NL_TIME_FIRST_WEEKDAY and _NL_TIME_WEEK_1STDAY but they are
1547 undocumented as is their return value and it is discouraged to use them.
1548 Beside, nl_langinfo isn't available on windows and the first day of the
1549 week isn't available at all on that system.
1551 const int FirstWeekDay
=1;
1555 debuga(_("Invalid number of weeks in -d parameter\n"));
1558 Date0
=localtime(&Today
);
1560 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1563 WeekBegin
=Today
-((Date0
->tm_wday
-FirstWeekDay
+7)%7)*24*60*60;
1564 WeekBegin
-=i
*7*24*60*60;
1565 Date0
=localtime(&WeekBegin
);
1567 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1570 y0
=Date0
->tm_year
+1900;
1573 WeekBegin
+=6*24*60*60;
1574 Date0
=localtime(&WeekBegin
);
1576 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1579 y1
=Date0
->tm_year
+1900;
1582 } else if (sscanf(date
,"month-%d",&i
)==1) {
1584 debuga(_("Invalid number of months in -d parameter\n"));
1587 Date0
=localtime(&Today
);
1589 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1592 if (Date0
->tm_mon
<i
%12) {
1593 y0
=Date0
->tm_year
+1900-i
/12-1;
1594 m0
=(Date0
->tm_mon
+12-i
%12)%12+1;
1597 y0
=Date0
->tm_year
+1900-i
/12;
1598 m0
=Date0
->tm_mon
-i
%12+1;
1601 memcpy(&Date1
,Date0
,sizeof(struct tm
));
1606 Date1
.tm_year
=y0
-1900;
1609 Date1
.tm_year
=y0
-1900+1;
1613 Date0
=localtime(&t1
);
1614 y1
=Date0
->tm_year
+1900;
1618 debuga(_("Invalid date range passed on command line\n"));
1623 *dfrom
=y0
*10000+m0
*100+d0
;
1624 *duntil
=y1
*10000+m1
*100+d1
;
1625 snprintf(date
,date_size
,"%02d/%02d/%04d-%02d/%02d/%04d",d0
,m0
,y0
,d1
,m1
,y1
);
1630 char *strlow(char *string
)
1636 for (s
= string
; *s
; ++s
)
1646 char *strup(char *string
)
1652 for (s
= string
; *s
; ++s
)
1660 void removetmp(const char *outdir
)
1665 if(!RemoveTempFiles
)
1669 debuga(_("Purging temporary file sarg-general\n"));
1671 if (snprintf(filename
,sizeof(filename
),"%s/sarg-general",outdir
)>=sizeof(filename
)) {
1672 debuga(_("(removetmp) directory too long to remove %s/sarg-period\n"),outdir
);
1675 if((fp_gen
=fopen(filename
,"w"))==NULL
){
1676 debuga(_("(removetmp) Cannot open file %s: %s\n"),filename
,strerror(errno
));
1679 totalger(fp_gen
,filename
);
1680 if (fclose(fp_gen
)==EOF
) {
1681 debuga(_("Failed to close %s after writing the total line: %s\n"),filename
,strerror(errno
));
1686 void load_excludecodes(const char *ExcludeCodes
)
1694 if(ExcludeCodes
[0] == '\0')
1697 if((fp_in
=fopen(ExcludeCodes
,"r"))==NULL
) {
1698 debuga(_("(util) Cannot open file %s (exclude_codes): %s\n"),ExcludeCodes
,strerror(errno
));
1702 if (fseek(fp_in
, 0, SEEK_END
)==-1) {
1703 debuga(_("Failed to move till the end of the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1706 MemSize
= ftell(fp_in
);
1708 debuga(_("Cannot get the size of file %s\n"),ExcludeCodes
);
1711 if (fseek(fp_in
, 0, SEEK_SET
)==-1) {
1712 debuga(_("Failed to rewind the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1717 if((excludecode
=(char *) malloc(MemSize
))==NULL
) {
1718 debuga(_("malloc error (%ld)\n"),MemSize
);
1721 memset(excludecode
,0,MemSize
);
1724 while(fgets(data
,sizeof(data
),fp_in
)!=NULL
) {
1725 if (data
[0]=='#') continue;
1726 for (i
=strlen(data
)-1 ; i
>=0 && (unsigned char)data
[i
]<=' ' ; i
--) data
[i
]='\0';
1728 if (Stored
+i
+2>=MemSize
) {
1729 debuga(_("Too many codes to exclude in file %s\n"),ExcludeCodes
);
1732 strcat(excludecode
,data
);
1733 strcat(excludecode
,";");
1741 void free_excludecodes(void)
1749 int vercode(const char *code
)
1754 if (excludecode
&& excludecode
[0]!='\0') {
1758 if (strncmp(code
,cod
,clen
)==0 && cod
[clen
]==';')
1760 cod
=strchr(cod
,';');
1767 void fixnone(char *str
)
1771 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--);
1772 if(i
==3 && strncmp(str
,"none",4) == 0)
1778 void fixendofline(char *str
)
1782 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--) str
[i
]=0;
1785 #ifdef LEGACY_TESTVALIDUSERCHAR
1786 int testvaliduserchar(const char *user
)
1791 for (y
=0; y
<strlen(UserInvalidChar
); y
++) {
1792 for (x
=0; x
<strlen(user
); x
++) {
1793 if(user
[x
] == UserInvalidChar
[y
])
1800 int testvaliduserchar(const char *user
)
1802 char * p_UserInvalidChar
= UserInvalidChar
;
1803 const char * p_user
;
1805 while( *p_UserInvalidChar
) {
1808 if( *p_UserInvalidChar
== *p_user
)
1812 p_UserInvalidChar
++ ;
1818 int compar( const void *a
, const void *b
)
1820 if( *(int *)a
> *(int *)b
) return 1;
1821 if( *(int *)a
< *(int *)b
) return -1;
1825 int getnumlist( char *buf
, numlist
*list
, const int len
, const int maxvalue
)
1827 int i
, j
, d
, flag
, r1
, r2
;
1828 char *pbuf
, **bp
, *strbufs
[ 24 ];
1831 strtok( buf
, " \t" );
1832 for( *bp
= strtok( NULL
, "," ), list
->len
= 0; *bp
; *bp
= strtok( NULL
, "," ) ) {
1833 if( ++bp
>= &strbufs
[ 24 ] )
1840 for( i
= 0; i
< list
->len
; i
++ ) {
1841 if( strchr( strbufs
[ i
], '-' ) != 0 ) {
1842 pbuf
= strbufs
[ i
];
1843 strtok( pbuf
, "-" );
1844 pbuf
= strtok( NULL
, "\0" );
1845 r1
= atoi( strbufs
[ i
] );
1846 if( ( r2
= atoi( pbuf
) ) >= maxvalue
|| r1
>= r2
)
1848 if( i
+ d
+ ( r2
- r1
) + 1 <= len
) {
1849 for( j
= r1
; j
<= r2
; j
++ )
1850 list
->list
[ i
+ d
++ ] = j
;
1855 if( ( list
->list
[ i
+ d
] = atoi( strbufs
[ i
] ) ) >= maxvalue
)
1859 qsort( list
->list
, list
->len
, sizeof( int ), compar
);
1862 for( i
= 0; i
< list
->len
- 1; i
++ )
1863 if( list
->list
[ i
] == list
->list
[ i
+ 1 ] ) {
1864 for( j
= i
+ 1; j
< list
->len
; j
++ )
1865 list
->list
[ j
- 1 ] = list
->list
[ j
];
1874 void show_info(FILE *fp_ou
)
1878 if(!ShowSargInfo
) return;
1879 zdate(ftime
, sizeof(ftime
), df
);
1880 fputs("<div class=\"info\">",fp_ou
);
1881 fprintf(fp_ou
,_("Generated by <a href='%s'>%s-%s</a> on %s"),URL
,PGM
,VERSION
,ftime
);
1882 fputs("</div>\n",fp_ou
);
1885 void show_sarg(FILE *fp_ou
, int depth
)
1889 if(!ShowSargLogo
) return;
1890 fputs("<div class=\"logo\"><a href=\"http://sarg.sourceforge.net\"><img src=\"",fp_ou
);
1891 for (i
=0 ; i
<depth
; i
++)
1893 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
);
1896 void write_logo_image(FILE *fp_ou
)
1898 if(LogoImage
[0]!='\0')
1899 fprintf(fp_ou
, "<div class=\"logo\"><img src=\"%s\" width=\"%s\" height=\"%s\" alt=\"Logo\"> %s</div>\n",LogoImage
,Width
,Height
,LogoText
);
1902 void write_html_head(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1906 fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n",fp_ou
);
1907 fprintf(fp_ou
, "<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n",CharSet
);
1908 if (page_title
) fprintf(fp_ou
,"<title>%s</title>\n",page_title
);
1910 if ((javascript
& HTML_JS_SORTTABLE
)!=0 && SortTableJs
[0]) {
1911 fputs("<script type=\"text/javascript\" src=\"",fp_ou
);
1912 if (strncmp(SortTableJs
,"../",3)==0) {
1913 for (i
=0 ; i
<depth
; i
++) fputs("../",fp_ou
);
1915 fputs(SortTableJs
,fp_ou
);
1916 fputs("\"></script>\n",fp_ou
);
1918 fputs("</head>\n<body>\n",fp_ou
);
1921 void write_html_header(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1923 write_html_head(fp_ou
,depth
,page_title
,javascript
);
1924 write_logo_image(fp_ou
);
1925 show_sarg(fp_ou
, depth
);
1926 fprintf(fp_ou
,"<div class=\"title\"><table cellpadding=\"0\" cellspacing=\"0\">\n<tr><th class=\"title_c\">%s</th></tr>\n",Title
);
1929 void close_html_header(FILE *fp_ou
)
1931 fputs("</table></div>\n",fp_ou
);
1934 int write_html_trailer(FILE *fp_ou
)
1937 if (fputs("</body>\n</html>\n",fp_ou
)==EOF
) return(-1);
1941 void output_html_string(FILE *fp_ou
,const char *str
,int maxlen
)
1945 while (*str
&& (maxlen
<=0 || i
<maxlen
)) {
1948 fputs("&",fp_ou
);
1951 fputs("<",fp_ou
);
1954 fputs(">",fp_ou
);
1957 fputs(""",fp_ou
);
1960 fputs("'",fp_ou
);
1968 if (maxlen
>0 && i
>=maxlen
)
1969 fputs("…",fp_ou
);
1972 void output_html_url(FILE *fp_ou
,const char *url
)
1976 fputs("&",fp_ou
);
1984 Write a host name inside an A tag of a HTML file. If the host name starts
1985 with a star, it is assumed to be an alias that cannot be put inside a link
1986 so the A tag is not written around the host name.
1988 \param fp_ou The handle of the HTML file.
1989 \param url The host to display in the HTML file.
1990 \param maxlen The maximum number of characters to print into the host name.
1992 void output_html_link(FILE *fp_ou
,const char *url
,int maxlen
)
1994 if (url
[0]==ALIAS_PREFIX
) {
1995 // this is an alias, no need for a A tag
1996 output_html_string(fp_ou
,url
+1,100);
1998 if (skip_scheme(url
)==url
)
1999 fputs("<a href=\"http://",fp_ou
);//no scheme in the url, assume http:// to make the link clickable
2001 fputs("<a href=\"",fp_ou
);//the scheme is in the url, no need to add one
2002 output_html_url(fp_ou
,url
);
2004 output_html_string(fp_ou
,url
,100);
2005 fputs("</a>",fp_ou
);
2009 void url_module(const char *url
, char *w2
)
2015 for(x
=strlen(url
)-1; x
>=0; x
--) {
2016 if(url
[x
] == '/' || y
>=sizeof(w
)-1) break;
2025 for(y
=y
-1; y
>=0; y
--) {
2032 Mangle an URL to produce a part that can be used as an anchor in
2033 a html <a name=""> tag.
2035 \param url The URL to mangle.
2036 \param anchor The buffer to write the mangled URL.
2037 \param size The size of the buffer.
2039 void url_to_anchor(const char *url
,char *anchor
,int size
)
2045 for (i
=0 ; url
[i
] && url
[i
]!='/' && url
[i
]!='?' ; i
++);
2052 // only keep really safe characters
2058 if(isalnum(url
[i
]) || url
[i
]=='-' || url
[i
]=='_' || url
[i
]=='.') {
2062 if (!skip
) anchor
[--j
]='_';
2080 printf(_("SARG Version: %s\n"),VERSION
);
2081 #if defined(ENABLE_NLS) && defined(HAVE_LOCALE_H)
2083 printf(_("\nFor the translation to work, a valid message file should be installed as "
2084 "\"%s/<Locale>/LC_MESSAGES/%s.mo\" where <Locale> is derived from the effective locale.\n"),LOCALEDIR
,PACKAGE_NAME
);
2085 if (CurrentLocale
) {
2086 printf(_("Currently effective locale is \"%s\".\n"),CurrentLocale
);
2088 printf(_("Locale is not set in the environment variable.\n"));
2090 // TRANSLATORS: You may change this message to tell the reader that the language is correctly supported.
2091 printf(_("If this message is in English, then your language is not supported or not correctly installed.\n"));
2097 char *get_param_value(const char *param
,char *line
)
2101 while (*line
==' ' || *line
=='\t') line
++;
2103 if (strncasecmp(line
,param
,plen
)) return(NULL
);
2104 if (line
[plen
]!=' ' && line
[plen
]!='\t') return(NULL
);
2106 while (*line
==' ' || *line
=='\t') line
++;
2110 void unlinkdir(const char *dir
,bool contentonly
)
2114 struct dirent
*direntp
;
2120 while ((direntp
= readdir(dirp
)) != NULL
) {
2121 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
2122 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
2124 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
2125 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
2129 err
=lstat(dname
,&st
);
2131 err
=stat(dname
,&st
);
2134 debuga(_("cannot stat %s\n"),dname
);
2137 if (S_ISREG(st
.st_mode
)) {
2138 if (unlink(dname
)) {
2139 debuga(_("Cannot delete \"%s\": %s\n"),dname
,strerror(errno
));
2142 } else if (S_ISDIR(st
.st_mode
)) {
2145 debuga(_("unknown path type %s\n"),dname
);
2152 debuga(_("Cannot delete \"%s\": %s\n"),dir
,strerror(errno
));
2159 Delete every file from the temporary directory where sarg is told to store its
2162 As any stray file left over by a previous run would be included in the report, we
2163 must delete every file from the temporary directory before we start processing the logs.
2165 But the temporary directory is given by the user either in the configuration file or
2166 on the command line. We check that the user didn't give a wrong directory by looking
2167 at the files stored in the directory. If a single file is not one of ours, we abort.
2169 \param dir The temporary directory to purge.
2171 void emptytmpdir(const char *dir
)
2175 struct dirent
*direntp
;
2181 static const char *TmpExt
[]=
2198 // make sure the temporary directory contains only our files
2199 while ((direntp
= readdir(dirp
)) != NULL
) {
2200 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
2201 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
2204 // is it one of our files
2205 dlen
=strlen(direntp
->d_name
);
2206 for (i
=sizeof(TmpExt
)/sizeof(TmpExt
[0])-1 ; i
>=0 ; i
--) {
2207 elen
=strlen(TmpExt
[i
]);
2208 if (dlen
>=elen
&& strcasecmp(direntp
->d_name
+dlen
-elen
,TmpExt
[i
])==0) break;
2211 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2212 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2213 "directory or manually delete the content of \"%s\"\n"),direntp
->d_name
,dir
,dir
);
2217 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
2218 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
2223 err
=lstat(dname
,&st
);
2225 err
=stat(dname
,&st
);
2228 debuga(_("cannot stat \"%s\"\n"),dname
);
2231 if (S_ISDIR(st
.st_mode
)) {
2233 } else if (!S_ISREG(st
.st_mode
)) {
2234 debuga(_("Unknown path type for \"%s\". Check temporary directory\n"),dname
);
2240 // now delete our files
2241 while ((direntp
= readdir(dirp
)) != NULL
) {
2242 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
2243 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
2246 // is it one of our files
2247 dlen
=strlen(direntp
->d_name
);
2248 for (i
=sizeof(TmpExt
)/sizeof(TmpExt
[0])-1 ; i
>=0 ; i
--) {
2249 elen
=strlen(TmpExt
[i
]);
2250 if (dlen
>=elen
&& strcasecmp(direntp
->d_name
+dlen
-elen
,TmpExt
[i
])==0) break;
2253 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2254 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2255 "directory or manually delete the content of \"%s\"\n"),direntp
->d_name
,dir
,dir
);
2259 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
2260 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
2264 err
=lstat(dname
,&st
);
2266 err
=stat(dname
,&st
);
2269 debuga(_("cannot stat \"%s\"\n"),dname
);
2272 if (S_ISREG(st
.st_mode
)) {
2273 if (unlink(dname
)) {
2274 debuga(_("Cannot delete \"%s\": %s\n"),dname
,strerror(errno
));
2278 debuga(_("unknown path type %s\n"),dname
);
2285 Extract an url, IPv4 or IPv6 from a buffer. The IP addresses may end with a
2288 \param buf The buffer to parse.
2289 \param text A pointer to set to the beginning of the string pattern. No terminating zero is inserted.
2290 The pointer may be NULL.
2291 \param ipv4 A 4 bytes buffer to store the bytes of the IPv4 address.
2292 \param ipv6 A 8 short integers buffer to store the values of the IPv6 address.
2293 \param nbits The number of prefix bits for an IP address.
2294 \param next The content of the line after the extracted address.
2296 \retval 3 The pattern is a IPv6 address.
2297 \retval 2 The pattern is a IPv4 address.
2298 \retval 1 The patter is a string.
2299 \retval 0 Empty pattern.
2301 int extract_address_mask(const char *buf
,const char **text
,unsigned char *ipv4
,unsigned short int *ipv6
,int *nbits
,const char **next
)
2306 unsigned int value4
, value6
;
2307 unsigned short int addr
[8];
2317 // skip leading spaces and tabs
2318 while (*buf
&& (*buf
==' ' || *buf
=='\t')) buf
++;
2320 // find out the nature of the pattern
2321 ip_size
=0x60 | 0x04;
2332 for (i
=0 ; (unsigned char)buf
[i
]>' ' && buf
[i
]!='/' && buf
[i
]!='?' && (!bracket
|| buf
[i
]!=']') && ip_size
; i
++) {
2333 if (ip_size
& 0x04) {
2334 if (isdigit(buf
[i
])) {
2336 port_num
=port_num
*10+(buf
[i
]-'0');
2337 if (port_num
>65535) ip_size
&=~0x04;
2339 value4
=value4
*10+(buf
[i
]-'0');
2340 if (value4
>0xFFU
) ip_size
&=~0x04;
2342 } else if (buf
[i
]=='.' && addr_len
<4) {
2343 addr
[addr_len
++]=(unsigned short)(value4
& 0xFFU
);
2345 } else if (!port
&& buf
[i
]==':') {
2351 if (ip_size
& 0x60) {
2352 if (isdigit(buf
[i
])) {
2353 value6
=(value6
<<4)+(buf
[i
]-'0');
2355 if (value6
>0xFFFFU
) ip_size
&=~0x60;
2356 } else if (toupper(buf
[i
])>='A' && toupper(buf
[i
])<='F') {
2357 value6
=(value6
<<4)+(toupper(buf
[i
])-'A'+10);
2359 if (value6
>0xFFFFU
) ip_size
&=~0x60;
2360 } else if (buf
[i
]==':' && addr_len
<8) {
2361 if (nibble6_len
>0) {
2362 addr
[addr_len
++]=(unsigned short)(value6
& 0xFFFFU
);
2366 if (buf
[i
+1]==':') {
2375 if (i
==0) return(0);
2376 if (ip_size
& 0x04) {
2380 addr
[addr_len
++]=(unsigned short)(value4
& 0xFFU
);
2382 if (ip_size
& 0x60) {
2383 if (pad_pos
<0 && addr_len
!=7) {
2385 } else if (pad_pos
>=0 && addr_len
>=7)
2387 else if (nibble6_len
>0)
2388 addr
[addr_len
++]=(unsigned short)(value6
& 0xFFFFU
);
2393 if (bracket
) (*text
)--;
2395 while ((unsigned char)buf
[i
]>' ') i
++;
2396 if (next
) *next
=buf
+i
;
2399 max_mask
=(ip_size
& 0x04) ? 4*8 : 8*16;
2403 while (isdigit(buf
[i
])) i
++;
2404 if (mask
<0 || mask
>max_mask
) mask
=max_mask
;
2407 if (ip_size
& 0x60 && bracket
&& buf
[i
]==']') i
++;
2408 if (next
) *next
=buf
+i
;
2409 if (ip_size
& 0x04) {
2410 if (nbits
) *nbits
=mask
;
2411 for (i
=0 ; i
<addr_len
; i
++)
2412 ipv4
[i
]=(unsigned char)addr
[i
];
2417 if (nbits
) *nbits
=mask
;
2422 ipv6
[j
++]=(unsigned short int)addr
[i
++];
2424 while (j
<pad_pos
+pad_len
)
2428 ipv6
[j
++]=(unsigned short int)addr
[i
++];