]>
git.ipfire.org Git - thirdparty/sarg.git/blob - util.c
2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
6 * please look at http://sarg.sourceforge.net/donations.php
8 * http://sourceforge.net/projects/sarg/forums/forum/363374
9 * ---------------------------------------------------------------------
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
27 // #define LEGACY_MY_ATOLL
28 // #define LEGACY_TESTVALIDUSERCHAR
30 #include "include/conf.h"
31 #include "include/defs.h"
33 #if defined(HAVE_BACKTRACE)
34 #define USE_GETWORD_BACKTRACE 1
36 #define USE_GETWORD_BACKTRACE 0
39 static char mtab1
[12][4]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
41 //! The list of the HTTP codes to exclude from the report.
42 static char *excludecode
=NULL
;
44 #if USE_GETWORD_BACKTRACE
45 static void getword_backtrace(void)
51 n
=backtrace(buffer
,sizeof(buffer
)/sizeof(buffer
[0]));
53 calls
=backtrace_symbols(buffer
,n
);
55 debuga(_("getword backtrace:\n"));
56 for (i
=0 ; i
<n
; i
++) {
57 fprintf(stderr
,"SARG: %d:%s\n",i
+1,calls
[i
]);
62 #endif //USE_GETWORD_BACKTRACE
64 void getword_start(struct getwordstruct
*gwarea
, const char *line
)
66 gwarea
->beginning
=line
;
71 void getword_restart(struct getwordstruct
*gwarea
)
73 if (gwarea
->modified
) {
74 debuga(_("Cannot parse again the line as it was modified\n"));
77 gwarea
->current
=gwarea
->beginning
;
80 int getword(char *word
, int limit
, struct getwordstruct
*gwarea
, char stop
)
84 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++) {
86 debuga(_("getword loop detected after %d bytes.\n"),x
);
87 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
88 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
89 debuga(_("searching for \'x%x\'\n"),stop
);
90 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
91 word
[(limit
>0) ? limit
-1 : 0]='\0';
92 #if USE_GETWORD_BACKTRACE
97 word
[x
] = gwarea
->current
[x
];
101 if (gwarea
->current
[x
]) ++x
;
106 int getword_limit(char *word
, int limit
, struct getwordstruct
*gwarea
, char stop
)
111 for(x
=0; x
<limit
&& gwarea
->current
[x
] && gwarea
->current
[x
] != stop
;x
++) {
112 word
[x
] = gwarea
->current
[x
];
116 while (*gwarea
->current
&& *gwarea
->current
!= stop
) gwarea
->current
++;
117 if (*gwarea
->current
) ++gwarea
->current
;
121 int getword_multisep(char *word
, int limit
, struct getwordstruct
*gwarea
, char stop
)
125 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++) {
127 debuga(_("getword_multisep loop detected.\n"));
128 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
129 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
130 debuga(_("searching for \'x%x\'\n"),stop
);
131 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
132 if (limit
>0) word
[limit
-1]='\0';
133 #if USE_GETWORD_BACKTRACE
136 //exit(EXIT_FAILURE);
139 word
[x
] = gwarea
->current
[x
];
143 while (gwarea
->current
[x
] && gwarea
->current
[x
]==stop
) ++x
;
148 int getword_skip(int limit
, struct getwordstruct
*gwarea
, char stop
)
152 for(x
=0;(gwarea
->current
[x
] && (gwarea
->current
[x
] != stop
));x
++) {
154 debuga(_("getword_skip loop detected after %d bytes.\n"),x
);
155 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
156 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
157 debuga(_("searching for \'x%x\'\n"),stop
);
158 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
159 #if USE_GETWORD_BACKTRACE
166 if (gwarea
->current
[x
]) ++x
;
171 int getword_atoll(long long int *number
, struct getwordstruct
*gwarea
, char stop
)
177 if (gwarea
->current
[0] == '-') {
180 } else if (gwarea
->current
[0] == '+') {
184 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
185 digit
=gwarea
->current
[x
]-'0';
186 if (*number
>= (LLONG_MAX
-digit
)/10) {
187 debuga(_("Integer overflow detected in getword_atoll in line %s\n"),gwarea
->beginning
);
190 *number
=(*number
* 10) + digit
;
192 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
193 debuga(_("getword_atoll loop detected after %d bytes.\n"),x
);
194 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
195 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
196 debuga(_("searching for \'x%x\'\n"),stop
);
197 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
198 #if USE_GETWORD_BACKTRACE
205 if (gwarea
->current
[x
]) ++x
;
210 int getword_atoi(int *number
, struct getwordstruct
*gwarea
, char stop
)
216 if (gwarea
->current
[0] == '-') {
219 } else if (gwarea
->current
[0] == '+') {
223 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
224 digit
=gwarea
->current
[x
]-'0';
225 if (*number
> (INT_MAX
-digit
)/10) {
226 debuga(_("Integer overflow detected in getword_atoi in line %s\n"),gwarea
->beginning
);
229 *number
=(*number
* 10) + digit
;
231 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
232 debuga(_("getword_atoi loop detected after %d bytes.\n"),x
);
233 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
234 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
235 debuga(_("searching for \'x%x\'\n"),stop
);
236 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
237 #if USE_GETWORD_BACKTRACE
244 if (gwarea
->current
[x
]) ++x
;
249 int getword_atol(long int *number
, struct getwordstruct
*gwarea
, char stop
)
255 if (gwarea
->current
[0] == '-') {
258 } else if (gwarea
->current
[0] == '+') {
262 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
263 digit
=gwarea
->current
[x
]-'0';
264 if (*number
> (LONG_MAX
-digit
)/10) {
265 debuga(_("Integer overflow detected in getword_atol in line %s\n"),gwarea
->beginning
);
268 *number
=(*number
* 10) + digit
;
270 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
271 debuga(_("getword_atol loop detected after %ld bytes.\n"),x
);
272 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
273 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
274 debuga(_("searching for \'x%x\'\n"),stop
);
275 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
276 #if USE_GETWORD_BACKTRACE
283 if (gwarea
->current
[x
]) ++x
;
288 int getword_atolu(unsigned long int *number
, struct getwordstruct
*gwarea
, char stop
)
293 if (gwarea
->current
[0] == '-') {
294 debuga(_("getword_atolu got a negative number.\n"));
295 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
296 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
299 if (gwarea
->current
[0] == '+') {
303 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
304 digit
=gwarea
->current
[x
]-'0';
305 if (*number
> (ULONG_MAX
-digit
)/10) {
306 debuga(_("Integer overflow detected in getword_atolu in line %s\n"),gwarea
->beginning
);
309 *number
=(*number
* 10) + digit
;
311 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
312 debuga(_("getword_atolu loop detected after %ld bytes.\n"),x
);
313 debuga(_("Line=\"%s\"\n"),gwarea
->beginning
);
314 debuga(_("Record=\"%s\"\n"),gwarea
->current
);
315 debuga(_("searching for \'x%x\'\n"),stop
);
316 //debuga(_("Maybe you have a broken record or garbage in your access.log file.\n"));
317 #if USE_GETWORD_BACKTRACE
323 if (gwarea
->current
[x
]) ++x
;
329 int getword_ptr(char *orig_line
,char **word
, struct getwordstruct
*gwarea
, char stop
)
332 \note Why pass the original buffer to the function ? Because we must modify it to
333 insert the terminating ASCII zero for the word we return and that's not compatible
334 with getword_restart(). Moreover, getword_start() sometime works on constant strings
335 so this function require the original buffer to detect any missuse.
341 if (orig_line
&& orig_line
!=gwarea
->beginning
) {
342 debuga(_("Invalid buffer passed to getword_ptr\n"));
346 start
=(gwarea
->current
-gwarea
->beginning
);
347 if (word
&& orig_line
) *word
=orig_line
+start
;
348 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++);
349 sep
=(gwarea
->current
[x
]!='\0');
350 if (word
&& orig_line
) orig_line
[start
+x
] = '\0';
357 #define MAXLLL 30 //!< Maximum number of digits in long long (a guess).
358 long long int my_atoll (const char *nptr
)
360 long long int returnval
=0LL;
361 int max_digits
= MAXLLL
;
363 // Soak up all the white space
364 while (isspace( *nptr
)) {
368 //For each character left to right
369 //change the character to a single digit
370 //multiply what we had before by 10 and add the new digit
372 while (--max_digits
&& isdigit( *nptr
))
374 returnval
= ( returnval
* 10 ) + ( *nptr
++ - '0' ) ;
380 int is_absolute(const char *path
)
382 if (*path
=='/') return(1);
384 if (isalpha(path
[0]) && path
[1]==':') return(1);
389 void my_mkdir(const char *name
)
395 if(!is_absolute(name
)) {
396 debuga(_("Invalid path (%s). Please, use absolute paths only.\n"),name
);
401 for (i
=0 ; name
[i
] ; i
++) {
403 debuga(_("directory name too long: %s\n"),name
);
406 if (chars
>0 && name
[i
] == '/') {
408 if (access(w0
, R_OK
) != 0) {
409 if (mkdir(w0
,0755)) {
410 debuga(_("Cannot create directory %s - %s\n"),w0
,strerror(errno
));
415 if (name
[i
] != '/') chars
++;
419 if (access(name
, R_OK
) != 0) {
420 if (mkdir(name
,0755)) {
421 debuga(_("Cannot create directory %s - %s\n"),name
,strerror(errno
));
428 void my_lltoa(unsigned long long int n
, char *s
, int ssize
, int len
)
437 debuga(_("The requested number of digits passed to my_lltoa (%d) is bigger than the output buffer size (%d)\n"),len
,ssize
);
442 s
[slen
++] = (n
% 10) + '0';
443 } while ((n
/= 10) > 0 && slen
<ssize
);
446 for (i
= 0, j
= slen
-1; i
<j
; i
++, j
--) {
454 for(j
=slen
; j
>=0; j
--)
461 int month2num(const char *month
)
465 for(m
=0 ; m
<12 && strcmp(mtab1
[m
],month
) != 0; m
++);
469 int builddia(int day
, int month
, int year
)
471 return(year
*10000+month
*100+day
);
475 void buildymd(const char *dia
, const char *mes
, const char *ano
, char *wdata
)
480 sprintf(wdata
,"%04d%02d%02d",atoi(ano
),nmes
+1,atoi(dia
));
484 int conv_month(const char *month
)
488 for(x
=0; x
<12 && strncmp(mtab1
[x
],month
,3)!=0; x
++);
493 const char *conv_month_name(int month
)
497 if (month
<1 || month
>12) {
498 snprintf(str
,sizeof(str
),"%03d",month
);
501 return(mtab1
[month
-1]);
505 void name_month(char *month
,int month_len
)
507 int x
, z
=atoi(month
)-1;
510 struct getwordstruct gwarea
;
512 strcpy(m
,_("January,February,March,April,May,June,July,August,September,October,November,December"));
513 getword_start(&gwarea
,m
);
516 if (getword_multisep(w
,sizeof(w
),&gwarea
,',')<0) {
517 debuga(_("The internal list of month names is invalid. Please report this bug to the translator.\n"));
520 if (getword_multisep(month
,month_len
,&gwarea
,',')<0) {
521 debuga(_("The internal list of month names is invalid. Please report this bug to the translator.\n"));
528 Write a debug message to stderr. The message is prefixed by "SARG:" to identify its origin.
530 \param msg The printf like message to format.
531 \param ... The arguments to format in the message.
533 void debuga(const char *msg
,...)
537 fputs(_("SARG: "),stderr
);
539 vfprintf(stderr
,msg
,ap
);
545 Write a debug message to stderr. The message is prefixed by "SARG: (info)".
547 \param msg The printf like message to format.
548 \param ... The arguments to format in the message.
550 void debugaz(const char *msg
,...)
554 fputs(_("SARG: (info) "),stderr
);
556 vfprintf(stderr
,msg
,ap
);
561 char *fixnum(long long int value
, int n
)
563 #define MAXLEN_FIXNUM 256
564 char num
[MAXLEN_FIXNUM
]="";
565 char buf
[MAXLEN_FIXNUM
* 2];
567 static char ret
[MAXLEN_FIXNUM
* 2];
569 register int i
, j
, k
;
571 static char abbrev
[30];
573 my_lltoa(value
, num
, sizeof(num
), 0);
575 if(DisplayedValues
==DISPLAY_ABBREV
) {
576 numlen
= strlen(num
);
578 sprintf(abbrev
,"%s",num
);
579 if(numlen
== 4 || numlen
== 7 || numlen
== 10 || numlen
== 13) {
580 snprintf(abbrev
,2,"%s",num
);
581 strncat(abbrev
,".",1);
582 strncat(abbrev
,num
+1,2);
583 if(!n
) return(abbrev
);
585 strncat(abbrev
,"K",1);
587 strncat(abbrev
,"M",1);
588 else if(numlen
== 10)
589 strncat(abbrev
,"G",1);
590 else if(numlen
== 13)
591 strncat(abbrev
,"T",1);
593 if(numlen
== 5 || numlen
== 8 || numlen
== 11 || numlen
== 14) {
594 snprintf(abbrev
,3,"%s",num
);
595 strncat(abbrev
,".",1);
596 strncat(abbrev
,num
+2,2);
597 if(!n
) return(abbrev
);
599 strncat(abbrev
,"K",1);
601 strncat(abbrev
,"M",1);
602 else if(numlen
== 11)
603 strncat(abbrev
,"G",1);
604 else if(numlen
== 14)
605 strncat(abbrev
,"T",1);
607 if(numlen
== 6 || numlen
== 9 || numlen
== 12 || numlen
== 15) {
608 snprintf(abbrev
,4,"%s",num
);
609 strncat(abbrev
,".",1);
610 strncat(abbrev
,num
+3,2);
611 if(!n
) return(abbrev
);
613 strncat(abbrev
,"K",1);
615 strncat(abbrev
,"M",1);
616 else if(numlen
== 12)
617 strncat(abbrev
,"G",1);
618 else if(numlen
== 15)
619 strncat(abbrev
,"T",1);
625 bzero(buf
, MAXLEN_FIXNUM
*2);
631 for ( i
= strlen(num
) - 1, j
= 0 ; i
> -1; i
--) {
632 if ( k
== 2 && i
!= 0 ) {
635 pbuf
[j
++] = (UseComma
) ? ',' : '.';
645 for ( i
= strlen(pbuf
) - 1, j
= 0 ; i
> -1; i
--, j
++)
654 char *fixnum2(long long int value
, int n
)
656 #define MAXLEN_FIXNUM2 1024
657 char num
[MAXLEN_FIXNUM2
];
658 char buf
[MAXLEN_FIXNUM2
* 2];
660 static char ret
[MAXLEN_FIXNUM2
* 2];
662 register int i
, j
, k
;
664 my_lltoa(value
, num
, sizeof(num
), 0);
665 bzero(buf
, MAXLEN_FIXNUM2
*2);
671 for ( i
= strlen(num
) - 1, j
= 0 ; i
> -1; i
--) {
672 if ( k
== 2 && i
!= 0 ) {
675 pbuf
[j
++] = (UseComma
) ? ',' : '.';
685 for ( i
= strlen(pbuf
) - 1, j
= 0 ; i
> -1; i
--, j
++)
694 char *buildtime(long long int elap
)
696 int num
= elap
/ 1000;
705 min
=(num
% 3600) / 60;
707 sprintf(buf
,"%02d:%02d:%02d",hor
,min
,sec
);
714 Get the date stored in the <tt>sarg-date</tt> file of a directory with the connection data.
716 \param dirname The directory to look for the connection directory.
717 \param name The name of the directory whose <tt>sarg-date</tt> file must be read.
718 \param data The buffer to store the content of the file. It must be more than 80
722 \retval -1 File not found.
724 int obtdate(const char *dirname
, const char *name
, char *data
)
729 sprintf(wdir
,"%s%s/sarg-date",dirname
,name
);
730 if ((fp_in
= fopen(wdir
, "rt")) == 0) {
731 sprintf(wdir
,"%s%s/date",dirname
,name
);
732 if ((fp_in
= fopen(wdir
, "rt")) == 0) {
738 if (!fgets(data
,80,fp_in
)) {
739 debuga(_("Failed to read the date in %s\n"),wdir
);
749 void formatdate(char *date
,int date_size
,int year
,int month
,int day
,int hour
,int minute
,int second
,int dst
)
755 memset(<m
,0,sizeof(ltm
));
756 if (year
>=1900) ltm
.tm_year
=year
-1900;
757 if (month
>=1 && month
<=12) ltm
.tm_mon
=month
-1;
758 if (day
>=1 && day
<=31) ltm
.tm_mday
=day
;
759 if (hour
>=0 && hour
<24) ltm
.tm_hour
=hour
;
760 if (minute
>=0 && minute
<60) ltm
.tm_min
=minute
;
761 if (second
>=0 && second
<60) ltm
.tm_sec
=second
;
763 unixtime
=mktime(<m
); //fill the missing entries
764 fulltm
=localtime(&unixtime
);
765 //strftime(date,date_size,"%a %b %d %H:%M:%S %Z %Y",fulltm);
766 strftime(date
,date_size
,"%c",fulltm
);
770 void computedate(int year
,int month
,int day
,struct tm
*t
)
772 memset(t
,0,sizeof(*t
));
773 t
->tm_year
=year
-1900;
779 int obtuser(const char *dirname
, const char *name
)
786 sprintf(wdir
,"%s%s/sarg-users",dirname
,name
);
787 if((fp_in
=fopen(wdir
,"r"))==NULL
) {
788 sprintf(wdir
,"%s%s/users",dirname
,name
);
789 if((fp_in
=fopen(wdir
,"r"))==NULL
) {
794 if (!fgets(tuser
,sizeof(tuser
),fp_in
)) {
795 debuga(_("Failed to read the number of users in %s\n"),wdir
);
805 void obttotal(const char *dirname
, const char *name
, int nuser
, long long int *tbytes
, long long int *media
)
810 char user
[MAX_USER_LEN
];
812 struct getwordstruct gwarea
;
818 sprintf(wdir
,"%s%s/sarg-general",dirname
,name
);
819 if ((fp_in
= fopen(wdir
, "r")) == 0) {
820 sprintf(wdir
,"%s%s/general",dirname
,name
);
821 if ((fp_in
= fopen(wdir
, "r")) == 0) {
826 if ((line
=longline_create())==NULL
) {
827 debuga(_("Not enough memory to read the file %s\n"),wdir
);
831 while((buf
=longline_read(fp_in
,line
))!=NULL
) {
832 if (strncmp(buf
,"TOTAL\t",6) == 0)
834 else if (strncmp(buf
,"TOTAL ",6) == 0)
838 getword_start(&gwarea
,buf
);
839 if (getword(user
,sizeof(user
),&gwarea
,sep
)<0) {
840 debuga(_("There is a invalid user in file %s\n"),wdir
);
843 if(strcmp(user
,"TOTAL") != 0)
845 if (getword_skip(MAXLEN
,&gwarea
,sep
)<0) {
846 debuga(_("There a broken total number of access in file %s\n"),wdir
);
849 if (getword_atoll(tbytes
,&gwarea
,sep
)<0) {
850 debuga(_("There is a broken number of bytes in file %s\n"),wdir
);
856 longline_destroy(&line
);
861 *media
=*tbytes
/ nuser
;
865 int getperiod_fromsarglog(const char *arqtt
,struct periodstruct
*period
)
868 int day0
, month0
, year0
, hour0
, minute0
;
869 int day1
, month1
, year1
, hour1
, minute1
;
872 memset(period
,0,sizeof(*period
));
875 while((str
=strstr(str
,"sarg-"))!=NULL
) {
877 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
878 day0
=(str
[0]-'0')*10+(str
[1]-'0');
879 if (day0
<1 || day0
>31) continue;
881 month0
=(str
[0]-'0')*10+(str
[1]-'0')-1;
882 if (month0
<0 || month0
>11) continue;
885 for (i
=0 ; isdigit(str
[i
]) && i
<4 ; i
++) year0
=year0
*10+(str
[i
]-'0');
888 if (str
[0]!='_') continue;
891 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
892 hour0
=(str
[0]-'0')*10+(str
[1]-'0');
894 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
895 minute0
=(str
[0]-'0')*10+(str
[1]-'0');
898 if (*str
!= '-') continue;
901 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
902 day1
=(str
[0]-'0')*10+(str
[1]-'0');
903 if (day1
<1 || day1
>31) continue;
905 month1
=(str
[0]-'0')*10+(str
[1]-'0')-1;
906 if (month1
<0 || month1
>11) continue;
909 for (i
=0 ; isdigit(str
[i
]) && i
<4 ; i
++) year1
=year1
*10+(str
[i
]-'0');
913 if (str
[0]!='_') continue;
916 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
917 hour1
=(str
[0]-'0')*10+(str
[1]-'0');
919 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
920 minute1
=(str
[0]-'0')*10+(str
[1]-'0');
923 period
->start
.tm_mday
=day0
;
924 period
->start
.tm_mon
=month0
;
925 period
->start
.tm_year
=year0
-1900;
926 period
->start
.tm_hour
=hour0
;
927 period
->start
.tm_min
=minute0
;
928 period
->end
.tm_mday
=day1
;
929 period
->end
.tm_mon
=month1
;
930 period
->end
.tm_year
=year1
-1900;
931 period
->end
.tm_hour
=hour1
;
932 period
->end
.tm_min
=minute1
;
938 void getperiod_fromrange(struct periodstruct
*period
,int dfrom
,int duntil
)
940 memset(&period
->start
,0,sizeof(period
->start
));
941 period
->start
.tm_mday
=dfrom
%100;
942 period
->start
.tm_mon
=(dfrom
/100)%100-1;
943 period
->start
.tm_year
=(dfrom
/10000)-1900;
945 memset(&period
->end
,0,sizeof(period
->end
));
946 period
->end
.tm_mday
=duntil
%100;
947 period
->end
.tm_mon
=(duntil
/100)%100-1;
948 period
->end
.tm_year
=(duntil
/10000)-1900;
952 Update the \a main period to encompass the period in \a candidate.
954 void getperiod_merge(struct periodstruct
*main
,struct periodstruct
*candidate
)
959 mdate
=(main
->start
.tm_year
)*10000+(main
->start
.tm_mon
)*100+main
->start
.tm_mday
;
960 cdate
=(candidate
->start
.tm_year
)*10000+(candidate
->start
.tm_mon
)*100+candidate
->start
.tm_mday
;
961 if (cdate
<mdate
) memcpy(&main
->start
,&candidate
->start
,sizeof(struct tm
));
963 mdate
=(main
->end
.tm_year
)*10000+(main
->end
.tm_mon
)*100+main
->end
.tm_mday
;
964 cdate
=(candidate
->end
.tm_year
)*10000+(candidate
->end
.tm_mon
)*100+candidate
->end
.tm_mday
;
965 if (cdate
>mdate
) memcpy(&main
->end
,&candidate
->end
,sizeof(struct tm
));
968 int getperiod_buildtext(struct periodstruct
*period
)
972 char text1
[40], text2
[40];
975 i
=strftime(text1
, sizeof(text1
), "%Y %b %d", &period
->start
);
977 i
=strftime(text1
, sizeof(text1
), "%d %b %Y", &period
->start
);
978 } else /*if (df=='w')*/ {
979 IndexTree
=INDEX_TREE_FILE
;
980 i
=strftime(text1
, sizeof(text1
), "%Y.%U", &period
->start
);
982 if (i
== 0) return(-1);
984 range
=(period
->start
.tm_year
!=period
->end
.tm_year
||
985 period
->start
.tm_mon
!=period
->end
.tm_mon
||
986 period
->start
.tm_mday
!=period
->end
.tm_mday
);
989 i
=strftime(text2
, sizeof(text2
)-i
, "%Y %b %d", &period
->end
);
990 } else if (df
=='e') {
991 i
=strftime(text2
, sizeof(text2
)-i
, "%d %b %Y", &period
->end
);
993 i
=strftime(text2
, sizeof(text2
)-i
, "%Y.%U", &period
->end
);
995 if (i
== 0) return(-1);
999 snprintf(period
->text
,sizeof(period
->text
),"%s-%s",text1
,text2
);
1000 snprintf(period
->html
,sizeof(period
->html
),"%s—%s",text1
,text2
);
1002 safe_strcpy(period
->text
,text1
,sizeof(period
->text
));
1003 safe_strcpy(period
->html
,text1
,sizeof(period
->html
));
1008 static void copy_images(void)
1010 FILE *img_in
, *img_ou
;
1012 char imgdir
[MAXLEN
];
1013 char srcfile
[MAXLEN
];
1014 char dstfile
[MAXLEN
];
1016 struct dirent
*direntp
;
1017 char buffer
[MAXLEN
];
1021 if (snprintf(images
,sizeof(images
),"%simages",outdir
)>=sizeof(images
)) {
1022 debuga(_("Cannot copy images to target directory %simages\n"),outdir
);
1025 if (access(images
,R_OK
)!=0) {
1026 if (mkdir(images
,0755)) {
1027 debuga(_("Cannot create directory %s - %s\n"),images
,strerror(errno
));
1032 strcpy(imgdir
,IMAGEDIR
);
1033 dirp
= opendir(imgdir
);
1035 debuga(_("(util) Can't open directory %s: %s\n"),imgdir
,strerror(errno
));
1038 while ((direntp
= readdir( dirp
)) != NULL
){
1039 if(direntp
->d_name
[0]=='.')
1041 sprintf(srcfile
,"%s/%s",imgdir
,direntp
->d_name
);
1042 if (stat(srcfile
,&info
)) {
1043 debuga(_("Cannot stat \"%s\" - %s\n"),srcfile
,strerror(errno
));
1046 if (S_ISREG(info
.st_mode
)) {
1047 sprintf(dstfile
,"%s/%s",images
,direntp
->d_name
);
1048 img_in
= fopen(srcfile
, "rb");
1050 img_ou
= fopen(dstfile
, "wb");
1052 while ((nread
= fread(buffer
,1,sizeof(buffer
),img_in
))>0) {
1053 if (fwrite(buffer
,1,nread
,img_ou
)!=nread
) {
1054 debuga(_("Failed to copy image %s to %s\n"),srcfile
,dstfile
);
1060 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open/create file", dstfile
, strerror(errno
));
1063 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open file", srcfile
, strerror(errno
));
1066 (void) closedir(dirp
);
1071 int vrfydir(const struct periodstruct
*per1
, const char *addr
, const char *site
, const char *us
, const char *form
)
1076 char dirname2
[MAXLEN
];
1084 strcpy(wdir
,outdir
);
1086 y1
=per1
->start
.tm_year
+1900;
1087 y2
=per1
->end
.tm_year
+1900;
1088 m1
=per1
->start
.tm_mon
+1;
1089 m2
=per1
->end
.tm_mon
+1;
1090 d1
=per1
->start
.tm_mday
;
1091 d2
=per1
->end
.tm_mday
;
1092 if(IndexTree
== INDEX_TREE_DATE
) {
1093 wlen
+=sprintf(wdir
+wlen
,"%04d",y1
);
1094 if(y1
!=y2
) wlen
+=sprintf(wdir
+wlen
,"-%04d",y2
);
1095 if(access(wdir
, R_OK
) != 0)
1098 wlen
+=sprintf(wdir
+wlen
,"/%02d",m1
);
1099 if(m1
!= m2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",m2
);
1100 if(access(wdir
, R_OK
) != 0)
1103 wlen
+=sprintf(wdir
+wlen
,"/%02d",d1
);
1104 if(d1
!=d2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",d2
);
1107 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%04d%s%02d-%04d%s%02d",y1
,
1108 conv_month_name(m1
),d1
,y2
,conv_month_name(m2
),d2
);
1109 } else if (df
== 'e') {
1110 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%02d%s%04d-%02d%s%04d",d1
,
1111 conv_month_name(m1
),y1
,d2
,conv_month_name(m2
),y2
);
1112 } else if (df
== 'w') {
1113 wlen2
=strftime(wdir
+wlen
, sizeof(wdir
)-wlen
, "%Y.%U", &per1
->start
);
1114 if (wlen2
==0) return(-1);
1120 struct userinfostruct
*uinfo
=userinfo_find_from_id(us
);
1123 strcat(wdir
,uinfo
->filename
);
1126 if(addr
[0] != '\0') {
1130 if(site
[0] != '\0') {
1135 strcpy(outdirname
,wdir
);
1137 if(IndexTree
!= INDEX_TREE_DATE
) {
1138 if(!OverwriteReport
) {
1140 if(access(wdir
,R_OK
) == 0) {
1141 sprintf(wdir
,"%s.%d",outdirname
,num
);
1150 debuga(_("File %s already exists, moved to %s\n"),outdirname
,wdir
);
1151 rename(outdirname
,wdir
);
1154 if(access(outdirname
,R_OK
) == 0) {
1155 unlinkdir(outdirname
,1);
1158 my_mkdir(outdirname
);
1160 strcpy(dirname2
,wdir
);
1161 if(!OverwriteReport
) {
1163 if(access(wdir
,R_OK
) == 0) {
1164 sprintf(wdir
,"%s.%d",dirname2
,num
);
1173 debuga(_("File %s already exists, moved to %s\n"),dirname2
,wdir
);
1174 rename(dirname2
,wdir
);
1175 strcpy(dirname2
,wdir
);
1178 if(access(wdir
,R_OK
) == 0) {
1183 if(access(wdir
, R_OK
) != 0)
1187 strcpy(dirname2
,wdir
);
1189 sprintf(wdir
,"%s/sarg-date",outdirname
);
1190 if ((fp_ou
= fopen(wdir
, "wt")) == 0) {
1191 debuga(_("cannot open %s for writing: %s\n"),wdir
,strerror(errno
));
1196 //strftime(wdir,sizeof(wdir),"%a %b %d %H:%M:%S %Z %Y",localtime(&curtime));
1197 loctm
=localtime(&curtime
);
1198 strftime(wdir
,sizeof(wdir
),"%Y-%m-%d %H:%M:%S",loctm
);
1199 if (fprintf(fp_ou
,"%s %d\n",wdir
,loctm
->tm_isdst
)<0) {
1200 debuga(_("Failed to write the date in %s\n"),wdir
);
1204 if (fclose(fp_ou
)==EOF
) {
1205 debuga(_("Failed to write the date in %s\n"),wdir
);
1215 Copy a string without overflowing the buffer. The copied string
1216 is properly terminated by an ASCII zero.
1218 \param dest The destination buffer.
1219 \param src The source buffer.
1220 \param length The size of the destination buffer. The program is aborted
1221 if the length is negative or zero.
1223 void safe_strcpy(char *dest
,const char *src
,int length
)
1226 debuga(_("Invalid buffer length passed to the function to safely copy a string\n"));
1229 strncpy(dest
,src
,length
-1);
1230 dest
[length
-1]='\0';
1233 void strip_latin(char *line
)
1240 for (i
=0;line
[i
];i
++){
1242 if (line
[i
]==';') skip
=0;
1254 void zdate(char *ftime
,int ftimesize
, char DateFormat
)
1260 local
= localtime(&t
);
1261 if (DateFormat
=='u')
1262 strftime(ftime
, ftimesize
, "%b/%d/%Y %H:%M", local
);
1263 else if (DateFormat
=='e')
1264 strftime(ftime
, ftimesize
, "%d/%b/%Y-%H:%M", local
);
1265 else if (DateFormat
=='w')
1266 strftime(ftime
, ftimesize
, "%W-%H-%M", local
);
1271 char *fixtime(long long int elap
)
1273 int num
= elap
/ 1000;
1277 static char buf
[12];
1280 min
=(num
% 3600) / 60;
1283 if(hor
==0 && min
==0 && sec
==0)
1286 sprintf(buf
,"%d:%02d:%02d",hor
,min
,sec
);
1292 void date_from(char *date
, int *dfrom
, int *duntil
)
1301 if (isdigit(date
[0])) {
1304 if (sscanf(date
,"%d/%d/%d%n",&d0
,&m0
,&y0
,&next
)!=3 || y0
<100 || m0
<1 || m0
>12 || d0
<1 || d0
>31 || next
<0) {
1305 debuga(_("The date passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1308 if (date
[next
]=='-') {
1309 if (sscanf(date
+next
+1,"%d/%d/%d",&d1
,&m1
,&y1
)!=3 || y1
<100 || m1
<1 || m1
>12 || d1
<1 || d1
>31) {
1310 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1313 } else if (date
[next
]!='\0') {
1314 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1324 struct tm
*Date0
,Date1
;
1326 if (time(&Today
)==(time_t)-1) {
1327 debuga(_("Failed to get the current time\n"));
1330 if (sscanf(date
,"day-%d",&i
)==1) {
1332 debuga(_("Invalid number of days in -d parameter\n"));
1336 Date0
=localtime(&Today
);
1338 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1341 y0
=y1
=Date0
->tm_year
+1900;
1342 m0
=m1
=Date0
->tm_mon
+1;
1343 d0
=d1
=Date0
->tm_mday
;
1344 } else if (sscanf(date
,"week-%d",&i
)==1) {
1346 There is no portable way to find the first day of the week even though the
1347 information is available in the locale. nl_langinfo has the unofficial
1348 parameters _NL_TIME_FIRST_WEEKDAY and _NL_TIME_WEEK_1STDAY but they are
1349 undocumented as is their return value and it is discouraged to use them.
1350 Beside, nl_langinfo isn't available on windows and the first day of the
1351 week isn't available at all on that system.
1353 const int FirstWeekDay
=1;
1357 debuga(_("Invalid number of weeks in -d parameter\n"));
1360 Date0
=localtime(&Today
);
1362 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1365 WeekBegin
=Today
-((Date0
->tm_wday
-FirstWeekDay
+7)%7)*24*60*60;
1366 WeekBegin
-=i
*7*24*60*60;
1367 Date0
=localtime(&WeekBegin
);
1369 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1372 y0
=Date0
->tm_year
+1900;
1375 WeekBegin
+=6*24*60*60;
1376 Date0
=localtime(&WeekBegin
);
1378 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1381 y1
=Date0
->tm_year
+1900;
1384 } else if (sscanf(date
,"month-%d",&i
)==1) {
1386 debuga(_("Invalid number of months in -d parameter\n"));
1389 Date0
=localtime(&Today
);
1391 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1394 if (Date0
->tm_mon
<i
%12) {
1395 y0
=Date0
->tm_year
+1900-i
/12-1;
1396 m0
=(Date0
->tm_mon
+12-i
%12)%12+1;
1399 y0
=Date0
->tm_year
+1900-i
/12;
1400 m0
=Date0
->tm_mon
-i
%12+1;
1403 memcpy(&Date1
,Date0
,sizeof(struct tm
));
1408 Date1
.tm_year
=y0
-1900;
1411 Date1
.tm_year
=y0
-1900+1;
1415 Date0
=localtime(&t1
);
1416 y1
=Date0
->tm_year
+1900;
1420 debuga(_("Invalid date range passed on command line\n"));
1425 *dfrom
=y0
*10000+m0
*100+d0
;
1426 *duntil
=y1
*10000+m1
*100+d1
;
1427 sprintf(date
,"%02d/%02d/%04d-%02d/%02d/%04d",d0
,m0
,y0
,d1
,m1
,y1
);
1432 char *strlow(char *string
)
1438 for (s
= string
; *s
; ++s
)
1448 char *strup(char *string
)
1454 for (s
= string
; *s
; ++s
)
1462 void removetmp(const char *outdir
)
1467 if(!RemoveTempFiles
)
1471 debuga(_("Purging temporary file sarg-general\n"));
1473 if (snprintf(filename
,sizeof(filename
),"%s/sarg-general",outdir
)>=sizeof(filename
)) {
1474 debuga(_("(removetmp) directory too long to remove %s/sarg-period\n"),outdir
);
1477 if((fp_gen
=fopen(filename
,"w"))==NULL
){
1478 debuga(_("(removetmp) Cannot open file %s: %s\n"),filename
,strerror(errno
));
1481 totalger(fp_gen
,filename
);
1482 if (fclose(fp_gen
)==EOF
) {
1483 debuga(_("Failed to close %s after writing the total line - %s\n"),filename
,strerror(errno
));
1488 void load_excludecodes(const char *ExcludeCodes
)
1496 if(ExcludeCodes
[0] == '\0')
1499 if((fp_in
=fopen(ExcludeCodes
,"r"))==NULL
) {
1500 debuga(_("(util) Cannot open file %s (exclude_codes): %s\n"),ExcludeCodes
,strerror(errno
));
1504 if (fseek(fp_in
, 0, SEEK_END
)==-1) {
1505 debuga(_("Failed to move till the end of the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1508 MemSize
= ftell(fp_in
);
1510 debuga(_("Cannot get the size of file %s\n"),ExcludeCodes
);
1513 if (fseek(fp_in
, 0, SEEK_SET
)==-1) {
1514 debuga(_("Failed to rewind the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1519 if((excludecode
=(char *) malloc(MemSize
))==NULL
) {
1520 debuga(_("malloc error (%ld)\n"),MemSize
);
1523 memset(excludecode
,0,MemSize
);
1526 while(fgets(data
,sizeof(data
),fp_in
)!=NULL
) {
1527 if (data
[0]=='#') continue;
1528 for (i
=strlen(data
)-1 ; i
>=0 && (unsigned char)data
[i
]<=' ' ; i
--) data
[i
]='\0';
1530 if (Stored
+i
+2>=MemSize
) {
1531 debuga(_("Too many codes to exclude in file %s\n"),ExcludeCodes
);
1534 strcat(excludecode
,data
);
1535 strcat(excludecode
,";");
1543 void free_excludecodes(void)
1551 int vercode(const char *code
)
1556 if (excludecode
&& excludecode
[0]!='\0') {
1560 if (strncmp(code
,cod
,clen
)==0 && cod
[clen
]==';')
1562 cod
=strchr(cod
,';');
1569 void fixnone(char *str
)
1573 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--);
1574 if(i
==3 && strncmp(str
,"none",4) == 0)
1580 void fixendofline(char *str
)
1584 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--) str
[i
]=0;
1587 #ifdef LEGACY_TESTVALIDUSERCHAR
1588 int testvaliduserchar(const char *user
)
1593 for (y
=0; y
<strlen(UserInvalidChar
); y
++) {
1594 for (x
=0; x
<strlen(user
); x
++) {
1595 if(user
[x
] == UserInvalidChar
[y
])
1602 int testvaliduserchar(const char *user
)
1604 char * p_UserInvalidChar
= UserInvalidChar
;
1605 const char * p_user
;
1607 while( *p_UserInvalidChar
) {
1610 if( *p_UserInvalidChar
== *p_user
)
1614 p_UserInvalidChar
++ ;
1620 int compar( const void *a
, const void *b
)
1622 if( *(int *)a
> *(int *)b
) return 1;
1623 if( *(int *)a
< *(int *)b
) return -1;
1627 int getnumlist( char *buf
, numlist
*list
, const int len
, const int maxvalue
)
1629 int i
, j
, d
, flag
, r1
, r2
;
1630 char *pbuf
, **bp
, *strbufs
[ 24 ];
1633 strtok( buf
, " \t" );
1634 for( *bp
= strtok( NULL
, "," ), list
->len
= 0; *bp
; *bp
= strtok( NULL
, "," ) ) {
1635 if( ++bp
>= &strbufs
[ 24 ] )
1642 for( i
= 0; i
< list
->len
; i
++ ) {
1643 if( strchr( strbufs
[ i
], '-' ) != 0 ) {
1644 pbuf
= strbufs
[ i
];
1645 strtok( pbuf
, "-" );
1646 pbuf
= strtok( NULL
, "\0" );
1647 r1
= atoi( strbufs
[ i
] );
1648 if( ( r2
= atoi( pbuf
) ) >= maxvalue
|| r1
>= r2
)
1650 if( i
+ d
+ ( r2
- r1
) + 1 <= len
) {
1651 for( j
= r1
; j
<= r2
; j
++ )
1652 list
->list
[ i
+ d
++ ] = j
;
1657 if( ( list
->list
[ i
+ d
] = atoi( strbufs
[ i
] ) ) >= maxvalue
)
1661 qsort( list
->list
, list
->len
, sizeof( int ), compar
);
1664 for( i
= 0; i
< list
->len
- 1; i
++ )
1665 if( list
->list
[ i
] == list
->list
[ i
+ 1 ] ) {
1666 for( j
= i
+ 1; j
< list
->len
; j
++ )
1667 list
->list
[ j
- 1 ] = list
->list
[ j
];
1677 char *get_size(const char *path
, const char *file
)
1680 static char response
[255];
1684 if (snprintf(cmd
,sizeof(cmd
),"du -skh %s%s",path
,file
)>=sizeof(cmd
)) {
1685 debuga(_("Cannot get disk space because the path %s%s is too long\n"),path
,file
);
1688 if ((fp
= popen(cmd
, "r")) == NULL
) {
1689 debuga(_("Cannot get disk space with command %s\n"),cmd
);
1692 if (!fgets(response
, sizeof(response
), fp
)) {
1693 debuga(_("Cannot get disk size with command %s\n"),cmd
);
1696 ptr
=strchr(response
,'\t');
1698 debuga(_("The command %s failed\n"),cmd
);
1707 void show_info(FILE *fp_ou
)
1711 if(!ShowSargInfo
) return;
1712 zdate(ftime
, sizeof(ftime
), df
);
1713 fprintf(fp_ou
,"<div class=\"info\">%s <a href='%s'>%s-%s</a> %s %s</div>\n",_("Generated by"),URL
,PGM
,VERSION
,_("on"),ftime
);
1716 void show_sarg(FILE *fp_ou
, int depth
)
1720 if(!ShowSargLogo
) return;
1721 fputs("<div class=\"logo\"><a href=\"http://sarg.sourceforge.net\"><img src=\"",fp_ou
);
1722 for (i
=0 ; i
<depth
; i
++)
1724 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
);
1727 void write_logo_image(FILE *fp_ou
)
1729 if(LogoImage
[0]!='\0')
1730 fprintf(fp_ou
, "<div class=\"logo\"><img src=\"%s\" width=\"%s\" height=\"%s\" alt=\"Logo\"> %s</div>\n",LogoImage
,Width
,Height
,LogoText
);
1733 void write_html_head(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1737 fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n",fp_ou
);
1738 fprintf(fp_ou
, "<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n",CharSet
);
1739 if (page_title
) fprintf(fp_ou
,"<title>%s</title>\n",page_title
);
1741 if ((javascript
& HTML_JS_SORTTABLE
)!=0 && SortTableJs
[0]) {
1742 fputs("<script type=\"text/javascript\" src=\"",fp_ou
);
1743 if (strncmp(SortTableJs
,"../",3)==0) {
1744 for (i
=0 ; i
<depth
; i
++) fputs("../",fp_ou
);
1746 fputs(SortTableJs
,fp_ou
);
1747 fputs("\"></script>\n",fp_ou
);
1749 fputs("</head>\n<body>\n",fp_ou
);
1752 void write_html_header(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1754 write_html_head(fp_ou
,depth
,page_title
,javascript
);
1755 write_logo_image(fp_ou
);
1756 show_sarg(fp_ou
, depth
);
1757 fprintf(fp_ou
,"<div class=\"title\"><table cellpadding=\"0\" cellspacing=\"0\">\n<tr><th class=\"title_c\">%s</th></tr>\n",Title
);
1760 void close_html_header(FILE *fp_ou
)
1762 fputs("</table></div>\n",fp_ou
);
1765 int write_html_trailer(FILE *fp_ou
)
1768 if (fputs("</body>\n</html>\n",fp_ou
)==EOF
) return(-1);
1772 void output_html_string(FILE *fp_ou
,const char *str
,int maxlen
)
1776 while (*str
&& (maxlen
<=0 || i
<maxlen
)) {
1779 fputs("&",fp_ou
);
1782 fputs("<",fp_ou
);
1785 fputs(">",fp_ou
);
1788 fputs(""",fp_ou
);
1791 fputs("'",fp_ou
);
1799 if (maxlen
>0 && i
>=maxlen
)
1800 fputs("…",fp_ou
);
1803 void output_html_url(FILE *fp_ou
,const char *url
)
1807 fputs("&",fp_ou
);
1815 Write a host name inside an A tag of a HTML file. If the host name starts
1816 with a star, it is assumed to be an alias that cannot be put inside a link
1817 so the A tag is not written around the host name.
1819 \param fp_ou The handle of the HTML file.
1820 \param url The host to display in the HTML file.
1821 \param maxlen The maximum number of characters to print into the host name.
1823 void output_html_link(FILE *fp_ou
,const char *url
,int maxlen
)
1825 if (url
[0]==ALIAS_PREFIX
) {
1826 // this is an alias, no need for a A tag
1827 output_html_string(fp_ou
,url
+1,100);
1829 if (skip_scheme(url
)==url
)
1830 fputs("<a href=\"http://",fp_ou
);//no scheme in the url, assume http:// to make the link clickable
1832 fputs("<a href=\"",fp_ou
);//the scheme is in the url, no need to add one
1833 output_html_url(fp_ou
,url
);
1835 output_html_string(fp_ou
,url
,100);
1836 fputs("</a>",fp_ou
);
1840 void url_module(const char *url
, char *w2
)
1846 for(x
=strlen(url
)-1; x
>=0; x
--) {
1847 if(url
[x
] == '/' || y
>=sizeof(w
)-1) break;
1856 for(y
=y
-1; y
>=0; y
--) {
1862 void url_to_file(const char *url
,char *file
,int filesize
)
1868 for(i
=0; i
<filesize
&& *url
; url
++) {
1869 if(isalnum(*url
) || *url
=='-' || *url
=='_' || *url
=='.') {
1873 if (!skip
) file
[i
++]='_';
1882 printf(_("SARG Version: %s\n"),VERSION
);
1886 char *get_param_value(const char *param
,char *line
)
1890 while (*line
==' ' || *line
=='\t') line
++;
1892 if (strncasecmp(line
,param
,plen
)) return(NULL
);
1893 if (line
[plen
]!=' ' && line
[plen
]!='\t') return(NULL
);
1895 while (*line
==' ' || *line
=='\t') line
++;
1899 void unlinkdir(const char *dir
,bool contentonly
)
1903 struct dirent
*direntp
;
1909 while ((direntp
= readdir(dirp
)) != NULL
) {
1910 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
1911 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
1913 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
1914 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
1918 err
=lstat(dname
,&st
);
1920 err
=stat(dname
,&st
);
1923 debuga(_("cannot stat %s\n"),dname
);
1926 if (S_ISREG(st
.st_mode
)) {
1927 if (unlink(dname
)) {
1928 debuga(_("Cannot delete \"%s\": %s\n"),dname
,strerror(errno
));
1931 } else if (S_ISDIR(st
.st_mode
)) {
1934 debuga(_("unknown path type %s\n"),dname
);
1941 debuga(_("Cannot delete \"%s\": %s\n"),dir
,strerror(errno
));
1948 Delete every file from the temporary directory where sarg is told to store its
1951 As any stray file left over by a previous run would be included in the report, we
1952 must delete every file from the temporary directory before we start processing the logs.
1954 But the temporary directory is given by the user either in the configuration file or
1955 on the command line. We check that the user didn't give a wrong directory by looking
1956 at the files stored in the directory. If a single file is not one of ours, we abort.
1958 \param dir The temporary directory to purge.
1960 void emptytmpdir(const char *dir
)
1964 struct dirent
*direntp
;
1970 static const char *TmpExt
[]=
1985 // make sure the temporary directory contains only our files
1986 while ((direntp
= readdir(dirp
)) != NULL
) {
1987 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
1988 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
1991 // is it one of our files
1992 dlen
=strlen(direntp
->d_name
);
1993 for (i
=sizeof(TmpExt
)/sizeof(TmpExt
[0])-1 ; i
>=0 ; i
--) {
1994 elen
=strlen(TmpExt
[i
]);
1995 if (dlen
>=elen
&& strcasecmp(direntp
->d_name
+dlen
-elen
,TmpExt
[i
])==0) break;
1998 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
1999 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2000 "directory or manually delete the content of \"%s\"\n"),direntp
->d_name
,dir
,dir
);
2004 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
2005 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
2010 err
=lstat(dname
,&st
);
2012 err
=stat(dname
,&st
);
2015 debuga(_("cannot stat \"%s\"\n"),dname
);
2018 if (S_ISDIR(st
.st_mode
)) {
2020 } else if (!S_ISREG(st
.st_mode
)) {
2021 debuga(_("Unknown path type \"%s\". Check your temporary directory\n"),dname
);
2027 // now delete our files
2028 while ((direntp
= readdir(dirp
)) != NULL
) {
2029 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
2030 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
2033 // is it one of our files
2034 dlen
=strlen(direntp
->d_name
);
2035 for (i
=sizeof(TmpExt
)/sizeof(TmpExt
[0])-1 ; i
>=0 ; i
--) {
2036 elen
=strlen(TmpExt
[i
]);
2037 if (dlen
>=elen
&& strcasecmp(direntp
->d_name
+dlen
-elen
,TmpExt
[i
])==0) break;
2040 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2041 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2042 "directory or manually delete the content of \"%s\"\n"),direntp
->d_name
,dir
,dir
);
2046 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
2047 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
2051 err
=lstat(dname
,&st
);
2053 err
=stat(dname
,&st
);
2056 debuga(_("cannot stat \"%s\"\n"),dname
);
2059 if (S_ISREG(st
.st_mode
)) {
2060 if (unlink(dname
)) {
2061 debuga(_("Cannot delete \"%s\": %s\n"),dname
,strerror(errno
));
2065 debuga(_("unknown path type %s\n"),dname
);
2072 Extract an url, IPv4 or IPv6 from a buffer. The IP addresses may end with a
2075 \param buf The buffer to parse.
2076 \param text A pointer to set to the beginning of the string pattern. No terminating zero is inserted.
2077 The pointer may be NULL.
2078 \param ipv4 A 4 bytes buffer to store the bytes of the IPv4 address.
2079 \param ipv6 A 8 short integers buffer to store the values of the IPv6 address.
2080 \param nbits The number of prefix bits for an IP address.
2081 \param next The content of the line after the extracted address.
2083 \retval 3 The pattern is a IPv6 address.
2084 \retval 2 The pattern is a IPv4 address.
2085 \retval 1 The patter is a string.
2086 \retval 0 Empty pattern.
2088 int extract_address_mask(const char *buf
,const char **text
,unsigned char *ipv4
,unsigned short int *ipv6
,int *nbits
,const char **next
)
2093 unsigned int value4
, value6
;
2094 unsigned short int addr
[8];
2104 // skip leading spaces and tabs
2105 while (*buf
&& (*buf
==' ' || *buf
=='\t')) buf
++;
2107 // find out the nature of the pattern
2108 ip_size
=0x60 | 0x04;
2119 for (i
=0 ; (unsigned char)buf
[i
]>' ' && buf
[i
]!='/' && buf
[i
]!='?' && (!bracket
|| buf
[i
]!=']') && ip_size
; i
++) {
2120 if (ip_size
& 0x04) {
2121 if (isdigit(buf
[i
])) {
2123 port_num
=port_num
*10+(buf
[i
]-'0');
2124 if (port_num
>65535) ip_size
&=~0x04;
2126 value4
=value4
*10+(buf
[i
]-'0');
2127 if (value4
>0xFFU
) ip_size
&=~0x04;
2129 } else if (buf
[i
]=='.' && addr_len
<4) {
2130 addr
[addr_len
++]=(unsigned short)(value4
& 0xFFU
);
2132 } else if (!port
&& buf
[i
]==':') {
2138 if (ip_size
& 0x60) {
2139 if (isdigit(buf
[i
])) {
2140 value6
=(value6
<<4)+(buf
[i
]-'0');
2142 if (value6
>0xFFFFU
) ip_size
&=~0x60;
2143 } else if (toupper(buf
[i
])>='A' && toupper(buf
[i
])<='F') {
2144 value6
=(value6
<<4)+(toupper(buf
[i
])-'A'+10);
2146 if (value6
>0xFFFFU
) ip_size
&=~0x60;
2147 } else if (buf
[i
]==':' && addr_len
<8) {
2148 if (nibble6_len
>0) {
2149 addr
[addr_len
++]=(unsigned short)(value6
& 0xFFFFU
);
2153 if (buf
[i
+1]==':') {
2162 if (i
==0) return(0);
2163 if (ip_size
& 0x04) {
2167 addr
[addr_len
++]=(unsigned short)(value4
& 0xFFU
);
2169 if (ip_size
& 0x60) {
2170 if (pad_pos
<0 && addr_len
!=7) {
2172 } else if (pad_pos
>=0 && addr_len
>=7)
2174 else if (nibble6_len
>0)
2175 addr
[addr_len
++]=(unsigned short)(value6
& 0xFFFFU
);
2180 if (bracket
) (*text
)--;
2182 while ((unsigned char)buf
[i
]>' ') i
++;
2183 if (next
) *next
=buf
+i
;
2186 max_mask
=(ip_size
& 0x04) ? 4*8 : 8*16;
2190 while (isdigit(buf
[i
])) i
++;
2191 if (mask
<0 || mask
>max_mask
) mask
=max_mask
;
2194 if (ip_size
& 0x60 && bracket
&& buf
[i
]==']') i
++;
2195 if (next
) *next
=buf
+i
;
2196 if (ip_size
& 0x04) {
2197 if (nbits
) *nbits
=mask
;
2198 for (i
=0 ; i
<addr_len
; i
++)
2199 ipv4
[i
]=(unsigned char)addr
[i
];
2204 if (nbits
) *nbits
=mask
;
2209 ipv6
[j
++]=(unsigned short int)addr
[i
++];
2211 while (j
<pad_pos
+pad_len
)
2215 ipv6
[j
++]=(unsigned short int)addr
[i
++];