]>
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
);
1058 if (fclose(img_ou
)==EOF
) {
1059 debuga(_("Error while copying image %s: %s\n"),dstfile
,strerror(errno
));
1063 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open/create file", dstfile
, strerror(errno
));
1066 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open file", srcfile
, strerror(errno
));
1069 (void) closedir(dirp
);
1074 int vrfydir(const struct periodstruct
*per1
, const char *addr
, const char *site
, const char *us
, const char *form
)
1079 char dirname2
[MAXLEN
];
1087 strcpy(wdir
,outdir
);
1089 y1
=per1
->start
.tm_year
+1900;
1090 y2
=per1
->end
.tm_year
+1900;
1091 m1
=per1
->start
.tm_mon
+1;
1092 m2
=per1
->end
.tm_mon
+1;
1093 d1
=per1
->start
.tm_mday
;
1094 d2
=per1
->end
.tm_mday
;
1095 if(IndexTree
== INDEX_TREE_DATE
) {
1096 wlen
+=sprintf(wdir
+wlen
,"%04d",y1
);
1097 if(y1
!=y2
) wlen
+=sprintf(wdir
+wlen
,"-%04d",y2
);
1098 if(access(wdir
, R_OK
) != 0)
1101 wlen
+=sprintf(wdir
+wlen
,"/%02d",m1
);
1102 if(m1
!= m2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",m2
);
1103 if(access(wdir
, R_OK
) != 0)
1106 wlen
+=sprintf(wdir
+wlen
,"/%02d",d1
);
1107 if(d1
!=d2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",d2
);
1110 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%04d%s%02d-%04d%s%02d",y1
,
1111 conv_month_name(m1
),d1
,y2
,conv_month_name(m2
),d2
);
1112 } else if (df
== 'e') {
1113 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%02d%s%04d-%02d%s%04d",d1
,
1114 conv_month_name(m1
),y1
,d2
,conv_month_name(m2
),y2
);
1115 } else if (df
== 'w') {
1116 wlen2
=strftime(wdir
+wlen
, sizeof(wdir
)-wlen
, "%Y.%U", &per1
->start
);
1117 if (wlen2
==0) return(-1);
1123 struct userinfostruct
*uinfo
=userinfo_find_from_id(us
);
1126 strcat(wdir
,uinfo
->filename
);
1129 if(addr
[0] != '\0') {
1133 if(site
[0] != '\0') {
1138 strcpy(outdirname
,wdir
);
1140 if(IndexTree
!= INDEX_TREE_DATE
) {
1141 if(!OverwriteReport
) {
1143 if(access(wdir
,R_OK
) == 0) {
1144 sprintf(wdir
,"%s.%d",outdirname
,num
);
1153 debuga(_("File %s already exists, moved to %s\n"),outdirname
,wdir
);
1154 rename(outdirname
,wdir
);
1157 if(access(outdirname
,R_OK
) == 0) {
1158 unlinkdir(outdirname
,1);
1161 my_mkdir(outdirname
);
1163 strcpy(dirname2
,wdir
);
1164 if(!OverwriteReport
) {
1166 if(access(wdir
,R_OK
) == 0) {
1167 sprintf(wdir
,"%s.%d",dirname2
,num
);
1176 debuga(_("File %s already exists, moved to %s\n"),dirname2
,wdir
);
1177 rename(dirname2
,wdir
);
1178 strcpy(dirname2
,wdir
);
1181 if(access(wdir
,R_OK
) == 0) {
1186 if(access(wdir
, R_OK
) != 0)
1190 strcpy(dirname2
,wdir
);
1192 sprintf(wdir
,"%s/sarg-date",outdirname
);
1193 if ((fp_ou
= fopen(wdir
, "wt")) == 0) {
1194 debuga(_("cannot open %s for writing: %s\n"),wdir
,strerror(errno
));
1199 //strftime(wdir,sizeof(wdir),"%a %b %d %H:%M:%S %Z %Y",localtime(&curtime));
1200 loctm
=localtime(&curtime
);
1201 strftime(wdir
,sizeof(wdir
),"%Y-%m-%d %H:%M:%S",loctm
);
1202 if (fprintf(fp_ou
,"%s %d\n",wdir
,loctm
->tm_isdst
)<0) {
1203 debuga(_("Failed to write the date in %s\n"),wdir
);
1207 if (fclose(fp_ou
)==EOF
) {
1208 debuga(_("Failed to write the date in %s: %s\n"),wdir
,strerror(errno
));
1217 Copy a string without overflowing the buffer. The copied string
1218 is properly terminated by an ASCII zero.
1220 \param dest The destination buffer.
1221 \param src The source buffer.
1222 \param length The size of the destination buffer. The program is aborted
1223 if the length is negative or zero.
1225 void safe_strcpy(char *dest
,const char *src
,int length
)
1228 debuga(_("Invalid buffer length passed to the function to safely copy a string\n"));
1231 strncpy(dest
,src
,length
-1);
1232 dest
[length
-1]='\0';
1235 void strip_latin(char *line
)
1242 for (i
=0;line
[i
];i
++){
1244 if (line
[i
]==';') skip
=0;
1256 void zdate(char *ftime
,int ftimesize
, char DateFormat
)
1262 local
= localtime(&t
);
1263 if (DateFormat
=='u')
1264 strftime(ftime
, ftimesize
, "%b/%d/%Y %H:%M", local
);
1265 else if (DateFormat
=='e')
1266 strftime(ftime
, ftimesize
, "%d/%b/%Y-%H:%M", local
);
1267 else if (DateFormat
=='w')
1268 strftime(ftime
, ftimesize
, "%W-%H-%M", local
);
1273 char *fixtime(long long int elap
)
1275 int num
= elap
/ 1000;
1279 static char buf
[12];
1282 min
=(num
% 3600) / 60;
1285 if(hor
==0 && min
==0 && sec
==0)
1288 sprintf(buf
,"%d:%02d:%02d",hor
,min
,sec
);
1294 void date_from(char *date
, int *dfrom
, int *duntil
)
1303 if (isdigit(date
[0])) {
1306 if (sscanf(date
,"%d/%d/%d%n",&d0
,&m0
,&y0
,&next
)!=3 || y0
<100 || m0
<1 || m0
>12 || d0
<1 || d0
>31 || next
<0) {
1307 debuga(_("The date passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1310 if (date
[next
]=='-') {
1311 if (sscanf(date
+next
+1,"%d/%d/%d",&d1
,&m1
,&y1
)!=3 || y1
<100 || m1
<1 || m1
>12 || d1
<1 || d1
>31) {
1312 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1315 } else if (date
[next
]!='\0') {
1316 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1326 struct tm
*Date0
,Date1
;
1328 if (time(&Today
)==(time_t)-1) {
1329 debuga(_("Failed to get the current time\n"));
1332 if (sscanf(date
,"day-%d",&i
)==1) {
1334 debuga(_("Invalid number of days in -d parameter\n"));
1338 Date0
=localtime(&Today
);
1340 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1343 y0
=y1
=Date0
->tm_year
+1900;
1344 m0
=m1
=Date0
->tm_mon
+1;
1345 d0
=d1
=Date0
->tm_mday
;
1346 } else if (sscanf(date
,"week-%d",&i
)==1) {
1348 There is no portable way to find the first day of the week even though the
1349 information is available in the locale. nl_langinfo has the unofficial
1350 parameters _NL_TIME_FIRST_WEEKDAY and _NL_TIME_WEEK_1STDAY but they are
1351 undocumented as is their return value and it is discouraged to use them.
1352 Beside, nl_langinfo isn't available on windows and the first day of the
1353 week isn't available at all on that system.
1355 const int FirstWeekDay
=1;
1359 debuga(_("Invalid number of weeks in -d parameter\n"));
1362 Date0
=localtime(&Today
);
1364 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1367 WeekBegin
=Today
-((Date0
->tm_wday
-FirstWeekDay
+7)%7)*24*60*60;
1368 WeekBegin
-=i
*7*24*60*60;
1369 Date0
=localtime(&WeekBegin
);
1371 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1374 y0
=Date0
->tm_year
+1900;
1377 WeekBegin
+=6*24*60*60;
1378 Date0
=localtime(&WeekBegin
);
1380 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1383 y1
=Date0
->tm_year
+1900;
1386 } else if (sscanf(date
,"month-%d",&i
)==1) {
1388 debuga(_("Invalid number of months in -d parameter\n"));
1391 Date0
=localtime(&Today
);
1393 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1396 if (Date0
->tm_mon
<i
%12) {
1397 y0
=Date0
->tm_year
+1900-i
/12-1;
1398 m0
=(Date0
->tm_mon
+12-i
%12)%12+1;
1401 y0
=Date0
->tm_year
+1900-i
/12;
1402 m0
=Date0
->tm_mon
-i
%12+1;
1405 memcpy(&Date1
,Date0
,sizeof(struct tm
));
1410 Date1
.tm_year
=y0
-1900;
1413 Date1
.tm_year
=y0
-1900+1;
1417 Date0
=localtime(&t1
);
1418 y1
=Date0
->tm_year
+1900;
1422 debuga(_("Invalid date range passed on command line\n"));
1427 *dfrom
=y0
*10000+m0
*100+d0
;
1428 *duntil
=y1
*10000+m1
*100+d1
;
1429 sprintf(date
,"%02d/%02d/%04d-%02d/%02d/%04d",d0
,m0
,y0
,d1
,m1
,y1
);
1434 char *strlow(char *string
)
1440 for (s
= string
; *s
; ++s
)
1450 char *strup(char *string
)
1456 for (s
= string
; *s
; ++s
)
1464 void removetmp(const char *outdir
)
1469 if(!RemoveTempFiles
)
1473 debuga(_("Purging temporary file sarg-general\n"));
1475 if (snprintf(filename
,sizeof(filename
),"%s/sarg-general",outdir
)>=sizeof(filename
)) {
1476 debuga(_("(removetmp) directory too long to remove %s/sarg-period\n"),outdir
);
1479 if((fp_gen
=fopen(filename
,"w"))==NULL
){
1480 debuga(_("(removetmp) Cannot open file %s: %s\n"),filename
,strerror(errno
));
1483 totalger(fp_gen
,filename
);
1484 if (fclose(fp_gen
)==EOF
) {
1485 debuga(_("Failed to close %s after writing the total line: %s\n"),filename
,strerror(errno
));
1490 void load_excludecodes(const char *ExcludeCodes
)
1498 if(ExcludeCodes
[0] == '\0')
1501 if((fp_in
=fopen(ExcludeCodes
,"r"))==NULL
) {
1502 debuga(_("(util) Cannot open file %s (exclude_codes): %s\n"),ExcludeCodes
,strerror(errno
));
1506 if (fseek(fp_in
, 0, SEEK_END
)==-1) {
1507 debuga(_("Failed to move till the end of the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1510 MemSize
= ftell(fp_in
);
1512 debuga(_("Cannot get the size of file %s\n"),ExcludeCodes
);
1515 if (fseek(fp_in
, 0, SEEK_SET
)==-1) {
1516 debuga(_("Failed to rewind the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1521 if((excludecode
=(char *) malloc(MemSize
))==NULL
) {
1522 debuga(_("malloc error (%ld)\n"),MemSize
);
1525 memset(excludecode
,0,MemSize
);
1528 while(fgets(data
,sizeof(data
),fp_in
)!=NULL
) {
1529 if (data
[0]=='#') continue;
1530 for (i
=strlen(data
)-1 ; i
>=0 && (unsigned char)data
[i
]<=' ' ; i
--) data
[i
]='\0';
1532 if (Stored
+i
+2>=MemSize
) {
1533 debuga(_("Too many codes to exclude in file %s\n"),ExcludeCodes
);
1536 strcat(excludecode
,data
);
1537 strcat(excludecode
,";");
1545 void free_excludecodes(void)
1553 int vercode(const char *code
)
1558 if (excludecode
&& excludecode
[0]!='\0') {
1562 if (strncmp(code
,cod
,clen
)==0 && cod
[clen
]==';')
1564 cod
=strchr(cod
,';');
1571 void fixnone(char *str
)
1575 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--);
1576 if(i
==3 && strncmp(str
,"none",4) == 0)
1582 void fixendofline(char *str
)
1586 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--) str
[i
]=0;
1589 #ifdef LEGACY_TESTVALIDUSERCHAR
1590 int testvaliduserchar(const char *user
)
1595 for (y
=0; y
<strlen(UserInvalidChar
); y
++) {
1596 for (x
=0; x
<strlen(user
); x
++) {
1597 if(user
[x
] == UserInvalidChar
[y
])
1604 int testvaliduserchar(const char *user
)
1606 char * p_UserInvalidChar
= UserInvalidChar
;
1607 const char * p_user
;
1609 while( *p_UserInvalidChar
) {
1612 if( *p_UserInvalidChar
== *p_user
)
1616 p_UserInvalidChar
++ ;
1622 int compar( const void *a
, const void *b
)
1624 if( *(int *)a
> *(int *)b
) return 1;
1625 if( *(int *)a
< *(int *)b
) return -1;
1629 int getnumlist( char *buf
, numlist
*list
, const int len
, const int maxvalue
)
1631 int i
, j
, d
, flag
, r1
, r2
;
1632 char *pbuf
, **bp
, *strbufs
[ 24 ];
1635 strtok( buf
, " \t" );
1636 for( *bp
= strtok( NULL
, "," ), list
->len
= 0; *bp
; *bp
= strtok( NULL
, "," ) ) {
1637 if( ++bp
>= &strbufs
[ 24 ] )
1644 for( i
= 0; i
< list
->len
; i
++ ) {
1645 if( strchr( strbufs
[ i
], '-' ) != 0 ) {
1646 pbuf
= strbufs
[ i
];
1647 strtok( pbuf
, "-" );
1648 pbuf
= strtok( NULL
, "\0" );
1649 r1
= atoi( strbufs
[ i
] );
1650 if( ( r2
= atoi( pbuf
) ) >= maxvalue
|| r1
>= r2
)
1652 if( i
+ d
+ ( r2
- r1
) + 1 <= len
) {
1653 for( j
= r1
; j
<= r2
; j
++ )
1654 list
->list
[ i
+ d
++ ] = j
;
1659 if( ( list
->list
[ i
+ d
] = atoi( strbufs
[ i
] ) ) >= maxvalue
)
1663 qsort( list
->list
, list
->len
, sizeof( int ), compar
);
1666 for( i
= 0; i
< list
->len
- 1; i
++ )
1667 if( list
->list
[ i
] == list
->list
[ i
+ 1 ] ) {
1668 for( j
= i
+ 1; j
< list
->len
; j
++ )
1669 list
->list
[ j
- 1 ] = list
->list
[ j
];
1679 char *get_size(const char *path
, const char *file
)
1682 static char response
[255];
1686 if (snprintf(cmd
,sizeof(cmd
),"du -skh %s%s",path
,file
)>=sizeof(cmd
)) {
1687 debuga(_("Cannot get disk space because the path %s%s is too long\n"),path
,file
);
1690 if ((fp
= popen(cmd
, "r")) == NULL
) {
1691 debuga(_("Cannot get disk space with command %s\n"),cmd
);
1694 if (!fgets(response
, sizeof(response
), fp
)) {
1695 debuga(_("Cannot get disk size with command %s\n"),cmd
);
1698 ptr
=strchr(response
,'\t');
1700 debuga(_("The command %s failed\n"),cmd
);
1709 void show_info(FILE *fp_ou
)
1713 if(!ShowSargInfo
) return;
1714 zdate(ftime
, sizeof(ftime
), df
);
1715 fprintf(fp_ou
,"<div class=\"info\">%s <a href='%s'>%s-%s</a> %s %s</div>\n",_("Generated by"),URL
,PGM
,VERSION
,_("on"),ftime
);
1718 void show_sarg(FILE *fp_ou
, int depth
)
1722 if(!ShowSargLogo
) return;
1723 fputs("<div class=\"logo\"><a href=\"http://sarg.sourceforge.net\"><img src=\"",fp_ou
);
1724 for (i
=0 ; i
<depth
; i
++)
1726 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
);
1729 void write_logo_image(FILE *fp_ou
)
1731 if(LogoImage
[0]!='\0')
1732 fprintf(fp_ou
, "<div class=\"logo\"><img src=\"%s\" width=\"%s\" height=\"%s\" alt=\"Logo\"> %s</div>\n",LogoImage
,Width
,Height
,LogoText
);
1735 void write_html_head(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1739 fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n",fp_ou
);
1740 fprintf(fp_ou
, "<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n",CharSet
);
1741 if (page_title
) fprintf(fp_ou
,"<title>%s</title>\n",page_title
);
1743 if ((javascript
& HTML_JS_SORTTABLE
)!=0 && SortTableJs
[0]) {
1744 fputs("<script type=\"text/javascript\" src=\"",fp_ou
);
1745 if (strncmp(SortTableJs
,"../",3)==0) {
1746 for (i
=0 ; i
<depth
; i
++) fputs("../",fp_ou
);
1748 fputs(SortTableJs
,fp_ou
);
1749 fputs("\"></script>\n",fp_ou
);
1751 fputs("</head>\n<body>\n",fp_ou
);
1754 void write_html_header(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1756 write_html_head(fp_ou
,depth
,page_title
,javascript
);
1757 write_logo_image(fp_ou
);
1758 show_sarg(fp_ou
, depth
);
1759 fprintf(fp_ou
,"<div class=\"title\"><table cellpadding=\"0\" cellspacing=\"0\">\n<tr><th class=\"title_c\">%s</th></tr>\n",Title
);
1762 void close_html_header(FILE *fp_ou
)
1764 fputs("</table></div>\n",fp_ou
);
1767 int write_html_trailer(FILE *fp_ou
)
1770 if (fputs("</body>\n</html>\n",fp_ou
)==EOF
) return(-1);
1774 void output_html_string(FILE *fp_ou
,const char *str
,int maxlen
)
1778 while (*str
&& (maxlen
<=0 || i
<maxlen
)) {
1781 fputs("&",fp_ou
);
1784 fputs("<",fp_ou
);
1787 fputs(">",fp_ou
);
1790 fputs(""",fp_ou
);
1793 fputs("'",fp_ou
);
1801 if (maxlen
>0 && i
>=maxlen
)
1802 fputs("…",fp_ou
);
1805 void output_html_url(FILE *fp_ou
,const char *url
)
1809 fputs("&",fp_ou
);
1817 Write a host name inside an A tag of a HTML file. If the host name starts
1818 with a star, it is assumed to be an alias that cannot be put inside a link
1819 so the A tag is not written around the host name.
1821 \param fp_ou The handle of the HTML file.
1822 \param url The host to display in the HTML file.
1823 \param maxlen The maximum number of characters to print into the host name.
1825 void output_html_link(FILE *fp_ou
,const char *url
,int maxlen
)
1827 if (url
[0]==ALIAS_PREFIX
) {
1828 // this is an alias, no need for a A tag
1829 output_html_string(fp_ou
,url
+1,100);
1831 if (skip_scheme(url
)==url
)
1832 fputs("<a href=\"http://",fp_ou
);//no scheme in the url, assume http:// to make the link clickable
1834 fputs("<a href=\"",fp_ou
);//the scheme is in the url, no need to add one
1835 output_html_url(fp_ou
,url
);
1837 output_html_string(fp_ou
,url
,100);
1838 fputs("</a>",fp_ou
);
1842 void url_module(const char *url
, char *w2
)
1848 for(x
=strlen(url
)-1; x
>=0; x
--) {
1849 if(url
[x
] == '/' || y
>=sizeof(w
)-1) break;
1858 for(y
=y
-1; y
>=0; y
--) {
1864 void url_to_file(const char *url
,char *file
,int filesize
)
1870 for(i
=0; i
<filesize
&& *url
; url
++) {
1871 if(isalnum(*url
) || *url
=='-' || *url
=='_' || *url
=='.') {
1875 if (!skip
) file
[i
++]='_';
1884 printf(_("SARG Version: %s\n"),VERSION
);
1888 char *get_param_value(const char *param
,char *line
)
1892 while (*line
==' ' || *line
=='\t') line
++;
1894 if (strncasecmp(line
,param
,plen
)) return(NULL
);
1895 if (line
[plen
]!=' ' && line
[plen
]!='\t') return(NULL
);
1897 while (*line
==' ' || *line
=='\t') line
++;
1901 void unlinkdir(const char *dir
,bool contentonly
)
1905 struct dirent
*direntp
;
1911 while ((direntp
= readdir(dirp
)) != NULL
) {
1912 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
1913 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
1915 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
1916 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
1920 err
=lstat(dname
,&st
);
1922 err
=stat(dname
,&st
);
1925 debuga(_("cannot stat %s\n"),dname
);
1928 if (S_ISREG(st
.st_mode
)) {
1929 if (unlink(dname
)) {
1930 debuga(_("Cannot delete \"%s\": %s\n"),dname
,strerror(errno
));
1933 } else if (S_ISDIR(st
.st_mode
)) {
1936 debuga(_("unknown path type %s\n"),dname
);
1943 debuga(_("Cannot delete \"%s\": %s\n"),dir
,strerror(errno
));
1950 Delete every file from the temporary directory where sarg is told to store its
1953 As any stray file left over by a previous run would be included in the report, we
1954 must delete every file from the temporary directory before we start processing the logs.
1956 But the temporary directory is given by the user either in the configuration file or
1957 on the command line. We check that the user didn't give a wrong directory by looking
1958 at the files stored in the directory. If a single file is not one of ours, we abort.
1960 \param dir The temporary directory to purge.
1962 void emptytmpdir(const char *dir
)
1966 struct dirent
*direntp
;
1972 static const char *TmpExt
[]=
1987 // make sure the temporary directory contains only our files
1988 while ((direntp
= readdir(dirp
)) != NULL
) {
1989 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
1990 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
1993 // is it one of our files
1994 dlen
=strlen(direntp
->d_name
);
1995 for (i
=sizeof(TmpExt
)/sizeof(TmpExt
[0])-1 ; i
>=0 ; i
--) {
1996 elen
=strlen(TmpExt
[i
]);
1997 if (dlen
>=elen
&& strcasecmp(direntp
->d_name
+dlen
-elen
,TmpExt
[i
])==0) break;
2000 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2001 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2002 "directory or manually delete the content of \"%s\"\n"),direntp
->d_name
,dir
,dir
);
2006 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
2007 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
2012 err
=lstat(dname
,&st
);
2014 err
=stat(dname
,&st
);
2017 debuga(_("cannot stat \"%s\"\n"),dname
);
2020 if (S_ISDIR(st
.st_mode
)) {
2022 } else if (!S_ISREG(st
.st_mode
)) {
2023 debuga(_("Unknown path type \"%s\". Check your temporary directory\n"),dname
);
2029 // now delete our files
2030 while ((direntp
= readdir(dirp
)) != NULL
) {
2031 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
2032 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
2035 // is it one of our files
2036 dlen
=strlen(direntp
->d_name
);
2037 for (i
=sizeof(TmpExt
)/sizeof(TmpExt
[0])-1 ; i
>=0 ; i
--) {
2038 elen
=strlen(TmpExt
[i
]);
2039 if (dlen
>=elen
&& strcasecmp(direntp
->d_name
+dlen
-elen
,TmpExt
[i
])==0) break;
2042 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2043 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2044 "directory or manually delete the content of \"%s\"\n"),direntp
->d_name
,dir
,dir
);
2048 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
2049 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
2053 err
=lstat(dname
,&st
);
2055 err
=stat(dname
,&st
);
2058 debuga(_("cannot stat \"%s\"\n"),dname
);
2061 if (S_ISREG(st
.st_mode
)) {
2062 if (unlink(dname
)) {
2063 debuga(_("Cannot delete \"%s\": %s\n"),dname
,strerror(errno
));
2067 debuga(_("unknown path type %s\n"),dname
);
2074 Extract an url, IPv4 or IPv6 from a buffer. The IP addresses may end with a
2077 \param buf The buffer to parse.
2078 \param text A pointer to set to the beginning of the string pattern. No terminating zero is inserted.
2079 The pointer may be NULL.
2080 \param ipv4 A 4 bytes buffer to store the bytes of the IPv4 address.
2081 \param ipv6 A 8 short integers buffer to store the values of the IPv6 address.
2082 \param nbits The number of prefix bits for an IP address.
2083 \param next The content of the line after the extracted address.
2085 \retval 3 The pattern is a IPv6 address.
2086 \retval 2 The pattern is a IPv4 address.
2087 \retval 1 The patter is a string.
2088 \retval 0 Empty pattern.
2090 int extract_address_mask(const char *buf
,const char **text
,unsigned char *ipv4
,unsigned short int *ipv6
,int *nbits
,const char **next
)
2095 unsigned int value4
, value6
;
2096 unsigned short int addr
[8];
2106 // skip leading spaces and tabs
2107 while (*buf
&& (*buf
==' ' || *buf
=='\t')) buf
++;
2109 // find out the nature of the pattern
2110 ip_size
=0x60 | 0x04;
2121 for (i
=0 ; (unsigned char)buf
[i
]>' ' && buf
[i
]!='/' && buf
[i
]!='?' && (!bracket
|| buf
[i
]!=']') && ip_size
; i
++) {
2122 if (ip_size
& 0x04) {
2123 if (isdigit(buf
[i
])) {
2125 port_num
=port_num
*10+(buf
[i
]-'0');
2126 if (port_num
>65535) ip_size
&=~0x04;
2128 value4
=value4
*10+(buf
[i
]-'0');
2129 if (value4
>0xFFU
) ip_size
&=~0x04;
2131 } else if (buf
[i
]=='.' && addr_len
<4) {
2132 addr
[addr_len
++]=(unsigned short)(value4
& 0xFFU
);
2134 } else if (!port
&& buf
[i
]==':') {
2140 if (ip_size
& 0x60) {
2141 if (isdigit(buf
[i
])) {
2142 value6
=(value6
<<4)+(buf
[i
]-'0');
2144 if (value6
>0xFFFFU
) ip_size
&=~0x60;
2145 } else if (toupper(buf
[i
])>='A' && toupper(buf
[i
])<='F') {
2146 value6
=(value6
<<4)+(toupper(buf
[i
])-'A'+10);
2148 if (value6
>0xFFFFU
) ip_size
&=~0x60;
2149 } else if (buf
[i
]==':' && addr_len
<8) {
2150 if (nibble6_len
>0) {
2151 addr
[addr_len
++]=(unsigned short)(value6
& 0xFFFFU
);
2155 if (buf
[i
+1]==':') {
2164 if (i
==0) return(0);
2165 if (ip_size
& 0x04) {
2169 addr
[addr_len
++]=(unsigned short)(value4
& 0xFFU
);
2171 if (ip_size
& 0x60) {
2172 if (pad_pos
<0 && addr_len
!=7) {
2174 } else if (pad_pos
>=0 && addr_len
>=7)
2176 else if (nibble6_len
>0)
2177 addr
[addr_len
++]=(unsigned short)(value6
& 0xFFFFU
);
2182 if (bracket
) (*text
)--;
2184 while ((unsigned char)buf
[i
]>' ') i
++;
2185 if (next
) *next
=buf
+i
;
2188 max_mask
=(ip_size
& 0x04) ? 4*8 : 8*16;
2192 while (isdigit(buf
[i
])) i
++;
2193 if (mask
<0 || mask
>max_mask
) mask
=max_mask
;
2196 if (ip_size
& 0x60 && bracket
&& buf
[i
]==']') i
++;
2197 if (next
) *next
=buf
+i
;
2198 if (ip_size
& 0x04) {
2199 if (nbits
) *nbits
=mask
;
2200 for (i
=0 ; i
<addr_len
; i
++)
2201 ipv4
[i
]=(unsigned char)addr
[i
];
2206 if (nbits
) *nbits
=mask
;
2211 ipv6
[j
++]=(unsigned short int)addr
[i
++];
2213 while (j
<pad_pos
+pad_len
)
2217 ipv6
[j
++]=(unsigned short int)addr
[i
++];