]>
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;
951 int getperiod_buildtext(struct periodstruct
*period
)
955 char text1
[40], text2
[40];
958 i
=strftime(text1
, sizeof(text1
), "%Y %b %d", &period
->start
);
960 i
=strftime(text1
, sizeof(text1
), "%d %b %Y", &period
->start
);
961 } else /*if (df=='w')*/ {
962 IndexTree
=INDEX_TREE_FILE
;
963 i
=strftime(text1
, sizeof(text1
), "%Y.%U", &period
->start
);
965 if (i
== 0) return(-1);
967 range
=(period
->start
.tm_year
!=period
->end
.tm_year
||
968 period
->start
.tm_mon
!=period
->end
.tm_mon
||
969 period
->start
.tm_mday
!=period
->end
.tm_mday
);
972 i
=strftime(text2
, sizeof(text2
)-i
, "%Y %b %d", &period
->end
);
973 } else if (df
=='e') {
974 i
=strftime(text2
, sizeof(text2
)-i
, "%d %b %Y", &period
->end
);
976 i
=strftime(text2
, sizeof(text2
)-i
, "%Y.%U", &period
->end
);
978 if (i
== 0) return(-1);
982 snprintf(period
->text
,sizeof(period
->text
),"%s-%s",text1
,text2
);
983 snprintf(period
->html
,sizeof(period
->html
),"%s—%s",text1
,text2
);
985 safe_strcpy(period
->text
,text1
,sizeof(period
->text
));
986 safe_strcpy(period
->html
,text1
,sizeof(period
->html
));
991 static void copy_images(void)
993 FILE *img_in
, *img_ou
;
996 char srcfile
[MAXLEN
];
997 char dstfile
[MAXLEN
];
999 struct dirent
*direntp
;
1000 char buffer
[MAXLEN
];
1004 if (snprintf(images
,sizeof(images
),"%simages",outdir
)>=sizeof(images
)) {
1005 debuga(_("Cannot copy images to target directory %simages\n"),outdir
);
1008 if (access(images
,R_OK
)!=0) {
1009 if (mkdir(images
,0755)) {
1010 debuga(_("Cannot create directory %s - %s\n"),images
,strerror(errno
));
1015 strcpy(imgdir
,IMAGEDIR
);
1016 dirp
= opendir(imgdir
);
1018 debuga(_("(util) Can't open directory %s: %s\n"),imgdir
,strerror(errno
));
1021 while ((direntp
= readdir( dirp
)) != NULL
){
1022 if(direntp
->d_name
[0]=='.')
1024 sprintf(srcfile
,"%s/%s",imgdir
,direntp
->d_name
);
1025 if (stat(srcfile
,&info
)) {
1026 debuga(_("Cannot stat \"%s\" - %s\n"),srcfile
,strerror(errno
));
1029 if (S_ISREG(info
.st_mode
)) {
1030 sprintf(dstfile
,"%s/%s",images
,direntp
->d_name
);
1031 img_in
= fopen(srcfile
, "rb");
1033 img_ou
= fopen(dstfile
, "wb");
1035 while ((nread
= fread(buffer
,1,sizeof(buffer
),img_in
))>0) {
1036 if (fwrite(buffer
,1,nread
,img_ou
)!=nread
) {
1037 debuga(_("Failed to copy image %s to %s\n"),srcfile
,dstfile
);
1043 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open/create file", dstfile
, strerror(errno
));
1046 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open file", srcfile
, strerror(errno
));
1049 (void) closedir(dirp
);
1054 int vrfydir(const struct periodstruct
*per1
, const char *addr
, const char *site
, const char *us
, const char *form
)
1059 char dirname2
[MAXLEN
];
1067 strcpy(wdir
,outdir
);
1069 y1
=per1
->start
.tm_year
+1900;
1070 y2
=per1
->end
.tm_year
+1900;
1071 m1
=per1
->start
.tm_mon
+1;
1072 m2
=per1
->end
.tm_mon
+1;
1073 d1
=per1
->start
.tm_mday
;
1074 d2
=per1
->end
.tm_mday
;
1075 if(IndexTree
== INDEX_TREE_DATE
) {
1076 wlen
+=sprintf(wdir
+wlen
,"%04d",y1
);
1077 if(y1
!=y2
) wlen
+=sprintf(wdir
+wlen
,"-%04d",y2
);
1078 if(access(wdir
, R_OK
) != 0)
1081 wlen
+=sprintf(wdir
+wlen
,"/%02d",m1
);
1082 if(m1
!= m2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",m2
);
1083 if(access(wdir
, R_OK
) != 0)
1086 wlen
+=sprintf(wdir
+wlen
,"/%02d",d1
);
1087 if(d1
!=d2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",d2
);
1090 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%04d%s%02d-%04d%s%02d",y1
,
1091 conv_month_name(m1
),d1
,y2
,conv_month_name(m2
),d2
);
1092 } else if (df
== 'e') {
1093 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%02d%s%04d-%02d%s%04d",d1
,
1094 conv_month_name(m1
),y1
,d2
,conv_month_name(m2
),y2
);
1095 } else if (df
== 'w') {
1096 wlen2
=strftime(wdir
+wlen
, sizeof(wdir
)-wlen
, "%Y.%U", &per1
->start
);
1097 if (wlen2
==0) return(-1);
1103 struct userinfostruct
*uinfo
=userinfo_find_from_id(us
);
1106 strcat(wdir
,uinfo
->filename
);
1109 if(addr
[0] != '\0') {
1113 if(site
[0] != '\0') {
1118 strcpy(outdirname
,wdir
);
1120 if(IndexTree
!= INDEX_TREE_DATE
) {
1121 if(!OverwriteReport
) {
1123 if(access(wdir
,R_OK
) == 0) {
1124 sprintf(wdir
,"%s.%d",outdirname
,num
);
1133 debuga(_("File %s already exists, moved to %s\n"),outdirname
,wdir
);
1134 rename(outdirname
,wdir
);
1137 if(access(outdirname
,R_OK
) == 0) {
1138 unlinkdir(outdirname
,1);
1141 my_mkdir(outdirname
);
1143 strcpy(dirname2
,wdir
);
1144 if(!OverwriteReport
) {
1146 if(access(wdir
,R_OK
) == 0) {
1147 sprintf(wdir
,"%s.%d",dirname2
,num
);
1156 debuga(_("File %s already exists, moved to %s\n"),dirname2
,wdir
);
1157 rename(dirname2
,wdir
);
1158 strcpy(dirname2
,wdir
);
1161 if(access(wdir
,R_OK
) == 0) {
1166 if(access(wdir
, R_OK
) != 0)
1170 strcpy(dirname2
,wdir
);
1172 sprintf(wdir
,"%s/sarg-date",outdirname
);
1173 if ((fp_ou
= fopen(wdir
, "wt")) == 0) {
1174 debuga(_("cannot open %s for writing\n"),wdir
);
1179 //strftime(wdir,sizeof(wdir),"%a %b %d %H:%M:%S %Z %Y",localtime(&curtime));
1180 loctm
=localtime(&curtime
);
1181 strftime(wdir
,sizeof(wdir
),"%Y-%m-%d %H:%M:%S",loctm
);
1182 if (fprintf(fp_ou
,"%s %d\n",wdir
,loctm
->tm_isdst
)<0) {
1183 debuga(_("Failed to write the date in %s\n"),wdir
);
1187 if (fclose(fp_ou
)==EOF
) {
1188 debuga(_("Failed to write the date in %s\n"),wdir
);
1198 Copy a string without overflowing the buffer. The copied string
1199 is properly terminated by an ASCII zero.
1201 \param dest The destination buffer.
1202 \param src The source buffer.
1203 \param length The size of the destination buffer. The program is aborted
1204 if the length is negative or zero.
1206 void safe_strcpy(char *dest
,const char *src
,int length
)
1209 debuga(_("Invalid buffer length passed to the function to safely copy a string\n"));
1212 strncpy(dest
,src
,length
-1);
1213 dest
[length
-1]='\0';
1216 void strip_latin(char *line
)
1223 for (i
=0;line
[i
];i
++){
1225 if (line
[i
]==';') skip
=0;
1237 void zdate(char *ftime
,int ftimesize
, char DateFormat
)
1243 local
= localtime(&t
);
1244 if (DateFormat
=='u')
1245 strftime(ftime
, ftimesize
, "%b/%d/%Y %H:%M", local
);
1246 else if (DateFormat
=='e')
1247 strftime(ftime
, ftimesize
, "%d/%b/%Y-%H:%M", local
);
1248 else if (DateFormat
=='w')
1249 strftime(ftime
, ftimesize
, "%W-%H-%M", local
);
1254 char *fixtime(long long int elap
)
1256 int num
= elap
/ 1000;
1260 static char buf
[12];
1263 min
=(num
% 3600) / 60;
1266 if(hor
==0 && min
==0 && sec
==0)
1269 sprintf(buf
,"%d:%02d:%02d",hor
,min
,sec
);
1275 void date_from(char *date
, int *dfrom
, int *duntil
)
1284 if (isdigit(date
[0])) {
1287 if (sscanf(date
,"%d/%d/%d%n",&d0
,&m0
,&y0
,&next
)!=3 || y0
<100 || m0
<1 || m0
>12 || d0
<1 || d0
>31 || next
<0) {
1288 debuga(_("The date passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1291 if (date
[next
]=='-') {
1292 if (sscanf(date
+next
+1,"%d/%d/%d",&d1
,&m1
,&y1
)!=3 || y1
<100 || m1
<1 || m1
>12 || d1
<1 || d1
>31) {
1293 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1296 } else if (date
[next
]!='\0') {
1297 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1307 struct tm
*Date0
,Date1
;
1309 if (time(&Today
)==(time_t)-1) {
1310 debuga(_("Failed to get the current time\n"));
1313 if (sscanf(date
,"day-%d",&i
)==1) {
1315 debuga(_("Invalid number of days in -d parameter\n"));
1319 Date0
=localtime(&Today
);
1321 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1324 y0
=y1
=Date0
->tm_year
+1900;
1325 m0
=m1
=Date0
->tm_mon
+1;
1326 d0
=d1
=Date0
->tm_mday
;
1327 } else if (sscanf(date
,"week-%d",&i
)==1) {
1329 There is no portable way to find the first day of the week even though the
1330 information is available in the locale. nl_langinfo has the unofficial
1331 parameters _NL_TIME_FIRST_WEEKDAY and _NL_TIME_WEEK_1STDAY but they are
1332 undocumented as is their return value and it is discouraged to use them.
1333 Beside, nl_langinfo isn't available on windows and the first day of the
1334 week isn't available at all on that system.
1336 const int FirstWeekDay
=1;
1340 debuga(_("Invalid number of weeks in -d parameter\n"));
1343 Date0
=localtime(&Today
);
1345 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1348 WeekBegin
=Today
-((Date0
->tm_wday
-FirstWeekDay
+7)%7)*24*60*60;
1349 WeekBegin
-=i
*7*24*60*60;
1350 Date0
=localtime(&WeekBegin
);
1352 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1355 y0
=Date0
->tm_year
+1900;
1358 WeekBegin
+=6*24*60*60;
1359 Date0
=localtime(&WeekBegin
);
1361 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1364 y1
=Date0
->tm_year
+1900;
1367 } else if (sscanf(date
,"month-%d",&i
)==1) {
1369 debuga(_("Invalid number of months in -d parameter\n"));
1372 Date0
=localtime(&Today
);
1374 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1377 if (Date0
->tm_mon
<i
%12) {
1378 y0
=Date0
->tm_year
+1900-i
/12-1;
1379 m0
=(Date0
->tm_mon
+12-i
%12)%12+1;
1382 y0
=Date0
->tm_year
+1900-i
/12;
1383 m0
=Date0
->tm_mon
-i
%12+1;
1386 memcpy(&Date1
,Date0
,sizeof(struct tm
));
1391 Date1
.tm_year
=y0
-1900;
1394 Date1
.tm_year
=y0
-1900+1;
1398 Date0
=localtime(&t1
);
1399 y1
=Date0
->tm_year
+1900;
1403 debuga(_("Invalid date range passed on command line\n"));
1408 *dfrom
=y0
*10000+m0
*100+d0
;
1409 *duntil
=y1
*10000+m1
*100+d1
;
1410 sprintf(date
,"%02d/%02d/%04d-%02d/%02d/%04d",d0
,m0
,y0
,d1
,m1
,y1
);
1415 char *strlow(char *string
)
1421 for (s
= string
; *s
; ++s
)
1431 char *strup(char *string
)
1437 for (s
= string
; *s
; ++s
)
1445 void removetmp(const char *outdir
)
1450 if(!RemoveTempFiles
)
1454 debuga(_("Purging temporary file sarg-general\n"));
1456 if (snprintf(filename
,sizeof(filename
),"%s/sarg-general",outdir
)>=sizeof(filename
)) {
1457 debuga(_("(removetmp) directory too long to remove %s/sarg-period\n"),outdir
);
1460 if((fp_gen
=fopen(filename
,"w"))==NULL
){
1461 debuga(_("(removetmp) Cannot open file %s\n"),filename
);
1464 totalger(fp_gen
,filename
);
1465 if (fclose(fp_gen
)==EOF
) {
1466 debuga(_("Failed to close %s after writing the total line - %s\n"),filename
,strerror(errno
));
1471 void load_excludecodes(const char *ExcludeCodes
)
1479 if(ExcludeCodes
[0] == '\0')
1482 if((fp_in
=fopen(ExcludeCodes
,"r"))==NULL
) {
1483 debuga(_("(util) Cannot open file %s (exclude_codes)\n"),ExcludeCodes
);
1487 if (fseek(fp_in
, 0, SEEK_END
)==-1) {
1488 debuga(_("Failed to move till the end of the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1491 MemSize
= ftell(fp_in
);
1493 debuga(_("Cannot get the size of file %s\n"),ExcludeCodes
);
1496 if (fseek(fp_in
, 0, SEEK_SET
)==-1) {
1497 debuga(_("Failed to rewind the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1502 if((excludecode
=(char *) malloc(MemSize
))==NULL
) {
1503 debuga(_("malloc error (%ld)\n"),MemSize
);
1506 memset(excludecode
,0,MemSize
);
1509 while(fgets(data
,sizeof(data
),fp_in
)!=NULL
) {
1510 if (data
[0]=='#') continue;
1511 for (i
=strlen(data
)-1 ; i
>=0 && (unsigned char)data
[i
]<=' ' ; i
--) data
[i
]='\0';
1513 if (Stored
+i
+2>=MemSize
) {
1514 debuga(_("Too many codes to exclude in file %s\n"),ExcludeCodes
);
1517 strcat(excludecode
,data
);
1518 strcat(excludecode
,";");
1526 void free_excludecodes(void)
1534 int vercode(const char *code
)
1539 if (excludecode
&& excludecode
[0]!='\0') {
1543 if (strncmp(code
,cod
,clen
)==0 && cod
[clen
]==';')
1545 cod
=strchr(cod
,';');
1552 void fixnone(char *str
)
1556 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--);
1557 if(i
==3 && strncmp(str
,"none",4) == 0)
1563 void fixendofline(char *str
)
1567 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--) str
[i
]=0;
1570 #ifdef LEGACY_TESTVALIDUSERCHAR
1571 int testvaliduserchar(const char *user
)
1576 for (y
=0; y
<strlen(UserInvalidChar
); y
++) {
1577 for (x
=0; x
<strlen(user
); x
++) {
1578 if(user
[x
] == UserInvalidChar
[y
])
1585 int testvaliduserchar(const char *user
)
1587 char * p_UserInvalidChar
= UserInvalidChar
;
1588 const char * p_user
;
1590 while( *p_UserInvalidChar
) {
1593 if( *p_UserInvalidChar
== *p_user
)
1597 p_UserInvalidChar
++ ;
1603 int compar( const void *a
, const void *b
)
1605 if( *(int *)a
> *(int *)b
) return 1;
1606 if( *(int *)a
< *(int *)b
) return -1;
1610 int getnumlist( char *buf
, numlist
*list
, const int len
, const int maxvalue
)
1612 int i
, j
, d
, flag
, r1
, r2
;
1613 char *pbuf
, **bp
, *strbufs
[ 24 ];
1616 strtok( buf
, " \t" );
1617 for( *bp
= strtok( NULL
, "," ), list
->len
= 0; *bp
; *bp
= strtok( NULL
, "," ) ) {
1618 if( ++bp
>= &strbufs
[ 24 ] )
1625 for( i
= 0; i
< list
->len
; i
++ ) {
1626 if( strchr( strbufs
[ i
], '-' ) != 0 ) {
1627 pbuf
= strbufs
[ i
];
1628 strtok( pbuf
, "-" );
1629 pbuf
= strtok( NULL
, "\0" );
1630 r1
= atoi( strbufs
[ i
] );
1631 if( ( r2
= atoi( pbuf
) ) >= maxvalue
|| r1
>= r2
)
1633 if( i
+ d
+ ( r2
- r1
) + 1 <= len
) {
1634 for( j
= r1
; j
<= r2
; j
++ )
1635 list
->list
[ i
+ d
++ ] = j
;
1640 if( ( list
->list
[ i
+ d
] = atoi( strbufs
[ i
] ) ) >= maxvalue
)
1644 qsort( list
->list
, list
->len
, sizeof( int ), compar
);
1647 for( i
= 0; i
< list
->len
- 1; i
++ )
1648 if( list
->list
[ i
] == list
->list
[ i
+ 1 ] ) {
1649 for( j
= i
+ 1; j
< list
->len
; j
++ )
1650 list
->list
[ j
- 1 ] = list
->list
[ j
];
1660 char *get_size(const char *path
, const char *file
)
1663 static char response
[255];
1667 if (snprintf(cmd
,sizeof(cmd
),"du -skh %s%s",path
,file
)>=sizeof(cmd
)) {
1668 debuga(_("Cannot get disk space because the path %s%s is too long\n"),path
,file
);
1671 if ((fp
= popen(cmd
, "r")) == NULL
) {
1672 debuga(_("Cannot get disk space with command %s\n"),cmd
);
1675 if (!fgets(response
, sizeof(response
), fp
)) {
1676 debuga(_("Cannot get disk size with command %s\n"),cmd
);
1679 ptr
=strchr(response
,'\t');
1681 debuga(_("The command %s failed\n"),cmd
);
1690 void show_info(FILE *fp_ou
)
1694 if(!ShowSargInfo
) return;
1695 zdate(ftime
, sizeof(ftime
), df
);
1696 fprintf(fp_ou
,"<div class=\"info\">%s <a href='%s'>%s-%s</a> %s %s</div>\n",_("Generated by"),URL
,PGM
,VERSION
,_("on"),ftime
);
1699 void show_sarg(FILE *fp_ou
, int depth
)
1703 if(!ShowSargLogo
) return;
1704 fputs("<div class=\"logo\"><a href=\"http://sarg.sourceforge.net\"><img src=\"",fp_ou
);
1705 for (i
=0 ; i
<depth
; i
++)
1707 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
);
1710 void write_logo_image(FILE *fp_ou
)
1712 if(LogoImage
[0]!='\0')
1713 fprintf(fp_ou
, "<div class=\"logo\"><img src=\"%s\" width=\"%s\" height=\"%s\" alt=\"Logo\"> %s</div>\n",LogoImage
,Width
,Height
,LogoText
);
1716 void write_html_head(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1720 fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n",fp_ou
);
1721 fprintf(fp_ou
, "<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n",CharSet
);
1722 if (page_title
) fprintf(fp_ou
,"<title>%s</title>\n",page_title
);
1724 if ((javascript
& HTML_JS_SORTTABLE
)!=0 && SortTableJs
[0]) {
1725 fputs("<script type=\"text/javascript\" src=\"",fp_ou
);
1726 if (strncmp(SortTableJs
,"../",3)==0) {
1727 for (i
=0 ; i
<depth
; i
++) fputs("../",fp_ou
);
1729 fputs(SortTableJs
,fp_ou
);
1730 fputs("\"></script>\n",fp_ou
);
1732 fputs("</head>\n<body>\n",fp_ou
);
1735 void write_html_header(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1737 write_html_head(fp_ou
,depth
,page_title
,javascript
);
1738 write_logo_image(fp_ou
);
1739 show_sarg(fp_ou
, depth
);
1740 fprintf(fp_ou
,"<div class=\"title\"><table cellpadding=\"0\" cellspacing=\"0\">\n<tr><th class=\"title_c\">%s</th></tr>\n",Title
);
1743 void close_html_header(FILE *fp_ou
)
1745 fputs("</table></div>\n",fp_ou
);
1748 int write_html_trailer(FILE *fp_ou
)
1751 if (fputs("</body>\n</html>\n",fp_ou
)==EOF
) return(-1);
1755 void output_html_string(FILE *fp_ou
,const char *str
,int maxlen
)
1759 while (*str
&& (maxlen
<=0 || i
<maxlen
)) {
1762 fputs("&",fp_ou
);
1765 fputs("<",fp_ou
);
1768 fputs(">",fp_ou
);
1771 fputs(""",fp_ou
);
1774 fputs("'",fp_ou
);
1782 if (maxlen
>0 && i
>=maxlen
)
1783 fputs("…",fp_ou
);
1786 void output_html_url(FILE *fp_ou
,const char *url
)
1790 fputs("&",fp_ou
);
1798 Write a host name inside an A tag of a HTML file. If the host name starts
1799 with a star, it is assumed to be an alias that cannot be put inside a link
1800 so the A tag is not written around the host name.
1802 \param fp_ou The handle of the HTML file.
1803 \param url The host to display in the HTML file.
1804 \param maxlen The maximum number of characters to print into the host name.
1806 void output_html_link(FILE *fp_ou
,const char *url
,int maxlen
)
1808 if (url
[0]==ALIAS_PREFIX
) {
1809 // this is an alias, no need for a A tag
1810 output_html_string(fp_ou
,url
+1,100);
1812 if (skip_scheme(url
)==url
)
1813 fputs("<a href=\"http://",fp_ou
);//no scheme in the url, assume http:// to make the link clickable
1815 fputs("<a href=\"",fp_ou
);//the scheme is in the url, no need to add one
1816 output_html_url(fp_ou
,url
);
1818 output_html_string(fp_ou
,url
,100);
1819 fputs("</a>",fp_ou
);
1823 void url_module(const char *url
, char *w2
)
1829 for(x
=strlen(url
)-1; x
>=0; x
--) {
1830 if(url
[x
] == '/' || y
>=sizeof(w
)-1) break;
1839 for(y
=y
-1; y
>=0; y
--) {
1845 void url_to_file(const char *url
,char *file
,int filesize
)
1851 for(i
=0; i
<filesize
&& *url
; url
++) {
1852 if(isalnum(*url
) || *url
=='-' || *url
=='_' || *url
=='.' || *url
=='%') {
1856 if (!skip
) file
[i
++]='_';
1865 printf(_("SARG Version: %s\n"),VERSION
);
1869 char *get_param_value(const char *param
,char *line
)
1873 while (*line
==' ' || *line
=='\t') line
++;
1875 if (strncasecmp(line
,param
,plen
)) return(NULL
);
1876 if (line
[plen
]!=' ' && line
[plen
]!='\t') return(NULL
);
1878 while (*line
==' ' || *line
=='\t') line
++;
1882 void unlinkdir(const char *dir
,bool contentonly
)
1886 struct dirent
*direntp
;
1892 while ((direntp
= readdir(dirp
)) != NULL
) {
1893 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
1894 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
1896 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
1897 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
1901 err
=lstat(dname
,&st
);
1903 err
=stat(dname
,&st
);
1906 debuga(_("cannot stat %s\n"),dname
);
1909 if (S_ISREG(st
.st_mode
)) {
1910 if (unlink(dname
)) {
1911 debuga(_("Cannot delete \"%s\": %s\n"),dname
,strerror(errno
));
1914 } else if (S_ISDIR(st
.st_mode
)) {
1917 debuga(_("unknown path type %s\n"),dname
);
1924 debuga(_("Cannot delete \"%s\": %s\n"),dir
,strerror(errno
));
1931 Delete every file from the temporary directory where sarg is told to store its
1934 As any stray file left over by a previous run would be included in the report, we
1935 must delete every file from the temporary directory before we start processing the logs.
1937 But the temporary directory is given by the user either in the configuration file or
1938 on the command line. We check that the user didn't give a wrong directory by looking
1939 at the files stored in the directory. If a single file is not one of ours, we abort.
1941 \param dir The temporary directory to purge.
1943 void emptytmpdir(const char *dir
)
1947 struct dirent
*direntp
;
1953 static const char *TmpExt
[]=
1968 // make sure the temporary directory contains only our files
1969 while ((direntp
= readdir(dirp
)) != NULL
) {
1970 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
1971 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
1974 // is it one of our files
1975 dlen
=strlen(direntp
->d_name
);
1976 for (i
=sizeof(TmpExt
)/sizeof(TmpExt
[0])-1 ; i
>=0 ; i
--) {
1977 elen
=strlen(TmpExt
[i
]);
1978 if (dlen
>=elen
&& strcasecmp(direntp
->d_name
+dlen
-elen
,TmpExt
[i
])==0) break;
1981 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
1982 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
1983 "directory or manually delete the content of \"%s\"\n"),direntp
->d_name
,dir
,dir
);
1987 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
1988 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
1993 err
=lstat(dname
,&st
);
1995 err
=stat(dname
,&st
);
1998 debuga(_("cannot stat \"%s\"\n"),dname
);
2001 if (S_ISDIR(st
.st_mode
)) {
2003 } else if (!S_ISREG(st
.st_mode
)) {
2004 debuga(_("Unknown path type \"%s\". Check your temporary directory\n"),dname
);
2010 // now delete our files
2011 while ((direntp
= readdir(dirp
)) != NULL
) {
2012 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
2013 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
2016 // is it one of our files
2017 dlen
=strlen(direntp
->d_name
);
2018 for (i
=sizeof(TmpExt
)/sizeof(TmpExt
[0])-1 ; i
>=0 ; i
--) {
2019 elen
=strlen(TmpExt
[i
]);
2020 if (dlen
>=elen
&& strcasecmp(direntp
->d_name
+dlen
-elen
,TmpExt
[i
])==0) break;
2023 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2024 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2025 "directory or manually delete the content of \"%s\"\n"),direntp
->d_name
,dir
,dir
);
2029 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
2030 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
2034 err
=lstat(dname
,&st
);
2036 err
=stat(dname
,&st
);
2039 debuga(_("cannot stat \"%s\"\n"),dname
);
2042 if (S_ISREG(st
.st_mode
)) {
2043 if (unlink(dname
)) {
2044 debuga(_("Cannot delete \"%s\": %s\n"),dname
,strerror(errno
));
2048 debuga(_("unknown path type %s\n"),dname
);
2055 Extract an url, IPv4 or IPv6 from a buffer. The IP addresses may end with a
2058 \param buf The buffer to parse.
2059 \param text A pointer to set to the beginning of the string pattern. No terminating zero is inserted.
2060 The pointer may be NULL.
2061 \param ipv4 A 4 bytes buffer to store the bytes of the IPv4 address.
2062 \param ipv6 A 8 short integers buffer to store the values of the IPv6 address.
2063 \param nbits The number of prefix bits for an IP address.
2064 \param next The content of the line after the extracted address.
2066 \retval 3 The pattern is a IPv6 address.
2067 \retval 2 The pattern is a IPv4 address.
2068 \retval 1 The patter is a string.
2069 \retval 0 Empty pattern.
2071 int extract_address_mask(const char *buf
,const char **text
,unsigned char *ipv4
,unsigned short int *ipv6
,int *nbits
,const char **next
)
2076 unsigned int value4
, value6
;
2077 unsigned short int addr
[8];
2087 // skip leading spaces and tabs
2088 while (*buf
&& (*buf
==' ' || *buf
=='\t')) buf
++;
2090 // find out the nature of the pattern
2091 ip_size
=0x60 | 0x04;
2102 for (i
=0 ; (unsigned char)buf
[i
]>' ' && buf
[i
]!='/' && buf
[i
]!='?' && (!bracket
|| buf
[i
]!=']') && ip_size
; i
++) {
2103 if (ip_size
& 0x04) {
2104 if (isdigit(buf
[i
])) {
2106 port_num
=port_num
*10+(buf
[i
]-'0');
2107 if (port_num
>65535) ip_size
&=~0x04;
2109 value4
=value4
*10+(buf
[i
]-'0');
2110 if (value4
>0xFFU
) ip_size
&=~0x04;
2112 } else if (buf
[i
]=='.' && addr_len
<4) {
2113 addr
[addr_len
++]=(unsigned short)(value4
& 0xFFU
);
2115 } else if (!port
&& buf
[i
]==':') {
2121 if (ip_size
& 0x60) {
2122 if (isdigit(buf
[i
])) {
2123 value6
=(value6
<<4)+(buf
[i
]-'0');
2125 if (value6
>0xFFFFU
) ip_size
&=~0x60;
2126 } else if (toupper(buf
[i
])>='A' && toupper(buf
[i
])<='F') {
2127 value6
=(value6
<<4)+(toupper(buf
[i
])-'A'+10);
2129 if (value6
>0xFFFFU
) ip_size
&=~0x60;
2130 } else if (buf
[i
]==':' && addr_len
<8) {
2131 if (nibble6_len
>0) {
2132 addr
[addr_len
++]=(unsigned short)(value6
& 0xFFFFU
);
2136 if (buf
[i
+1]==':') {
2145 if (i
==0) return(0);
2146 if (ip_size
& 0x04) {
2150 addr
[addr_len
++]=(unsigned short)(value4
& 0xFFU
);
2152 if (ip_size
& 0x60) {
2153 if (pad_pos
<0 && addr_len
!=7) {
2155 } else if (pad_pos
>=0 && addr_len
>=7)
2157 else if (nibble6_len
>0)
2158 addr
[addr_len
++]=(unsigned short)(value6
& 0xFFFFU
);
2163 if (bracket
) (*text
)--;
2165 while ((unsigned char)buf
[i
]>' ') i
++;
2166 if (next
) *next
=buf
+i
;
2169 max_mask
=(ip_size
& 0x04) ? 4*8 : 8*16;
2173 while (isdigit(buf
[i
])) i
++;
2174 if (mask
<0 || mask
>max_mask
) mask
=max_mask
;
2177 if (ip_size
& 0x60 && bracket
&& buf
[i
]==']') i
++;
2178 if (next
) *next
=buf
+i
;
2179 if (ip_size
& 0x04) {
2180 if (nbits
) *nbits
=mask
;
2181 for (i
=0 ; i
<addr_len
; i
++)
2182 ipv4
[i
]=(unsigned char)addr
[i
];
2187 if (nbits
) *nbits
=mask
;
2192 ipv6
[j
++]=(unsigned short int)addr
[i
++];
2194 while (j
<pad_pos
+pad_len
)
2198 ipv6
[j
++]=(unsigned short int)addr
[i
++];