]>
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 printf("SARG: getword loop detected after %d bytes.\n",x
);
87 printf("SARG: Line=\"%s\"\n",gwarea
->beginning
);
88 printf("SARG: Record=\"%s\"\n",gwarea
->current
);
89 printf("SARG: searching for \'x%x\'\n",stop
);
90 //printf("SARG: 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 printf("SARG: getword_multisep loop detected.\n");
128 printf("SARG: Line=\"%s\"\n",gwarea
->beginning
);
129 printf("SARG: Record=\"%s\"\n",gwarea
->current
);
130 printf("SARG: searching for \'x%x\'\n",stop
);
131 //printf("SARG: 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 printf("SARG: getword_skip loop detected after %d bytes.\n",x
);
155 printf("SARG: Line=\"%s\"\n",gwarea
->beginning
);
156 printf("SARG: Record=\"%s\"\n",gwarea
->current
);
157 printf("SARG: searching for \'x%x\'\n",stop
);
158 //printf("SARG: 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 printf("SARG: getword_atoll loop detected after %d bytes.\n",x
);
194 printf("SARG: Line=\"%s\"\n",gwarea
->beginning
);
195 printf("SARG: Record=\"%s\"\n",gwarea
->current
);
196 printf("SARG: searching for \'x%x\'\n",stop
);
197 //printf("SARG: 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 printf("SARG: getword_atoi loop detected after %d bytes.\n",x
);
233 printf("SARG: Line=\"%s\"\n",gwarea
->beginning
);
234 printf("SARG: Record=\"%s\"\n",gwarea
->current
);
235 printf("SARG: searching for \'x%x\'\n",stop
);
236 //printf("SARG: 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
;
250 int getword_ptr(char *orig_line
,char **word
, struct getwordstruct
*gwarea
, char stop
)
253 \note Why pass the original buffer to the function ? Because we must modify it to
254 insert the terminating ASCII zero for the word we return and that's not compatible
255 with getword_restart(). Moreover, getword_start() sometime works on constant strings
256 so this function require the original buffer to detect any missuse.
262 if (orig_line
&& orig_line
!=gwarea
->beginning
) {
263 debuga(_("Invalid buffer passed to getword_ptr\n"));
267 start
=(gwarea
->current
-gwarea
->beginning
);
268 if (word
&& orig_line
) *word
=orig_line
+start
;
269 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++);
270 sep
=(gwarea
->current
[x
]!='\0');
271 if (word
&& orig_line
) orig_line
[start
+x
] = '\0';
278 #define MAXLLL 30 //!< Maximum number of digits in long long (a guess).
279 long long int my_atoll (const char *nptr
)
281 long long int returnval
=0LL;
282 int max_digits
= MAXLLL
;
284 // Soak up all the white space
285 while (isspace( *nptr
)) {
289 //For each character left to right
290 //change the character to a single digit
291 //multiply what we had before by 10 and add the new digit
293 while (--max_digits
&& isdigit( *nptr
))
295 returnval
= ( returnval
* 10 ) + ( *nptr
++ - '0' ) ;
301 int is_absolute(const char *path
)
303 if (*path
=='/') return(1);
305 if (isalpha(path
[0]) && path
[1]==':') return(1);
310 void my_mkdir(const char *name
)
316 if(!is_absolute(name
)) {
317 debuga(_("Invalid path (%s). Please, use absolute paths only.\n"),name
);
318 debuga(_("process aborted.\n"));
323 for (i
=0 ; name
[i
] ; i
++) {
325 debuga(_("directory name too long: %s\n"),name
);
328 if (chars
>0 && name
[i
] == '/') {
330 if (access(w0
, R_OK
) != 0) {
331 if (mkdir(w0
,0755)) {
332 debuga(_("Cannot create directory %s - %s\n"),w0
,strerror(errno
));
333 debuga(_("process aborted.\n"));
338 if (name
[i
] != '/') chars
++;
342 if (access(name
, R_OK
) != 0) {
343 if (mkdir(name
,0755)) {
344 debuga(_("Cannot create directory %s - %s\n"),name
,strerror(errno
));
345 debuga(_("process aborted.\n"));
352 void my_lltoa(unsigned long long int n
, char *s
, int ssize
, int len
)
361 debuga(_("The requested number of digits passed to my_lltoa (%d) is bigger than the output buffer size (%d)\n"),len
,ssize
);
366 s
[slen
++] = (n
% 10) + '0';
367 } while ((n
/= 10) > 0 && slen
<ssize
);
370 for (i
= 0, j
= slen
-1; i
<j
; i
++, j
--) {
378 for(j
=slen
; j
>=0; j
--)
385 int month2num(const char *month
)
389 for(m
=0 ; m
<12 && strcmp(mtab1
[m
],month
) != 0; m
++);
393 int builddia(int day
, int month
, int year
)
395 return(year
*10000+month
*100+day
);
399 void buildymd(const char *dia
, const char *mes
, const char *ano
, char *wdata
)
404 sprintf(wdata
,"%04d%02d%02d",atoi(ano
),nmes
+1,atoi(dia
));
408 int conv_month(const char *month
)
412 for(x
=0; x
<12 && strncmp(mtab1
[x
],month
,3)!=0; x
++);
417 const char *conv_month_name(int month
)
421 if (month
<1 || month
>12) {
422 snprintf(str
,sizeof(str
),"%03d",month
);
425 return(mtab1
[month
-1]);
429 void name_month(char *month
,int month_len
)
431 int x
, z
=atoi(month
)-1;
434 struct getwordstruct gwarea
;
436 strcpy(m
,_("January,February,March,April,May,June,July,August,September,October,November,December"));
437 getword_start(&gwarea
,m
);
440 if (getword_multisep(w
,sizeof(w
),&gwarea
,',')<0) {
441 printf("SARG: Maybe you have a broken record or garbage in the names of the months.\n");
444 if (getword_multisep(month
,month_len
,&gwarea
,',')<0) {
445 printf("SARG: Maybe you have a broken record or garbage in the name of the months.\n");
452 Write a debug message to stderr. The message is prefixed by "SARG:" to identify its origin.
454 \param msg The printf like message to format.
455 \param ... The arguments to format in the message.
457 void debuga(const char *msg
,...)
461 fputs(_("SARG: "),stderr
);
463 vfprintf(stderr
,msg
,ap
);
469 Write a debug message to stderr. The message is prefixed by "SARG: (info)".
471 \param msg The printf like message to format.
472 \param ... The arguments to format in the message.
474 void debugaz(const char *msg
,...)
478 fputs(_("SARG: (info) "),stderr
);
480 vfprintf(stderr
,msg
,ap
);
485 char *fixnum(long long int value
, int n
)
487 #define MAXLEN_FIXNUM 256
488 char num
[MAXLEN_FIXNUM
]="";
489 char buf
[MAXLEN_FIXNUM
* 2];
491 static char ret
[MAXLEN_FIXNUM
* 2];
493 register int i
, j
, k
;
495 static char abbrev
[30];
497 my_lltoa(value
, num
, sizeof(num
), 0);
499 if(DisplayedValues
==DISPLAY_ABBREV
) {
500 numlen
= strlen(num
);
502 sprintf(abbrev
,"%s",num
);
503 if(numlen
== 4 || numlen
== 7 || numlen
== 10 || numlen
== 13) {
504 snprintf(abbrev
,2,"%s",num
);
505 strncat(abbrev
,".",1);
506 strncat(abbrev
,num
+1,2);
507 if(!n
) return(abbrev
);
509 strncat(abbrev
,"K",1);
511 strncat(abbrev
,"M",1);
512 else if(numlen
== 10)
513 strncat(abbrev
,"G",1);
514 else if(numlen
== 13)
515 strncat(abbrev
,"T",1);
517 if(numlen
== 5 || numlen
== 8 || numlen
== 11 || numlen
== 14) {
518 snprintf(abbrev
,3,"%s",num
);
519 strncat(abbrev
,".",1);
520 strncat(abbrev
,num
+2,2);
521 if(!n
) return(abbrev
);
523 strncat(abbrev
,"K",1);
525 strncat(abbrev
,"M",1);
526 else if(numlen
== 11)
527 strncat(abbrev
,"G",1);
528 else if(numlen
== 14)
529 strncat(abbrev
,"T",1);
531 if(numlen
== 6 || numlen
== 9 || numlen
== 12 || numlen
== 15) {
532 snprintf(abbrev
,4,"%s",num
);
533 strncat(abbrev
,".",1);
534 strncat(abbrev
,num
+3,2);
535 if(!n
) return(abbrev
);
537 strncat(abbrev
,"K",1);
539 strncat(abbrev
,"M",1);
540 else if(numlen
== 12)
541 strncat(abbrev
,"G",1);
542 else if(numlen
== 15)
543 strncat(abbrev
,"T",1);
549 bzero(buf
, MAXLEN_FIXNUM
*2);
555 for ( i
= strlen(num
) - 1, j
= 0 ; i
> -1; i
--) {
556 if ( k
== 2 && i
!= 0 ) {
559 pbuf
[j
++] = (UseComma
) ? ',' : '.';
569 for ( i
= strlen(pbuf
) - 1, j
= 0 ; i
> -1; i
--, j
++)
578 char *fixnum2(long long int value
, int n
)
580 #define MAXLEN_FIXNUM2 1024
581 char num
[MAXLEN_FIXNUM2
];
582 char buf
[MAXLEN_FIXNUM2
* 2];
584 static char ret
[MAXLEN_FIXNUM2
* 2];
586 register int i
, j
, k
;
588 my_lltoa(value
, num
, sizeof(num
), 0);
589 bzero(buf
, MAXLEN_FIXNUM2
*2);
595 for ( i
= strlen(num
) - 1, j
= 0 ; i
> -1; i
--) {
596 if ( k
== 2 && i
!= 0 ) {
599 pbuf
[j
++] = (UseComma
) ? ',' : '.';
609 for ( i
= strlen(pbuf
) - 1, j
= 0 ; i
> -1; i
--, j
++)
618 char *buildtime(long long int elap
)
620 int num
= elap
/ 1000;
629 min
=(num
% 3600) / 60;
631 sprintf(buf
,"%02d:%02d:%02d",hor
,min
,sec
);
638 Get the date stored in the <tt>sarg-date</tt> file of a directory with the connection data.
640 \param dirname The directory to look for the connection directory.
641 \param name The name of the directory whose <tt>sarg-date</tt> file must be read.
642 \param data The buffer to store the content of the file. It must be more than 80
646 \retval -1 File not found.
648 int obtdate(const char *dirname
, const char *name
, char *data
)
653 sprintf(wdir
,"%s%s/sarg-date",dirname
,name
);
654 if ((fp_in
= fopen(wdir
, "rt")) == 0) {
655 sprintf(wdir
,"%s%s/date",dirname
,name
);
656 if ((fp_in
= fopen(wdir
, "rt")) == 0) {
662 if (!fgets(data
,80,fp_in
)) {
663 debuga(_("Failed to read the date in %s\n"),wdir
);
673 void formatdate(char *date
,int date_size
,int year
,int month
,int day
,int hour
,int minute
,int second
,int dst
)
679 memset(<m
,0,sizeof(ltm
));
680 if (year
>=1900) ltm
.tm_year
=year
-1900;
681 if (month
>=1 && month
<=12) ltm
.tm_mon
=month
-1;
682 if (day
>=1 && day
<=31) ltm
.tm_mday
=day
;
683 if (hour
>=0 && hour
<24) ltm
.tm_hour
=hour
;
684 if (minute
>=0 && minute
<60) ltm
.tm_min
=minute
;
685 if (second
>=0 && second
<60) ltm
.tm_sec
=second
;
687 unixtime
=mktime(<m
); //fill the missing entries
688 fulltm
=localtime(&unixtime
);
689 //strftime(date,date_size,"%a %b %d %H:%M:%S %Z %Y",fulltm);
690 strftime(date
,date_size
,"%c",fulltm
);
694 void computedate(int year
,int month
,int day
,struct tm
*t
)
696 memset(t
,0,sizeof(*t
));
697 t
->tm_year
=year
-1900;
703 int obtuser(const char *dirname
, const char *name
)
710 sprintf(wdir
,"%s%s/sarg-users",dirname
,name
);
711 if((fp_in
=fopen(wdir
,"r"))==NULL
) {
712 sprintf(wdir
,"%s%s/users",dirname
,name
);
713 if((fp_in
=fopen(wdir
,"r"))==NULL
) {
718 if (!fgets(tuser
,sizeof(tuser
),fp_in
)) {
719 debuga(_("Failed to read the number of users in %s\n"),wdir
);
729 void obttotal(const char *dirname
, const char *name
, int nuser
, long long int *tbytes
, long long int *media
)
734 char user
[MAX_USER_LEN
];
736 struct getwordstruct gwarea
;
742 sprintf(wdir
,"%s%s/sarg-general",dirname
,name
);
743 if ((fp_in
= fopen(wdir
, "r")) == 0) {
744 sprintf(wdir
,"%s%s/general",dirname
,name
);
745 if ((fp_in
= fopen(wdir
, "r")) == 0) {
750 if ((line
=longline_create())==NULL
) {
751 debuga(_("Not enough memory to read the file %s\n"),wdir
);
755 while((buf
=longline_read(fp_in
,line
))!=NULL
) {
756 if (strncmp(buf
,"TOTAL\t",6) == 0)
758 else if (strncmp(buf
,"TOTAL ",6) == 0)
762 getword_start(&gwarea
,buf
);
763 if (getword(user
,sizeof(user
),&gwarea
,sep
)<0) {
764 debuga(_("There is a invalid user in file %s\n"),wdir
);
767 if(strcmp(user
,"TOTAL") != 0)
769 if (getword_skip(MAXLEN
,&gwarea
,sep
)<0) {
770 debuga(_("There a broken total number of access in file %s\n"),wdir
);
773 if (getword_atoll(tbytes
,&gwarea
,sep
)<0) {
774 debuga(_("There is a broken number of bytes in file %s\n"),wdir
);
780 longline_destroy(&line
);
785 *media
=*tbytes
/ nuser
;
789 int getperiod_fromsarglog(const char *arqtt
,struct periodstruct
*period
)
792 int day0
, month0
, year0
, hour0
, minute0
;
793 int day1
, month1
, year1
, hour1
, minute1
;
796 memset(period
,0,sizeof(*period
));
799 while((str
=strstr(str
,"sarg-"))!=NULL
) {
801 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
802 day0
=(str
[0]-'0')*10+(str
[1]-'0');
803 if (day0
<1 || day0
>31) continue;
805 month0
=(str
[0]-'0')*10+(str
[1]-'0')-1;
806 if (month0
<0 || month0
>11) continue;
809 for (i
=0 ; isdigit(str
[i
]) && i
<4 ; i
++) year0
=year0
*10+(str
[i
]-'0');
812 if (str
[0]!='_') continue;
815 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
816 hour0
=(str
[0]-'0')*10+(str
[1]-'0');
818 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
819 minute0
=(str
[0]-'0')*10+(str
[1]-'0');
822 if (*str
!= '-') continue;
825 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
826 day1
=(str
[0]-'0')*10+(str
[1]-'0');
827 if (day1
<1 || day1
>31) continue;
829 month1
=(str
[0]-'0')*10+(str
[1]-'0')-1;
830 if (month1
<0 || month1
>11) continue;
833 for (i
=0 ; isdigit(str
[i
]) && i
<4 ; i
++) year1
=year1
*10+(str
[i
]-'0');
837 if (str
[0]!='_') continue;
840 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
841 hour1
=(str
[0]-'0')*10+(str
[1]-'0');
843 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
844 minute1
=(str
[0]-'0')*10+(str
[1]-'0');
847 period
->start
.tm_mday
=day0
;
848 period
->start
.tm_mon
=month0
;
849 period
->start
.tm_year
=year0
-1900;
850 period
->start
.tm_hour
=hour0
;
851 period
->start
.tm_min
=minute0
;
852 period
->end
.tm_mday
=day1
;
853 period
->end
.tm_mon
=month1
;
854 period
->end
.tm_year
=year1
-1900;
855 period
->end
.tm_hour
=hour1
;
856 period
->end
.tm_min
=minute1
;
862 void getperiod_fromrange(struct periodstruct
*period
,int dfrom
,int duntil
)
864 memset(&period
->start
,0,sizeof(period
->start
));
865 period
->start
.tm_mday
=dfrom
%100;
866 period
->start
.tm_mon
=(dfrom
/100)%100-1;
867 period
->start
.tm_year
=(dfrom
/10000)-1900;
869 memset(&period
->end
,0,sizeof(period
->end
));
870 period
->end
.tm_mday
=duntil
%100;
871 period
->end
.tm_mon
=(duntil
/100)%100-1;
872 period
->end
.tm_year
=(duntil
/10000)-1900;
875 int getperiod_buildtext(struct periodstruct
*period
)
879 char text1
[40], text2
[40];
882 i
=strftime(text1
, sizeof(text1
), "%Y %b %d", &period
->start
);
883 }else if(df
[0]=='e') {
884 i
=strftime(text1
, sizeof(text1
), "%d %b %Y", &period
->start
);
885 } else /*if(df[0]=='w')*/ {
886 IndexTree
=INDEX_TREE_FILE
;
887 i
=strftime(text1
, sizeof(text1
), "%Y.%U", &period
->start
);
889 if (i
== 0) return(-1);
891 range
=(period
->start
.tm_year
!=period
->end
.tm_year
||
892 period
->start
.tm_mon
!=period
->end
.tm_mon
||
893 period
->start
.tm_mday
!=period
->end
.tm_mday
);
896 i
=strftime(text2
, sizeof(text2
)-i
, "%Y %b %d", &period
->end
);
897 } else if(df
[0]=='e') {
898 i
=strftime(text2
, sizeof(text2
)-i
, "%d %b %Y", &period
->end
);
900 i
=strftime(text2
, sizeof(text2
)-i
, "%Y.%U", &period
->end
);
902 if (i
== 0) return(-1);
906 snprintf(period
->text
,sizeof(period
->text
),"%s-%s",text1
,text2
);
907 snprintf(period
->html
,sizeof(period
->html
),"%s—%s",text1
,text2
);
909 safe_strcpy(period
->text
,text1
,sizeof(period
->text
));
910 safe_strcpy(period
->html
,text1
,sizeof(period
->html
));
915 static void copy_images(void)
917 FILE *img_in
, *img_ou
;
920 char srcfile
[MAXLEN
];
921 char dstfile
[MAXLEN
];
923 struct dirent
*direntp
;
928 if (snprintf(images
,sizeof(images
),"%simages",outdir
)>=sizeof(images
)) {
929 debuga(_("Cannot copy images to target directory %simages\n"),outdir
);
932 if (access(images
,R_OK
)!=0) {
933 if (mkdir(images
,0755)) {
934 debuga(_("Cannot create directory %s - %s\n"),images
,strerror(errno
));
939 strcpy(imgdir
,IMAGEDIR
);
940 dirp
= opendir(imgdir
);
942 debuga(_("(util) Can't open directory %s: %s\n"),imgdir
,strerror(errno
));
945 while ((direntp
= readdir( dirp
)) != NULL
){
946 if(direntp
->d_name
[0]=='.')
948 sprintf(srcfile
,"%s/%s",imgdir
,direntp
->d_name
);
949 if (stat(srcfile
,&info
)) {
950 debuga(_("Cannot stat \"%s\" - %s\n"),srcfile
,strerror(errno
));
953 if (S_ISREG(info
.st_mode
)) {
954 sprintf(dstfile
,"%s/%s",images
,direntp
->d_name
);
955 img_in
= fopen(srcfile
, "rb");
957 img_ou
= fopen(dstfile
, "wb");
959 while ((nread
= fread(buffer
,1,sizeof(buffer
),img_in
))>0) {
960 if (fwrite(buffer
,1,nread
,img_ou
)!=nread
) {
961 debuga(_("Failed to copy image %s to %s\n"),srcfile
,dstfile
);
967 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open/create file", dstfile
, strerror(errno
));
970 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open file", srcfile
, strerror(errno
));
973 (void) closedir(dirp
);
978 int vrfydir(const struct periodstruct
*per1
, const char *addr
, const char *site
, const char *us
, const char *form
)
983 char dirname2
[MAXLEN
];
993 y1
=per1
->start
.tm_year
+1900;
994 y2
=per1
->end
.tm_year
+1900;
995 m1
=per1
->start
.tm_mon
+1;
996 m2
=per1
->end
.tm_mon
+1;
997 d1
=per1
->start
.tm_mday
;
998 d2
=per1
->end
.tm_mday
;
999 if(IndexTree
== INDEX_TREE_DATE
) {
1000 wlen
+=sprintf(wdir
+wlen
,"%04d",y1
);
1001 if(y1
!=y2
) wlen
+=sprintf(wdir
+wlen
,"-%04d",y2
);
1002 if(access(wdir
, R_OK
) != 0)
1005 wlen
+=sprintf(wdir
+wlen
,"/%02d",m1
);
1006 if(m1
!= m2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",m2
);
1007 if(access(wdir
, R_OK
) != 0)
1010 wlen
+=sprintf(wdir
+wlen
,"/%02d",d1
);
1011 if(d1
!=d2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",d2
);
1014 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%04d%s%02d-%04d%s%02d",y1
,
1015 conv_month_name(m1
),d1
,y2
,conv_month_name(m2
),d2
);
1016 } else if(df
[0] == 'e') {
1017 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%02d%s%04d-%02d%s%04d",d1
,
1018 conv_month_name(m1
),y1
,d2
,conv_month_name(m2
),y2
);
1019 } else if(df
[0] == 'w') {
1020 wlen2
=strftime(wdir
+wlen
, sizeof(wdir
)-wlen
, "%Y.%U", &per1
->start
);
1021 if (wlen2
==0) return(-1);
1027 struct userinfostruct
*uinfo
=userinfo_find_from_id(us
);
1030 strcat(wdir
,uinfo
->filename
);
1033 if(addr
[0] != '\0') {
1037 if(site
[0] != '\0') {
1042 strcpy(outdirname
,wdir
);
1044 if(IndexTree
!= INDEX_TREE_DATE
) {
1045 if(!OverwriteReport
) {
1047 if(access(wdir
,R_OK
) == 0) {
1048 sprintf(wdir
,"%s.%d",outdirname
,num
);
1057 debuga(_("File %s already exists, moved to %s\n"),outdirname
,wdir
);
1058 rename(outdirname
,wdir
);
1061 if(access(outdirname
,R_OK
) == 0) {
1062 unlinkdir(outdirname
,1);
1065 my_mkdir(outdirname
);
1067 strcpy(dirname2
,wdir
);
1068 if(!OverwriteReport
) {
1070 if(access(wdir
,R_OK
) == 0) {
1071 sprintf(wdir
,"%s.%d",dirname2
,num
);
1080 debuga(_("File %s already exists, moved to %s\n"),dirname2
,wdir
);
1081 rename(dirname2
,wdir
);
1082 strcpy(dirname2
,wdir
);
1085 if(access(wdir
,R_OK
) == 0) {
1090 if(access(wdir
, R_OK
) != 0)
1094 strcpy(dirname2
,wdir
);
1096 sprintf(wdir
,"%s/sarg-date",outdirname
);
1097 if ((fp_ou
= fopen(wdir
, "wt")) == 0) {
1098 debuga(_("cannot open %s for writing\n"),wdir
);
1103 //strftime(wdir,sizeof(wdir),"%a %b %d %H:%M:%S %Z %Y",localtime(&curtime));
1104 loctm
=localtime(&curtime
);
1105 strftime(wdir
,sizeof(wdir
),"%Y-%m-%d %H:%M:%S",loctm
);
1106 if (fprintf(fp_ou
,"%s %d\n",wdir
,loctm
->tm_isdst
)<0) {
1107 debuga(_("Failed to write the date in %s\n"),wdir
);
1111 if (fclose(fp_ou
)==EOF
) {
1112 debuga(_("Failed to write the date in %s\n"),wdir
);
1122 Copy a string without overflowing the buffer. The copied string
1123 is properly terminated by an ASCII zero.
1125 \param dest The destination buffer.
1126 \param src The source buffer.
1127 \param length The size of the destination buffer. The program is aborted
1128 if the length is negative or zero.
1130 void safe_strcpy(char *dest
,const char *src
,int length
)
1133 debuga(_("Invalid buffer length passed to the function to safely copy a string\n"));
1136 strncpy(dest
,src
,length
-1);
1137 dest
[length
-1]='\0';
1140 void strip_latin(char *line
)
1147 for (i
=0;line
[i
];i
++){
1149 if (line
[i
]==';') skip
=0;
1161 void zdate(char *ftime
,int ftimesize
, const char *DateFormat
)
1167 local
= localtime(&t
);
1168 if(strcmp(DateFormat
,"u") == 0)
1169 strftime(ftime
, ftimesize
, "%b/%d/%Y %H:%M", local
);
1170 if(strcmp(DateFormat
,"e") == 0)
1171 strftime(ftime
, ftimesize
, "%d/%b/%Y-%H:%M", local
);
1172 if(strcmp(DateFormat
,"w") == 0)
1173 strftime(ftime
, ftimesize
, "%W-%H-%M", local
);
1178 char *fixtime(long long int elap
)
1180 int num
= elap
/ 1000;
1184 static char buf
[12];
1187 min
=(num
% 3600) / 60;
1190 if(hor
==0 && min
==0 && sec
==0)
1193 sprintf(buf
,"%d:%02d:%02d",hor
,min
,sec
);
1199 void date_from(char *date
, int *dfrom
, int *duntil
)
1208 if (isdigit(date
[0])) {
1211 if (sscanf(date
,"%d/%d/%d%n",&d0
,&m0
,&y0
,&next
)!=3 || y0
<100 || m0
<1 || m0
>12 || d0
<1 || d0
>31 || next
<0) {
1212 debuga(_("The date passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1215 if (date
[next
]=='-') {
1216 if (sscanf(date
+next
+1,"%d/%d/%d",&d1
,&m1
,&y1
)!=3 || y1
<100 || m1
<1 || m1
>12 || d1
<1 || d1
>31) {
1217 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1220 } else if (date
[next
]!='\0') {
1221 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1231 struct tm
*Date0
,Date1
;
1233 if (time(&Today
)==(time_t)-1) {
1234 debuga(_("Failed to get the current time\n"));
1237 if (sscanf(date
,"day-%d",&i
)==1) {
1239 debuga(_("Invalid number of days in -d parameter\n"));
1243 Date0
=localtime(&Today
);
1245 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1248 y0
=y1
=Date0
->tm_year
+1900;
1249 m0
=m1
=Date0
->tm_mon
+1;
1250 d0
=d1
=Date0
->tm_mday
;
1251 } else if (sscanf(date
,"week-%d",&i
)==1) {
1253 There is no portable way to find the first day of the week even though the
1254 information is available in the locale. nl_langinfo has the unofficial
1255 parameters _NL_TIME_FIRST_WEEKDAY and _NL_TIME_WEEK_1STDAY but they are
1256 undocumented as is their return value and it is discouraged to use them.
1257 Beside, nl_langinfo isn't available on windows and the first day of the
1258 week isn't available at all on that system.
1260 const int FirstWeekDay
=1;
1264 debuga(_("Invalid number of weeks in -d parameter\n"));
1267 Date0
=localtime(&Today
);
1269 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1272 WeekBegin
=Today
-((Date0
->tm_wday
-FirstWeekDay
+7)%7)*24*60*60;
1273 WeekBegin
-=i
*7*24*60*60;
1274 Date0
=localtime(&WeekBegin
);
1276 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1279 y0
=Date0
->tm_year
+1900;
1282 WeekBegin
+=6*24*60*60;
1283 Date0
=localtime(&WeekBegin
);
1285 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1288 y1
=Date0
->tm_year
+1900;
1291 } else if (sscanf(date
,"month-%d",&i
)==1) {
1293 debuga(_("Invalid number of months in -d parameter\n"));
1296 Date0
=localtime(&Today
);
1298 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1301 if (Date0
->tm_mon
<i
%12) {
1302 y0
=Date0
->tm_year
+1900-i
/12-1;
1303 m0
=(Date0
->tm_mon
+12-i
%12)%12+1;
1306 y0
=Date0
->tm_year
+1900-i
/12;
1307 m0
=Date0
->tm_mon
-i
%12+1;
1310 memcpy(&Date1
,Date0
,sizeof(struct tm
));
1315 Date1
.tm_year
=y0
-1900;
1318 Date1
.tm_year
=y0
-1900+1;
1322 Date0
=localtime(&t1
);
1323 y1
=Date0
->tm_year
+1900;
1327 debuga(_("Invalid date range passed on command line\n"));
1332 *dfrom
=y0
*10000+m0
*100+d0
;
1333 *duntil
=y1
*10000+m1
*100+d1
;
1334 sprintf(date
,"%02d/%02d/%04d-%02d/%02d/%04d",d0
,m0
,y0
,d1
,m1
,y1
);
1339 char *strlow(char *string
)
1345 for (s
= string
; *s
; ++s
)
1355 char *strup(char *string
)
1361 for (s
= string
; *s
; ++s
)
1369 void removetmp(const char *outdir
)
1374 if(!RemoveTempFiles
)
1378 debuga(_("Purging temporary file sarg-general\n"));
1380 if (snprintf(filename
,sizeof(filename
),"%s/sarg-general",outdir
)>=sizeof(filename
)) {
1381 debuga(_("(removetmp) directory too long to remove %s/sarg-period\n"),outdir
);
1384 if((fp_gen
=fopen(filename
,"w"))==NULL
){
1385 debuga(_("(removetmp) Cannot open file %s\n"),filename
);
1388 totalger(fp_gen
,filename
);
1389 if (fclose(fp_gen
)==EOF
) {
1390 debuga(_("Failed to close %s after writing the total line - %s\n"),filename
,strerror(errno
));
1395 void load_excludecodes(const char *ExcludeCodes
)
1403 if(ExcludeCodes
[0] == '\0')
1406 if((fp_in
=fopen(ExcludeCodes
,"r"))==NULL
) {
1407 debuga(_("(util) Cannot open file %s (exclude_codes)\n"),ExcludeCodes
);
1411 if (fseek(fp_in
, 0, SEEK_END
)==-1) {
1412 debuga(_("Failed to move till the end of the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1415 MemSize
= ftell(fp_in
);
1417 debuga(_("Cannot get the size of file %s\n"),ExcludeCodes
);
1420 if (fseek(fp_in
, 0, SEEK_SET
)==-1) {
1421 debuga(_("Failed to rewind the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1426 if((excludecode
=(char *) malloc(MemSize
))==NULL
) {
1427 debuga(_("malloc error (%ld)\n"),MemSize
);
1430 memset(excludecode
,0,MemSize
);
1433 while(fgets(data
,sizeof(data
),fp_in
)!=NULL
) {
1434 if (data
[0]=='#') continue;
1435 for (i
=strlen(data
)-1 ; i
>=0 && (unsigned char)data
[i
]<=' ' ; i
--) data
[i
]='\0';
1437 if (Stored
+i
+2>=MemSize
) {
1438 debuga(_("Too many codes to exclude in file %s\n"),ExcludeCodes
);
1441 strcat(excludecode
,data
);
1442 strcat(excludecode
,";");
1450 void free_excludecodes(void)
1458 int vercode(const char *code
)
1463 if (excludecode
&& excludecode
[0]!='\0') {
1467 if (strncmp(code
,cod
,clen
)==0 && cod
[clen
]==';')
1469 cod
=strchr(cod
,';');
1476 void fixnone(char *str
)
1480 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--);
1481 if(i
==3 && strncmp(str
,"none",4) == 0)
1487 void fixendofline(char *str
)
1491 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--) str
[i
]=0;
1494 #ifdef LEGACY_TESTVALIDUSERCHAR
1495 int testvaliduserchar(const char *user
)
1500 for (y
=0; y
<strlen(UserInvalidChar
); y
++) {
1501 for (x
=0; x
<strlen(user
); x
++) {
1502 if(user
[x
] == UserInvalidChar
[y
])
1509 int testvaliduserchar(const char *user
)
1511 char * p_UserInvalidChar
= UserInvalidChar
;
1512 const char * p_user
;
1514 while( *p_UserInvalidChar
) {
1517 if( *p_UserInvalidChar
== *p_user
)
1521 p_UserInvalidChar
++ ;
1527 int compar( const void *a
, const void *b
)
1529 if( *(int *)a
> *(int *)b
) return 1;
1530 if( *(int *)a
< *(int *)b
) return -1;
1534 int getnumlist( char *buf
, numlist
*list
, const int len
, const int maxvalue
)
1536 int i
, j
, d
, flag
, r1
, r2
;
1537 char *pbuf
, **bp
, *strbufs
[ 24 ];
1540 strtok( buf
, " \t" );
1541 for( *bp
= strtok( NULL
, "," ), list
->len
= 0; *bp
; *bp
= strtok( NULL
, "," ) ) {
1542 if( ++bp
>= &strbufs
[ 24 ] )
1549 for( i
= 0; i
< list
->len
; i
++ ) {
1550 if( strchr( strbufs
[ i
], '-' ) != 0 ) {
1551 pbuf
= strbufs
[ i
];
1552 strtok( pbuf
, "-" );
1553 pbuf
= strtok( NULL
, "\0" );
1554 r1
= atoi( strbufs
[ i
] );
1555 if( ( r2
= atoi( pbuf
) ) >= maxvalue
|| r1
>= r2
)
1557 if( i
+ d
+ ( r2
- r1
) + 1 <= len
) {
1558 for( j
= r1
; j
<= r2
; j
++ )
1559 list
->list
[ i
+ d
++ ] = j
;
1564 if( ( list
->list
[ i
+ d
] = atoi( strbufs
[ i
] ) ) >= maxvalue
)
1568 qsort( list
->list
, list
->len
, sizeof( int ), compar
);
1571 for( i
= 0; i
< list
->len
- 1; i
++ )
1572 if( list
->list
[ i
] == list
->list
[ i
+ 1 ] ) {
1573 for( j
= i
+ 1; j
< list
->len
; j
++ )
1574 list
->list
[ j
- 1 ] = list
->list
[ j
];
1584 char *get_size(const char *path
, const char *file
)
1587 static char response
[255];
1591 if (snprintf(cmd
,sizeof(cmd
),"du -skh %s%s",path
,file
)>=sizeof(cmd
)) {
1592 debuga(_("Cannot get disk space because the path %s%s is too long\n"),path
,file
);
1595 if ((fp
= popen(cmd
, "r")) == NULL
) {
1596 debuga(_("Cannot get disk space with command %s\n"),cmd
);
1599 if (!fgets(response
, sizeof(response
), fp
)) {
1600 debuga(_("Cannot get disk size with command %s\n"),cmd
);
1603 ptr
=strchr(response
,'\t');
1605 debuga(_("The command %s failed\n"),cmd
);
1614 void show_info(FILE *fp_ou
)
1618 if(!ShowSargInfo
) return;
1619 zdate(ftime
, sizeof(ftime
), DateFormat
);
1620 fprintf(fp_ou
,"<div class=\"info\">%s <a href='%s'>%s-%s</a> %s %s</div>\n",_("Generated by"),URL
,PGM
,VERSION
,_("on"),ftime
);
1623 void show_sarg(FILE *fp_ou
, int depth
)
1627 if(!ShowSargLogo
) return;
1628 fputs("<div class=\"logo\"><a href=\"http://sarg.sourceforge.net\"><img src=\"",fp_ou
);
1629 for (i
=0 ; i
<depth
; i
++)
1631 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
);
1634 void write_logo_image(FILE *fp_ou
)
1636 if(LogoImage
[0]!='\0')
1637 fprintf(fp_ou
, "<div class=\"logo\"><img src=\"%s\" width=\"%s\" height=\"%s\" alt=\"Logo\"> %s</div>\n",LogoImage
,Width
,Height
,LogoText
);
1640 void write_html_head(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1644 fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n",fp_ou
);
1645 fprintf(fp_ou
, "<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n",CharSet
);
1646 if (page_title
) fprintf(fp_ou
,"<title>%s</title>\n",page_title
);
1648 if ((javascript
& HTML_JS_SORTTABLE
)!=0 && SortTableJs
[0]) {
1649 fputs("<script type=\"text/javascript\" src=\"",fp_ou
);
1650 if (strncmp(SortTableJs
,"../",3)==0) {
1651 for (i
=0 ; i
<depth
; i
++) fputs("../",fp_ou
);
1653 fputs(SortTableJs
,fp_ou
);
1654 fputs("\"></script>\n",fp_ou
);
1656 fputs("</head>\n<body>\n",fp_ou
);
1659 void write_html_header(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1661 write_html_head(fp_ou
,depth
,page_title
,javascript
);
1662 write_logo_image(fp_ou
);
1663 show_sarg(fp_ou
, depth
);
1664 fprintf(fp_ou
,"<div class=\"title\"><table cellpadding=\"0\" cellspacing=\"0\">\n<tr><th class=\"title_c\">%s</th></tr>\n",Title
);
1667 void close_html_header(FILE *fp_ou
)
1669 fputs("</table></div>\n",fp_ou
);
1672 int write_html_trailer(FILE *fp_ou
)
1675 if (fputs("</body>\n</html>\n",fp_ou
)==EOF
) return(-1);
1679 void output_html_string(FILE *fp_ou
,const char *str
,int maxlen
)
1683 while (*str
&& (maxlen
<=0 || i
<maxlen
)) {
1686 fputs("&",fp_ou
);
1689 fputs("<",fp_ou
);
1692 fputs(">",fp_ou
);
1695 fputs(""",fp_ou
);
1698 fputs("'",fp_ou
);
1706 if (maxlen
>0 && i
>=maxlen
)
1707 fputs("…",fp_ou
);
1710 void output_html_url(FILE *fp_ou
,const char *url
)
1714 fputs("&",fp_ou
);
1722 Write a host name inside an A tag of a HTML file. If the host name starts
1723 with a star, it is assumed to be an alias that cannot be put inside a link
1724 so the A tag is not written around the host name.
1726 \param fp_ou The handle of the HTML file.
1727 \param url The host to display in the HTML file.
1728 \param maxlen The maximum number of characters to print into the host name.
1730 void output_html_link(FILE *fp_ou
,const char *url
,int maxlen
)
1732 if (url
[0]==ALIAS_PREFIX
) {
1733 // this is an alias, no need for a A tag
1734 output_html_string(fp_ou
,url
+1,100);
1736 if (skip_scheme(url
)==url
)
1737 fputs("<a href=\"http://",fp_ou
);//no scheme in the url, assume http:// to make the link clickable
1739 fputs("<a href=\"",fp_ou
);//the scheme is in the url, no need to add one
1740 output_html_url(fp_ou
,url
);
1742 output_html_string(fp_ou
,url
,100);
1743 fputs("</a>",fp_ou
);
1747 void url_module(const char *url
, char *w2
)
1753 for(x
=strlen(url
)-1; x
>=0; x
--) {
1754 if(url
[x
] == '/' || y
>=sizeof(w
)-1) break;
1763 for(y
=y
-1; y
>=0; y
--) {
1769 void url_to_file(const char *url
,char *file
,int filesize
)
1775 for(i
=0; i
<filesize
&& *url
; url
++) {
1776 if(isalnum(*url
) || *url
=='-' || *url
=='_' || *url
=='.' || *url
=='%') {
1780 if (!skip
) file
[i
++]='_';
1789 printf(_("SARG Version: %s\n"),VERSION
);
1793 char *get_param_value(const char *param
,char *line
)
1797 while (*line
==' ' || *line
=='\t') line
++;
1799 if (strncasecmp(line
,param
,plen
)) return(NULL
);
1800 if (line
[plen
]!=' ' && line
[plen
]!='\t') return(NULL
);
1802 while (*line
==' ' || *line
=='\t') line
++;
1806 void unlinkdir(const char *dir
,int contentonly
)
1810 struct dirent
*direntp
;
1816 while ((direntp
= readdir(dirp
)) != NULL
) {
1817 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
1818 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
1820 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
1821 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
1825 err
=lstat(dname
,&st
);
1827 err
=stat(dname
,&st
);
1830 debuga(_("cannot stat %s\n"),dname
);
1833 if (S_ISREG(st
.st_mode
)) {
1834 if (unlink(dname
)) {
1835 debuga(_("cannot delete %s - %s\n"),dname
,strerror(errno
));
1838 } else if (S_ISDIR(st
.st_mode
)) {
1841 debuga(_("unknown path type %s\n"),dname
);
1848 debuga(_("cannot delete %s - %s\n"),dir
,strerror(errno
));
1855 Extract an url, IPv4 or IPv6 from a buffer. The IP addresses may end with a
1858 \param buf The buffer to parse.
1859 \param text A pointer to set to the beginning of the string pattern. No terminating zero is inserted.
1860 \param ipv4 A 4 bytes buffer to store the bytes of the IPv4 address.
1861 \param ipv6 A 8 short integers buffer to store the values of the IPv6 address.
1862 \param nbits The number of prefix bits for an IP address.
1863 \param next The content of the line after the extracted address.
1865 \retval 3 The pattern is a IPv6 address.
1866 \retval 2 The pattern is a IPv4 address.
1867 \retval 1 The patter is a string.
1868 \retval 0 Empty pattern.
1870 int extract_address_mask(const char *buf
,const char **text
,unsigned char *ipv4
,unsigned short int *ipv6
,int *nbits
,const char **next
)
1875 unsigned int value4
, value6
;
1876 unsigned short int addr
[8];
1884 // skip leading spaces and tabs
1885 while (*buf
&& (*buf
==' ' || *buf
=='\t')) buf
++;
1887 // find out the nature of the pattern
1888 ip_size
=0x60 | 0x04;
1899 for (i
=0 ; (unsigned char)buf
[i
]>' ' && buf
[i
]!='/' && buf
[i
]!='?' && (!bracket
|| buf
[i
]!=']') && ip_size
; i
++) {
1900 if (ip_size
& 0x04) {
1901 if (isdigit(buf
[i
])) {
1902 value4
=value4
*10+(buf
[i
]-'0');
1903 if (value4
>0xFFU
) ip_size
&=~0x04;
1904 } else if (buf
[i
]=='.' && addr_len
<4) {
1905 addr
[addr_len
++]=(unsigned short)(value4
& 0xFFU
);
1911 if (ip_size
& 0x60) {
1912 if (isdigit(buf
[i
])) {
1913 value6
=(value6
<<4)+(buf
[i
]-'0');
1915 if (value6
>0xFFFFU
) ip_size
&=~0x60;
1916 } else if (toupper(buf
[i
])>='A' && toupper(buf
[i
])<='F') {
1917 value6
=(value6
<<4)+(toupper(buf
[i
])-'A'+10);
1919 if (value6
>0xFFFFU
) ip_size
&=~0x60;
1920 } else if (buf
[i
]==':' && addr_len
<8) {
1921 if (nibble6_len
>0) {
1922 addr
[addr_len
++]=(unsigned short)(value6
& 0xFFFFU
);
1926 if (buf
[i
+1]==':') {
1935 if (i
==0) return(0);
1936 if (ip_size
& 0x04) {
1940 addr
[addr_len
++]=(unsigned short)(value4
& 0xFFU
);
1942 if (ip_size
& 0x60) {
1943 if (pad_pos
<0 && addr_len
!=7) {
1945 } else if (pad_pos
>=0 && addr_len
>=7)
1947 else if (nibble6_len
>0)
1948 addr
[addr_len
++]=(unsigned short)(value6
& 0xFFFFU
);
1952 if (bracket
) (*text
)--;
1953 while ((unsigned char)buf
[i
]>' ') i
++;
1954 if (next
) *next
=buf
+i
;
1957 max_mask
=(ip_size
& 0x04) ? 4*8 : 8*16;
1961 while (isdigit(buf
[i
])) i
++;
1962 if (mask
<0 || mask
>max_mask
) mask
=max_mask
;
1965 if (ip_size
& 0x60 && bracket
&& buf
[i
]==']') i
++;
1966 if (next
) *next
=buf
+i
;
1967 if (ip_size
& 0x04) {
1968 if (nbits
) *nbits
=mask
;
1969 for (i
=0 ; i
<addr_len
; i
++)
1970 ipv4
[i
]=(unsigned char)addr
[i
];
1975 if (nbits
) *nbits
=mask
;
1980 ipv6
[j
++]=(unsigned short int)addr
[i
++];
1982 while (j
<pad_pos
+pad_len
)
1986 ipv6
[j
++]=(unsigned short int)addr
[i
++];