]>
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 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
101 word
[(limit
>0) ? limit
-1 : 0]='\0';
102 #if USE_GETWORD_BACKTRACE
107 word
[x
] = gwarea
->current
[x
];
111 if (gwarea
->current
[x
]) ++x
;
116 int getword_limit(char *word
, int limit
, struct getwordstruct
*gwarea
, char stop
)
121 for(x
=0; x
<limit
&& gwarea
->current
[x
] && gwarea
->current
[x
] != stop
;x
++) {
122 word
[x
] = gwarea
->current
[x
];
126 while (*gwarea
->current
&& *gwarea
->current
!= stop
) gwarea
->current
++;
127 if (*gwarea
->current
) ++gwarea
->current
;
131 int getword_multisep(char *word
, int limit
, struct getwordstruct
*gwarea
, char stop
)
135 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++) {
137 debuga(_("End of word not found in getword_multisep after %d bytes.\n"),x
);
138 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
139 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
140 debuga(_("searching for \'x%x\'\n"),stop
);
141 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
142 if (limit
>0) word
[limit
-1]='\0';
143 #if USE_GETWORD_BACKTRACE
146 //exit(EXIT_FAILURE);
149 word
[x
] = gwarea
->current
[x
];
153 while (gwarea
->current
[x
] && gwarea
->current
[x
]==stop
) ++x
;
158 int getword_skip(int limit
, struct getwordstruct
*gwarea
, char stop
)
162 for(x
=0;(gwarea
->current
[x
] && (gwarea
->current
[x
] != stop
));x
++) {
164 debuga(_("End of word not found in getword_skip after %d bytes.\n"),x
);
165 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
166 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
167 debuga(_("searching for \'x%x\'\n"),stop
);
168 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
169 #if USE_GETWORD_BACKTRACE
176 if (gwarea
->current
[x
]) ++x
;
181 int getword_atoll(long long int *number
, struct getwordstruct
*gwarea
, char stop
)
187 if (gwarea
->current
[0] == '-') {
190 } else if (gwarea
->current
[0] == '+') {
194 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
195 digit
=gwarea
->current
[x
]-'0';
196 if (*number
>= (LLONG_MAX
-digit
)/10) {
197 debuga(_("Integer overflow detected in getword_atoll in line %s\n"),gwarea
->beginning
);
200 *number
=(*number
* 10) + digit
;
202 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
203 debuga(_("End of number not found in getword_atoll after %d bytes.\n"),x
);
204 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
205 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
206 debuga(_("searching for \'x%x\'\n"),stop
);
207 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
208 #if USE_GETWORD_BACKTRACE
215 if (gwarea
->current
[x
]) ++x
;
220 int getword_atoi(int *number
, struct getwordstruct
*gwarea
, char stop
)
226 if (gwarea
->current
[0] == '-') {
229 } else if (gwarea
->current
[0] == '+') {
233 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
234 digit
=gwarea
->current
[x
]-'0';
235 if (*number
> (INT_MAX
-digit
)/10) {
236 debuga(_("Integer overflow detected in getword_atoi in line %s\n"),gwarea
->beginning
);
239 *number
=(*number
* 10) + digit
;
241 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
242 debuga(_("End of number not found in getword_atoi after %d bytes.\n"),x
);
243 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
244 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
245 debuga(_("searching for \'x%x\'\n"),stop
);
246 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
247 #if USE_GETWORD_BACKTRACE
254 if (gwarea
->current
[x
]) ++x
;
259 int getword_atol(long int *number
, struct getwordstruct
*gwarea
, char stop
)
265 if (gwarea
->current
[0] == '-') {
268 } else if (gwarea
->current
[0] == '+') {
272 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
273 digit
=gwarea
->current
[x
]-'0';
274 if (*number
> (LONG_MAX
-digit
)/10) {
275 debuga(_("Integer overflow detected in getword_atol in line %s\n"),gwarea
->beginning
);
278 *number
=(*number
* 10) + digit
;
280 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
281 debuga(_("End of number not found in getword_atol after %ld bytes.\n"),x
);
282 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
283 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
284 debuga(_("searching for \'x%x\'\n"),stop
);
285 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
286 #if USE_GETWORD_BACKTRACE
293 if (gwarea
->current
[x
]) ++x
;
298 int getword_atolu(unsigned long int *number
, struct getwordstruct
*gwarea
, char stop
)
303 if (gwarea
->current
[0] == '-') {
304 debuga(_("getword_atolu got a negative number.\n"));
305 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
306 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
309 if (gwarea
->current
[0] == '+') {
313 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
314 digit
=gwarea
->current
[x
]-'0';
315 if (*number
> (ULONG_MAX
-digit
)/10) {
316 debuga(_("Integer overflow detected in getword_atolu in line %s\n"),gwarea
->beginning
);
319 *number
=(*number
* 10) + digit
;
321 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
322 debuga(_("End of number not found in getword_atolu after %ld bytes.\n"),x
);
323 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
324 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
325 debuga(_("searching for \'x%x\'\n"),stop
);
326 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
327 #if USE_GETWORD_BACKTRACE
333 if (gwarea
->current
[x
]) ++x
;
339 int getword_ptr(char *orig_line
,char **word
, struct getwordstruct
*gwarea
, char stop
)
342 \note Why pass the original buffer to the function ? Because we must modify it to
343 insert the terminating ASCII zero for the word we return and that's not compatible
344 with getword_restart(). Moreover, getword_start() sometime works on constant strings
345 so this function require the original buffer to detect any missuse.
351 if (orig_line
&& orig_line
!=gwarea
->beginning
) {
352 debuga(_("Invalid buffer passed to getword_ptr\n"));
356 start
=(gwarea
->current
-gwarea
->beginning
);
357 if (word
&& orig_line
) *word
=orig_line
+start
;
358 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++);
359 sep
=(gwarea
->current
[x
]!='\0');
360 if (word
&& orig_line
) orig_line
[start
+x
] = '\0';
367 #define MAXLLL 30 //!< Maximum number of digits in long long (a guess).
368 long long int my_atoll (const char *nptr
)
370 long long int returnval
=0LL;
371 int max_digits
= MAXLLL
;
373 // Soak up all the white space
374 while (isspace( *nptr
)) {
378 //For each character left to right
379 //change the character to a single digit
380 //multiply what we had before by 10 and add the new digit
382 while (--max_digits
&& isdigit( *nptr
))
384 returnval
= ( returnval
* 10 ) + ( *nptr
++ - '0' ) ;
390 int is_absolute(const char *path
)
392 if (*path
=='/') return(1);
394 if (isalpha(path
[0]) && path
[1]==':') return(1);
399 int PortableMkDir(const char *path
,int mode
)
401 #if defined(__linux__)
402 int mkerror
=mkdir(path
,mode
);
405 int mkerror
=_mkdir(path
);
410 void my_mkdir(const char *name
)
416 if(!is_absolute(name
)) {
417 debuga(_("Invalid path (%s). Please, use absolute paths only.\n"),name
);
422 for (i
=0 ; name
[i
] ; i
++) {
424 debuga(_("directory name too long: %s\n"),name
);
427 if (chars
>0 && name
[i
] == '/') {
429 if (access(w0
, R_OK
) != 0) {
430 if (PortableMkDir(w0
,0755)) {
431 debuga(_("Cannot create directory %s - %s\n"),w0
,strerror(errno
));
436 if (name
[i
] != '/') chars
++;
440 if (access(name
, R_OK
) != 0) {
441 if (PortableMkDir(name
,0755)) {
442 debuga(_("Cannot create directory %s - %s\n"),name
,strerror(errno
));
449 void my_lltoa(unsigned long long int n
, char *s
, int ssize
, int len
)
458 debuga(_("The requested number of digits passed to my_lltoa (%d) is bigger than the output buffer size (%d)\n"),len
,ssize
);
463 s
[slen
++] = (n
% 10) + '0';
464 } while ((n
/= 10) > 0 && slen
<ssize
);
467 for (i
= 0, j
= slen
-1; i
<j
; i
++, j
--) {
475 for(j
=slen
; j
>=0; j
--)
482 int month2num(const char *month
)
486 for(m
=0 ; m
<12 && strcmp(mtab1
[m
],month
) != 0; m
++);
490 int builddia(int day
, int month
, int year
)
492 return(year
*10000+month
*100+day
);
498 \param date1 The first date to compare.
499 \param date2 The second date to compare.
501 \retval -1 If date1<date2.
502 \retval 0 If date1==date2.
503 \retval 1 if date1>date2.
505 int compare_date(struct tm
*date1
,struct tm
*date2
)
507 if (date1
->tm_year
<date2
->tm_year
) return(-1);
508 if (date1
->tm_year
>date2
->tm_year
) return(1);
509 if (date1
->tm_mon
<date2
->tm_mon
) return(-1);
510 if (date1
->tm_mon
>date2
->tm_mon
) return(1);
511 if (date1
->tm_mday
<date2
->tm_mday
) return(-1);
512 if (date1
->tm_mday
>date2
->tm_mday
) return(1);
513 if (date1
->tm_hour
<date2
->tm_hour
) return(-1);
514 if (date1
->tm_hour
>date2
->tm_hour
) return(1);
515 if (date1
->tm_min
<date2
->tm_min
) return(-1);
516 if (date1
->tm_min
>date2
->tm_min
) return(1);
517 if (date1
->tm_sec
<date2
->tm_sec
) return(-1);
518 if (date1
->tm_sec
>date2
->tm_sec
) return(1);
522 void buildymd(const char *dia
, const char *mes
, const char *ano
, char *wdata
,int wdata_size
)
527 snprintf(wdata
,wdata_size
,"%04d%02d%02d",atoi(ano
),nmes
+1,atoi(dia
));
531 int conv_month(const char *month
)
535 for(x
=0; x
<12 && strncmp(mtab1
[x
],month
,3)!=0; x
++);
540 const char *conv_month_name(int month
)
544 if (month
<1 || month
>12) {
545 snprintf(str
,sizeof(str
),"%03d",month
);
548 return(mtab1
[month
-1]);
552 Write a debug message to stderr. The message is prefixed by "SARG:" to identify its origin.
554 \param msg The printf like message to format.
555 \param ... The arguments to format in the message.
557 void debuga(const char *msg
,...)
561 fputs(_("SARG: "),stderr
);
563 vfprintf(stderr
,msg
,ap
);
569 Write a debug message to stderr. The message is prefixed by "SARG: (info)".
571 \param msg The printf like message to format.
572 \param ... The arguments to format in the message.
574 void debugaz(const char *msg
,...)
578 fputs(_("SARG: (info) "),stderr
);
580 vfprintf(stderr
,msg
,ap
);
585 char *fixnum(long long int value
, int n
)
587 #define MAXLEN_FIXNUM 256
588 char num
[MAXLEN_FIXNUM
]="";
589 char buf
[MAXLEN_FIXNUM
* 2];
591 static char ret
[MAXLEN_FIXNUM
* 2];
593 register int i
, j
, k
;
595 static char abbrev
[30]="";
597 my_lltoa(value
, num
, sizeof(num
), 0);
599 if(DisplayedValues
==DISPLAY_ABBREV
) {
600 numlen
= strlen(num
);
603 else if (numlen
%3 == 1) {
605 abbrev
[1]=(UseComma
) ? ',' : '.';
610 else if (numlen
%3 == 2) {
613 abbrev
[2]=(UseComma
) ? ',' : '.';
618 else if (numlen
%3 == 0) {
622 abbrev
[3]=(UseComma
) ? ',' : '.';
631 else if (numlen
<= 6)
633 else if (numlen
<= 9)
635 else if (numlen
<= 12)
637 else if (numlen
<= 15)
639 else if (numlen
>= 18)
641 else if (numlen
<= 21)
643 else if (numlen
<= 24)
645 else if (numlen
<= 27)
648 strcat(abbrev
,"???");
653 memset(buf
,0,MAXLEN_FIXNUM
*2);
659 for ( i
= strlen(num
) - 1, j
= 0 ; i
> -1; i
--) {
660 if ( k
== 2 && i
!= 0 ) {
663 pbuf
[j
++] = (UseComma
) ? ',' : '.';
673 for ( i
= strlen(pbuf
) - 1, j
= 0 ; i
> -1; i
--, j
++)
682 char *fixnum2(long long int value
, int n
)
684 #define MAXLEN_FIXNUM2 1024
685 char num
[MAXLEN_FIXNUM2
];
686 char buf
[MAXLEN_FIXNUM2
* 2];
688 static char ret
[MAXLEN_FIXNUM2
* 2];
690 register int i
, j
, k
;
692 my_lltoa(value
, num
, sizeof(num
), 0);
693 memset(buf
,0,MAXLEN_FIXNUM2
*2);
699 for ( i
= strlen(num
) - 1, j
= 0 ; i
> -1; i
--) {
700 if ( k
== 2 && i
!= 0 ) {
703 pbuf
[j
++] = (UseComma
) ? ',' : '.';
713 for ( i
= strlen(pbuf
) - 1, j
= 0 ; i
> -1; i
--, j
++)
722 char *buildtime(long long int elap
)
724 long int num
= elap
/ 1000LL;
731 min
=(num
% 3600L) / 60L;
733 snprintf(buf
,sizeof(buf
),"%02d:%02d:%02d",hor
,min
,sec
);
740 Get the date stored in the <tt>sarg-date</tt> file of a directory with the connection data.
742 \param dirname The directory to look for the connection directory.
743 \param name The name of the directory whose <tt>sarg-date</tt> file must be read.
744 \param data The buffer to store the content of the file. It must be more than 80
748 \retval -1 File not found.
750 int obtdate(const char *dirname
, const char *name
, char *data
)
755 if (snprintf(wdir
,sizeof(wdir
),"%s%s/sarg-date",dirname
,name
)>=sizeof(wdir
)) {
756 debuga(_("Buffer to small to store %s%s/sarg-date"),dirname
,name
);
759 if ((fp_in
= fopen(wdir
, "rt")) == 0) {
760 if (snprintf(wdir
,sizeof(wdir
),"%s%s/date",dirname
,name
)>=sizeof(wdir
)) {
761 debuga(_("Buffer to small to store %s%s/date"),dirname
,name
);
764 if ((fp_in
= fopen(wdir
, "rt")) == 0) {
770 if (!fgets(data
,80,fp_in
)) {
771 debuga(_("Failed to read the date in %s\n"),wdir
);
781 void formatdate(char *date
,int date_size
,int year
,int month
,int day
,int hour
,int minute
,int second
,int dst
)
787 memset(<m
,0,sizeof(ltm
));
788 if (year
>=1900) ltm
.tm_year
=year
-1900;
789 if (month
>=1 && month
<=12) ltm
.tm_mon
=month
-1;
790 if (day
>=1 && day
<=31) ltm
.tm_mday
=day
;
791 if (hour
>=0 && hour
<24) ltm
.tm_hour
=hour
;
792 if (minute
>=0 && minute
<60) ltm
.tm_min
=minute
;
793 if (second
>=0 && second
<60) ltm
.tm_sec
=second
;
795 unixtime
=mktime(<m
); //fill the missing entries
796 fulltm
=localtime(&unixtime
);
797 //strftime(date,date_size,"%a %b %d %H:%M:%S %Z %Y",fulltm);
798 strftime(date
,date_size
,"%c",fulltm
);
802 void computedate(int year
,int month
,int day
,struct tm
*t
)
804 memset(t
,0,sizeof(*t
));
805 t
->tm_year
=year
-1900;
811 int obtuser(const char *dirname
, const char *name
)
818 if (snprintf(wdir
,sizeof(wdir
),"%s%s/sarg-users",dirname
,name
)>=sizeof(wdir
)) {
819 debuga(_("Buffer too small to store %s%s/sarg-users"),dirname
,name
);
822 if((fp_in
=fopen(wdir
,"r"))==NULL
) {
823 if (snprintf(wdir
,sizeof(wdir
),"%s%s/users",dirname
,name
)>=sizeof(wdir
)) {
824 debuga(_("Buffer too small to store %s%s/users"),dirname
,name
);
827 if((fp_in
=fopen(wdir
,"r"))==NULL
) {
832 if (!fgets(tuser
,sizeof(tuser
),fp_in
)) {
833 debuga(_("Failed to read the number of users in %s\n"),wdir
);
843 void obttotal(const char *dirname
, const char *name
, int nuser
, long long int *tbytes
, long long int *media
)
848 char user
[MAX_USER_LEN
];
850 struct getwordstruct gwarea
;
856 if (snprintf(wdir
,sizeof(wdir
),"%s%s/sarg-general",dirname
,name
)>=sizeof(wdir
)) {
857 debuga(_("Buffer too small to store %s%s/sarg-general"),dirname
,name
);
860 if ((fp_in
= fopen(wdir
, "r")) == 0) {
861 if (snprintf(wdir
,sizeof(wdir
),"%s%s/general",dirname
,name
)>=sizeof(wdir
)) {
862 debuga(_("Buffer too small to store %s%s/general"),dirname
,name
);
865 if ((fp_in
= fopen(wdir
, "r")) == 0) {
870 if ((line
=longline_create())==NULL
) {
871 debuga(_("Not enough memory to read the file %s\n"),wdir
);
875 while((buf
=longline_read(fp_in
,line
))!=NULL
) {
876 if (strncmp(buf
,"TOTAL\t",6) == 0)
878 else if (strncmp(buf
,"TOTAL ",6) == 0)
882 getword_start(&gwarea
,buf
);
883 if (getword(user
,sizeof(user
),&gwarea
,sep
)<0) {
884 debuga(_("There is a invalid user in file %s\n"),wdir
);
887 if(strcmp(user
,"TOTAL") != 0)
889 if (getword_skip(MAXLEN
,&gwarea
,sep
)<0) {
890 debuga(_("There a broken total number of access in file %s\n"),wdir
);
893 if (getword_atoll(tbytes
,&gwarea
,sep
)<0) {
894 debuga(_("There is a broken number of bytes in file %s\n"),wdir
);
900 longline_destroy(&line
);
905 *media
=*tbytes
/ nuser
;
909 int getperiod_fromsarglog(const char *arqtt
,struct periodstruct
*period
)
912 int day0
, month0
, year0
, hour0
, minute0
;
913 int day1
, month1
, year1
, hour1
, minute1
;
916 memset(period
,0,sizeof(*period
));
919 while((str
=strstr(str
,"sarg-"))!=NULL
) {
921 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
922 day0
=(str
[0]-'0')*10+(str
[1]-'0');
923 if (day0
<1 || day0
>31) continue;
925 month0
=(str
[0]-'0')*10+(str
[1]-'0')-1;
926 if (month0
<0 || month0
>11) continue;
929 for (i
=0 ; isdigit(str
[i
]) && i
<4 ; i
++) year0
=year0
*10+(str
[i
]-'0');
932 if (str
[0]!='_') continue;
935 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
936 hour0
=(str
[0]-'0')*10+(str
[1]-'0');
938 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
939 minute0
=(str
[0]-'0')*10+(str
[1]-'0');
942 if (*str
!= '-') continue;
945 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
946 day1
=(str
[0]-'0')*10+(str
[1]-'0');
947 if (day1
<1 || day1
>31) continue;
949 month1
=(str
[0]-'0')*10+(str
[1]-'0')-1;
950 if (month1
<0 || month1
>11) continue;
953 for (i
=0 ; isdigit(str
[i
]) && i
<4 ; i
++) year1
=year1
*10+(str
[i
]-'0');
957 if (str
[0]!='_') continue;
960 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
961 hour1
=(str
[0]-'0')*10+(str
[1]-'0');
963 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
964 minute1
=(str
[0]-'0')*10+(str
[1]-'0');
967 period
->start
.tm_mday
=day0
;
968 period
->start
.tm_mon
=month0
;
969 period
->start
.tm_year
=year0
-1900;
970 period
->start
.tm_hour
=hour0
;
971 period
->start
.tm_min
=minute0
;
972 period
->end
.tm_mday
=day1
;
973 period
->end
.tm_mon
=month1
;
974 period
->end
.tm_year
=year1
-1900;
975 period
->end
.tm_hour
=hour1
;
976 period
->end
.tm_min
=minute1
;
982 void getperiod_fromrange(struct periodstruct
*period
,int dfrom
,int duntil
)
984 memset(&period
->start
,0,sizeof(period
->start
));
985 period
->start
.tm_mday
=dfrom
%100;
986 period
->start
.tm_mon
=(dfrom
/100)%100-1;
987 period
->start
.tm_year
=(dfrom
/10000)-1900;
989 memset(&period
->end
,0,sizeof(period
->end
));
990 period
->end
.tm_mday
=duntil
%100;
991 period
->end
.tm_mon
=(duntil
/100)%100-1;
992 period
->end
.tm_year
=(duntil
/10000)-1900;
996 Update the \a main period to encompass the period in \a candidate.
998 void getperiod_merge(struct periodstruct
*main
,struct periodstruct
*candidate
)
1003 mdate
=(main
->start
.tm_year
)*10000+(main
->start
.tm_mon
)*100+main
->start
.tm_mday
;
1004 cdate
=(candidate
->start
.tm_year
)*10000+(candidate
->start
.tm_mon
)*100+candidate
->start
.tm_mday
;
1005 if (cdate
<mdate
) memcpy(&main
->start
,&candidate
->start
,sizeof(struct tm
));
1007 mdate
=(main
->end
.tm_year
)*10000+(main
->end
.tm_mon
)*100+main
->end
.tm_mday
;
1008 cdate
=(candidate
->end
.tm_year
)*10000+(candidate
->end
.tm_mon
)*100+candidate
->end
.tm_mday
;
1009 if (cdate
>mdate
) memcpy(&main
->end
,&candidate
->end
,sizeof(struct tm
));
1012 int getperiod_buildtext(struct periodstruct
*period
)
1016 char text1
[40], text2
[40];
1019 i
=strftime(text1
, sizeof(text1
), "%Y %b %d", &period
->start
);
1020 } else if(df
=='e') {
1021 i
=strftime(text1
, sizeof(text1
), "%d %b %Y", &period
->start
);
1022 } else /*if (df=='w')*/ {
1023 IndexTree
=INDEX_TREE_FILE
;
1024 i
=strftime(text1
, sizeof(text1
), "%Y.%U", &period
->start
);
1026 if (i
== 0) return(-1);
1028 range
=(period
->start
.tm_year
!=period
->end
.tm_year
||
1029 period
->start
.tm_mon
!=period
->end
.tm_mon
||
1030 period
->start
.tm_mday
!=period
->end
.tm_mday
);
1033 i
=strftime(text2
, sizeof(text2
)-i
, "%Y %b %d", &period
->end
);
1034 } else if (df
=='e') {
1035 i
=strftime(text2
, sizeof(text2
)-i
, "%d %b %Y", &period
->end
);
1037 i
=strftime(text2
, sizeof(text2
)-i
, "%Y.%U", &period
->end
);
1039 if (i
== 0) return(-1);
1043 snprintf(period
->text
,sizeof(period
->text
),"%s-%s",text1
,text2
);
1044 snprintf(period
->html
,sizeof(period
->html
),"%s—%s",text1
,text2
);
1046 safe_strcpy(period
->text
,text1
,sizeof(period
->text
));
1047 safe_strcpy(period
->html
,text1
,sizeof(period
->html
));
1052 static void copy_images(void)
1054 FILE *img_in
, *img_ou
;
1056 char srcfile
[MAXLEN
];
1057 char dstfile
[MAXLEN
];
1059 struct dirent
*direntp
;
1060 char buffer
[MAXLEN
];
1064 if (snprintf(images
,sizeof(images
),"%simages",outdir
)>=sizeof(images
)) {
1065 debuga(_("Cannot copy images to target directory %simages\n"),outdir
);
1068 if (access(images
,R_OK
)!=0) {
1069 if (PortableMkDir(images
,0755)) {
1070 debuga(_("Cannot create directory %s - %s\n"),images
,strerror(errno
));
1075 dirp
= opendir(ImageDir
);
1077 debuga(_("(util) Can't open directory %s: %s\n"),ImageDir
,strerror(errno
));
1080 while ((direntp
= readdir( dirp
)) != NULL
){
1081 if(direntp
->d_name
[0]=='.')
1083 if (snprintf(srcfile
,sizeof(srcfile
),"%s/%s",ImageDir
,direntp
->d_name
)>=sizeof(srcfile
)) {
1084 debuga(_("Buffer too small to store %s/%s"),ImageDir
,direntp
->d_name
);
1087 if (stat(srcfile
,&info
)) {
1088 debuga(_("Cannot stat \"%s\" - %s\n"),srcfile
,strerror(errno
));
1091 if (S_ISREG(info
.st_mode
)) {
1092 if (snprintf(dstfile
,sizeof(dstfile
),"%s/%s",images
,direntp
->d_name
)>=sizeof(dstfile
)) {
1093 debuga(_("Buffer too small to store %s/%s"),images
,direntp
->d_name
);
1096 img_in
= fopen(srcfile
, "rb");
1098 img_ou
= fopen(dstfile
, "wb");
1100 while ((nread
= fread(buffer
,1,sizeof(buffer
),img_in
))>0) {
1101 if (fwrite(buffer
,1,nread
,img_ou
)!=nread
) {
1102 debuga(_("Failed to copy image %s to %s\n"),srcfile
,dstfile
);
1106 if (fclose(img_ou
)==EOF
) {
1107 debuga(_("Error while copying image %s: %s\n"),dstfile
,strerror(errno
));
1111 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open/create file", dstfile
, strerror(errno
));
1114 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open file", srcfile
, strerror(errno
));
1117 (void) closedir(dirp
);
1123 * Check if the proposed file name conforms to the directory structure layed out
1124 * as a file tree. It is used to check if the file name enumerated while scanning
1125 * a directory content may have been created by sarg running with IndexTree set to
1128 bool IsTreeFileDirName(const char *Name
)
1133 // start year (date format u) or start day (date format e)
1134 if (!isdigit(Name
[0]) || !isdigit(Name
[1])) return(false);
1136 if (isdigit(Name
[2]) && isdigit(Name
[3]))
1138 // date format is either u or w
1142 if (!isdigit(Name
[5]) || !isdigit(Name
[6])) return(false);
1143 return(true);//date format w is confirmed
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])) return(false);
1161 else if (isalpha(Name
[2]) && isalpha(Name
[3]) && isalpha(Name
[4]))
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]) || !isdigit(Name
[2]) || !isdigit(Name
[3])) return(false);
1181 if (Name
[0]!='-') return(false);
1184 if (DateFormat
=='u')
1186 if (!isdigit(Name
[0]) || !isdigit(Name
[1]) || !isdigit(Name
[2]) || !isdigit(Name
[3])) return(false);
1189 if (!isalpha(Name
[0]) || !isalpha(Name
[1]) || !isalpha(Name
[2])) return(false);
1190 for (i
=11 ; i
>=0 && memcmp(mtab1
[i
],Name
,3) ; i
--);
1191 if (i
<0) return(false);
1194 if (!isdigit(Name
[0]) || !isdigit(Name
[1])) return(false);
1197 else //DateFormat=='e'
1199 if (!isdigit(Name
[0]) || !isdigit(Name
[1])) return(false);
1202 if (!isalpha(Name
[0]) || !isalpha(Name
[1]) || !isalpha(Name
[2])) return(false);
1203 for (i
=11 ; i
>=0 && memcmp(mtab1
[i
],Name
,3) ; i
--);
1204 if (i
<0) return(false);
1207 if (!isdigit(Name
[0]) || !isdigit(Name
[1]) || !isdigit(Name
[2]) || !isdigit(Name
[3])) return(false);
1211 * The directory name may contains additional characters such as a counter if
1212 * a previous report is never overwritten.
1218 * Check if the proposed file name can be the year part of a report tree build with
1219 * IndexTree set to INDEX_TREE_DATE.
1221 bool IsTreeYearFileName(const char *Name
)
1223 if (!isdigit(Name
[0]) || !isdigit(Name
[1]) || !isdigit(Name
[2]) || !isdigit(Name
[3])) return(false);
1228 if (!isdigit(Name
[0]) || !isdigit(Name
[1]) || !isdigit(Name
[2]) || !isdigit(Name
[3])) return(false);
1231 if (Name
[0]) return(false);
1236 * Check if the proposed file name can be the month part of a report tree build with
1237 * IndexTree set to INDEX_TREE_DATE.
1239 bool IsTreeMonthFileName(const char *Name
)
1243 if (!isdigit(Name
[0]) || !isdigit(Name
[1])) return(false);
1244 m
=(Name
[0]-'0')*10+(Name
[1]-'0');
1245 if (m
<1 || m
>12) return(false);
1250 if (!isdigit(Name
[0]) || !isdigit(Name
[1])) return(false);
1251 m
=(Name
[0]-'0')*10+(Name
[1]-'0');
1252 if (m
<1 || m
>12) return(false);
1255 if (Name
[0]) return(false);
1260 * Check if the proposed file name can be the day part of a report tree build with
1261 * IndexTree set to INDEX_TREE_DATE.
1263 bool IsTreeDayFileName(const char *Name
)
1267 if (!isdigit(Name
[0]) || !isdigit(Name
[1])) return(false);
1268 d
=(Name
[0]-'0')*10+(Name
[1]-'0');
1269 if (d
<1 || d
>31) return(false);
1273 if (!isdigit(Name
[0]) || !isdigit(Name
[1])) return(false);
1274 d
=(Name
[0]-'0')*10+(Name
[1]-'0');
1275 if (d
<1 || d
>31) return(false);
1278 * The directory name may contains additional characters such as a counter if
1279 * a previous report is never overwritten.
1284 int vrfydir(const struct periodstruct
*per1
, const char *addr
, const char *site
, const char *us
, const char *form
)
1289 char dirname2
[MAXLEN
];
1297 strcpy(wdir
,outdir
);
1299 y1
=per1
->start
.tm_year
+1900;
1300 y2
=per1
->end
.tm_year
+1900;
1301 m1
=per1
->start
.tm_mon
+1;
1302 m2
=per1
->end
.tm_mon
+1;
1303 d1
=per1
->start
.tm_mday
;
1304 d2
=per1
->end
.tm_mday
;
1305 if(IndexTree
== INDEX_TREE_DATE
) {
1306 wlen
+=sprintf(wdir
+wlen
,"%04d",y1
);
1307 if(y1
!=y2
) wlen
+=sprintf(wdir
+wlen
,"-%04d",y2
);
1308 if(access(wdir
, R_OK
) != 0)
1311 wlen
+=sprintf(wdir
+wlen
,"/%02d",m1
);
1312 if(m1
!= m2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",m2
);
1313 if(access(wdir
, R_OK
) != 0)
1316 wlen
+=sprintf(wdir
+wlen
,"/%02d",d1
);
1317 if(d1
!=d2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",d2
);
1320 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%04d%s%02d-%04d%s%02d",y1
,
1321 conv_month_name(m1
),d1
,y2
,conv_month_name(m2
),d2
);
1322 } else if (df
== 'e') {
1323 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%02d%s%04d-%02d%s%04d",d1
,
1324 conv_month_name(m1
),y1
,d2
,conv_month_name(m2
),y2
);
1325 } else if (df
== 'w') {
1326 wlen2
=strftime(wdir
+wlen
, sizeof(wdir
)-wlen
, "%Y.%U", &per1
->start
);
1327 if (wlen2
==0) return(-1);
1333 struct userinfostruct
*uinfo
=userinfo_find_from_id(us
);
1336 strcat(wdir
,uinfo
->filename
);
1339 if(addr
[0] != '\0') {
1343 if(site
[0] != '\0') {
1348 strcpy(outdirname
,wdir
);
1350 if(IndexTree
!= INDEX_TREE_DATE
) {
1351 if(!OverwriteReport
) {
1353 if(access(wdir
,R_OK
) == 0) {
1354 sprintf(wdir
,"%s.%d",outdirname
,num
);
1363 debuga(_("File %s already exists, moved to %s\n"),outdirname
,wdir
);
1364 rename(outdirname
,wdir
);
1367 if(access(outdirname
,R_OK
) == 0) {
1368 unlinkdir(outdirname
,1);
1371 my_mkdir(outdirname
);
1373 strcpy(dirname2
,wdir
);
1374 if(!OverwriteReport
) {
1376 if(access(wdir
,R_OK
) == 0) {
1377 sprintf(wdir
,"%s.%d",dirname2
,num
);
1386 debuga(_("File %s already exists, moved to %s\n"),dirname2
,wdir
);
1387 rename(dirname2
,wdir
);
1388 strcpy(dirname2
,wdir
);
1391 if(access(wdir
,R_OK
) == 0) {
1396 if(access(wdir
, R_OK
) != 0)
1400 strcpy(dirname2
,wdir
);
1402 if (snprintf(wdir
,sizeof(wdir
),"%s/sarg-date",outdirname
)>=sizeof(wdir
)) {
1403 debuga(_("Buffer too small to store %s/sarg-date"),outdirname
);
1406 if ((fp_ou
= fopen(wdir
, "wt")) == 0) {
1407 debuga(_("cannot open %s for writing: %s\n"),wdir
,strerror(errno
));
1412 //strftime(wdir,sizeof(wdir),"%a %b %d %H:%M:%S %Z %Y",localtime(&curtime));
1413 loctm
=localtime(&curtime
);
1414 strftime(wdir
,sizeof(wdir
),"%Y-%m-%d %H:%M:%S",loctm
);
1415 if (fprintf(fp_ou
,"%s %d\n",wdir
,loctm
->tm_isdst
)<0) {
1416 debuga(_("Failed to write the date in %s\n"),wdir
);
1420 if (fclose(fp_ou
)==EOF
) {
1421 debuga(_("Failed to write the date in %s: %s\n"),wdir
,strerror(errno
));
1430 Copy a string without overflowing the buffer. The copied string
1431 is properly terminated by an ASCII zero.
1433 \param dest The destination buffer.
1434 \param src The source buffer.
1435 \param length The size of the destination buffer. The program is aborted
1436 if the length is negative or zero.
1438 void safe_strcpy(char *dest
,const char *src
,int length
)
1441 debuga(_("Invalid buffer length passed to the function to safely copy a string\n"));
1444 strncpy(dest
,src
,length
-1);
1445 dest
[length
-1]='\0';
1448 void strip_latin(char *line
)
1455 for (i
=0;line
[i
];i
++){
1457 if (line
[i
]==';') skip
=0;
1469 void zdate(char *ftime
,int ftimesize
, char DateFormat
)
1475 local
= localtime(&t
);
1476 if (DateFormat
=='u')
1477 strftime(ftime
, ftimesize
, "%b/%d/%Y %H:%M", local
);
1478 else if (DateFormat
=='e')
1479 strftime(ftime
, ftimesize
, "%d/%b/%Y-%H:%M", local
);
1480 else if (DateFormat
=='w')
1481 strftime(ftime
, ftimesize
, "%W-%H-%M", local
);
1486 char *fixtime(long long int elap
)
1488 long int num
= elap
/ 1000LL;
1492 static char buf
[20];
1495 min
=(num
% 3600L) / 60L;
1498 if(hor
==0 && min
==0 && sec
==0)
1501 snprintf(buf
,sizeof(buf
),"%d:%02d:%02d",hor
,min
,sec
);
1507 void date_from(char *date
,int date_size
, int *dfrom
, int *duntil
)
1516 if (isdigit(date
[0])) {
1519 if (sscanf(date
,"%d/%d/%d%n",&d0
,&m0
,&y0
,&next
)!=3 || y0
<100 || m0
<1 || m0
>12 || d0
<1 || d0
>31 || next
<0) {
1520 debuga(_("The date passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1523 if (date
[next
]=='-') {
1524 if (sscanf(date
+next
+1,"%d/%d/%d",&d1
,&m1
,&y1
)!=3 || y1
<100 || m1
<1 || m1
>12 || d1
<1 || d1
>31) {
1525 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1528 } else if (date
[next
]!='\0') {
1529 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1539 struct tm
*Date0
,Date1
;
1541 if (time(&Today
)==(time_t)-1) {
1542 debuga(_("Failed to get the current time\n"));
1545 if (sscanf(date
,"day-%d",&i
)==1) {
1547 debuga(_("Invalid number of days in -d parameter\n"));
1551 Date0
=localtime(&Today
);
1553 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1556 y0
=y1
=Date0
->tm_year
+1900;
1557 m0
=m1
=Date0
->tm_mon
+1;
1558 d0
=d1
=Date0
->tm_mday
;
1559 } else if (sscanf(date
,"week-%d",&i
)==1) {
1561 There is no portable way to find the first day of the week even though the
1562 information is available in the locale. nl_langinfo has the unofficial
1563 parameters _NL_TIME_FIRST_WEEKDAY and _NL_TIME_WEEK_1STDAY but they are
1564 undocumented as is their return value and it is discouraged to use them.
1565 Beside, nl_langinfo isn't available on windows and the first day of the
1566 week isn't available at all on that system.
1568 const int FirstWeekDay
=1;
1572 debuga(_("Invalid number of weeks in -d parameter\n"));
1575 Date0
=localtime(&Today
);
1577 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1580 WeekBegin
=Today
-((Date0
->tm_wday
-FirstWeekDay
+7)%7)*24*60*60;
1581 WeekBegin
-=i
*7*24*60*60;
1582 Date0
=localtime(&WeekBegin
);
1584 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1587 y0
=Date0
->tm_year
+1900;
1590 WeekBegin
+=6*24*60*60;
1591 Date0
=localtime(&WeekBegin
);
1593 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1596 y1
=Date0
->tm_year
+1900;
1599 } else if (sscanf(date
,"month-%d",&i
)==1) {
1601 debuga(_("Invalid number of months in -d parameter\n"));
1604 Date0
=localtime(&Today
);
1606 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1609 if (Date0
->tm_mon
<i
%12) {
1610 y0
=Date0
->tm_year
+1900-i
/12-1;
1611 m0
=(Date0
->tm_mon
+12-i
%12)%12+1;
1614 y0
=Date0
->tm_year
+1900-i
/12;
1615 m0
=Date0
->tm_mon
-i
%12+1;
1618 memcpy(&Date1
,Date0
,sizeof(struct tm
));
1623 Date1
.tm_year
=y0
-1900;
1626 Date1
.tm_year
=y0
-1900+1;
1630 Date0
=localtime(&t1
);
1631 y1
=Date0
->tm_year
+1900;
1635 debuga(_("Invalid date range passed on command line\n"));
1640 *dfrom
=y0
*10000+m0
*100+d0
;
1641 *duntil
=y1
*10000+m1
*100+d1
;
1642 snprintf(date
,date_size
,"%02d/%02d/%04d-%02d/%02d/%04d",d0
,m0
,y0
,d1
,m1
,y1
);
1647 char *strlow(char *string
)
1653 for (s
= string
; *s
; ++s
)
1663 char *strup(char *string
)
1669 for (s
= string
; *s
; ++s
)
1677 void removetmp(const char *outdir
)
1682 if(!RemoveTempFiles
)
1686 debuga(_("Purging temporary file sarg-general\n"));
1688 if (snprintf(filename
,sizeof(filename
),"%s/sarg-general",outdir
)>=sizeof(filename
)) {
1689 debuga(_("(removetmp) directory too long to remove %s/sarg-period\n"),outdir
);
1692 if((fp_gen
=fopen(filename
,"w"))==NULL
){
1693 debuga(_("(removetmp) Cannot open file %s: %s\n"),filename
,strerror(errno
));
1696 totalger(fp_gen
,filename
);
1697 if (fclose(fp_gen
)==EOF
) {
1698 debuga(_("Failed to close %s after writing the total line: %s\n"),filename
,strerror(errno
));
1703 void load_excludecodes(const char *ExcludeCodes
)
1711 if(ExcludeCodes
[0] == '\0')
1714 if((fp_in
=fopen(ExcludeCodes
,"r"))==NULL
) {
1715 debuga(_("(util) Cannot open file %s (exclude_codes): %s\n"),ExcludeCodes
,strerror(errno
));
1719 if (fseek(fp_in
, 0, SEEK_END
)==-1) {
1720 debuga(_("Failed to move till the end of the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1723 MemSize
= ftell(fp_in
);
1725 debuga(_("Cannot get the size of file %s\n"),ExcludeCodes
);
1728 if (fseek(fp_in
, 0, SEEK_SET
)==-1) {
1729 debuga(_("Failed to rewind the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1734 if((excludecode
=(char *) malloc(MemSize
))==NULL
) {
1735 debuga(_("malloc error (%ld)\n"),MemSize
);
1738 memset(excludecode
,0,MemSize
);
1741 while(fgets(data
,sizeof(data
),fp_in
)!=NULL
) {
1742 if (data
[0]=='#') continue;
1743 for (i
=strlen(data
)-1 ; i
>=0 && (unsigned char)data
[i
]<=' ' ; i
--) data
[i
]='\0';
1745 if (Stored
+i
+2>=MemSize
) {
1746 debuga(_("Too many codes to exclude in file %s\n"),ExcludeCodes
);
1749 strcat(excludecode
,data
);
1750 strcat(excludecode
,";");
1758 void free_excludecodes(void)
1766 int vercode(const char *code
)
1771 if (excludecode
&& excludecode
[0]!='\0') {
1775 if (strncmp(code
,cod
,clen
)==0 && cod
[clen
]==';')
1777 cod
=strchr(cod
,';');
1784 void fixnone(char *str
)
1788 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--);
1789 if(i
==3 && strncmp(str
,"none",4) == 0)
1795 void fixendofline(char *str
)
1799 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--) str
[i
]=0;
1802 #ifdef LEGACY_TESTVALIDUSERCHAR
1803 int testvaliduserchar(const char *user
)
1808 for (y
=0; y
<strlen(UserInvalidChar
); y
++) {
1809 for (x
=0; x
<strlen(user
); x
++) {
1810 if(user
[x
] == UserInvalidChar
[y
])
1817 int testvaliduserchar(const char *user
)
1819 char * p_UserInvalidChar
= UserInvalidChar
;
1820 const char * p_user
;
1822 while( *p_UserInvalidChar
) {
1825 if( *p_UserInvalidChar
== *p_user
)
1829 p_UserInvalidChar
++ ;
1835 int compar( const void *a
, const void *b
)
1837 if( *(int *)a
> *(int *)b
) return 1;
1838 if( *(int *)a
< *(int *)b
) return -1;
1842 int getnumlist( char *buf
, numlist
*list
, const int len
, const int maxvalue
)
1844 int i
, j
, d
, flag
, r1
, r2
;
1845 char *pbuf
, **bp
, *strbufs
[ 24 ];
1848 strtok( buf
, " \t" );
1849 for( *bp
= strtok( NULL
, "," ), list
->len
= 0; *bp
; *bp
= strtok( NULL
, "," ) ) {
1850 if( ++bp
>= &strbufs
[ 24 ] )
1857 for( i
= 0; i
< list
->len
; i
++ ) {
1858 if( strchr( strbufs
[ i
], '-' ) != 0 ) {
1859 pbuf
= strbufs
[ i
];
1860 strtok( pbuf
, "-" );
1861 pbuf
= strtok( NULL
, "\0" );
1862 r1
= atoi( strbufs
[ i
] );
1863 if( ( r2
= atoi( pbuf
) ) >= maxvalue
|| r1
>= r2
)
1865 if( i
+ d
+ ( r2
- r1
) + 1 <= len
) {
1866 for( j
= r1
; j
<= r2
; j
++ )
1867 list
->list
[ i
+ d
++ ] = j
;
1872 if( ( list
->list
[ i
+ d
] = atoi( strbufs
[ i
] ) ) >= maxvalue
)
1876 qsort( list
->list
, list
->len
, sizeof( int ), compar
);
1879 for( i
= 0; i
< list
->len
- 1; i
++ )
1880 if( list
->list
[ i
] == list
->list
[ i
+ 1 ] ) {
1881 for( j
= i
+ 1; j
< list
->len
; j
++ )
1882 list
->list
[ j
- 1 ] = list
->list
[ j
];
1891 void show_info(FILE *fp_ou
)
1895 if(!ShowSargInfo
) return;
1896 zdate(ftime
, sizeof(ftime
), df
);
1897 fputs("<div class=\"info\">",fp_ou
);
1898 fprintf(fp_ou
,_("Generated by <a href='%s'>%s-%s</a> on %s"),URL
,PGM
,VERSION
,ftime
);
1899 fputs("</div>\n",fp_ou
);
1902 void show_sarg(FILE *fp_ou
, int depth
)
1906 if(!ShowSargLogo
) return;
1907 fputs("<div class=\"logo\"><a href=\"http://sarg.sourceforge.net\"><img src=\"",fp_ou
);
1908 for (i
=0 ; i
<depth
; i
++)
1910 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
);
1913 void write_logo_image(FILE *fp_ou
)
1915 if(LogoImage
[0]!='\0')
1916 fprintf(fp_ou
, "<div class=\"logo\"><img src=\"%s\" width=\"%s\" height=\"%s\" alt=\"Logo\"> %s</div>\n",LogoImage
,Width
,Height
,LogoText
);
1919 void write_html_head(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1923 fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n",fp_ou
);
1924 fprintf(fp_ou
, "<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n",CharSet
);
1925 if (page_title
) fprintf(fp_ou
,"<title>%s</title>\n",page_title
);
1927 if ((javascript
& HTML_JS_SORTTABLE
)!=0 && SortTableJs
[0]) {
1928 fputs("<script type=\"text/javascript\" src=\"",fp_ou
);
1929 if (strncmp(SortTableJs
,"../",3)==0) {
1930 for (i
=0 ; i
<depth
; i
++) fputs("../",fp_ou
);
1932 fputs(SortTableJs
,fp_ou
);
1933 fputs("\"></script>\n",fp_ou
);
1935 fputs("</head>\n<body>\n",fp_ou
);
1938 void write_html_header(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1940 write_html_head(fp_ou
,depth
,page_title
,javascript
);
1941 write_logo_image(fp_ou
);
1942 show_sarg(fp_ou
, depth
);
1943 fprintf(fp_ou
,"<div class=\"title\"><table cellpadding=\"0\" cellspacing=\"0\">\n<tr><th class=\"title_c\">%s</th></tr>\n",Title
);
1946 void close_html_header(FILE *fp_ou
)
1948 fputs("</table></div>\n",fp_ou
);
1951 int write_html_trailer(FILE *fp_ou
)
1954 if (fputs("</body>\n</html>\n",fp_ou
)==EOF
) return(-1);
1958 void output_html_string(FILE *fp_ou
,const char *str
,int maxlen
)
1962 while (*str
&& (maxlen
<=0 || i
<maxlen
)) {
1965 fputs("&",fp_ou
);
1968 fputs("<",fp_ou
);
1971 fputs(">",fp_ou
);
1974 fputs(""",fp_ou
);
1977 fputs("'",fp_ou
);
1985 if (maxlen
>0 && i
>=maxlen
)
1986 fputs("…",fp_ou
);
1989 void output_html_url(FILE *fp_ou
,const char *url
)
1993 fputs("&",fp_ou
);
2001 Write a host name inside an A tag of a HTML file. If the host name starts
2002 with a star, it is assumed to be an alias that cannot be put inside a link
2003 so the A tag is not written around the host name.
2005 \param fp_ou The handle of the HTML file.
2006 \param url The host to display in the HTML file.
2007 \param maxlen The maximum number of characters to print into the host name.
2009 void output_html_link(FILE *fp_ou
,const char *url
,int maxlen
)
2011 if (url
[0]==ALIAS_PREFIX
) {
2012 // this is an alias, no need for a A tag
2013 output_html_string(fp_ou
,url
+1,100);
2015 if (skip_scheme(url
)==url
)
2016 fputs("<a href=\"http://",fp_ou
);//no scheme in the url, assume http:// to make the link clickable
2018 fputs("<a href=\"",fp_ou
);//the scheme is in the url, no need to add one
2019 output_html_url(fp_ou
,url
);
2021 output_html_string(fp_ou
,url
,100);
2022 fputs("</a>",fp_ou
);
2026 void url_module(const char *url
, char *w2
)
2032 for(x
=strlen(url
)-1; x
>=0; x
--) {
2033 if(url
[x
] == '/' || y
>=sizeof(w
)-1) break;
2042 for(y
=y
-1; y
>=0; y
--) {
2049 Mangle an URL to produce a part that can be used as an anchor in
2050 a html <a name=""> tag.
2052 \param url The URL to mangle.
2053 \param anchor The buffer to write the mangled URL.
2054 \param size The size of the buffer.
2056 void url_to_anchor(const char *url
,char *anchor
,int size
)
2062 for (i
=0 ; url
[i
] && url
[i
]!='/' && url
[i
]!='?' ; i
++);
2069 // only keep really safe characters
2075 if(isalnum(url
[i
]) || url
[i
]=='-' || url
[i
]=='_' || url
[i
]=='.') {
2079 if (!skip
) anchor
[--j
]='_';
2097 printf(_("SARG Version: %s\n"),VERSION
);
2098 #if defined(ENABLE_NLS) && defined(HAVE_LOCALE_H)
2100 printf(_("\nFor the translation to work, a valid message file should be installed as "
2101 "\"%s/<Locale>/LC_MESSAGES/%s.mo\" where <Locale> is derived from the effective locale.\n"),LOCALEDIR
,PACKAGE_NAME
);
2102 if (CurrentLocale
) {
2103 printf(_("Currently effective locale is \"%s\".\n"),CurrentLocale
);
2105 printf(_("Locale is not set in the environment variable.\n"));
2107 // TRANSLATORS: You may change this message to tell the reader that the language is correctly supported.
2108 printf(_("If this message is in English, then your language is not supported or not correctly installed.\n"));
2114 char *get_param_value(const char *param
,char *line
)
2118 while (*line
==' ' || *line
=='\t') line
++;
2120 if (strncasecmp(line
,param
,plen
)) return(NULL
);
2121 if (line
[plen
]!=' ' && line
[plen
]!='\t') return(NULL
);
2123 while (*line
==' ' || *line
=='\t') line
++;
2127 void unlinkdir(const char *dir
,bool contentonly
)
2131 struct dirent
*direntp
;
2137 while ((direntp
= readdir(dirp
)) != NULL
) {
2138 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
2139 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
2141 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
2142 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
2146 err
=lstat(dname
,&st
);
2148 err
=stat(dname
,&st
);
2151 debuga(_("cannot stat %s\n"),dname
);
2154 if (S_ISREG(st
.st_mode
)) {
2155 if (unlink(dname
)) {
2156 debuga(_("Cannot delete \"%s\": %s\n"),dname
,strerror(errno
));
2159 } else if (S_ISDIR(st
.st_mode
)) {
2162 debuga(_("unknown path type %s\n"),dname
);
2169 debuga(_("Cannot delete \"%s\": %s\n"),dir
,strerror(errno
));
2176 Delete every file from the temporary directory where sarg is told to store its
2179 As any stray file left over by a previous run would be included in the report, we
2180 must delete every file from the temporary directory before we start processing the logs.
2182 But the temporary directory is given by the user either in the configuration file or
2183 on the command line. We check that the user didn't give a wrong directory by looking
2184 at the files stored in the directory. If a single file is not one of ours, we abort.
2186 \param dir The temporary directory to purge.
2188 void emptytmpdir(const char *dir
)
2192 struct dirent
*direntp
;
2198 static const char *TmpExt
[]=
2215 // make sure the temporary directory contains only our files
2216 while ((direntp
= readdir(dirp
)) != NULL
) {
2217 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
2218 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
2221 // is it one of our files
2222 dlen
=strlen(direntp
->d_name
);
2223 for (i
=sizeof(TmpExt
)/sizeof(TmpExt
[0])-1 ; i
>=0 ; i
--) {
2224 elen
=strlen(TmpExt
[i
]);
2225 if (dlen
>=elen
&& strcasecmp(direntp
->d_name
+dlen
-elen
,TmpExt
[i
])==0) break;
2228 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2229 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2230 "directory or manually delete the content of \"%s\"\n"),direntp
->d_name
,dir
,dir
);
2234 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
2235 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
2240 err
=lstat(dname
,&st
);
2242 err
=stat(dname
,&st
);
2245 debuga(_("cannot stat \"%s\"\n"),dname
);
2248 if (S_ISDIR(st
.st_mode
)) {
2250 } else if (!S_ISREG(st
.st_mode
)) {
2251 debuga(_("Unknown path type for \"%s\". Check temporary directory\n"),dname
);
2257 // now delete our files
2258 while ((direntp
= readdir(dirp
)) != NULL
) {
2259 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
2260 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
2263 // is it one of our files
2264 dlen
=strlen(direntp
->d_name
);
2265 for (i
=sizeof(TmpExt
)/sizeof(TmpExt
[0])-1 ; i
>=0 ; i
--) {
2266 elen
=strlen(TmpExt
[i
]);
2267 if (dlen
>=elen
&& strcasecmp(direntp
->d_name
+dlen
-elen
,TmpExt
[i
])==0) break;
2270 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2271 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2272 "directory or manually delete the content of \"%s\"\n"),direntp
->d_name
,dir
,dir
);
2276 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
2277 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
2281 err
=lstat(dname
,&st
);
2283 err
=stat(dname
,&st
);
2286 debuga(_("cannot stat \"%s\"\n"),dname
);
2289 if (S_ISREG(st
.st_mode
)) {
2290 if (unlink(dname
)) {
2291 debuga(_("Cannot delete \"%s\": %s\n"),dname
,strerror(errno
));
2295 debuga(_("unknown path type %s\n"),dname
);
2302 Extract an url, IPv4 or IPv6 from a buffer. The IP addresses may end with a
2305 \param buf The buffer to parse.
2306 \param text A pointer to set to the beginning of the string pattern. No terminating zero is inserted.
2307 The pointer may be NULL.
2308 \param ipv4 A 4 bytes buffer to store the bytes of the IPv4 address.
2309 \param ipv6 A 8 short integers buffer to store the values of the IPv6 address.
2310 \param nbits The number of prefix bits for an IP address.
2311 \param next The content of the line after the extracted address.
2313 \retval 3 The pattern is a IPv6 address.
2314 \retval 2 The pattern is a IPv4 address.
2315 \retval 1 The patter is a string.
2316 \retval 0 Empty pattern.
2318 int extract_address_mask(const char *buf
,const char **text
,unsigned char *ipv4
,unsigned short int *ipv6
,int *nbits
,const char **next
)
2323 unsigned int value4
, value6
;
2324 unsigned short int addr
[8];
2334 // skip leading spaces and tabs
2335 while (*buf
&& (*buf
==' ' || *buf
=='\t')) buf
++;
2337 // find out the nature of the pattern
2338 ip_size
=0x60 | 0x04;
2349 for (i
=0 ; (unsigned char)buf
[i
]>' ' && buf
[i
]!='/' && buf
[i
]!='?' && (!bracket
|| buf
[i
]!=']') && ip_size
; i
++) {
2350 if (ip_size
& 0x04) {
2351 if (isdigit(buf
[i
])) {
2353 port_num
=port_num
*10+(buf
[i
]-'0');
2354 if (port_num
>65535) ip_size
&=~0x04;
2356 value4
=value4
*10+(buf
[i
]-'0');
2357 if (value4
>0xFFU
) ip_size
&=~0x04;
2359 } else if (buf
[i
]=='.' && addr_len
<4) {
2360 addr
[addr_len
++]=(unsigned short)(value4
& 0xFFU
);
2362 } else if (!port
&& buf
[i
]==':') {
2368 if (ip_size
& 0x60) {
2369 if (isdigit(buf
[i
])) {
2370 value6
=(value6
<<4)+(buf
[i
]-'0');
2372 if (value6
>0xFFFFU
) ip_size
&=~0x60;
2373 } else if (toupper(buf
[i
])>='A' && toupper(buf
[i
])<='F') {
2374 value6
=(value6
<<4)+(toupper(buf
[i
])-'A'+10);
2376 if (value6
>0xFFFFU
) ip_size
&=~0x60;
2377 } else if (buf
[i
]==':' && addr_len
<8) {
2378 if (nibble6_len
>0) {
2379 addr
[addr_len
++]=(unsigned short)(value6
& 0xFFFFU
);
2383 if (buf
[i
+1]==':') {
2392 if (i
==0) return(0);
2393 if (ip_size
& 0x04) {
2397 addr
[addr_len
++]=(unsigned short)(value4
& 0xFFU
);
2399 if (ip_size
& 0x60) {
2400 if (pad_pos
<0 && addr_len
!=7) {
2402 } else if (pad_pos
>=0 && addr_len
>=7)
2404 else if (nibble6_len
>0)
2405 addr
[addr_len
++]=(unsigned short)(value6
& 0xFFFFU
);
2410 if (bracket
) (*text
)--;
2412 while ((unsigned char)buf
[i
]>' ') i
++;
2413 if (next
) *next
=buf
+i
;
2416 max_mask
=(ip_size
& 0x04) ? 4*8 : 8*16;
2420 while (isdigit(buf
[i
])) i
++;
2421 if (mask
<0 || mask
>max_mask
) mask
=max_mask
;
2424 if (ip_size
& 0x60 && bracket
&& buf
[i
]==']') i
++;
2425 if (next
) *next
=buf
+i
;
2426 if (ip_size
& 0x04) {
2427 if (nbits
) *nbits
=mask
;
2428 for (i
=0 ; i
<addr_len
; i
++)
2429 ipv4
[i
]=(unsigned char)addr
[i
];
2434 if (nbits
) *nbits
=mask
;
2439 ipv6
[j
++]=(unsigned short int)addr
[i
++];
2441 while (j
<pad_pos
+pad_len
)
2445 ipv6
[j
++]=(unsigned short int)addr
[i
++];