]> git.ipfire.org Git - thirdparty/sarg.git/blob - util.c
Fix several possible sprintf buffer overflows
[thirdparty/sarg.git] / util.c
1 /*
2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
3 * 1998, 2013
4 *
5 * SARG donations:
6 * please look at http://sarg.sourceforge.net/donations.php
7 * Support:
8 * http://sourceforge.net/projects/sarg/forums/forum/363374
9 * ---------------------------------------------------------------------
10 *
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.
15 *
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.
20 *
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.
24 *
25 */
26
27 // #define LEGACY_MY_ATOLL
28 // #define LEGACY_TESTVALIDUSERCHAR
29
30 #include "include/conf.h"
31 #include "include/defs.h"
32
33 #if defined(HAVE_BACKTRACE)
34 #define USE_GETWORD_BACKTRACE 1
35 #else
36 #define USE_GETWORD_BACKTRACE 0
37 #endif
38
39 static char mtab1[12][4]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
40
41 //! The list of the HTTP codes to exclude from the report.
42 static char *excludecode=NULL;
43
44 extern char *CurrentLocale;
45
46 #if USE_GETWORD_BACKTRACE
47 static void getword_backtrace(void)
48 {
49 void *buffer[5];
50 int i, n;
51 char **calls;
52
53 n=backtrace(buffer,sizeof(buffer)/sizeof(buffer[0]));
54 if (n<=0) return;
55 calls=backtrace_symbols(buffer,n);
56 if (calls) {
57 /* TRANSLATORS: "getword" is the function displaying
58 * the backtrace leading to its execution.
59 */
60 debuga(_("getword backtrace:\n"));
61 for (i=0 ; i<n ; i++) {
62 fprintf(stderr,"SARG: %d:%s\n",i+1,calls[i]);
63 }
64 free(calls);
65 }
66 }
67 #endif //USE_GETWORD_BACKTRACE
68
69 void getword_start(struct getwordstruct *gwarea, const char *line)
70 {
71 gwarea->beginning=line;
72 gwarea->current=line;
73 gwarea->modified=0;
74 }
75
76 void getword_restart(struct getwordstruct *gwarea)
77 {
78 if (gwarea->modified) {
79 debuga(_("Cannot parse again the line as it was modified\n"));
80 exit(EXIT_FAILURE);
81 }
82 gwarea->current=gwarea->beginning;
83 }
84
85 int getword(char *word, int limit, struct getwordstruct *gwarea, char stop)
86 {
87 int x;
88
89 for(x=0;((gwarea->current[x]) && (gwarea->current[x] != stop ));x++) {
90 if(x>=limit) {
91 /* TRANSLATORS: %s is the name of the function reporting this error.
92 */
93 debuga(_("Loop detected in %s after %d bytes.\n"),__func__,x);
94 debuga(_("Line=\"%s\"\n"),gwarea->beginning);
95 debuga(_("Record=\"%s\"\n"),gwarea->current);
96 debuga(_("searching for \'x%x\'\n"),stop);
97 word[(limit>0) ? limit-1 : 0]='\0';
98 #if USE_GETWORD_BACKTRACE
99 getword_backtrace();
100 #endif
101 return(-1);
102 }
103 word[x] = gwarea->current[x];
104 }
105
106 word[x] = '\0';
107 if (gwarea->current[x]) ++x;
108 gwarea->current+=x;
109 return(0);
110 }
111
112 int getword_limit(char *word, int limit, struct getwordstruct *gwarea, char stop)
113 {
114 int x;
115
116 limit--;
117 for(x=0; x<limit && gwarea->current[x] && gwarea->current[x] != stop ;x++) {
118 word[x] = gwarea->current[x];
119 }
120 word[x] = '\0';
121 gwarea->current+=x;
122 while (*gwarea->current && *gwarea->current != stop) gwarea->current++;
123 if (*gwarea->current) ++gwarea->current;
124 return(0);
125 }
126
127 int getword_multisep(char *word, int limit, struct getwordstruct *gwarea, char stop)
128 {
129 int x;
130
131 for(x=0;((gwarea->current[x]) && (gwarea->current[x] != stop ));x++) {
132 if(x>=limit) {
133 /* TRANSLATORS: %s is the name of the function reporting this error.
134 */
135 debuga(_("Loop detected in %s after %d bytes.\n"),__func__,x);
136 debuga(_("Line=\"%s\"\n"),gwarea->beginning);
137 debuga(_("Record=\"%s\"\n"),gwarea->current);
138 debuga(_("searching for \'x%x\'\n"),stop);
139 if (limit>0) word[limit-1]='\0';
140 #if USE_GETWORD_BACKTRACE
141 getword_backtrace();
142 #endif
143 //exit(EXIT_FAILURE);
144 return(-1);
145 }
146 word[x] = gwarea->current[x];
147 }
148
149 word[x] = '\0';
150 while (gwarea->current[x] && gwarea->current[x]==stop) ++x;
151 gwarea->current+=x;
152 return(0);
153 }
154
155 int getword_skip(int limit, struct getwordstruct *gwarea, char stop)
156 {
157 int x;
158
159 for(x=0;(gwarea->current[x] && (gwarea->current[x] != stop ));x++) {
160 if(x>=limit) {
161 /* TRANSLATORS: %s is the name of the function reporting this error.
162 */
163 debuga(_("Loop detected in %s after %d bytes.\n"),__func__,x);
164 debuga(_("Line=\"%s\"\n"),gwarea->beginning);
165 debuga(_("Record=\"%s\"\n"),gwarea->current);
166 debuga(_("searching for \'x%x\'\n"),stop);
167 #if USE_GETWORD_BACKTRACE
168 getword_backtrace();
169 #endif
170 return(-1);
171 }
172 }
173
174 if (gwarea->current[x]) ++x;
175 gwarea->current+=x;
176 return(0);
177 }
178
179 int getword_atoll(long long int *number, struct getwordstruct *gwarea, char stop)
180 {
181 int x;
182 int sign=+1;
183 int digit;
184
185 if (gwarea->current[0] == '-') {
186 gwarea->current++;
187 sign=-1;
188 } else if (gwarea->current[0] == '+') {
189 gwarea->current++;
190 }
191 *number=0LL;
192 for(x=0;isdigit(gwarea->current[x]);x++) {
193 digit=gwarea->current[x]-'0';
194 if (*number >= (LLONG_MAX-digit)/10) {
195 /* TRANSLATORS: The first %s is the name of the function displaying
196 * this message.
197 */
198 debuga(_("Integer overflow detected in %s in line \"%s\"\n"),__func__,gwarea->beginning);
199 return(-1);
200 }
201 *number=(*number * 10) + digit;
202 }
203 if(gwarea->current[x] && gwarea->current[x]!=stop) {
204 /* TRANSLATORS: %s is the name of the function reporting this error.
205 */
206 debuga(_("Loop detected in %s after %d bytes.\n"),__func__,x);
207 debuga(_("Line=\"%s\"\n"),gwarea->beginning);
208 debuga(_("Record=\"%s\"\n"),gwarea->current);
209 debuga(_("searching for \'x%x\'\n"),stop);
210 #if USE_GETWORD_BACKTRACE
211 getword_backtrace();
212 #endif
213 return(-1);
214 }
215 *number*=sign;
216
217 if (gwarea->current[x]) ++x;
218 gwarea->current+=x;
219 return(0);
220 }
221
222 int getword_atoi(int *number, struct getwordstruct *gwarea, char stop)
223 {
224 int x;
225 int sign=+1;
226 int digit;
227
228 if (gwarea->current[0] == '-') {
229 gwarea->current++;
230 sign=-1;
231 } else if (gwarea->current[0] == '+') {
232 gwarea->current++;
233 }
234 *number=0;
235 for(x=0;isdigit(gwarea->current[x]);x++) {
236 digit=gwarea->current[x]-'0';
237 if (*number > (INT_MAX-digit)/10) {
238 /* TRANSLATORS: The first %s is the name of the function displaying
239 * this message.
240 */
241 debuga(_("Integer overflow detected in %s in line \"%s\"\n"),__func__,gwarea->beginning);
242 return(-1);
243 }
244 *number=(*number * 10) + digit;
245 }
246 if(gwarea->current[x] && gwarea->current[x]!=stop) {
247 /* TRANSLATORS: %s is the name of the function reporting this error.
248 */
249 debuga(_("Loop detected in %s after %d bytes.\n"),__func__,x);
250 debuga(_("Line=\"%s\"\n"),gwarea->beginning);
251 debuga(_("Record=\"%s\"\n"),gwarea->current);
252 debuga(_("searching for \'x%x\'\n"),stop);
253 #if USE_GETWORD_BACKTRACE
254 getword_backtrace();
255 #endif
256 return(-1);
257 }
258 *number*=sign;
259
260 if (gwarea->current[x]) ++x;
261 gwarea->current+=x;
262 return(0);
263 }
264
265
266 int getword_ptr(char *orig_line,char **word, struct getwordstruct *gwarea, char stop)
267 {
268 /*!
269 \note Why pass the original buffer to the function ? Because we must modify it to
270 insert the terminating ASCII zero for the word we return and that's not compatible
271 with getword_restart(). Moreover, getword_start() sometime works on constant strings
272 so this function require the original buffer to detect any missuse.
273 */
274 int x;
275 int sep;
276 int start;
277
278 if (orig_line && orig_line!=gwarea->beginning) {
279 debuga(_("Invalid buffer passed to getword_ptr\n"));
280 return(-1);
281 }
282
283 start=(gwarea->current-gwarea->beginning);
284 if (word && orig_line) *word=orig_line+start;
285 for(x=0;((gwarea->current[x]) && (gwarea->current[x] != stop ));x++);
286 sep=(gwarea->current[x]!='\0');
287 if (word && orig_line) orig_line[start+x] = '\0';
288 if (sep) ++x;
289 gwarea->current+=x;
290 gwarea->modified=1;
291 return(0);
292 }
293
294 #define MAXLLL 30 //!< Maximum number of digits in long long (a guess).
295 long long int my_atoll (const char *nptr)
296 {
297 long long int returnval=0LL;
298 int max_digits = MAXLLL ;
299
300 // Soak up all the white space
301 while (isspace( *nptr )) {
302 nptr++;
303 }
304
305 //For each character left to right
306 //change the character to a single digit
307 //multiply what we had before by 10 and add the new digit
308
309 while (--max_digits && isdigit( *nptr ))
310 {
311 returnval = ( returnval * 10 ) + ( *nptr++ - '0' ) ;
312 }
313
314 return returnval;
315 }
316
317 int is_absolute(const char *path)
318 {
319 if (*path=='/') return(1);
320 #ifdef WINDOWS
321 if (isalpha(path[0]) && path[1]==':') return(1);
322 #endif
323 return(0);
324 }
325
326 void my_mkdir(const char *name)
327 {
328 char w0[MAXLEN];
329 int i;
330 int chars;
331
332 if(!is_absolute(name)) {
333 debuga(_("Invalid path \"%s\". Please, use absolute paths only.\n"),name);
334 exit(EXIT_FAILURE);
335 }
336
337 chars=0;
338 for (i=0 ; name[i] ; i++) {
339 if (i>=sizeof(w0)) {
340 debuga(_("Path too long: "));
341 debuga_more("%s\n",name);
342 exit(EXIT_FAILURE);
343 }
344 if (chars>0 && name[i] == '/') {
345 w0[i] = '\0';
346 if (access(w0, R_OK) != 0) {
347 if (mkdir(w0,0755)) {
348 debuga(_("Cannot create directory \"%s\": %s\n"),w0,strerror(errno));
349 exit(EXIT_FAILURE);
350 }
351 }
352 }
353 if (name[i] != '/') chars++;
354 w0[i] = name[i];
355 }
356
357 if (access(name, R_OK) != 0) {
358 if (mkdir(name,0755)) {
359 debuga(_("Cannot create directory \"%s\": %s\n"),name,strerror(errno));
360 exit(EXIT_FAILURE);
361 }
362 }
363 }
364
365
366 void my_lltoa(unsigned long long int n, char *s, int ssize, int len)
367 {
368 int i;
369 int slen = 0;
370 int j;
371 char c;
372
373 ssize--;
374 if (len>ssize) {
375 debuga(_("The requested number of digits passed to my_lltoa (%d) is bigger than the output buffer size (%d)\n"),len,ssize);
376 abort();
377 }
378
379 do {
380 s[slen++] = (n % 10) + '0';
381 } while ((n /= 10) > 0 && slen<ssize);
382 s[slen] = '\0';
383
384 for (i = 0, j = slen-1; i<j; i++, j--) {
385 c = s[i];
386 s[i] = s[j];
387 s[j] = c;
388 }
389
390 if(len>slen) {
391 i=len-slen;
392 for(j=slen; j>=0; j--)
393 s[j+i]=s[j];
394 for(j=0 ; j<i ; j++)
395 s[j]='0';
396 }
397 }
398
399 int month2num(const char *month)
400 {
401 int m;
402
403 for(m=0 ; m<12 && strcmp(mtab1[m],month) != 0; m++);
404 return(m);
405 }
406
407 int builddia(int day, int month, int year)
408 {
409 return(year*10000+month*100+day);
410 }
411
412
413 void buildymd(const char *dia, const char *mes, const char *ano, char *wdata,int wdata_size)
414 {
415 int nmes;
416
417 nmes=month2num(mes);
418 snprintf(wdata,wdata_size,"%04d%02d%02d",atoi(ano),nmes+1,atoi(dia));
419 }
420
421
422 int conv_month(const char *month)
423 {
424 int x;
425
426 for(x=0; x<12 && strncmp(mtab1[x],month,3)!=0; x++);
427 return(x+1);
428 }
429
430
431 const char *conv_month_name(int month)
432 {
433 static char str[4];
434
435 if (month<1 || month>12) {
436 snprintf(str,sizeof(str),"%03d",month);
437 return(str);
438 }
439 return(mtab1[month-1]);
440 }
441
442
443 void name_month(char *month,int month_len)
444 {
445 int x, z=atoi(month)-1;
446 char m[255];
447 char w[20];
448 struct getwordstruct gwarea;
449
450 strcpy(m,_("January,February,March,April,May,June,July,August,September,October,November,December"));
451 getword_start(&gwarea,m);
452
453 for(x=0; x<z; x++)
454 if (getword_multisep(w,sizeof(w),&gwarea,',')<0) {
455 debuga(_("The internal list of month names is invalid. Please report this bug to the translator.\n"));
456 exit(EXIT_FAILURE);
457 }
458 if (getword_multisep(month,month_len,&gwarea,',')<0) {
459 debuga(_("The internal list of month names is invalid. Please report this bug to the translator.\n"));
460 exit(EXIT_FAILURE);
461 }
462 }
463
464
465 /*!
466 Write a debug message to stderr. The message is prefixed by "SARG:" to identify its origin.
467
468 \param msg The printf like message to format.
469 \param ... The arguments to format in the message.
470 */
471 void debuga(const char *msg,...)
472 {
473 va_list ap;
474
475 fputs(_("SARG: "),stderr);
476 va_start(ap,msg);
477 vfprintf(stderr,msg,ap);
478 va_end(ap);
479 }
480
481 /*!
482 Write a debug message to stderr. The message is supposed
483 to be displayed after a message from debuga().
484
485 \param msg The printf like message to format.
486 \param ... The arguments to format in the message.
487 */
488 void debuga_more(const char *msg,...)
489 {
490 va_list ap;
491
492 va_start(ap,msg);
493 vfprintf(stderr,msg,ap);
494 va_end(ap);
495 }
496
497 /*!
498 Write a debug message to stderr. The message is prefixed by "SARG:" to identify its origin.
499
500 \param pos Where, in the source code, this message comes from.
501 \param msg The printf like message to format.
502 \param ... The arguments to format in the message.
503 */
504 void debugapos(const char *pos,const char *msg,...)
505 {
506 va_list ap;
507
508 /* TRANSLATORS: This text is printed on the console before any message from
509 * the debug log with level "debug".
510 */
511 fputs(_("SARG: "),stderr);
512 fprintf(stderr,"(%s) ",pos);
513 va_start(ap,msg);
514 vfprintf(stderr,msg,ap);
515 va_end(ap);
516 }
517
518 /*!
519 Write a debug message to stderr. The message is prefixed by "SARG: (info)".
520
521 \param msg The printf like message to format.
522 \param ... The arguments to format in the message.
523 */
524 void debugaz(const char *msg,...)
525 {
526 va_list ap;
527
528 /* TRANSLATORS: This text is printed on the console before any message from
529 * the debug log with level "info".
530 */
531 fputs(_("SARG: (info) "),stderr);
532 va_start(ap,msg);
533 vfprintf(stderr,msg,ap);
534 va_end(ap);
535 }
536
537
538 char *fixnum(long long int value, int n)
539 {
540 #define MAXLEN_FIXNUM 256
541 char num[MAXLEN_FIXNUM]="";
542 char buf[MAXLEN_FIXNUM * 2];
543 char *pbuf;
544 static char ret[MAXLEN_FIXNUM * 2];
545 char *pret;
546 register int i, j, k;
547 int numlen;
548 static char abbrev[30];
549
550 my_lltoa(value, num, sizeof(num), 0);
551
552 if(DisplayedValues==DISPLAY_ABBREV) {
553 numlen = strlen(num);
554 if(numlen <= 3)
555 sprintf(abbrev,"%s",num);
556 if(numlen == 4 || numlen == 7 || numlen == 10 || numlen == 13) {
557 snprintf(abbrev,2,"%s",num);
558 strncat(abbrev,".",1);
559 strncat(abbrev,num+1,2);
560 if(!n) return(abbrev);
561 if(numlen == 4)
562 strncat(abbrev,"K",1);
563 else if(numlen == 7)
564 strncat(abbrev,"M",1);
565 else if(numlen == 10)
566 strncat(abbrev,"G",1);
567 else if(numlen == 13)
568 strncat(abbrev,"T",1);
569 }
570 if(numlen == 5 || numlen == 8 || numlen == 11 || numlen == 14) {
571 snprintf(abbrev,3,"%s",num);
572 strncat(abbrev,".",1);
573 strncat(abbrev,num+2,2);
574 if(!n) return(abbrev);
575 if(numlen == 5)
576 strncat(abbrev,"K",1);
577 else if(numlen == 8)
578 strncat(abbrev,"M",1);
579 else if(numlen == 11)
580 strncat(abbrev,"G",1);
581 else if(numlen == 14)
582 strncat(abbrev,"T",1);
583 }
584 if(numlen == 6 || numlen == 9 || numlen == 12 || numlen == 15) {
585 snprintf(abbrev,4,"%s",num);
586 strncat(abbrev,".",1);
587 strncat(abbrev,num+3,2);
588 if(!n) return(abbrev);
589 if(numlen == 6)
590 strncat(abbrev,"K",1);
591 else if(numlen == 9)
592 strncat(abbrev,"M",1);
593 else if(numlen == 12)
594 strncat(abbrev,"G",1);
595 else if(numlen == 15)
596 strncat(abbrev,"T",1);
597 }
598
599 return(abbrev);
600 }
601
602 bzero(buf, MAXLEN_FIXNUM*2);
603
604 pbuf = buf;
605 pret = ret;
606 k = 0;
607
608 for ( i = strlen(num) - 1, j = 0 ; i > -1; i--) {
609 if ( k == 2 && i != 0 ) {
610 k = 0;
611 pbuf[j++] = num[i];
612 pbuf[j++] = (UseComma) ? ',' : '.';
613 continue;
614 }
615 pbuf[j] = num[i];
616 j++;
617 k++;
618 }
619
620 pret[0]='\0';
621
622 for ( i = strlen(pbuf) - 1, j = 0 ; i > -1; i--, j++)
623 pret[j] = pbuf[i];
624
625 pret[j] = '\0';
626
627 return pret;
628 }
629
630
631 char *fixnum2(long long int value, int n)
632 {
633 #define MAXLEN_FIXNUM2 1024
634 char num[MAXLEN_FIXNUM2];
635 char buf[MAXLEN_FIXNUM2 * 2];
636 char *pbuf;
637 static char ret[MAXLEN_FIXNUM2 * 2];
638 char *pret;
639 register int i, j, k;
640
641 my_lltoa(value, num, sizeof(num), 0);
642 bzero(buf, MAXLEN_FIXNUM2*2);
643
644 pbuf = buf;
645 pret = ret;
646 k = 0;
647
648 for ( i = strlen(num) - 1, j = 0 ; i > -1; i--) {
649 if ( k == 2 && i != 0 ) {
650 k = 0;
651 pbuf[j++] = num[i];
652 pbuf[j++] = (UseComma) ? ',' : '.';
653 continue;
654 }
655 pbuf[j] = num[i];
656 j++;
657 k++;
658 }
659
660 pret[0]='\0';
661
662 for ( i = strlen(pbuf) - 1, j = 0 ; i > -1; i--, j++)
663 pret[j] = pbuf[i];
664
665 pret[j] = '\0';
666
667 return pret;
668 }
669
670
671 char *buildtime(long long int elap)
672 {
673 long int num = elap / 1000LL;
674 int hor = 0;
675 int min = 0;
676 int sec = 0;
677 static char buf[20];
678
679 hor=num / 3600L;
680 min=(num % 3600L) / 60L;
681 sec=num % 60L;
682 snprintf(buf,sizeof(buf),"%02d:%02d:%02d",hor,min,sec);
683
684 return(buf);
685 }
686
687
688 /*!
689 Get the date stored in the <tt>sarg-date</tt> file of a directory with the connection data.
690
691 \param dirname The directory to look for the connection directory.
692 \param name The name of the directory whose <tt>sarg-date</tt> file must be read.
693 \param data The buffer to store the content of the file. It must be more than 80
694 bytes long.
695
696 \retval 0 No error.
697 \retval -1 File not found.
698 */
699 int obtdate(const char *dirname, const char *name, char *data)
700 {
701 FILE *fp_in;
702 char wdir[MAXLEN];
703
704 if (snprintf(wdir,sizeof(wdir),"%s%s/sarg-date",dirname,name)>=sizeof(wdir)) {
705 debuga(_("Buffer to small to store %s%s/sarg-date"),dirname,name);
706 exit(EXIT_FAILURE);
707 }
708 if ((fp_in = fopen(wdir, "rt")) == 0) {
709 if (snprintf(wdir,sizeof(wdir),"%s%s/date",dirname,name)>=sizeof(wdir)) {
710 debuga(_("Buffer to small to store %s%s/date"),dirname,name);
711 exit(EXIT_FAILURE);
712 }
713 if ((fp_in = fopen(wdir, "rt")) == 0) {
714 data[0]='\0';
715 return(-1);
716 }
717 }
718
719 if (!fgets(data,80,fp_in)) {
720 /* TRANSLATORS: %s is a file name.
721 */
722 debuga(_("Failed to read the date in \"%s\"\n"),wdir);
723 exit(EXIT_FAILURE);
724 }
725 fclose(fp_in);
726 fixendofline(data);
727
728 return(0);
729 }
730
731
732 void formatdate(char *date,int date_size,int year,int month,int day,int hour,int minute,int second,int dst)
733 {
734 struct tm ltm;
735 time_t unixtime;
736 struct tm *fulltm;
737
738 memset(&ltm,0,sizeof(ltm));
739 if (year>=1900) ltm.tm_year=year-1900;
740 if (month>=1 && month<=12) ltm.tm_mon=month-1;
741 if (day>=1 && day<=31) ltm.tm_mday=day;
742 if (hour>=0 && hour<24) ltm.tm_hour=hour;
743 if (minute>=0 && minute<60) ltm.tm_min=minute;
744 if (second>=0 && second<60) ltm.tm_sec=second;
745 ltm.tm_isdst=dst;
746 unixtime=mktime(&ltm); //fill the missing entries
747 fulltm=localtime(&unixtime);
748 //strftime(date,date_size,"%a %b %d %H:%M:%S %Z %Y",fulltm);
749 strftime(date,date_size,"%c",fulltm);
750 }
751
752
753 void computedate(int year,int month,int day,struct tm *t)
754 {
755 memset(t,0,sizeof(*t));
756 t->tm_year=year-1900;
757 t->tm_mon=month-1;
758 t->tm_mday=day;
759 }
760
761
762 int obtuser(const char *dirname, const char *name)
763 {
764 FILE *fp_in;
765 char wdir[MAXLEN];
766 char tuser[20];
767 int nuser;
768
769 if (snprintf(wdir,sizeof(wdir),"%s%s/sarg-users",dirname,name)>=sizeof(wdir)) {
770 debuga(_("Buffer too small to store %s%s/sarg-users"),dirname,name);
771 exit(EXIT_FAILURE);
772 }
773 if((fp_in=fopen(wdir,"r"))==NULL) {
774 if (snprintf(wdir,sizeof(wdir),"%s%s/users",dirname,name)>=sizeof(wdir)) {
775 debuga(_("Buffer too small to store %s%s/users"),dirname,name);
776 exit(EXIT_FAILURE);
777 }
778 if((fp_in=fopen(wdir,"r"))==NULL) {
779 return(0);
780 }
781 }
782
783 if (!fgets(tuser,sizeof(tuser),fp_in)) {
784 /* TRANSLATORS: %s is a file name.
785 */
786 debuga(_("Failed to read the number of users in \"%s\"\n"),wdir);
787 exit(EXIT_FAILURE);
788 }
789 fclose(fp_in);
790 nuser=atoi(tuser);
791
792 return(nuser);
793 }
794
795
796 void obttotal(const char *dirname, const char *name, int nuser, long long int *tbytes, long long int *media)
797 {
798 FILE *fp_in;
799 char *buf;
800 char wdir[MAXLEN];
801 char user[MAX_USER_LEN];
802 char sep;
803 struct getwordstruct gwarea;
804 longline line;
805
806 *tbytes=0;
807 *media=0;
808
809 if (snprintf(wdir,sizeof(wdir),"%s%s/sarg-general",dirname,name)>=sizeof(wdir)) {
810 debuga(_("Buffer too small to store %s%s/sarg-general"),dirname,name);
811 exit(EXIT_FAILURE);
812 }
813 if ((fp_in = fopen(wdir, "r")) == 0) {
814 if (snprintf(wdir,sizeof(wdir),"%s%s/general",dirname,name)>=sizeof(wdir)) {
815 debuga(_("Buffer too small to store %s%s/general"),dirname,name);
816 exit(EXIT_FAILURE);
817 }
818 if ((fp_in = fopen(wdir, "r")) == 0) {
819 return;
820 }
821 }
822
823 if ((line=longline_create())==NULL) {
824 debuga(_("Not enough memory to read file \"%s\"\n"),wdir);
825 exit(EXIT_FAILURE);
826 }
827
828 while((buf=longline_read(fp_in,line))!=NULL) {
829 if (strncmp(buf,"TOTAL\t",6) == 0)
830 sep='\t'; //new file
831 else if (strncmp(buf,"TOTAL ",6) == 0)
832 sep=' '; //old file
833 else
834 continue;
835 getword_start(&gwarea,buf);
836 if (getword(user,sizeof(user),&gwarea,sep)<0) {
837 debuga(_("Invalid user in file \"%s\"\n"),wdir);
838 exit(EXIT_FAILURE);
839 }
840 if(strcmp(user,"TOTAL") != 0)
841 continue;
842 if (getword_skip(MAXLEN,&gwarea,sep)<0) {
843 debuga(_("Invalid total number of accesses in file \"%s\"\n"),wdir);
844 exit(EXIT_FAILURE);
845 }
846 if (getword_atoll(tbytes,&gwarea,sep)<0) {
847 debuga(_("Invalid number of bytes in file \"%s\"\n"),wdir);
848 exit(EXIT_FAILURE);
849 }
850 break;
851 }
852 fclose(fp_in);
853 longline_destroy(&line);
854
855 if (nuser <= 0)
856 return;
857
858 *media=*tbytes / nuser;
859 return;
860 }
861
862 int getperiod_fromsarglog(const char *arqtt,struct periodstruct *period)
863 {
864 const char *str;
865 int day0, month0, year0, hour0, minute0;
866 int day1, month1, year1, hour1, minute1;
867 int i;
868
869 memset(period,0,sizeof(*period));
870
871 str=arqtt;
872 while((str=strstr(str,"sarg-"))!=NULL) {
873 str+=5;
874 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
875 day0=(str[0]-'0')*10+(str[1]-'0');
876 if (day0<1 || day0>31) continue;
877 str+=2;
878 month0=(str[0]-'0')*10+(str[1]-'0')-1;
879 if (month0<0 || month0>11) continue;
880 str+=2;
881 year0=0;
882 for (i=0 ; isdigit(str[i]) && i<4 ; i++) year0=year0*10+(str[i]-'0');
883 if (i!=4) continue;
884 str+=4;
885 if (str[0]!='_') continue;
886 str++;
887
888 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
889 hour0=(str[0]-'0')*10+(str[1]-'0');
890 str+=2;
891 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
892 minute0=(str[0]-'0')*10+(str[1]-'0');
893 str+=2;
894
895 if (*str != '-') continue;
896 str++;
897
898 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
899 day1=(str[0]-'0')*10+(str[1]-'0');
900 if (day1<1 || day1>31) continue;
901 str+=2;
902 month1=(str[0]-'0')*10+(str[1]-'0')-1;
903 if (month1<0 || month1>11) continue;
904 str+=2;
905 year1=0;
906 for (i=0 ; isdigit(str[i]) && i<4 ; i++) year1=year1*10+(str[i]-'0');
907 if (i!=4) continue;
908 str+=4;
909
910 if (str[0]!='_') continue;
911 str++;
912
913 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
914 hour1=(str[0]-'0')*10+(str[1]-'0');
915 str+=2;
916 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
917 minute1=(str[0]-'0')*10+(str[1]-'0');
918 str+=2;
919
920 period->start.tm_mday=day0;
921 period->start.tm_mon=month0;
922 period->start.tm_year=year0-1900;
923 period->start.tm_hour=hour0;
924 period->start.tm_min=minute0;
925 period->end.tm_mday=day1;
926 period->end.tm_mon=month1;
927 period->end.tm_year=year1-1900;
928 period->end.tm_hour=hour1;
929 period->end.tm_min=minute1;
930 return(0);
931 }
932 return(-1);
933 }
934
935 void getperiod_fromrange(struct periodstruct *period,int dfrom,int duntil)
936 {
937 memset(&period->start,0,sizeof(period->start));
938 period->start.tm_mday=dfrom%100;
939 period->start.tm_mon=(dfrom/100)%100-1;
940 period->start.tm_year=(dfrom/10000)-1900;
941
942 memset(&period->end,0,sizeof(period->end));
943 period->end.tm_mday=duntil%100;
944 period->end.tm_mon=(duntil/100)%100-1;
945 period->end.tm_year=(duntil/10000)-1900;
946 }
947
948 int getperiod_buildtext(struct periodstruct *period)
949 {
950 int i;
951 int range;
952 char text1[40], text2[40];
953
954 if(df[0]=='u') {
955 i=strftime(text1, sizeof(text1), "%Y %b %d", &period->start);
956 }else if(df[0]=='e') {
957 i=strftime(text1, sizeof(text1), "%d %b %Y", &period->start);
958 } else /*if(df[0]=='w')*/ {
959 IndexTree=INDEX_TREE_FILE;
960 i=strftime(text1, sizeof(text1), "%Y.%U", &period->start);
961 }
962 if (i == 0) return(-1);
963
964 range=(period->start.tm_year!=period->end.tm_year ||
965 period->start.tm_mon!=period->end.tm_mon ||
966 period->start.tm_mday!=period->end.tm_mday);
967 if (range) {
968 if(df[0]=='u') {
969 i=strftime(text2, sizeof(text2)-i, "%Y %b %d", &period->end);
970 } else if(df[0]=='e') {
971 i=strftime(text2, sizeof(text2)-i, "%d %b %Y", &period->end);
972 } else {
973 i=strftime(text2, sizeof(text2)-i, "%Y.%U", &period->end);
974 }
975 if (i == 0) return(-1);
976 }
977
978 if (range) {
979 snprintf(period->text,sizeof(period->text),"%s-%s",text1,text2);
980 snprintf(period->html,sizeof(period->html),"%s&mdash;%s",text1,text2);
981 } else {
982 safe_strcpy(period->text,text1,sizeof(period->text));
983 safe_strcpy(period->html,text1,sizeof(period->html));
984 }
985 return(0);
986 }
987
988 static void copy_images(void)
989 {
990 FILE *img_in, *img_ou;
991 char images[512];
992 char imgdir[MAXLEN];
993 char srcfile[MAXLEN];
994 char dstfile[MAXLEN];
995 DIR *dirp;
996 struct dirent *direntp;
997 char buffer[MAXLEN];
998 size_t nread;
999 struct stat info;
1000
1001 if (snprintf(images,sizeof(images),"%simages",outdir)>=sizeof(images)) {
1002 debuga(_("Path too long: "));
1003 debuga_more("%simages\n",outdir);
1004 exit(EXIT_FAILURE);
1005 }
1006 if (access(images,R_OK)!=0) {
1007 if (mkdir(images,0755)) {
1008 debuga(_("Cannot create directory \"%s\": %s\n"),images,strerror(errno));
1009 exit(EXIT_FAILURE);
1010 }
1011 }
1012
1013 strcpy(imgdir,IMAGEDIR);
1014 dirp = opendir(imgdir);
1015 if(dirp==NULL) {
1016 debugapos("util",_("Cannot open directory \"%s\": %s\n"),imgdir,strerror(errno));
1017 return;
1018 }
1019 while ((direntp = readdir( dirp )) != NULL ){
1020 if(direntp->d_name[0]=='.')
1021 continue;
1022 if (snprintf(srcfile,sizeof(srcfile),"%s/%s",imgdir,direntp->d_name)>=sizeof(srcfile)) {
1023 debuga(_("Buffer too small to store %s/%s"),imgdir,direntp->d_name);
1024 exit(EXIT_FAILURE);
1025 }
1026 if (stat(srcfile,&info)) {
1027 debuga(_("Cannot stat \"%s\": %s\n"),srcfile,strerror(errno));
1028 continue;
1029 }
1030 if (S_ISREG(info.st_mode)) {
1031 if (snprintf(dstfile,sizeof(dstfile),"%s/%s",images,direntp->d_name)>=sizeof(dstfile)) {
1032 debuga(_("Buffer too small to store %s/%s"),images,direntp->d_name);
1033 exit(EXIT_FAILURE);
1034 }
1035 img_in = fopen(srcfile, "rb");
1036 if(img_in!=NULL) {
1037 img_ou = fopen(dstfile, "wb");
1038 if(img_ou!=NULL) {
1039 while ((nread = fread(buffer,1,sizeof(buffer),img_in))>0) {
1040 if (fwrite(buffer,1,nread,img_ou)!=nread) {
1041 debuga(_("Failed to copy image \"%s\" to \"%s\"\n"),srcfile,dstfile);
1042 break;
1043 }
1044 }
1045 fclose(img_ou);
1046 } else
1047 debugapos("util",_("Cannot open file \"%s\": %s\n"), dstfile, strerror(errno));
1048 fclose(img_in);
1049 } else
1050 debugapos("util",_("Cannot open file \"%s\": %s\n"),srcfile, strerror(errno));
1051 }
1052 }
1053 (void) closedir(dirp);
1054
1055 return;
1056 }
1057
1058 int vrfydir(const struct periodstruct *per1, const char *addr, const char *site, const char *us, const char *form)
1059 {
1060 FILE *fp_ou;
1061 int num=1, count=0;
1062 char wdir[MAXLEN];
1063 char dirname2[MAXLEN];
1064 int y1, y2;
1065 int m1, m2;
1066 int d1, d2;
1067 int wlen, wlen2;
1068 time_t curtime;
1069 struct tm *loctm;
1070
1071 strcpy(wdir,outdir);
1072 wlen=strlen(wdir);
1073 y1=per1->start.tm_year+1900;
1074 y2=per1->end.tm_year+1900;
1075 m1=per1->start.tm_mon+1;
1076 m2=per1->end.tm_mon+1;
1077 d1=per1->start.tm_mday;
1078 d2=per1->end.tm_mday;
1079 if(IndexTree == INDEX_TREE_DATE) {
1080 wlen+=sprintf(wdir+wlen,"%04d",y1);
1081 if(y1!=y2) wlen+=sprintf(wdir+wlen,"-%04d",y2);
1082 if(access(wdir, R_OK) != 0)
1083 my_mkdir(wdir);
1084
1085 wlen+=sprintf(wdir+wlen,"/%02d",m1);
1086 if(m1 != m2) wlen+=sprintf(wdir+wlen,"-%02d",m2);
1087 if(access(wdir, R_OK) != 0)
1088 my_mkdir(wdir);
1089
1090 wlen+=sprintf(wdir+wlen,"/%02d",d1);
1091 if(d1!=d2) wlen+=sprintf(wdir+wlen,"-%02d",d2);
1092 } else {
1093 if(df[0] == 'u') {
1094 wlen=snprintf(wdir+wlen,sizeof(wdir)-wlen,"%04d%s%02d-%04d%s%02d",y1,
1095 conv_month_name(m1),d1,y2,conv_month_name(m2),d2);
1096 } else if(df[0] == 'e') {
1097 wlen=snprintf(wdir+wlen,sizeof(wdir)-wlen,"%02d%s%04d-%02d%s%04d",d1,
1098 conv_month_name(m1),y1,d2,conv_month_name(m2),y2);
1099 } else if(df[0] == 'w') {
1100 wlen2=strftime(wdir+wlen, sizeof(wdir)-wlen, "%Y.%U", &per1->start);
1101 if (wlen2==0) return(-1);
1102 wlen+=wlen2;
1103 }
1104 }
1105
1106 if(us[0] != '\0') {
1107 struct userinfostruct *uinfo=userinfo_find_from_id(us);
1108 if (uinfo) {
1109 strcat(wdir,"-");
1110 strcat(wdir,uinfo->filename);
1111 }
1112 }
1113 if(addr[0] != '\0') {
1114 strcat(wdir,"-");
1115 strcat(wdir,addr);
1116 }
1117 if(site[0] != '\0') {
1118 strcat(wdir,"-");
1119 strcat(wdir,site);
1120 }
1121
1122 strcpy(outdirname,wdir);
1123
1124 if(IndexTree != INDEX_TREE_DATE) {
1125 if(!OverwriteReport) {
1126 while(num) {
1127 if(access(wdir,R_OK) == 0) {
1128 sprintf(wdir,"%s.%d",outdirname,num);
1129 num++;
1130 count++;
1131 } else
1132 break;
1133 }
1134
1135 if(count > 0) {
1136 if(debug)
1137 debuga(_("File \"%s\" already exists, moved to \"%s\"\n"),outdirname,wdir);
1138 rename(outdirname,wdir);
1139 }
1140 } else {
1141 if(access(outdirname,R_OK) == 0) {
1142 unlinkdir(outdirname,1);
1143 }
1144 }
1145 my_mkdir(outdirname);
1146 } else {
1147 strcpy(dirname2,wdir);
1148 if(!OverwriteReport) {
1149 while(num) {
1150 if(access(wdir,R_OK) == 0) {
1151 sprintf(wdir,"%s.%d",dirname2,num);
1152 num++;
1153 count++;
1154 } else
1155 break;
1156 }
1157
1158 if(count > 0) {
1159 if(debug)
1160 debuga(_("File \"%s\" already exists, moved to \"%s\"\n"),dirname2,wdir);
1161 rename(dirname2,wdir);
1162 strcpy(dirname2,wdir);
1163 }
1164 } else {
1165 if(access(wdir,R_OK) == 0) {
1166 unlinkdir(wdir,1);
1167 }
1168 }
1169
1170 if(access(wdir, R_OK) != 0)
1171 my_mkdir(wdir);
1172 }
1173
1174 strcpy(dirname2,wdir);
1175
1176 if (snprintf(wdir,sizeof(wdir),"%s/sarg-date",outdirname)>=sizeof(wdir)) {
1177 debuga(_("Buffer too small to store %s/sarg-date"),outdirname);
1178 exit(EXIT_FAILURE);
1179 }
1180 if ((fp_ou = fopen(wdir, "wt")) == 0) {
1181 debuga(_("Cannot open file \"%s\": %s\n"),wdir,strerror(errno));
1182 perror("SARG:");
1183 exit(EXIT_FAILURE);
1184 }
1185 time(&curtime);
1186 //strftime(wdir,sizeof(wdir),"%a %b %d %H:%M:%S %Z %Y",localtime(&curtime));
1187 loctm=localtime(&curtime);
1188 strftime(wdir,sizeof(wdir),"%Y-%m-%d %H:%M:%S",loctm);
1189 if (fprintf(fp_ou,"%s %d\n",wdir,loctm->tm_isdst)<0) {
1190 debuga(_("Failed to write the date in \"%s\"\n"),wdir);
1191 perror("SARG:");
1192 exit(EXIT_FAILURE);
1193 }
1194 if (fclose(fp_ou)==EOF) {
1195 debuga(_("Failed to close file \"%s\": %s\n"),wdir,strerror(errno));
1196 perror("SARG:");
1197 exit(EXIT_FAILURE);
1198 }
1199
1200 copy_images();
1201 return(0);
1202 }
1203
1204 /*!
1205 Copy a string without overflowing the buffer. The copied string
1206 is properly terminated by an ASCII zero.
1207
1208 \param dest The destination buffer.
1209 \param src The source buffer.
1210 \param length The size of the destination buffer. The program is aborted
1211 if the length is negative or zero.
1212 */
1213 void safe_strcpy(char *dest,const char *src,int length)
1214 {
1215 if (length<=0) {
1216 debuga(_("Invalid buffer length passed to the function to safely copy a string\n"));
1217 exit(EXIT_FAILURE);
1218 }
1219 strncpy(dest,src,length-1);
1220 dest[length-1]='\0';
1221 }
1222
1223 void strip_latin(char *line)
1224 {
1225 int i,j;
1226 int skip;
1227
1228 j=0;
1229 skip=0;
1230 for (i=0;line[i];i++){
1231 if (skip){
1232 if (line[i]==';') skip=0;
1233 } else {
1234 if (line[i]=='&')
1235 skip=1;
1236 else
1237 line[j++]=line[i];
1238 }
1239 }
1240 line[j]='\0';
1241 return;
1242 }
1243
1244 void zdate(char *ftime,int ftimesize, const char *DateFormat)
1245 {
1246 time_t t;
1247 struct tm *local;
1248
1249 t = time(NULL);
1250 local = localtime(&t);
1251 if(strcmp(DateFormat,"u") == 0)
1252 strftime(ftime, ftimesize, "%b/%d/%Y %H:%M", local);
1253 if(strcmp(DateFormat,"e") == 0)
1254 strftime(ftime, ftimesize, "%d/%b/%Y-%H:%M", local);
1255 if(strcmp(DateFormat,"w") == 0)
1256 strftime(ftime, ftimesize, "%W-%H-%M", local);
1257 return;
1258 }
1259
1260
1261 char *fixtime(long long int elap)
1262 {
1263 long int num = elap / 1000LL;
1264 int hor = 0;
1265 int min = 0;
1266 int sec = 0;
1267 static char buf[20];
1268
1269 hor=num / 3600L;
1270 min=(num % 3600L) / 60L;
1271 sec=num % 60L;
1272
1273 if(hor==0 && min==0 && sec==0)
1274 strcpy(buf,"0");
1275 else
1276 snprintf(buf,sizeof(buf),"%d:%02d:%02d",hor,min,sec);
1277
1278 return buf;
1279 }
1280
1281
1282 void date_from(char *date,int date_size, int *dfrom, int *duntil)
1283 {
1284 int d0=0;
1285 int m0=0;
1286 int y0=0;
1287 int d1=0;
1288 int m1=0;
1289 int y1=0;
1290
1291 if (isdigit(date[0])) {
1292 int next=-1;
1293
1294 if (sscanf(date,"%d/%d/%d%n",&d0,&m0,&y0,&next)!=3 || y0<100 || m0<1 || m0>12 || d0<1 || d0>31 || next<0) {
1295 debuga(_("The date passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1296 exit(EXIT_FAILURE);
1297 }
1298 if (date[next]=='-') {
1299 if (sscanf(date+next+1,"%d/%d/%d",&d1,&m1,&y1)!=3 || y1<100 || m1<1 || m1>12 || d1<1 || d1>31) {
1300 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1301 exit(EXIT_FAILURE);
1302 }
1303 } else if (date[next]!='\0') {
1304 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1305 exit(EXIT_FAILURE);
1306 } else {
1307 d1=d0;
1308 m1=m0;
1309 y1=y0;
1310 }
1311 } else {
1312 int i;
1313 time_t Today,t1;
1314 struct tm *Date0,Date1;
1315
1316 if (time(&Today)==(time_t)-1) {
1317 debuga(_("Failed to get the current time\n"));
1318 exit(EXIT_FAILURE);
1319 }
1320 if (sscanf(date,"day-%d",&i)==1) {
1321 if (i<0) {
1322 debuga(_("Invalid number of days in -d parameter\n"));
1323 exit(EXIT_FAILURE);
1324 }
1325 Today-=i*24*60*60;
1326 Date0=localtime(&Today);
1327 if (Date0==NULL) {
1328 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1329 exit(EXIT_FAILURE);
1330 }
1331 y0=y1=Date0->tm_year+1900;
1332 m0=m1=Date0->tm_mon+1;
1333 d0=d1=Date0->tm_mday;
1334 } else if (sscanf(date,"week-%d",&i)==1) {
1335 /*
1336 There is no portable way to find the first day of the week even though the
1337 information is available in the locale. nl_langinfo has the unofficial
1338 parameters _NL_TIME_FIRST_WEEKDAY and _NL_TIME_WEEK_1STDAY but they are
1339 undocumented as is their return value and it is discouraged to use them.
1340 Beside, nl_langinfo isn't available on windows and the first day of the
1341 week isn't available at all on that system.
1342 */
1343 const int FirstWeekDay=1;
1344 time_t WeekBegin;
1345
1346 if (i<0) {
1347 debuga(_("Invalid number of weeks in -d parameter\n"));
1348 exit(EXIT_FAILURE);
1349 }
1350 Date0=localtime(&Today);
1351 if (Date0==NULL) {
1352 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1353 exit(EXIT_FAILURE);
1354 }
1355 WeekBegin=Today-((Date0->tm_wday-FirstWeekDay+7)%7)*24*60*60;
1356 WeekBegin-=i*7*24*60*60;
1357 Date0=localtime(&WeekBegin);
1358 if (Date0==NULL) {
1359 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1360 exit(EXIT_FAILURE);
1361 }
1362 y0=Date0->tm_year+1900;
1363 m0=Date0->tm_mon+1;
1364 d0=Date0->tm_mday;
1365 WeekBegin+=6*24*60*60;
1366 Date0=localtime(&WeekBegin);
1367 if (Date0==NULL) {
1368 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1369 exit(EXIT_FAILURE);
1370 }
1371 y1=Date0->tm_year+1900;
1372 m1=Date0->tm_mon+1;
1373 d1=Date0->tm_mday;
1374 } else if (sscanf(date,"month-%d",&i)==1) {
1375 if (i<0) {
1376 debuga(_("Invalid number of months in -d parameter\n"));
1377 exit(EXIT_FAILURE);
1378 }
1379 Date0=localtime(&Today);
1380 if (Date0==NULL) {
1381 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1382 exit(EXIT_FAILURE);
1383 }
1384 if (Date0->tm_mon<i%12) {
1385 y0=Date0->tm_year+1900-i/12-1;
1386 m0=(Date0->tm_mon+12-i%12)%12+1;
1387 d0=1;
1388 } else {
1389 y0=Date0->tm_year+1900-i/12;
1390 m0=Date0->tm_mon-i%12+1;
1391 d0=1;
1392 }
1393 memcpy(&Date1,Date0,sizeof(struct tm));
1394 Date1.tm_isdst=-1;
1395 Date1.tm_mday=1;
1396 if (m0<12) {
1397 Date1.tm_mon=m0;
1398 Date1.tm_year=y0-1900;
1399 } else {
1400 Date1.tm_mon=0;
1401 Date1.tm_year=y0-1900+1;
1402 }
1403 t1=mktime(&Date1);
1404 t1-=24*60*60;
1405 Date0=localtime(&t1);
1406 y1=Date0->tm_year+1900;
1407 m1=Date0->tm_mon+1;
1408 d1=Date0->tm_mday;
1409 } else {
1410 debuga(_("Invalid date range passed on command line\n"));
1411 exit(EXIT_FAILURE);
1412 }
1413 }
1414
1415 *dfrom=y0*10000+m0*100+d0;
1416 *duntil=y1*10000+m1*100+d1;
1417 snprintf(date,date_size,"%02d/%02d/%04d-%02d/%02d/%04d",d0,m0,y0,d1,m1,y1);
1418 return;
1419 }
1420
1421
1422 char *strlow(char *string)
1423 {
1424 char *s;
1425
1426 if (string)
1427 {
1428 for (s = string; *s; ++s)
1429 *s = tolower(*s);
1430 }
1431
1432 return string;
1433 }
1434
1435
1436
1437
1438 char *strup(char *string)
1439 {
1440 char *s;
1441
1442 if (string)
1443 {
1444 for (s = string; *s; ++s)
1445 *s = toupper(*s);
1446 }
1447
1448 return string;
1449 }
1450
1451
1452 void removetmp(const char *outdir)
1453 {
1454 FILE *fp_gen;
1455 char filename[256];
1456
1457 if(!RemoveTempFiles)
1458 return;
1459
1460 if(debug) {
1461 debuga(_("Purging temporary file sarg-general\n"));
1462 }
1463 if (snprintf(filename,sizeof(filename),"%s/sarg-general",outdir)>=sizeof(filename)) {
1464 debugapos("removetmp",_("Path too long: "));
1465 debuga_more("%s/sarg-period\n",outdir);
1466 exit(EXIT_FAILURE);
1467 }
1468 if((fp_gen=fopen(filename,"w"))==NULL){
1469 debugapos("removetmp",_("Cannot open file \"%s\": %s\n"),filename,strerror(errno));
1470 exit(EXIT_FAILURE);
1471 }
1472 totalger(fp_gen,filename);
1473 if (fclose(fp_gen)==EOF) {
1474 debuga(_("Failed to close file \"%s\": %s\n"),filename,strerror(errno));
1475 exit(EXIT_FAILURE);
1476 }
1477 }
1478
1479 void load_excludecodes(const char *ExcludeCodes)
1480 {
1481 FILE *fp_in;
1482 char data[80];
1483 int i;
1484 int Stored;
1485 long int MemSize;
1486
1487 if(ExcludeCodes[0] == '\0')
1488 return;
1489
1490 if((fp_in=fopen(ExcludeCodes,"r"))==NULL) {
1491 debugapos("util",_("Cannot open file \"%s\": %s\n"),ExcludeCodes,strerror(errno));
1492 exit(EXIT_FAILURE);
1493 }
1494
1495 if (fseek(fp_in, 0, SEEK_END)==-1) {
1496 debuga(_("Failed to move till the end of file \"%s\": %s\n"),ExcludeCodes,strerror(errno));
1497 exit(EXIT_FAILURE);
1498 }
1499 MemSize = ftell(fp_in);
1500 if (MemSize<0) {
1501 debuga(_("Cannot get the size of file \"%s\": %s\n"),ExcludeCodes,strerror(errno));
1502 exit(EXIT_FAILURE);
1503 }
1504 if (fseek(fp_in, 0, SEEK_SET)==-1) {
1505 debuga(_("Failed to rewind file \"%s\": %s\n"),ExcludeCodes,strerror(errno));
1506 exit(EXIT_FAILURE);
1507 }
1508
1509 MemSize+=1;
1510 if((excludecode=(char *) malloc(MemSize))==NULL) {
1511 debuga(_("malloc failed to allocate %ld bytes\n"),MemSize);
1512 exit(EXIT_FAILURE);
1513 }
1514 memset(excludecode,0,MemSize);
1515
1516 Stored=0;
1517 while(fgets(data,sizeof(data),fp_in)!=NULL) {
1518 if (data[0]=='#') continue;
1519 for (i=strlen(data)-1 ; i>=0 && (unsigned char)data[i]<=' ' ; i--) data[i]='\0';
1520 if (i<0) continue;
1521 if (Stored+i+2>=MemSize) {
1522 debuga(_("Too many codes to exclude in file \"%s\"\n"),ExcludeCodes);
1523 break;
1524 }
1525 strcat(excludecode,data);
1526 strcat(excludecode,";");
1527 Stored+=i+1;
1528 }
1529
1530 fclose(fp_in);
1531 return;
1532 }
1533
1534 void free_excludecodes(void)
1535 {
1536 if (excludecode) {
1537 free(excludecode);
1538 excludecode=NULL;
1539 }
1540 }
1541
1542 int vercode(const char *code)
1543 {
1544 char *cod;
1545 int clen;
1546
1547 if (excludecode && excludecode[0]!='\0') {
1548 clen=strlen(code);
1549 cod=excludecode;
1550 while (cod) {
1551 if (strncmp(code,cod,clen)==0 && cod[clen]==';')
1552 return 1;
1553 cod=strchr(cod,';');
1554 if (cod) cod++;
1555 }
1556 }
1557 return 0;
1558 }
1559
1560 void fixnone(char *str)
1561 {
1562 int i;
1563
1564 for (i=strlen(str)-1 ; i>=0 && (unsigned char)str[i]<=' ' ; i--);
1565 if(i==3 && strncmp(str,"none",4) == 0)
1566 str[0]='\0';
1567
1568 return;
1569 }
1570
1571 void fixendofline(char *str)
1572 {
1573 int i;
1574
1575 for (i=strlen(str)-1 ; i>=0 && (unsigned char)str[i]<=' ' ; i--) str[i]=0;
1576 }
1577
1578 #ifdef LEGACY_TESTVALIDUSERCHAR
1579 int testvaliduserchar(const char *user)
1580 {
1581 int x=0;
1582 int y=0;
1583
1584 for (y=0; y<strlen(UserInvalidChar); y++) {
1585 for (x=0; x<strlen(user); x++) {
1586 if(user[x] == UserInvalidChar[y])
1587 return 1;
1588 }
1589 }
1590 return 0;
1591 }
1592 #else
1593 int testvaliduserchar(const char *user)
1594 {
1595 char * p_UserInvalidChar = UserInvalidChar ;
1596 const char * p_user ;
1597
1598 while( *p_UserInvalidChar ) {
1599 p_user = user ;
1600 while ( *p_user ) {
1601 if( *p_UserInvalidChar == *p_user )
1602 return 1;
1603 p_user++ ;
1604 }
1605 p_UserInvalidChar++ ;
1606 }
1607 return 0;
1608 }
1609 #endif
1610
1611 int compar( const void *a, const void *b )
1612 {
1613 if( *(int *)a > *(int *)b ) return 1;
1614 if( *(int *)a < *(int *)b ) return -1;
1615 return 0;
1616 }
1617
1618 int getnumlist( char *buf, numlist *list, const int len, const int maxvalue )
1619 {
1620 int i, j, d, flag, r1, r2;
1621 char *pbuf, **bp, *strbufs[ 24 ];
1622
1623 bp = strbufs;
1624 strtok( buf, " \t" );
1625 for( *bp = strtok( NULL, "," ), list->len = 0; *bp; *bp = strtok( NULL, "," ) ) {
1626 if( ++bp >= &strbufs[ 24 ] )
1627 break;
1628 list->len++;
1629 }
1630 if( ! list->len )
1631 return -1;
1632 d = 0;
1633 for( i = 0; i < list->len; i++ ) {
1634 if( strchr( strbufs[ i ], '-' ) != 0 ) {
1635 pbuf = strbufs[ i ];
1636 strtok( pbuf, "-" );
1637 pbuf = strtok( NULL, "\0" );
1638 r1 = atoi( strbufs[ i ] );
1639 if( ( r2 = atoi( pbuf ) ) >= maxvalue || r1 >= r2 )
1640 return -1;
1641 if( i + d + ( r2 - r1 ) + 1 <= len ) {
1642 for( j = r1; j <= r2; j++ )
1643 list->list[ i + d++ ] = j;
1644 d--;
1645 }
1646 }
1647 else
1648 if( ( list->list[ i + d ] = atoi( strbufs[ i ] ) ) >= maxvalue )
1649 return 1;
1650 }
1651 list->len += d;
1652 qsort( list->list, list->len, sizeof( int ), compar );
1653 do {
1654 flag = 0;
1655 for( i = 0; i < list->len - 1; i++ )
1656 if( list->list[ i ] == list->list[ i + 1 ] ) {
1657 for( j = i + 1; j < list->len; j++ )
1658 list->list[ j - 1 ] = list->list[ j ];
1659 list->len--;
1660 flag = 1;
1661 break;
1662 }
1663 } while( flag );
1664 return 0;
1665 }
1666
1667
1668 char *get_size(const char *path, const char *file)
1669 {
1670 FILE *fp;
1671 static char response[255];
1672 char cmd[255];
1673 char *ptr;
1674
1675 if (snprintf(cmd,sizeof(cmd),"du -skh \"%s%s\"",path,file)>=sizeof(cmd)) {
1676 debuga(_("Cannot get disk space because the path \"%s%s\" is too long\n"),path,file);
1677 exit(EXIT_FAILURE);
1678 }
1679 if ((fp = popen(cmd, "r")) == NULL) {
1680 debuga(_("Cannot get disk space with command %s\n"),cmd);
1681 exit(EXIT_FAILURE);
1682 }
1683 if (!fgets(response, sizeof(response), fp)) {
1684 debuga(_("Cannot get disk size with command %s\n"),cmd);
1685 exit(EXIT_FAILURE);
1686 }
1687 ptr=strchr(response,'\t');
1688 if (ptr==NULL) {
1689 /* TRANSLATORS: First %s is the command to get the occuped disk size (namely, du -skh "...").
1690 * The second %s is the string returned by the command.
1691 */
1692 debuga(_("The command to compute the occupied disk size (%s) returned the unknown string %s\n"),cmd,response);
1693 exit(EXIT_FAILURE);
1694 }
1695 pclose(fp);
1696 *ptr='\0';
1697
1698 return (response);
1699 }
1700
1701 void show_info(FILE *fp_ou)
1702 {
1703 char ftime[127];
1704 char pgmurl[250];
1705
1706 if(!ShowSargInfo) return;
1707 zdate(ftime, sizeof(ftime), DateFormat);
1708 fputs("<div class=\"info\">",fp_ou);
1709 snprintf(pgmurl,sizeof(pgmurl),"<a href='%s'>%s-%s</a>",URL,PGM,VERSION);
1710 fprintf(fp_ou,_("Generated by %s on %s"),pgmurl,ftime);
1711 fputs("</div>\n",fp_ou);
1712 }
1713
1714 void show_sarg(FILE *fp_ou, int depth)
1715 {
1716 int i;
1717
1718 if(!ShowSargLogo) return;
1719 fputs("<div class=\"logo\"><a href=\"http://sarg.sourceforge.net\"><img src=\"",fp_ou);
1720 for (i=0 ; i<depth ; i++)
1721 fputs("../",fp_ou);
1722 fputs("images/sarg.png\" title=\"SARG, Squid Analysis Report Generator. Logo by Osamu Matsuzaki\" alt=\"Sarg\"></a>&nbsp;Squid Analysis Report Generator</div>\n",fp_ou);
1723 }
1724
1725 void write_logo_image(FILE *fp_ou)
1726 {
1727 if(LogoImage[0]!='\0')
1728 fprintf(fp_ou, "<div class=\"logo\"><img src=\"%s\" width=\"%s\" height=\"%s\" alt=\"Logo\">&nbsp;%s</div>\n",LogoImage,Width,Height,LogoText);
1729 }
1730
1731 void write_html_head(FILE *fp_ou, int depth, const char *page_title,int javascript)
1732 {
1733 int i;
1734
1735 fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n",fp_ou);
1736 fprintf(fp_ou, "<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n",CharSet);
1737 if (page_title) fprintf(fp_ou,"<title>%s</title>\n",page_title);
1738 css(fp_ou);
1739 if ((javascript & HTML_JS_SORTTABLE)!=0 && SortTableJs[0]) {
1740 fputs("<script type=\"text/javascript\" src=\"",fp_ou);
1741 if (strncmp(SortTableJs,"../",3)==0) {
1742 for (i=0 ; i<depth ; i++) fputs("../",fp_ou);
1743 }
1744 fputs(SortTableJs,fp_ou);
1745 fputs("\"></script>\n",fp_ou);
1746 }
1747 fputs("</head>\n<body>\n",fp_ou);
1748 }
1749
1750 void write_html_header(FILE *fp_ou, int depth, const char *page_title,int javascript)
1751 {
1752 write_html_head(fp_ou,depth,page_title,javascript);
1753 write_logo_image(fp_ou);
1754 show_sarg(fp_ou, depth);
1755 fprintf(fp_ou,"<div class=\"title\"><table cellpadding=\"0\" cellspacing=\"0\">\n<tr><th class=\"title_c\">%s</th></tr>\n",Title);
1756 }
1757
1758 void close_html_header(FILE *fp_ou)
1759 {
1760 fputs("</table></div>\n",fp_ou);
1761 }
1762
1763 int write_html_trailer(FILE *fp_ou)
1764 {
1765 show_info(fp_ou);
1766 if (fputs("</body>\n</html>\n",fp_ou)==EOF) return(-1);
1767 return(0);
1768 }
1769
1770 void output_html_string(FILE *fp_ou,const char *str,int maxlen)
1771 {
1772 int i=0;
1773
1774 while (*str && (maxlen<=0 || i<maxlen)) {
1775 switch (*str) {
1776 case '&':
1777 fputs("&amp;",fp_ou);
1778 break;
1779 case '<':
1780 fputs("&lt;",fp_ou);
1781 break;
1782 case '>':
1783 fputs("&gt;",fp_ou);
1784 break;
1785 case '"':
1786 fputs("&quot;",fp_ou);
1787 break;
1788 case '\'':
1789 fputs("&#39;",fp_ou);
1790 break;
1791 default:
1792 fputc(*str,fp_ou);
1793 }
1794 str++;
1795 i++;
1796 }
1797 if (maxlen>0 && i>=maxlen)
1798 fputs("&hellip;",fp_ou);
1799 }
1800
1801 void output_html_url(FILE *fp_ou,const char *url)
1802 {
1803 while (*url) {
1804 if (*url=='&')
1805 fputs("&amp;",fp_ou);
1806 else
1807 fputc(*url,fp_ou);
1808 url++;
1809 }
1810 }
1811
1812 /*!
1813 Write a host name inside an A tag of a HTML file. If the host name starts
1814 with a star, it is assumed to be an alias that cannot be put inside a link
1815 so the A tag is not written around the host name.
1816
1817 \param fp_ou The handle of the HTML file.
1818 \param url The host to display in the HTML file.
1819 \param maxlen The maximum number of characters to print into the host name.
1820 */
1821 void output_html_link(FILE *fp_ou,const char *url,int maxlen)
1822 {
1823 if (url[0]==ALIAS_PREFIX) {
1824 // this is an alias, no need for a A tag
1825 output_html_string(fp_ou,url+1,100);
1826 } else {
1827 if (skip_scheme(url)==url)
1828 fputs("<a href=\"http://",fp_ou);//no scheme in the url, assume http:// to make the link clickable
1829 else
1830 fputs("<a href=\"",fp_ou);//the scheme is in the url, no need to add one
1831 output_html_url(fp_ou,url);
1832 fputs("\">",fp_ou);
1833 output_html_string(fp_ou,url,100);
1834 fputs("</a>",fp_ou);
1835 }
1836 }
1837
1838 void url_module(const char *url, char *w2)
1839 {
1840 int x, y;
1841 char w[255];
1842
1843 y=0;
1844 for(x=strlen(url)-1; x>=0; x--) {
1845 if(url[x] == '/' || y>=sizeof(w)-1) break;
1846 w[y++]=url[x];
1847 }
1848 if (x<0) {
1849 w2[0]='\0';
1850 return;
1851 }
1852
1853 x=0;
1854 for(y=y-1; y>=0; y--) {
1855 w2[x++]=w[y];
1856 }
1857 w2[x]='\0';
1858 }
1859
1860 void url_to_file(const char *url,char *file,int filesize)
1861 {
1862 int i,skip;
1863
1864 filesize--;
1865 skip=0;
1866 for(i=0; i<filesize && *url; url++) {
1867 if(isalnum(*url) || *url=='-' || *url=='_' || *url=='.' || *url=='%') {
1868 file[i++]=*url;
1869 skip=0;
1870 } else {
1871 if (!skip) file[i++]='_';
1872 skip=1;
1873 }
1874 }
1875 file[i]='\0';
1876 }
1877
1878 void version(void)
1879 {
1880 printf(_("SARG version: %s\n"),VERSION);
1881 #if defined(ENABLE_NLS) && defined(HAVE_LOCALE_H)
1882 if (debug) {
1883 printf(_("\nFor the translation to work, a valid message file should be installed as "
1884 "\"%s/<Locale>/LC_MESSAGES/%s.mo\" where <Locale> is derived from the effective locale.\n"),LOCALEDIR,PACKAGE_NAME);
1885 if (CurrentLocale) {
1886 printf(_("Currently effective locale is \"%s\".\n"),CurrentLocale);
1887 } else {
1888 printf(_("Locale is not set in the environment variable.\n"));
1889 }
1890 // TRANSLATORS: You may change this message to tell the reader that the language is correctly supported.
1891 printf(_("If this message is in English, then your language is not supported or not correctly installed.\n"));
1892 }
1893 #endif
1894 exit(EXIT_SUCCESS);
1895 }
1896
1897 char *get_param_value(const char *param,char *line)
1898 {
1899 int plen;
1900
1901 while (*line==' ' || *line=='\t') line++;
1902 plen=strlen(param);
1903 if (strncasecmp(line,param,plen)) return(NULL);
1904 if (line[plen]!=' ' && line[plen]!='\t') return(NULL);
1905 line+=plen;
1906 while (*line==' ' || *line=='\t') line++;
1907 return(line);
1908 }
1909
1910 void unlinkdir(const char *dir,bool contentonly)
1911 {
1912 struct stat st;
1913 DIR *dirp;
1914 struct dirent *direntp;
1915 char dname[MAXLEN];
1916 int err;
1917
1918 dirp=opendir(dir);
1919 if (!dirp) return;
1920 while ((direntp = readdir(dirp)) != NULL) {
1921 if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' ||
1922 (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
1923 continue;
1924 if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
1925 debuga(_("Path too long: "));
1926 debuga_more("%s/%s\n",dir,direntp->d_name);
1927 exit(EXIT_FAILURE);
1928 }
1929 #ifdef HAVE_LSTAT
1930 err=lstat(dname,&st);
1931 #else
1932 err=stat(dname,&st);
1933 #endif
1934 if (err) {
1935 debuga(_("Cannot stat \"%s\": %s\n"),dname,strerror(errno));
1936 exit(EXIT_FAILURE);
1937 }
1938 if (S_ISREG(st.st_mode)) {
1939 if (unlink(dname)) {
1940 debuga(_("Cannot delete \"%s\": %s\n"),dname,strerror(errno));
1941 exit(EXIT_FAILURE);
1942 }
1943 } else if (S_ISDIR(st.st_mode)) {
1944 unlinkdir(dname,0);
1945 } else {
1946 debuga(_("Unknown path type \"%s\"\n"),dname);
1947 }
1948 }
1949 closedir(dirp);
1950
1951 if (!contentonly) {
1952 if (rmdir(dir)) {
1953 debuga(_("Cannot delete \"%s\": %s\n"),dir,strerror(errno));
1954 exit(EXIT_FAILURE);
1955 }
1956 }
1957 }
1958
1959 /*!
1960 Delete every file from the temporary directory where sarg is told to store its
1961 temporary files.
1962
1963 As any stray file left over by a previous run would be included in the report, we
1964 must delete every file from the temporary directory before we start processing the logs.
1965
1966 But the temporary directory is given by the user either in the configuration file or
1967 on the command line. We check that the user didn't give a wrong directory by looking
1968 at the files stored in the directory. If a single file is not one of ours, we abort.
1969
1970 \param dir The temporary directory to purge.
1971 */
1972 void emptytmpdir(const char *dir)
1973 {
1974 struct stat st;
1975 DIR *dirp;
1976 struct dirent *direntp;
1977 int dlen;
1978 int elen;
1979 char dname[MAXLEN];
1980 int err;
1981 int i;
1982 static const char *TmpExt[]=
1983 {
1984 ".int_unsort",
1985 ".int_log",
1986 ".day",
1987 "htmlrel.txt",
1988 ".user_unsort",
1989 ".user_log",
1990 ".utmp",
1991 ".ip"
1992 };
1993
1994 dirp=opendir(dir);
1995 if (!dirp) return;
1996
1997 // make sure the temporary directory contains only our files
1998 while ((direntp = readdir(dirp)) != NULL) {
1999 if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' ||
2000 (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
2001 continue;
2002
2003 // is it one of our files
2004 dlen=strlen(direntp->d_name);
2005 for (i=sizeof(TmpExt)/sizeof(TmpExt[0])-1 ; i>=0 ; i--) {
2006 elen=strlen(TmpExt[i]);
2007 if (dlen>=elen && strcasecmp(direntp->d_name+dlen-elen,TmpExt[i])==0) break;
2008 }
2009 if (i<0) {
2010 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2011 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2012 "directory or manually delete the content of \"%s\"\n"),direntp->d_name,dir,dir);
2013 exit(EXIT_FAILURE);
2014 }
2015
2016 if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
2017 debuga(_("Path too long: "));
2018 debuga_more("%s/%s\n",dir,direntp->d_name);
2019 exit(EXIT_FAILURE);
2020 }
2021
2022 #ifdef HAVE_LSTAT
2023 err=lstat(dname,&st);
2024 #else
2025 err=stat(dname,&st);
2026 #endif
2027 if (err) {
2028 debuga(_("Cannot stat \"%s\": %s\n"),dname,strerror(errno));
2029 exit(EXIT_FAILURE);
2030 }
2031 if (S_ISDIR(st.st_mode)) {
2032 unlinkdir(dname,0);
2033 } else if (!S_ISREG(st.st_mode)) {
2034 debuga(_("Unknown path type \"%s\". Check your temporary directory\n"),dname);
2035 exit(EXIT_FAILURE);
2036 }
2037 }
2038 rewinddir(dirp);
2039
2040 // now delete our files
2041 while ((direntp = readdir(dirp)) != NULL) {
2042 if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' ||
2043 (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
2044 continue;
2045
2046 // is it one of our files
2047 dlen=strlen(direntp->d_name);
2048 for (i=sizeof(TmpExt)/sizeof(TmpExt[0])-1 ; i>=0 ; i--) {
2049 elen=strlen(TmpExt[i]);
2050 if (dlen>=elen && strcasecmp(direntp->d_name+dlen-elen,TmpExt[i])==0) break;
2051 }
2052 if (i<0) {
2053 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2054 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2055 "directory or manually delete the content of \"%s\"\n"),direntp->d_name,dir,dir);
2056 exit(EXIT_FAILURE);
2057 }
2058
2059 if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
2060 debuga(_("Path too long: "));
2061 debuga_more("%s/%s\n",dir,direntp->d_name);
2062 exit(EXIT_FAILURE);
2063 }
2064 #ifdef HAVE_LSTAT
2065 err=lstat(dname,&st);
2066 #else
2067 err=stat(dname,&st);
2068 #endif
2069 if (err) {
2070 debuga(_("Cannot stat \"%s\": %s\n"),dname,strerror(errno));
2071 exit(EXIT_FAILURE);
2072 }
2073 if (S_ISREG(st.st_mode)) {
2074 if (unlink(dname)) {
2075 debuga(_("Cannot delete \"%s\": %s\n"),dname,strerror(errno));
2076 exit(EXIT_FAILURE);
2077 }
2078 } else {
2079 debuga(_("Unknown path type \"%s\"\n"),dname);
2080 }
2081 }
2082 closedir(dirp);
2083 }
2084
2085 /*!
2086 Extract an url, IPv4 or IPv6 from a buffer. The IP addresses may end with a
2087 prefix size.
2088
2089 \param buf The buffer to parse.
2090 \param text A pointer to set to the beginning of the string pattern. No terminating zero is inserted.
2091 The pointer may be NULL.
2092 \param ipv4 A 4 bytes buffer to store the bytes of the IPv4 address.
2093 \param ipv6 A 8 short integers buffer to store the values of the IPv6 address.
2094 \param nbits The number of prefix bits for an IP address.
2095 \param next The content of the line after the extracted address.
2096
2097 \retval 3 The pattern is a IPv6 address.
2098 \retval 2 The pattern is a IPv4 address.
2099 \retval 1 The patter is a string.
2100 \retval 0 Empty pattern.
2101 */
2102 int extract_address_mask(const char *buf,const char **text,unsigned char *ipv4,unsigned short int *ipv6,int *nbits,const char **next)
2103 {
2104 int i;
2105 int j;
2106 int ip_size;
2107 unsigned int value4, value6;
2108 unsigned short int addr[8];
2109 int addr_len;
2110 int nibble6_len;
2111 int mask, max_mask;
2112 int pad_pos;
2113 int pad_len;
2114 bool bracket=false;
2115 bool port=false;
2116 bool port_num=0;
2117
2118 // skip leading spaces and tabs
2119 while (*buf && (*buf==' ' || *buf=='\t')) buf++;
2120
2121 // find out the nature of the pattern
2122 ip_size=0x60 | 0x04;
2123 if (*buf=='[') {
2124 bracket=true;
2125 ip_size=0x60;
2126 buf++;
2127 }
2128 value4=0U;
2129 value6=0U;
2130 addr_len=0;
2131 nibble6_len=0;
2132 pad_pos=-1;
2133 for (i=0 ; (unsigned char)buf[i]>' ' && buf[i]!='/' && buf[i]!='?' && (!bracket || buf[i]!=']') && ip_size ; i++) {
2134 if (ip_size & 0x04) {
2135 if (isdigit(buf[i])) {
2136 if (port) {
2137 port_num=port_num*10+(buf[i]-'0');
2138 if (port_num>65535) ip_size&=~0x04;
2139 } else {
2140 value4=value4*10+(buf[i]-'0');
2141 if (value4>0xFFU) ip_size&=~0x04;
2142 }
2143 } else if (buf[i]=='.' && addr_len<4) {
2144 addr[addr_len++]=(unsigned short)(value4 & 0xFFU);
2145 value4=0U;
2146 } else if (!port && buf[i]==':') {
2147 port=true;
2148 } else {
2149 ip_size&=~0x04;
2150 }
2151 }
2152 if (ip_size & 0x60) {
2153 if (isdigit(buf[i])) {
2154 value6=(value6<<4)+(buf[i]-'0');
2155 nibble6_len++;
2156 if (value6>0xFFFFU) ip_size&=~0x60;
2157 } else if (toupper(buf[i])>='A' && toupper(buf[i])<='F') {
2158 value6=(value6<<4)+(toupper(buf[i])-'A'+10);
2159 nibble6_len++;
2160 if (value6>0xFFFFU) ip_size&=~0x60;
2161 } else if (buf[i]==':' && addr_len<8) {
2162 if (nibble6_len>0) {
2163 addr[addr_len++]=(unsigned short)(value6 & 0xFFFFU);
2164 nibble6_len=0;
2165 }
2166 value6=0U;
2167 if (buf[i+1]==':') {
2168 pad_pos=addr_len;
2169 i++;
2170 }
2171 } else {
2172 ip_size&=~0x60;
2173 }
2174 }
2175 }
2176 if (i==0) return(0);
2177 if (ip_size & 0x04) {
2178 if (addr_len!=3)
2179 ip_size&=~0x04;
2180 else
2181 addr[addr_len++]=(unsigned short)(value4 & 0xFFU);
2182 }
2183 if (ip_size & 0x60) {
2184 if (pad_pos<0 && addr_len!=7) {
2185 ip_size&=~0x60;
2186 } else if (pad_pos>=0 && addr_len>=7)
2187 ip_size&=~0x60;
2188 else if (nibble6_len>0)
2189 addr[addr_len++]=(unsigned short)(value6 & 0xFFFFU);
2190 }
2191 if (!ip_size) {
2192 if (text) {
2193 *text=buf;
2194 if (bracket) (*text)--;
2195 }
2196 while ((unsigned char)buf[i]>' ') i++;
2197 if (next) *next=buf+i;
2198 return(1);
2199 }
2200 max_mask=(ip_size & 0x04) ? 4*8 : 8*16;
2201 if (buf[i]=='/') {
2202 i++;
2203 mask=atoi(buf+i);
2204 while (isdigit(buf[i])) i++;
2205 if (mask<0 || mask>max_mask) mask=max_mask;
2206 } else
2207 mask=max_mask;
2208 if (ip_size & 0x60 && bracket && buf[i]==']') i++;
2209 if (next) *next=buf+i;
2210 if (ip_size & 0x04) {
2211 if (nbits) *nbits=mask;
2212 for (i=0 ; i<addr_len ; i++)
2213 ipv4[i]=(unsigned char)addr[i];
2214 return(2);
2215 }
2216
2217 // IPv6 address
2218 if (nbits) *nbits=mask;
2219 i=0;
2220 j=0;
2221 if (pad_pos>=0) {
2222 while (i<pad_pos)
2223 ipv6[j++]=(unsigned short int)addr[i++];
2224 pad_len=8-addr_len;
2225 while (j<pad_pos+pad_len)
2226 ipv6[j++]=0;
2227 }
2228 while (i<addr_len)
2229 ipv6[j++]=(unsigned short int)addr[i++];
2230 return(3);
2231 }