"Fossies" - the Fresh Open Source Software Archive 
Member "sarg-2.4.0/util.c" (24 Dec 2019, 70350 Bytes) of package /linux/privat/sarg-2.4.0.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "util.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
2.3.11_vs_2.4.0.
1 /*
2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
3 * 1998, 2015
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(__MINGW32__) && defined(HAVE_DIRECT_H)
34 #define NO_OLDNAMES 1
35 #include <direct.h>
36 #endif
37
38 #if defined(HAVE_BACKTRACE)
39 #define USE_GETWORD_BACKTRACE 1
40 #else
41 #define USE_GETWORD_BACKTRACE 0
42 #endif
43
44 static char mtab1[12][4]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
45
46 //! The list of the HTTP codes to exclude from the report.
47 static char *excludecode=NULL;
48
49 //! Directory where the images are stored.
50 char ImageDir[MAXLEN]=IMAGEDIR;
51
52 extern char *CurrentLocale;
53
54 #if USE_GETWORD_BACKTRACE
55 static void getword_backtrace(void)
56 {
57 void *buffer[5];
58 int i, n;
59 char **calls;
60
61 n=backtrace(buffer,sizeof(buffer)/sizeof(buffer[0]));
62 if (n<=0) return;
63 calls=backtrace_symbols(buffer,n);
64 if (calls) {
65 debuga(__FILE__,__LINE__,_("getword backtrace:\n"));
66 for (i=0 ; i<n ; i++) {
67 fprintf(stderr,"SARG: %d:%s\n",i+1,calls[i]);
68 }
69 free(calls);
70 }
71 }
72 #endif //USE_GETWORD_BACKTRACE
73
74 void getword_start(struct getwordstruct *gwarea, const char *line)
75 {
76 gwarea->beginning=line;
77 gwarea->current=line;
78 gwarea->modified=0;
79 }
80
81 void getword_restart(struct getwordstruct *gwarea)
82 {
83 if (gwarea->modified) {
84 debuga(__FILE__,__LINE__,_("Cannot parse again the line as it was modified\n"));
85 exit(EXIT_FAILURE);
86 }
87 gwarea->current=gwarea->beginning;
88 }
89
90 int getword(char *word, int limit, struct getwordstruct *gwarea, char stop)
91 {
92 int x;
93
94 for (x=0;((gwarea->current[x]) && (gwarea->current[x] != stop ));x++) {
95 if (x>=limit) {
96 /*
97 TRANSLATORS: The %s is the name of the function reporting the
98 error message.
99 */
100 debuga(__FILE__,__LINE__,_("End of word not found in %s after %d bytes.\n"),__func__,x);
101 debuga(__FILE__,__LINE__,_("Line=\"%s\"\n"),gwarea->beginning);
102 debuga(__FILE__,__LINE__,_("Record=\"%s\"\n"),gwarea->current);
103 debuga(__FILE__,__LINE__,_("searching for \'x%x\'\n"),stop);
104 word[(limit>0) ? limit-1 : 0]='\0';
105 #if USE_GETWORD_BACKTRACE
106 getword_backtrace();
107 #endif
108 return(-1);
109 }
110 word[x] = gwarea->current[x];
111 }
112
113 word[x] = '\0';
114 if (gwarea->current[x]) ++x;
115 gwarea->current+=x;
116 return(0);
117 }
118
119 int getword_limit(char *word, int limit, struct getwordstruct *gwarea, char stop)
120 {
121 int x;
122
123 limit--;
124 for (x=0; x<limit && gwarea->current[x] && gwarea->current[x] != stop ;x++) {
125 word[x] = gwarea->current[x];
126 }
127 word[x] = '\0';
128 gwarea->current+=x;
129 while (*gwarea->current && *gwarea->current != stop) gwarea->current++;
130 if (*gwarea->current) ++gwarea->current;
131 return(0);
132 }
133
134 int getword_multisep(char *word, int limit, struct getwordstruct *gwarea, char stop)
135 {
136 int x;
137
138 for (x=0;((gwarea->current[x]) && (gwarea->current[x] != stop ));x++) {
139 if (x>=limit) {
140 debuga(__FILE__,__LINE__,_("End of word not found in %s after %d bytes.\n"),__func__,x);
141 debuga(__FILE__,__LINE__,_("Line=\"%s\"\n"),gwarea->beginning);
142 debuga(__FILE__,__LINE__,_("Record=\"%s\"\n"),gwarea->current);
143 debuga(__FILE__,__LINE__,_("searching for \'x%x\'\n"),stop);
144 if (limit>0) word[limit-1]='\0';
145 #if USE_GETWORD_BACKTRACE
146 getword_backtrace();
147 #endif
148 //exit(EXIT_FAILURE);
149 return(-1);
150 }
151 word[x] = gwarea->current[x];
152 }
153
154 word[x] = '\0';
155 while (gwarea->current[x] && gwarea->current[x]==stop) ++x;
156 gwarea->current+=x;
157 return(0);
158 }
159
160 int getword_skip(int limit, struct getwordstruct *gwarea, char stop)
161 {
162 int x;
163
164 for (x=0;(gwarea->current[x] && (gwarea->current[x] != stop ));x++) {
165 if (x>=limit) {
166 debuga(__FILE__,__LINE__,_("End of word not found in %s after %d bytes.\n"),__func__,x);
167 debuga(__FILE__,__LINE__,_("Line=\"%s\"\n"),gwarea->beginning);
168 debuga(__FILE__,__LINE__,_("Record=\"%s\"\n"),gwarea->current);
169 debuga(__FILE__,__LINE__,_("searching for \'x%x\'\n"),stop);
170 #if USE_GETWORD_BACKTRACE
171 getword_backtrace();
172 #endif
173 return(-1);
174 }
175 }
176
177 if (gwarea->current[x]) ++x;
178 gwarea->current+=x;
179 return(0);
180 }
181
182 int getword_atoll(long long int *number, struct getwordstruct *gwarea, char stop)
183 {
184 int x;
185 int sign=+1;
186 int digit;
187
188 if (gwarea->current[0] == '-') {
189 gwarea->current++;
190 sign=-1;
191 } else if (gwarea->current[0] == '+') {
192 gwarea->current++;
193 }
194 *number=0LL;
195 for (x=0;isdigit(gwarea->current[x]);x++) {
196 digit=gwarea->current[x]-'0';
197 if (*number >= (LLONG_MAX-digit)/10) {
198 /*
199 TRANSLATORS: The first %s is the function name (in the source code) where the
200 overflow is detected.
201 */
202 debuga(__FILE__,__LINE__,_("Integer overflow detected in %s in line %s\n"),__func__,gwarea->beginning);
203 return(-1);
204 }
205 *number=(*number * 10) + digit;
206 }
207 if (gwarea->current[x] && gwarea->current[x]!=stop) {
208 /*
209 TRANSLATORS: The %s is the function name, in the source code, where the problem occured.
210 */
211 debuga(__FILE__,__LINE__,_("End of number not found in %s after %d bytes.\n"),__func__,x);
212 debuga(__FILE__,__LINE__,_("Line=\"%s\"\n"),gwarea->beginning);
213 debuga(__FILE__,__LINE__,_("Record=\"%s\"\n"),gwarea->current);
214 debuga(__FILE__,__LINE__,_("searching for \'x%x\'\n"),stop);
215 #if USE_GETWORD_BACKTRACE
216 getword_backtrace();
217 #endif
218 return(-1);
219 }
220 *number*=sign;
221
222 if (gwarea->current[x]) ++x;
223 gwarea->current+=x;
224 return(0);
225 }
226
227 int getword_atoi(int *number, struct getwordstruct *gwarea, char stop)
228 {
229 int x;
230 int sign=+1;
231 int digit;
232
233 if (gwarea->current[0] == '-') {
234 gwarea->current++;
235 sign=-1;
236 } else if (gwarea->current[0] == '+') {
237 gwarea->current++;
238 }
239 *number=0;
240 for (x=0;isdigit(gwarea->current[x]);x++) {
241 digit=gwarea->current[x]-'0';
242 if (*number > (INT_MAX-digit)/10) {
243 debuga(__FILE__,__LINE__,_("Integer overflow detected in %s in line %s\n"),__func__,gwarea->beginning);
244 return(-1);
245 }
246 *number=(*number * 10) + digit;
247 }
248 if (gwarea->current[x] && gwarea->current[x]!=stop) {
249 debuga(__FILE__,__LINE__,_("End of number not found in %s after %d bytes.\n"),__func__,x);
250 debuga(__FILE__,__LINE__,_("Line=\"%s\"\n"),gwarea->beginning);
251 debuga(__FILE__,__LINE__,_("Record=\"%s\"\n"),gwarea->current);
252 debuga(__FILE__,__LINE__,_("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 int getword_atol(long int *number, struct getwordstruct *gwarea, char stop)
266 {
267 int x;
268 long int sign=+1;
269 int digit;
270
271 if (gwarea->current[0] == '-') {
272 gwarea->current++;
273 sign=-1;
274 } else if (gwarea->current[0] == '+') {
275 gwarea->current++;
276 }
277 *number=0;
278 for (x=0;isdigit(gwarea->current[x]);x++) {
279 digit=gwarea->current[x]-'0';
280 if (*number > (LONG_MAX-digit)/10) {
281 debuga(__FILE__,__LINE__,_("Integer overflow detected in %s in line %s\n"),__func__,gwarea->beginning);
282 return(-1);
283 }
284 *number=(*number * 10) + digit;
285 }
286 if (gwarea->current[x] && gwarea->current[x]!=stop) {
287 debuga(__FILE__,__LINE__,_("End of number not found in %s after %d bytes.\n"),__func__,x);
288 debuga(__FILE__,__LINE__,_("Line=\"%s\"\n"),gwarea->beginning);
289 debuga(__FILE__,__LINE__,_("Record=\"%s\"\n"),gwarea->current);
290 debuga(__FILE__,__LINE__,_("searching for \'x%x\'\n"),stop);
291 #if USE_GETWORD_BACKTRACE
292 getword_backtrace();
293 #endif
294 return(-1);
295 }
296 *number*=sign;
297
298 if (gwarea->current[x]) ++x;
299 gwarea->current+=x;
300 return(0);
301 }
302
303 int getword_atolu(unsigned long int *number, struct getwordstruct *gwarea, char stop)
304 {
305 int x;
306 int digit;
307
308 if (gwarea->current[0] == '-') {
309 debuga(__FILE__,__LINE__,_("getword_atolu got a negative number.\n"));
310 debuga(__FILE__,__LINE__,_("Line=\"%s\"\n"),gwarea->beginning);
311 debuga(__FILE__,__LINE__,_("Record=\"%s\"\n"),gwarea->current);
312 return(-1);
313 }
314 if (gwarea->current[0] == '+') {
315 gwarea->current++;
316 }
317 *number=0;
318 for (x=0;isdigit(gwarea->current[x]);x++) {
319 digit=gwarea->current[x]-'0';
320 if (*number > (ULONG_MAX-digit)/10) {
321 debuga(__FILE__,__LINE__,_("Integer overflow detected in %s in line %s\n"),__func__,gwarea->beginning);
322 return(-1);
323 }
324 *number=(*number * 10) + digit;
325 }
326 if (gwarea->current[x] && gwarea->current[x]!=stop) {
327 debuga(__FILE__,__LINE__,_("End of number not found in %s after %d bytes.\n"),__func__,x);
328 debuga(__FILE__,__LINE__,_("Line=\"%s\"\n"),gwarea->beginning);
329 debuga(__FILE__,__LINE__,_("Record=\"%s\"\n"),gwarea->current);
330 debuga(__FILE__,__LINE__,_("searching for \'x%x\'\n"),stop);
331 #if USE_GETWORD_BACKTRACE
332 getword_backtrace();
333 #endif
334 return(-1);
335 }
336
337 if (gwarea->current[x]) ++x;
338 gwarea->current+=x;
339 return(0);
340 }
341
342
343 int getword_ptr(char *orig_line,char **word, struct getwordstruct *gwarea, char stop)
344 {
345 /*!
346 \note Why pass the original buffer to the function ? Because we must modify it to
347 insert the terminating ASCII zero for the word we return and that's not compatible
348 with getword_restart(). Moreover, getword_start() sometime works on constant strings
349 so this function require the original buffer to detect any missuse.
350 */
351 int x;
352 int sep;
353 int start;
354
355 if (orig_line && orig_line!=gwarea->beginning) {
356 debuga(__FILE__,__LINE__,_("Invalid buffer passed to getword_ptr\n"));
357 return(-1);
358 }
359
360 start=(gwarea->current-gwarea->beginning);
361 if (word && orig_line) *word=orig_line+start;
362 for (x=0;((gwarea->current[x]) && (gwarea->current[x] != stop ));x++);
363 sep=(gwarea->current[x]!='\0');
364 if (word && orig_line) orig_line[start+x] = '\0';
365 if (sep) ++x;
366 gwarea->current+=x;
367 gwarea->modified=1;
368 return(0);
369 }
370
371 #define MAXLLL 30 //!< Maximum number of digits in long long (a guess).
372 long long int my_atoll (const char *nptr)
373 {
374 long long int returnval=0LL;
375 int max_digits = MAXLLL ;
376
377 // Soak up all the white space
378 while (isspace( *nptr )) {
379 nptr++;
380 }
381
382 //For each character left to right
383 //change the character to a single digit
384 //multiply what we had before by 10 and add the new digit
385
386 while (--max_digits && isdigit( *nptr ))
387 {
388 returnval = ( returnval * 10 ) + ( *nptr++ - '0' ) ;
389 }
390
391 return returnval;
392 }
393
394 int is_absolute(const char *path)
395 {
396 if (*path=='/') return(1);
397 #ifdef _WIN32
398 if (isalpha(path[0]) && path[1]==':') return(1);
399 #endif
400 return(0);
401 }
402
403 int PortableMkDir(const char *path,int mode)
404 {
405 #if defined(__linux__)
406 int mkerror=mkdir(path,mode);
407 #else //mingw
408 (void)mode;
409 int mkerror=_mkdir(path);
410 #endif
411 return(mkerror);
412 }
413
414 /*!
415 * Recursively create a path by adding missing directory until the whole path is created.
416 * \param name The path to create.
417 * \return True if the directory was created or false if it already existed
418 */
419 bool my_mkdir(const char *name)
420 {
421 char w0[MAXLEN];
422 int i;
423 int chars;
424 bool created = false;
425 struct stat st;
426
427 if (!is_absolute(name)) {
428 debuga(__FILE__,__LINE__,_("Invalid path (%s). Please, use absolute paths only.\n"),name);
429 exit(EXIT_FAILURE);
430 }
431
432 chars=0;
433 for (i=0 ; name[i] ; i++) {
434 if (i>=sizeof(w0)) {
435 debuga(__FILE__,__LINE__,_("Path too long: "));
436 debuga_more("%s\n",name);
437 exit(EXIT_FAILURE);
438 }
439 if (chars>0 && name[i] == '/') {
440 w0[i] = '\0';
441 if (access(w0, R_OK) != 0) {
442 if (PortableMkDir(w0,0755)) {
443 debuga(__FILE__,__LINE__,_("Cannot create directory \"%s\": %s\n"),w0,strerror(errno));
444 exit(EXIT_FAILURE);
445 }
446 }
447 }
448 if (name[i] != '/') chars++;
449 w0[i] = name[i];
450 }
451
452 if (access(name, R_OK) != 0) {
453 if (PortableMkDir(name,0755)) {
454 debuga(__FILE__,__LINE__,_("Cannot create directory \"%s\": %s\n"),name,strerror(errno));
455 exit(EXIT_FAILURE);
456 }
457 created = true;
458 }
459 if (!created) {
460 /*
461 * Check the final path is a directory (symlink to a directory is ok).
462 */
463 if (stat(name, &st)) {
464 debuga(__FILE__,__LINE__,_("Cannot stat \"%s\": %s\n"), name, strerror(errno));
465 exit(EXIT_FAILURE);
466 }
467 if (!S_ISDIR(st.st_mode)) {
468 debuga(__FILE__,__LINE__,_("Directory \"%s\" can't be created because the path already exists and is not a directory\n"), name);
469 exit(EXIT_FAILURE);
470 }
471 }
472 return created;
473 }
474
475 void makeTmpDir(const char *tmp)
476 {
477 /*
478 * We must ensure the temporary directory is ours. In particular, we must make sure no malicious
479 * users managed to create or replace the temporary directory with a symlink to a system directory.
480 * As sarg purges the content of the temporary directory upon exit, should the temporary directory
481 * be hijacked, sarg could be tricked in deleting system files such as /bin or users files in /home
482 * or logs in /var/log.
483 *
484 * The code first create the temporary directory. If it wasn't created, the content is checked and
485 * purged if it looks safe to delete every file and directory it contains.
486 */
487 if (!my_mkdir(tmp)) {
488 if (debug) debuga(__FILE__, __LINE__, _("Purging temporary directory \"%s\"\n"), tmp);
489 emptytmpdir(tmp);
490 }
491 }
492
493 void my_lltoa(unsigned long long int n, char *s, int ssize, int len)
494 {
495 int i;
496 int slen = 0;
497 int j;
498 char c;
499
500 ssize--;
501 if (len>ssize) {
502 debuga(__FILE__,__LINE__,_("The requested number of digits passed to my_lltoa (%d) is bigger than the output buffer size (%d)\n"),len,ssize);
503 abort();
504 }
505
506 do {
507 s[slen++] = (n % 10) + '0';
508 } while ((n /= 10) > 0 && slen<ssize);
509 s[slen] = '\0';
510
511 for (i = 0, j = slen-1; i<j; i++, j--) {
512 c = s[i];
513 s[i] = s[j];
514 s[j] = c;
515 }
516
517 if (len>slen) {
518 i=len-slen;
519 for (j=slen; j>=0; j--)
520 s[j+i]=s[j];
521 for (j=0 ; j<i ; j++)
522 s[j]='0';
523 }
524 }
525
526 int month2num(const char *month)
527 {
528 int m;
529
530 for (m=0 ; m<12 && strcmp(mtab1[m],month) != 0; m++);
531 return(m);
532 }
533
534 int builddia(int day, int month, int year)
535 {
536 return(year*10000+month*100+day);
537 }
538
539 /*!
540 Compare two dates.
541
542 \param date1 The first date to compare.
543 \param date2 The second date to compare.
544
545 \retval -1 If date1<date2.
546 \retval 0 If date1==date2.
547 \retval 1 if date1>date2.
548 */
549 int compare_date(const struct tm *date1,const struct tm *date2)
550 {
551 if (date1->tm_year<date2->tm_year) return(-1);
552 if (date1->tm_year>date2->tm_year) return(1);
553 if (date1->tm_mon<date2->tm_mon) return(-1);
554 if (date1->tm_mon>date2->tm_mon) return(1);
555 if (date1->tm_mday<date2->tm_mday) return(-1);
556 if (date1->tm_mday>date2->tm_mday) return(1);
557 if (date1->tm_hour<date2->tm_hour) return(-1);
558 if (date1->tm_hour>date2->tm_hour) return(1);
559 if (date1->tm_min<date2->tm_min) return(-1);
560 if (date1->tm_min>date2->tm_min) return(1);
561 if (date1->tm_sec<date2->tm_sec) return(-1);
562 if (date1->tm_sec>date2->tm_sec) return(1);
563 return(0);
564 }
565
566 void buildymd(const char *dia, const char *mes, const char *ano, char *wdata,int wdata_size)
567 {
568 int nmes;
569
570 nmes=month2num(mes);
571 snprintf(wdata,wdata_size,"%04d%02d%02d",atoi(ano),nmes+1,atoi(dia));
572 }
573
574
575 int conv_month(const char *month)
576 {
577 int x;
578
579 for (x=0; x<12 && strncmp(mtab1[x],month,3)!=0; x++);
580 return(x+1);
581 }
582
583
584 const char *conv_month_name(int month)
585 {
586 static char str[4];
587
588 if (month<1 || month>12) {
589 snprintf(str,sizeof(str),"%03d",month);
590 return(str);
591 }
592 return(mtab1[month-1]);
593 }
594
595 /*!
596 Write a debug message to stderr. The message is prefixed by "SARG:" to identify its origin.
597
598 \param msg The printf like message to format.
599 \param ... The arguments to format in the message.
600 */
601 void debuga(const char *File,int Line,const char *msg,...)
602 {
603 va_list ap;
604
605 if (debugz>=LogLevel_Source) {
606 /* The path is removed because every source file is in the same directory.
607 * There is no point in reporting the full path from the build directory.
608 */
609 const char *ptr=strrchr(File,'/');
610 if (!ptr) ptr=File;
611 /* TRANSLATORS: This is the prefix to stderr messages when the debug level is
612 set to display the source file (%s) and the line number (%d). */
613 fprintf(stderr,_("SARG(%s:%d): "),ptr,Line);
614 } else {
615 /* TRANSLATORS: This is the prefix to stderr messages when the debug level
616 is low. */
617 fputs(_("SARG: "),stderr);
618 }
619 va_start(ap,msg);
620 vfprintf(stderr,msg,ap);
621 va_end(ap);
622 }
623
624 /*!
625 Write a debug message to stderr. The message is supposed
626 to be displayed after a message from debuga().
627
628 \param msg The printf like message to format.
629 \param ... The arguments to format in the message.
630 */
631 void debuga_more(const char *msg,...)
632 {
633 va_list ap;
634
635 va_start(ap,msg);
636 vfprintf(stderr,msg,ap);
637 va_end(ap);
638 }
639
640 /*!
641 Write a debug message to stderr. The message is prefixed by "SARG: (info)".
642
643 \param msg The printf like message to format.
644 \param ... The arguments to format in the message.
645 */
646 void debugaz(const char *File,int Line,const char *msg,...)
647 {
648 va_list ap;
649
650 if (debugz>=LogLevel_Source) {
651 /* The path is removed because every source file is in the same directory.
652 * There is no point in reporting the full path from the build directory.
653 */
654 const char *ptr=strrchr(File,'/');
655 if (!ptr) ptr=File;
656 /* TRANSLATORS: This is the prefix to information messages when the debug level is
657 set to display the source file (%s) and the line number (%d). */
658 fprintf(stderr,_("SARG(%s:%d): (info) "),ptr,Line);
659 } else {
660 /* TRANSLATORS: This is the prefix to information messages when the debug level
661 is low. */
662 fputs(_("SARG: (info) "),stderr);
663 }
664 va_start(ap,msg);
665 vfprintf(stderr,msg,ap);
666 va_end(ap);
667 }
668
669
670 char *fixnum(long long int value, int n)
671 {
672 #define MAXLEN_FIXNUM 256
673 char num[MAXLEN_FIXNUM]="";
674 char buf[MAXLEN_FIXNUM * 2];
675 char *pbuf;
676 static char ret[MAXLEN_FIXNUM * 2];
677 char *pret;
678 register int i, j, k;
679 int numlen;
680 static char abbrev[30]="";
681
682 my_lltoa(value, num, sizeof(num), 0);
683
684 if (DisplayedValues==DISPLAY_ABBREV) {
685 numlen = strlen(num);
686 if (numlen <= 3)
687 strcpy(abbrev,num);
688 else if (numlen%3 == 1) {
689 abbrev[0]=num[0];
690 abbrev[1]=(UseComma) ? ',' : '.';
691 abbrev[2]=num[1];
692 abbrev[3]=num[2];
693 abbrev[4]='\0';
694 }
695 else if (numlen%3 == 2) {
696 abbrev[0]=num[0];
697 abbrev[1]=num[1];
698 abbrev[2]=(UseComma) ? ',' : '.';
699 abbrev[3]=num[2];
700 abbrev[4]=num[3];
701 abbrev[5]='\0';
702 }
703 else if (numlen%3 == 0) {
704 abbrev[0]=num[0];
705 abbrev[1]=num[1];
706 abbrev[2]=num[2];
707 abbrev[3]=(UseComma) ? ',' : '.';
708 abbrev[4]=num[3];
709 abbrev[5]=num[4];
710 abbrev[6]='\0';
711 }
712 if (n) {
713 if (numlen <= 3) {
714 //no prefix
715 }
716 else if (numlen <= 6)
717 strcat(abbrev,"K");
718 else if (numlen <= 9)
719 strcat(abbrev,"M");
720 else if (numlen <= 12)
721 strcat(abbrev,"G");
722 else if (numlen <= 15)
723 strcat(abbrev,"T");
724 else if (numlen >= 18)
725 strcat(abbrev,"P");
726 else if (numlen <= 21)
727 strcat(abbrev,"E");
728 else if (numlen <= 24)
729 strcat(abbrev,"Z");
730 else if (numlen <= 27)
731 strcat(abbrev,"Y");
732 else
733 strcat(abbrev,"???");
734 }
735 return(abbrev);
736 }
737
738 memset(buf,0,MAXLEN_FIXNUM*2);
739
740 pbuf = buf;
741 pret = ret;
742 k = 0;
743
744 for ( i = strlen(num) - 1, j = 0 ; i > -1; i--) {
745 if ( k == 2 && i != 0 ) {
746 k = 0;
747 pbuf[j++] = num[i];
748 pbuf[j++] = (UseComma) ? ',' : '.';
749 continue;
750 }
751 pbuf[j] = num[i];
752 j++;
753 k++;
754 }
755
756 pret[0]='\0';
757
758 for ( i = strlen(pbuf) - 1, j = 0 ; i > -1; i--, j++)
759 pret[j] = pbuf[i];
760
761 pret[j] = '\0';
762
763 return pret;
764 }
765
766
767 char *fixnum2(long long int value, int n)
768 {
769 #define MAXLEN_FIXNUM2 1024
770 char num[MAXLEN_FIXNUM2];
771 char buf[MAXLEN_FIXNUM2 * 2];
772 char *pbuf;
773 static char ret[MAXLEN_FIXNUM2 * 2];
774 char *pret;
775 register int i, j, k;
776
777 my_lltoa(value, num, sizeof(num), 0);
778 memset(buf,0,MAXLEN_FIXNUM2*2);
779
780 pbuf = buf;
781 pret = ret;
782 k = 0;
783
784 for ( i = strlen(num) - 1, j = 0 ; i > -1; i--) {
785 if ( k == 2 && i != 0 ) {
786 k = 0;
787 pbuf[j++] = num[i];
788 pbuf[j++] = (UseComma) ? ',' : '.';
789 continue;
790 }
791 pbuf[j] = num[i];
792 j++;
793 k++;
794 }
795
796 pret[0]='\0';
797
798 for ( i = strlen(pbuf) - 1, j = 0 ; i > -1; i--, j++)
799 pret[j] = pbuf[i];
800
801 pret[j] = '\0';
802
803 return pret;
804 }
805
806
807 char *buildtime(long long int elap)
808 {
809 long int num = elap / 1000LL;
810 int hor = 0;
811 int min = 0;
812 int sec = 0;
813 static char buf[20];
814
815 hor=num / 3600L;
816 min=(num % 3600L) / 60L;
817 sec=num % 60L;
818 snprintf(buf,sizeof(buf),"%02d:%02d:%02d",hor,min,sec);
819
820 return(buf);
821 }
822
823
824 /*!
825 Get the date stored in the <tt>sarg-date</tt> file of a directory with the connection data.
826
827 \param dirname The directory to look for the connection directory.
828 \param name The name of the directory whose <tt>sarg-date</tt> file must be read.
829 \param data The buffer to store the content of the file. It must be more than 80
830 bytes long.
831
832 \retval 0 No error.
833 \retval -1 File not found.
834 */
835 int obtdate(const char *dirname, const char *name, char *data)
836 {
837 FILE *fp_in;
838 char wdir[MAXLEN];
839
840 if (snprintf(wdir,sizeof(wdir),"%s%s/sarg-date",dirname,name)>=sizeof(wdir)) {
841 debuga(__FILE__,__LINE__,_("Buffer too small to store "));
842 debuga_more("%s%s/sarg-date",dirname,name);
843 exit(EXIT_FAILURE);
844 }
845 if ((fp_in = fopen(wdir, "rt")) == 0) {
846 if (snprintf(wdir,sizeof(wdir),"%s%s/date",dirname,name)>=sizeof(wdir)) {
847 debuga(__FILE__,__LINE__,_("Buffer too small to store "));
848 debuga_more("%s%s/date",dirname,name);
849 exit(EXIT_FAILURE);
850 }
851 if ((fp_in = fopen(wdir, "rt")) == 0) {
852 data[0]='\0';
853 return(-1);
854 }
855 }
856
857 if (!fgets(data,80,fp_in)) {
858 debuga(__FILE__,__LINE__,_("Failed to read the date in file \"%s\"\n"),wdir);
859 exit(EXIT_FAILURE);
860 }
861 if (fclose(fp_in)==EOF) {
862 debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),wdir,strerror(errno));
863 exit(EXIT_FAILURE);
864 }
865 fixendofline(data);
866
867 return(0);
868 }
869
870
871 void formatdate(char *date,int date_size,int year,int month,int day,int hour,int minute,int second,int dst)
872 {
873 struct tm ltm;
874 time_t unixtime;
875 struct tm *fulltm;
876
877 memset(<m,0,sizeof(ltm));
878 if (year>=1900) ltm.tm_year=year-1900;
879 if (month>=1 && month<=12) ltm.tm_mon=month-1;
880 if (day>=1 && day<=31) ltm.tm_mday=day;
881 if (hour>=0 && hour<24) ltm.tm_hour=hour;
882 if (minute>=0 && minute<60) ltm.tm_min=minute;
883 if (second>=0 && second<60) ltm.tm_sec=second;
884 ltm.tm_isdst=dst;
885 unixtime=mktime(<m); //fill the missing entries
886 fulltm=localtime(&unixtime);
887 //strftime(date,date_size,"%a %b %d %H:%M:%S %Z %Y",fulltm);
888 strftime(date,date_size,"%c",fulltm);
889 }
890
891
892 void computedate(int year,int month,int day,struct tm *t)
893 {
894 memset(t,0,sizeof(*t));
895 t->tm_year=year-1900;
896 t->tm_mon=month-1;
897 t->tm_mday=day;
898 }
899
900
901 int obtuser(const char *dirname, const char *name)
902 {
903 FILE *fp_in;
904 char wdir[MAXLEN];
905 char tuser[20];
906 int nuser;
907
908 if (snprintf(wdir,sizeof(wdir),"%s%s/sarg-users",dirname,name)>=sizeof(wdir)) {
909 debuga(__FILE__,__LINE__,_("Buffer too small to store "));
910 debuga_more("%s%s/sarg-users",dirname,name);
911 exit(EXIT_FAILURE);
912 }
913 if ((fp_in=fopen(wdir,"r"))==NULL) {
914 if (snprintf(wdir,sizeof(wdir),"%s%s/users",dirname,name)>=sizeof(wdir)) {
915 debuga(__FILE__,__LINE__,_("Buffer too small to store "));
916 debuga_more("%s%s/users",dirname,name);
917 exit(EXIT_FAILURE);
918 }
919 if ((fp_in=fopen(wdir,"r"))==NULL) {
920 return(0);
921 }
922 }
923
924 if (!fgets(tuser,sizeof(tuser),fp_in)) {
925 debuga(__FILE__,__LINE__,_("Failed to read the number of users in file \"%s\"\n"),wdir);
926 exit(EXIT_FAILURE);
927 }
928 if (fclose(fp_in)==EOF) {
929 debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),wdir,strerror(errno));
930 exit(EXIT_FAILURE);
931 }
932 nuser=atoi(tuser);
933
934 return(nuser);
935 }
936
937
938 void obttotal(const char *dirname, const char *name, int nuser, long long int *tbytes, long long int *media)
939 {
940 FileObject *fp_in;
941 char *buf;
942 char wdir[MAXLEN];
943 char user[MAX_USER_LEN];
944 char sep;
945 struct getwordstruct gwarea;
946 longline line;
947
948 *tbytes=0;
949 *media=0;
950
951 if (snprintf(wdir,sizeof(wdir),"%s%s/sarg-general",dirname,name)>=sizeof(wdir)) {
952 debuga(__FILE__,__LINE__,_("Buffer too small to store "));
953 debuga_more("%s%s/sarg-general",dirname,name);
954 exit(EXIT_FAILURE);
955 }
956 if ((fp_in = FileObject_Open(wdir)) == NULL) {
957 if (snprintf(wdir,sizeof(wdir),"%s%s/general",dirname,name)>=sizeof(wdir)) {
958 debuga(__FILE__,__LINE__,_("Buffer too small to store "));
959 debuga_more("%s%s/general",dirname,name);
960 exit(EXIT_FAILURE);
961 }
962 if ((fp_in = FileObject_Open(wdir)) == NULL) {
963 return;
964 }
965 }
966
967 if ((line=longline_create())==NULL) {
968 debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),wdir);
969 exit(EXIT_FAILURE);
970 }
971
972 while((buf=longline_read(fp_in,line))!=NULL) {
973 if (strncmp(buf,"TOTAL\t",6) == 0)
974 sep='\t'; //new file
975 else if (strncmp(buf,"TOTAL ",6) == 0)
976 sep=' '; //old file
977 else
978 continue;
979 getword_start(&gwarea,buf);
980 if (getword(user,sizeof(user),&gwarea,sep)<0) {
981 debuga(__FILE__,__LINE__,_("Invalid user in file \"%s\"\n"),wdir);
982 exit(EXIT_FAILURE);
983 }
984 if (strcmp(user,"TOTAL") != 0)
985 continue;
986 if (getword_skip(MAXLEN,&gwarea,sep)<0) {
987 debuga(__FILE__,__LINE__,_("Invalid total number of accesses in file \"%s\"\n"),wdir);
988 exit(EXIT_FAILURE);
989 }
990 if (getword_atoll(tbytes,&gwarea,sep)<0) {
991 debuga(__FILE__,__LINE__,_("Invalid number of bytes in file \"%s\"\n"),wdir);
992 exit(EXIT_FAILURE);
993 }
994 break;
995 }
996 if (FileObject_Close(fp_in)) {
997 debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),wdir,FileObject_GetLastCloseError());
998 exit(EXIT_FAILURE);
999 }
1000 longline_destroy(&line);
1001
1002 if (nuser <= 0)
1003 return;
1004
1005 *media=*tbytes / nuser;
1006 return;
1007 }
1008
1009 int getperiod_fromsarglog(const char *arqtt,struct periodstruct *period)
1010 {
1011 const char *str;
1012 int day0, month0, year0, hour0, minute0;
1013 int day1, month1, year1, hour1, minute1;
1014 int i;
1015
1016 memset(period,0,sizeof(*period));
1017
1018 str=arqtt;
1019 while((str=strstr(str,"sarg-"))!=NULL) {
1020 str+=5;
1021 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
1022 day0=(str[0]-'0')*10+(str[1]-'0');
1023 if (day0<1 || day0>31) continue;
1024 str+=2;
1025 month0=(str[0]-'0')*10+(str[1]-'0')-1;
1026 if (month0<0 || month0>11) continue;
1027 str+=2;
1028 year0=0;
1029 for (i=0 ; isdigit(str[i]) && i<4 ; i++) year0=year0*10+(str[i]-'0');
1030 if (i!=4 || year0<1900) continue;
1031 str+=4;
1032 if (str[0]!='_') continue;
1033 str++;
1034
1035 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
1036 hour0=(str[0]-'0')*10+(str[1]-'0');
1037 str+=2;
1038 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
1039 minute0=(str[0]-'0')*10+(str[1]-'0');
1040 str+=2;
1041
1042 if (*str != '-') continue;
1043 str++;
1044
1045 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
1046 day1=(str[0]-'0')*10+(str[1]-'0');
1047 if (day1<1 || day1>31) continue;
1048 str+=2;
1049 month1=(str[0]-'0')*10+(str[1]-'0')-1;
1050 if (month1<0 || month1>11) continue;
1051 str+=2;
1052 year1=0;
1053 for (i=0 ; isdigit(str[i]) && i<4 ; i++) year1=year1*10+(str[i]-'0');
1054 if (i!=4 || year1<1900) continue;
1055 str+=4;
1056
1057 if (str[0]!='_') continue;
1058 str++;
1059
1060 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
1061 hour1=(str[0]-'0')*10+(str[1]-'0');
1062 str+=2;
1063 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
1064 minute1=(str[0]-'0')*10+(str[1]-'0');
1065 str+=2;
1066
1067 period->start.tm_mday=day0;
1068 period->start.tm_mon=month0;
1069 period->start.tm_year=year0-1900;
1070 period->start.tm_hour=hour0;
1071 period->start.tm_min=minute0;
1072 period->end.tm_mday=day1;
1073 period->end.tm_mon=month1;
1074 period->end.tm_year=year1-1900;
1075 period->end.tm_hour=hour1;
1076 period->end.tm_min=minute1;
1077 return(0);
1078 }
1079 return(-1);
1080 }
1081
1082 /*!
1083 Fill the period with the specified range.
1084
1085 \param period The period to change.
1086 \param ReadFilter Filter containing the date range to write into the period.
1087 */
1088 void getperiod_fromrange(struct periodstruct *period,const struct ReadLogDataStruct *ReadFilter)
1089 {
1090 int dfrom=ReadFilter->StartDate;
1091 int duntil=ReadFilter->EndDate;
1092
1093 memset(&period->start,0,sizeof(period->start));
1094 period->start.tm_mday=dfrom%100;
1095 period->start.tm_mon=(dfrom/100)%100-1;
1096 period->start.tm_year=(dfrom/10000)-1900;
1097
1098 memset(&period->end,0,sizeof(period->end));
1099 period->end.tm_mday=duntil%100;
1100 period->end.tm_mon=(duntil/100)%100-1;
1101 period->end.tm_year=(duntil/10000)-1900;
1102 }
1103
1104 /*!
1105 Get the range from a period.
1106
1107 \param period The period to convert to a range.
1108 \param dfrom The variable to store the range beginning. It can be NULL.
1109 \param duntil The variable to store the range end. It can be NULL.
1110 */
1111 void getperiod_torange(const struct periodstruct *period,int *dfrom,int *duntil)
1112 {
1113 if (dfrom)
1114 *dfrom=(period->start.tm_year+1900)*10000+(period->start.tm_mon+1)*100+period->start.tm_mday;
1115 if (duntil)
1116 *duntil=(period->end.tm_year+1900)*10000+(period->end.tm_mon+1)*100+period->end.tm_mday;
1117 }
1118
1119 /*!
1120 Update the \a main period to encompass the period in \a candidate.
1121 */
1122 void getperiod_merge(struct periodstruct *main,struct periodstruct *candidate)
1123 {
1124 int cdate;
1125 int mdate;
1126
1127 mdate=(main->start.tm_year)*10000+(main->start.tm_mon)*100+main->start.tm_mday;
1128 cdate=(candidate->start.tm_year)*10000+(candidate->start.tm_mon)*100+candidate->start.tm_mday;
1129 if (mdate==0 || cdate<mdate) memcpy(&main->start,&candidate->start,sizeof(struct tm));
1130
1131 mdate=(main->end.tm_year)*10000+(main->end.tm_mon)*100+main->end.tm_mday;
1132 cdate=(candidate->end.tm_year)*10000+(candidate->end.tm_mon)*100+candidate->end.tm_mday;
1133 if (cdate>mdate) memcpy(&main->end,&candidate->end,sizeof(struct tm));
1134 }
1135
1136 int getperiod_buildtext(struct periodstruct *period)
1137 {
1138 int i;
1139 int range;
1140 char text1[40], text2[40];
1141
1142 if (df=='u') {
1143 i=strftime(text1, sizeof(text1), "%Y %b %d", &period->start);
1144 } else if (df=='e') {
1145 i=strftime(text1, sizeof(text1), "%d %b %Y", &period->start);
1146 } else /*if (df=='w')*/ {
1147 IndexTree=INDEX_TREE_FILE;
1148 i=strftime(text1, sizeof(text1), "%Y.%U", &period->start);
1149 }
1150 if (i == 0) return(-1);
1151
1152 range=(period->start.tm_year!=period->end.tm_year ||
1153 period->start.tm_mon!=period->end.tm_mon ||
1154 period->start.tm_mday!=period->end.tm_mday);
1155 if (range) {
1156 if (df=='u') {
1157 i=strftime(text2, sizeof(text2)-i, "%Y %b %d", &period->end);
1158 } else if (df=='e') {
1159 i=strftime(text2, sizeof(text2)-i, "%d %b %Y", &period->end);
1160 } else {
1161 i=strftime(text2, sizeof(text2)-i, "%Y.%U", &period->end);
1162 }
1163 if (i == 0) return(-1);
1164 }
1165
1166 if (range) {
1167 snprintf(period->text,sizeof(period->text),"%s-%s",text1,text2);
1168 snprintf(period->html,sizeof(period->html),"%s—%s",text1,text2);
1169 } else {
1170 safe_strcpy(period->text,text1,sizeof(period->text));
1171 safe_strcpy(period->html,text1,sizeof(period->html));
1172 }
1173 return(0);
1174 }
1175
1176 static void copy_images(void)
1177 {
1178 FILE *img_in, *img_ou;
1179 char images[512];
1180 char srcfile[MAXLEN];
1181 char dstfile[MAXLEN];
1182 DIR *dirp;
1183 struct dirent *direntp;
1184 char buffer[MAXLEN];
1185 size_t nread;
1186 struct stat info;
1187
1188 if (snprintf(images,sizeof(images),"%simages",outdir)>=sizeof(images)) {
1189 debuga(__FILE__,__LINE__,_("Cannot copy images to target directory %simages\n"),outdir);
1190 exit(EXIT_FAILURE);
1191 }
1192 if (access(images,R_OK)!=0) {
1193 if (PortableMkDir(images,0755)) {
1194 debuga(__FILE__,__LINE__,_("Cannot create directory \"%s\": %s\n"),images,strerror(errno));
1195 exit(EXIT_FAILURE);
1196 }
1197 }
1198
1199 dirp = opendir(ImageDir);
1200 if (dirp==NULL) {
1201 debuga(__FILE__,__LINE__,_("Cannot open directory \"%s\": %s\n"),ImageDir,strerror(errno));
1202 return;
1203 }
1204 while ((direntp = readdir( dirp )) != NULL ){
1205 if (direntp->d_name[0]=='.')
1206 continue;
1207 if (snprintf(srcfile,sizeof(srcfile),"%s/%s",ImageDir,direntp->d_name)>=sizeof(srcfile)) {
1208 debuga(__FILE__,__LINE__,_("Buffer too small to store "));
1209 debuga_more("%s/%s",ImageDir,direntp->d_name);
1210 exit(EXIT_FAILURE);
1211 }
1212 if (stat(srcfile,&info)) {
1213 debuga(__FILE__,__LINE__,_("Cannot stat \"%s\": %s\n"),srcfile,strerror(errno));
1214 continue;
1215 }
1216 if (S_ISREG(info.st_mode)) {
1217 if (snprintf(dstfile,sizeof(dstfile),"%s/%s",images,direntp->d_name)>=sizeof(dstfile)) {
1218 debuga(__FILE__,__LINE__,_("Buffer too small to store "));
1219 debuga_more("%s/%s",images,direntp->d_name);
1220 exit(EXIT_FAILURE);
1221 }
1222 img_in = fopen(srcfile, "rb");
1223 if (img_in!=NULL) {
1224 img_ou = fopen(dstfile, "wb");
1225 if (img_ou!=NULL) {
1226 while ((nread = fread(buffer,1,sizeof(buffer),img_in))>0) {
1227 if (fwrite(buffer,1,nread,img_ou)!=nread) {
1228 debuga(__FILE__,__LINE__,_("Failed to copy image \"%s\" to \"%s\"\n"),srcfile,dstfile);
1229 break;
1230 }
1231 }
1232 if (fclose(img_ou)==EOF) {
1233 debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),dstfile,strerror(errno));
1234 exit(EXIT_FAILURE);
1235 }
1236 } else
1237 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"), dstfile, strerror(errno));
1238 if (fclose(img_in)==EOF) {
1239 debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),srcfile,strerror(errno));
1240 exit(EXIT_FAILURE);
1241 }
1242 } else
1243 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"), srcfile, strerror(errno));
1244 }
1245 }
1246 (void) closedir(dirp);
1247
1248 return;
1249 }
1250
1251 /*!
1252 * Check if the proposed file name conforms to the directory structure layed out
1253 * as a file tree. It is used to check if the file name enumerated while scanning
1254 * a directory content may have been created by sarg running with IndexTree set to
1255 * INDEX_TREE_FILE.
1256 */
1257 bool IsTreeFileDirName(const char *Name)
1258 {
1259 char DateFormat;
1260 int i;
1261
1262 // start year (date format u) or start day (date format e)
1263 if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
1264
1265 if (isdigit(Name[2]) && isdigit(Name[3]))
1266 {
1267 // date format is either u or w
1268 if (Name[4]=='.')
1269 {
1270 // date format is w
1271 if (!isdigit(Name[5]) || !isdigit(Name[6])) return(false);
1272 return(true);//date format w is confirmed
1273 }
1274
1275 // date format is u
1276 Name+=4;
1277
1278 // start month
1279 if (!isalpha(Name[0]) || !isalpha(Name[1]) || !isalpha(Name[2])) return(false);
1280 for (i=11 ; i>=0 && memcmp(mtab1[i],Name,3) ; i--);
1281 if (i<0) return(false);
1282 Name+=3;
1283
1284 // start day
1285 if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
1286 Name+=2;
1287
1288 DateFormat='u';
1289 }
1290 else if (isalpha(Name[2]) && isalpha(Name[3]) && isalpha(Name[4]))
1291 {
1292 // date format is e
1293 Name+=2;
1294
1295 // start month
1296 if (!isalpha(Name[0]) || !isalpha(Name[1]) || !isalpha(Name[2])) return(false);
1297 for (i=11 ; i>=0 && memcmp(mtab1[i],Name,3) ; i--);
1298 if (i<0) return(false);
1299 Name+=3;
1300
1301 // start day
1302 if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3])) return(false);
1303 Name+=4;
1304
1305 DateFormat='e';
1306 }
1307 else
1308 return(false);
1309
1310 if (Name[0]!='-') return(false);
1311 Name++;
1312
1313 if (DateFormat=='u')
1314 {
1315 if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3])) return(false);
1316 Name+=4;
1317
1318 if (!isalpha(Name[0]) || !isalpha(Name[1]) || !isalpha(Name[2])) return(false);
1319 for (i=11 ; i>=0 && memcmp(mtab1[i],Name,3) ; i--);
1320 if (i<0) return(false);
1321 Name+=3;
1322
1323 if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
1324 Name+=2;
1325 }
1326 else //DateFormat=='e'
1327 {
1328 if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
1329 Name+=2;
1330
1331 if (!isalpha(Name[0]) || !isalpha(Name[1]) || !isalpha(Name[2])) return(false);
1332 for (i=11 ; i>=0 && memcmp(mtab1[i],Name,3) ; i--);
1333 if (i<0) return(false);
1334 Name+=3;
1335
1336 if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3])) return(false);
1337 Name+=4;
1338 }
1339 /*
1340 * The directory name may contains additional characters such as a counter if
1341 * a previous report is never overwritten.
1342 */
1343 return(true);
1344 }
1345
1346 /*!
1347 * Check if the proposed file name can be the year part of a report tree build with
1348 * IndexTree set to INDEX_TREE_DATE.
1349 */
1350 bool IsTreeYearFileName(const char *Name)
1351 {
1352 if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3])) return(false);
1353 Name+=4;
1354 if (Name[0]=='-')
1355 {
1356 Name++;
1357 if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3])) return(false);
1358 Name+=4;
1359 }
1360 if (Name[0]) return(false);
1361 return(true);
1362 }
1363
1364 /*!
1365 * Check if the proposed file name can be the month part of a report tree build with
1366 * IndexTree set to INDEX_TREE_DATE.
1367 */
1368 bool IsTreeMonthFileName(const char *Name)
1369 {
1370 int m;
1371
1372 if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
1373 m=(Name[0]-'0')*10+(Name[1]-'0');
1374 if (m<1 || m>12) return(false);
1375 Name+=2;
1376 if (Name[0]=='-')
1377 {
1378 Name++;
1379 if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
1380 m=(Name[0]-'0')*10+(Name[1]-'0');
1381 if (m<1 || m>12) return(false);
1382 Name+=2;
1383 }
1384 if (Name[0]) return(false);
1385 return(true);
1386 }
1387
1388 /*!
1389 * Check if the proposed file name can be the day part of a report tree build with
1390 * IndexTree set to INDEX_TREE_DATE.
1391 */
1392 bool IsTreeDayFileName(const char *Name)
1393 {
1394 int d;
1395
1396 if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
1397 d=(Name[0]-'0')*10+(Name[1]-'0');
1398 if (d<1 || d>31) return(false);
1399 if (Name[2]=='-')
1400 {
1401 Name+=3;
1402 if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
1403 d=(Name[0]-'0')*10+(Name[1]-'0');
1404 if (d<1 || d>31) return(false);
1405 }
1406 /*
1407 * The directory name may contains additional characters such as a counter if
1408 * a previous report is never overwritten.
1409 */
1410 return(true);
1411 }
1412
1413 /*!
1414 * Create a directory to generate a report for the specified connection data
1415 * and populate it with the a <tt>sarg-date</tt> file containing the current
1416 * date.
1417 *
1418 * The function also create an <tt>images</tt> directory in \a dir and copy all
1419 * the files from the <tt>SYSCONFDIR/images</tt> into that directory.
1420 *
1421 * \param per1 The date range in the form: YYYYMMMDD-YYYYMMMDD or DDMMMYYYY-DDMMMYYYY depending on the value of
1422 * ::DateFormat.
1423 * \param addr The ip address or host name to which the report is limited. If the string is empty, all the addresses are accepted.
1424 * \param site The destination site to which the report is limited. If the string is empty, all the sites are accepted.
1425 * \param us The user to whom the report is limited. It is an empty string if all the users are accepted.
1426 */
1427 int vrfydir(const struct periodstruct *per1, const char *addr, const char *site, const char *us)
1428 {
1429 FILE *fp_ou;
1430 char wdir[MAXLEN];
1431 int y1, y2;
1432 int m1, m2;
1433 int d1, d2;
1434 int wlen, wlen2;
1435 time_t curtime;
1436 struct tm *loctm;
1437
1438 strcpy(wdir,outdir);
1439 wlen=strlen(wdir);
1440 y1=per1->start.tm_year+1900;
1441 y2=per1->end.tm_year+1900;
1442 m1=per1->start.tm_mon+1;
1443 m2=per1->end.tm_mon+1;
1444 d1=per1->start.tm_mday;
1445 d2=per1->end.tm_mday;
1446 if (IndexTree == INDEX_TREE_DATE) {
1447 wlen+=sprintf(wdir+wlen,"%04d",y1);
1448 if (y1!=y2) wlen+=sprintf(wdir+wlen,"-%04d",y2);
1449 if (access(wdir, R_OK) != 0)
1450 my_mkdir(wdir);
1451
1452 wlen+=sprintf(wdir+wlen,"/%02d",m1);
1453 if (m1 != m2) wlen+=sprintf(wdir+wlen,"-%02d",m2);
1454 if (access(wdir, R_OK) != 0)
1455 my_mkdir(wdir);
1456
1457 wlen+=sprintf(wdir+wlen,"/%02d",d1);
1458 if (d1!=d2) wlen+=sprintf(wdir+wlen,"-%02d",d2);
1459 } else {
1460 if (df == 'u') {
1461 wlen=snprintf(wdir+wlen,sizeof(wdir)-wlen,"%04d%s%02d-%04d%s%02d",y1,
1462 conv_month_name(m1),d1,y2,conv_month_name(m2),d2);
1463 } else if (df == 'e') {
1464 wlen=snprintf(wdir+wlen,sizeof(wdir)-wlen,"%02d%s%04d-%02d%s%04d",d1,
1465 conv_month_name(m1),y1,d2,conv_month_name(m2),y2);
1466 } else if (df == 'w') {
1467 wlen2=strftime(wdir+wlen, sizeof(wdir)-wlen, "%Y.%U", &per1->start);
1468 if (wlen2==0) return(-1);
1469 wlen+=wlen2;
1470 }
1471 }
1472
1473 if (us[0] != '\0') {
1474 struct userinfostruct *uinfo=userinfo_find_from_id(us);
1475 if (uinfo) {
1476 strcat(wdir,"-");
1477 strcat(wdir,uinfo->filename);
1478 }
1479 }
1480 if (addr[0] != '\0') {
1481 strcat(wdir,"-");
1482 strcat(wdir,addr);
1483 }
1484 if (site[0] != '\0') {
1485 strcat(wdir,"-");
1486 strcat(wdir,site);
1487 }
1488
1489 strcpy(outdirname,wdir);
1490
1491 // manufacture a new unique name if configured to keep old reports or overwrite old report if configured to do so
1492 if (!OverwriteReport) {
1493 int num=1;
1494
1495 while (access(wdir,R_OK)==0 || errno==EACCES) //file exist or can't be read
1496 {
1497 format_path(__FILE__, __LINE__, wdir, sizeof(wdir), "%s.%d", outdirname, num);
1498 num++;
1499 }
1500 if (num>1) {
1501 if (debug)
1502 debuga(__FILE__,__LINE__,_("File \"%s\" already exists, moved to \"%s\"\n"),outdirname,wdir);
1503 rename(outdirname,wdir);
1504 }
1505 } else {
1506 if (access(outdirname,R_OK) == 0) {
1507 unlinkdir(outdirname,1);
1508 }
1509 }
1510 my_mkdir(outdirname);
1511
1512 // create sarg-date to keep track of the report creation date
1513 if (snprintf(wdir,sizeof(wdir),"%s/sarg-date",outdirname)>=sizeof(wdir)) {
1514 debuga(__FILE__,__LINE__,_("Buffer too small to store "));
1515 debuga_more("%s/sarg-date",outdirname);
1516 exit(EXIT_FAILURE);
1517 }
1518 if ((fp_ou = fopen(wdir, "wt")) == 0) {
1519 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),wdir,strerror(errno));
1520 perror("SARG:");
1521 exit(EXIT_FAILURE);
1522 }
1523 time(&curtime);
1524 //strftime(wdir,sizeof(wdir),"%a %b %d %H:%M:%S %Z %Y",localtime(&curtime));
1525 loctm=localtime(&curtime);
1526 strftime(wdir,sizeof(wdir),"%Y-%m-%d %H:%M:%S",loctm);
1527 if (fprintf(fp_ou,"%s %d\n",wdir,loctm->tm_isdst)<0) {
1528 debuga(__FILE__,__LINE__,_("Failed to write the date in \"%s\"\n"),wdir);
1529 perror("SARG:");
1530 exit(EXIT_FAILURE);
1531 }
1532 if (fclose(fp_ou)==EOF) {
1533 debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),wdir,strerror(errno));
1534 exit(EXIT_FAILURE);
1535 }
1536
1537 copy_images();
1538 return(0);
1539 }
1540
1541 /*!
1542 Copy a string without overflowing the buffer. The copied string
1543 is properly terminated by an ASCII zero.
1544
1545 \param dest The destination buffer.
1546 \param src The source buffer.
1547 \param length The size of the destination buffer. The program is aborted
1548 if the length is negative or zero.
1549 */
1550 void safe_strcpy(char *dest,const char *src,int length)
1551 {
1552 if (length<=0) {
1553 debuga(__FILE__,__LINE__,_("Invalid buffer length passed to the function to safely copy a string\n"));
1554 exit(EXIT_FAILURE);
1555 }
1556 strncpy(dest,src,length-1);
1557 dest[length-1]='\0';
1558 }
1559
1560 void strip_latin(char *line)
1561 {
1562 int i,j;
1563 int skip;
1564
1565 j=0;
1566 skip=0;
1567 for (i=0;line[i];i++){
1568 if (skip){
1569 if (line[i]==';') skip=0;
1570 } else {
1571 if (line[i]=='&')
1572 skip=1;
1573 else
1574 line[j++]=line[i];
1575 }
1576 }
1577 line[j]='\0';
1578 return;
1579 }
1580
1581 void zdate(char *ftime,int ftimesize, char DateFormat)
1582 {
1583 time_t t;
1584 struct tm *local;
1585
1586 t = time(NULL);
1587 local = localtime(&t);
1588 if (DateFormat=='u')
1589 strftime(ftime, ftimesize, "%b/%d/%Y %H:%M", local);
1590 else if (DateFormat=='e')
1591 strftime(ftime, ftimesize, "%d/%b/%Y-%H:%M", local);
1592 else if (DateFormat=='w')
1593 strftime(ftime, ftimesize, "%W-%H-%M", local);
1594 return;
1595 }
1596
1597
1598 char *fixtime(long long int elap)
1599 {
1600 long int num = elap / 1000LL;
1601 int hor = 0;
1602 int min = 0;
1603 int sec = 0;
1604 static char buf[20];
1605
1606 hor=num / 3600L;
1607 min=(num % 3600L) / 60L;
1608 sec=num % 60L;
1609
1610 if (hor==0 && min==0 && sec==0)
1611 strcpy(buf,"0");
1612 else
1613 snprintf(buf,sizeof(buf),"%d:%02d:%02d",hor,min,sec);
1614
1615 return buf;
1616 }
1617
1618
1619 void date_from(struct ReadLogDataStruct *ReadFilter)
1620 {
1621 int d0=0;
1622 int m0=0;
1623 int y0=0;
1624 int d1=0;
1625 int m1=0;
1626 int y1=0;
1627
1628 if (isdigit(ReadFilter->DateRange[0])) {
1629 int next=-1;
1630
1631 if (sscanf(ReadFilter->DateRange,"%d/%d/%d%n",&d0,&m0,&y0,&next)!=3 || y0<100 || m0<1 || m0>12 || d0<1 || d0>31 || next<0) {
1632 debuga(__FILE__,__LINE__,_("The date passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1633 exit(EXIT_FAILURE);
1634 }
1635 if (ReadFilter->DateRange[next]=='-') {
1636 if (sscanf(ReadFilter->DateRange+next+1,"%d/%d/%d",&d1,&m1,&y1)!=3 || y1<100 || m1<1 || m1>12 || d1<1 || d1>31) {
1637 debuga(__FILE__,__LINE__,_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1638 exit(EXIT_FAILURE);
1639 }
1640 } else if (ReadFilter->DateRange[next]!='\0') {
1641 debuga(__FILE__,__LINE__,_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1642 exit(EXIT_FAILURE);
1643 } else {
1644 d1=d0;
1645 m1=m0;
1646 y1=y0;
1647 }
1648 } else {
1649 int i;
1650 time_t Today,t1;
1651 struct tm *Date0,Date1;
1652
1653 if (time(&Today)==(time_t)-1) {
1654 debuga(__FILE__,__LINE__,_("Failed to get the current time\n"));
1655 exit(EXIT_FAILURE);
1656 }
1657 if (sscanf(ReadFilter->DateRange,"day-%d",&i)==1) {
1658 if (i<0) {
1659 debuga(__FILE__,__LINE__,_("Invalid number of days in -d parameter\n"));
1660 exit(EXIT_FAILURE);
1661 }
1662 Today-=i*24*60*60;
1663 Date0=localtime(&Today);
1664 if (Date0==NULL) {
1665 debuga(__FILE__,__LINE__,_("Cannot convert local time: %s\n"),strerror(errno));
1666 exit(EXIT_FAILURE);
1667 }
1668 y0=y1=Date0->tm_year+1900;
1669 m0=m1=Date0->tm_mon+1;
1670 d0=d1=Date0->tm_mday;
1671 } else if (sscanf(ReadFilter->DateRange,"week-%d",&i)==1) {
1672 /*
1673 There is no portable way to find the first day of the week even though the
1674 information is available in the locale. nl_langinfo has the unofficial
1675 parameters _NL_TIME_FIRST_WEEKDAY and _NL_TIME_WEEK_1STDAY but they are
1676 undocumented as is their return value and it is discouraged to use them.
1677 Beside, nl_langinfo isn't available on windows and the first day of the
1678 week isn't available at all on that system.
1679 */
1680 const int FirstWeekDay=1;
1681 time_t WeekBegin;
1682
1683 if (i<0) {
1684 debuga(__FILE__,__LINE__,_("Invalid number of weeks in -d parameter\n"));
1685 exit(EXIT_FAILURE);
1686 }
1687 Date0=localtime(&Today);
1688 if (Date0==NULL) {
1689 debuga(__FILE__,__LINE__,_("Cannot convert local time: %s\n"),strerror(errno));
1690 exit(EXIT_FAILURE);
1691 }
1692 WeekBegin=Today-((Date0->tm_wday-FirstWeekDay+7)%7)*24*60*60;
1693 WeekBegin-=i*7*24*60*60;
1694 Date0=localtime(&WeekBegin);
1695 if (Date0==NULL) {
1696 debuga(__FILE__,__LINE__,_("Cannot convert local time: %s\n"),strerror(errno));
1697 exit(EXIT_FAILURE);
1698 }
1699 y0=Date0->tm_year+1900;
1700 m0=Date0->tm_mon+1;
1701 d0=Date0->tm_mday;
1702 WeekBegin+=6*24*60*60;
1703 Date0=localtime(&WeekBegin);
1704 if (Date0==NULL) {
1705 debuga(__FILE__,__LINE__,_("Cannot convert local time: %s\n"),strerror(errno));
1706 exit(EXIT_FAILURE);
1707 }
1708 y1=Date0->tm_year+1900;
1709 m1=Date0->tm_mon+1;
1710 d1=Date0->tm_mday;
1711 } else if (sscanf(ReadFilter->DateRange,"month-%d",&i)==1) {
1712 if (i<0) {
1713 debuga(__FILE__,__LINE__,_("Invalid number of months in -d parameter\n"));
1714 exit(EXIT_FAILURE);
1715 }
1716 Date0=localtime(&Today);
1717 if (Date0==NULL) {
1718 debuga(__FILE__,__LINE__,_("Cannot convert local time: %s\n"),strerror(errno));
1719 exit(EXIT_FAILURE);
1720 }
1721 if (Date0->tm_mon<i%12) {
1722 y0=Date0->tm_year+1900-i/12-1;
1723 m0=(Date0->tm_mon+12-i%12)%12+1;
1724 d0=1;
1725 } else {
1726 y0=Date0->tm_year+1900-i/12;
1727 m0=Date0->tm_mon-i%12+1;
1728 d0=1;
1729 }
1730 memcpy(&Date1,Date0,sizeof(struct tm));
1731 Date1.tm_isdst=-1;
1732 Date1.tm_mday=1;
1733 if (m0<12) {
1734 Date1.tm_mon=m0;
1735 Date1.tm_year=y0-1900;
1736 } else {
1737 Date1.tm_mon=0;
1738 Date1.tm_year=y0-1900+1;
1739 }
1740 t1=mktime(&Date1);
1741 t1-=24*60*60;
1742 Date0=localtime(&t1);
1743 y1=Date0->tm_year+1900;
1744 m1=Date0->tm_mon+1;
1745 d1=Date0->tm_mday;
1746 } else {
1747 debuga(__FILE__,__LINE__,_("Invalid date range passed on command line\n"));
1748 exit(EXIT_FAILURE);
1749 }
1750 }
1751
1752 ReadFilter->StartDate=y0*10000+m0*100+d0;
1753 ReadFilter->EndDate=y1*10000+m1*100+d1;
1754 snprintf(ReadFilter->DateRange,sizeof(ReadFilter->DateRange),"%02d/%02d/%04d-%02d/%02d/%04d",d0,m0,y0,d1,m1,y1);
1755 return;
1756 }
1757
1758
1759 char *strlow(char *string)
1760 {
1761 char *s;
1762
1763 if (string)
1764 {
1765 for (s = string; *s; ++s)
1766 *s = tolower(*s);
1767 }
1768
1769 return string;
1770 }
1771
1772
1773
1774
1775 char *strup(char *string)
1776 {
1777 char *s;
1778
1779 if (string)
1780 {
1781 for (s = string; *s; ++s)
1782 *s = toupper(*s);
1783 }
1784
1785 return string;
1786 }
1787
1788
1789 void removetmp(const char *outdir)
1790 {
1791 FILE *fp_gen;
1792 char filename[256];
1793
1794 if (!RemoveTempFiles)
1795 return;
1796
1797 if (debug) {
1798 debuga(__FILE__,__LINE__,_("Purging temporary file sarg-general\n"));
1799 }
1800 if (snprintf(filename,sizeof(filename),"%s/sarg-general",outdir)>=sizeof(filename)) {
1801 debuga(__FILE__,__LINE__,_("Path too long: "));
1802 debuga_more("%s/sarg-period\n",outdir);
1803 exit(EXIT_FAILURE);
1804 }
1805 if ((fp_gen=fopen(filename,"w"))==NULL){
1806 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),filename,strerror(errno));
1807 exit(EXIT_FAILURE);
1808 }
1809 totalger(fp_gen,filename);
1810 if (fclose(fp_gen)==EOF) {
1811 debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),filename,strerror(errno));
1812 exit(EXIT_FAILURE);
1813 }
1814 }
1815
1816 void load_excludecodes(const char *ExcludeCodes)
1817 {
1818 FILE *fp_in;
1819 char data[80];
1820 int i;
1821 int Stored;
1822 long int MemSize;
1823
1824 if (ExcludeCodes[0] == '\0')
1825 return;
1826
1827 if ((fp_in=fopen(ExcludeCodes,"r"))==NULL) {
1828 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),ExcludeCodes,strerror(errno));
1829 exit(EXIT_FAILURE);
1830 }
1831
1832 if (fseek(fp_in, 0, SEEK_END)==-1) {
1833 debuga(__FILE__,__LINE__,_("Failed to move till the end of file \"%s\": %s\n"),ExcludeCodes,strerror(errno));
1834 exit(EXIT_FAILURE);
1835 }
1836 MemSize = ftell(fp_in);
1837 if (MemSize<0) {
1838 debuga(__FILE__,__LINE__,_("Cannot get the size of file \"%s\"\n"),ExcludeCodes);
1839 exit(EXIT_FAILURE);
1840 }
1841 if (fseek(fp_in, 0, SEEK_SET)==-1) {
1842 debuga(__FILE__,__LINE__,_("Failed to rewind file \"%s\": %s\n"),ExcludeCodes,strerror(errno));
1843 exit(EXIT_FAILURE);
1844 }
1845
1846 MemSize+=1;
1847 if ((excludecode=(char *) malloc(MemSize))==NULL) {
1848 debuga(__FILE__,__LINE__,_("malloc error (%ld bytes required)\n"),MemSize);
1849 exit(EXIT_FAILURE);
1850 }
1851 memset(excludecode,0,MemSize);
1852
1853 Stored=0;
1854 while(fgets(data,sizeof(data),fp_in)!=NULL) {
1855 if (data[0]=='#') continue;
1856 for (i=strlen(data)-1 ; i>=0 && (unsigned char)data[i]<=' ' ; i--) data[i]='\0';
1857 if (i<0) continue;
1858 if (Stored+i+2>=MemSize) {
1859 debuga(__FILE__,__LINE__,_("Too many codes to exclude in file \"%s\"\n"),ExcludeCodes);
1860 break;
1861 }
1862 strcat(excludecode,data);
1863 strcat(excludecode,";");
1864 Stored+=i+1;
1865 }
1866
1867 if (fclose(fp_in)==EOF) {
1868 debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),ExcludeCodes,strerror(errno));
1869 exit(EXIT_FAILURE);
1870 }
1871 return;
1872 }
1873
1874 void free_excludecodes(void)
1875 {
1876 if (excludecode) {
1877 free(excludecode);
1878 excludecode=NULL;
1879 }
1880 }
1881
1882 int vercode(const char *code)
1883 {
1884 char *cod;
1885 int clen;
1886
1887 if (excludecode && excludecode[0]!='\0') {
1888 clen=strlen(code);
1889 cod=excludecode;
1890 while (cod) {
1891 if (strncmp(code,cod,clen)==0 && cod[clen]==';')
1892 return 1;
1893 cod=strchr(cod,';');
1894 if (cod) cod++;
1895 }
1896 }
1897 return 0;
1898 }
1899
1900 void fixnone(char *str)
1901 {
1902 int i;
1903
1904 for (i=strlen(str)-1 ; i>=0 && (unsigned char)str[i]<=' ' ; i--);
1905 if (i==3 && strncmp(str,"none",4) == 0)
1906 str[0]='\0';
1907
1908 return;
1909 }
1910
1911 void fixendofline(char *str)
1912 {
1913 int i;
1914
1915 for (i=strlen(str)-1 ; i>=0 && (unsigned char)str[i]<=' ' ; i--) str[i]=0;
1916 }
1917
1918 #ifdef LEGACY_TESTVALIDUSERCHAR
1919 int testvaliduserchar(const char *user)
1920 {
1921 int x=0;
1922 int y=0;
1923
1924 for (y=0; y<strlen(UserInvalidChar); y++) {
1925 for (x=0; x<strlen(user); x++) {
1926 if (user[x] == UserInvalidChar[y])
1927 return 1;
1928 }
1929 }
1930 return 0;
1931 }
1932 #else
1933 int testvaliduserchar(const char *user)
1934 {
1935 char * p_UserInvalidChar = UserInvalidChar ;
1936 const char * p_user ;
1937
1938 while( *p_UserInvalidChar ) {
1939 p_user = user ;
1940 while ( *p_user ) {
1941 if ( *p_UserInvalidChar == *p_user )
1942 return 1;
1943 p_user++ ;
1944 }
1945 p_UserInvalidChar++ ;
1946 }
1947 return 0;
1948 }
1949 #endif
1950
1951 int compar( const void *a, const void *b )
1952 {
1953 if ( *(int *)a > *(int *)b ) return 1;
1954 if ( *(int *)a < *(int *)b ) return -1;
1955 return 0;
1956 }
1957
1958 /*!
1959 * Store a range in a list.
1960 *
1961 * \param paramname Name of the configuration parameter providing the list.
1962 * \param list List where to store the numbers.
1963 * \param d0 Start range or -1 to store only one value.
1964 * \param d End range if d0>=0 or the single value to store.
1965 */
1966 static void storenumlist(const char *paramname, int *list, int d0, int d)
1967 {
1968 if (d0<0)
1969 {
1970 list[d]=1;
1971 }
1972 else
1973 {
1974 int i;
1975
1976 if (d<d0)
1977 {
1978 debuga(__FILE__,__LINE__,_("Ending value %d is less than or equal to starting value %d in parameter \"%s\"\n"),d,d0,paramname);
1979 exit(EXIT_FAILURE);
1980 }
1981 for (i=d0 ; i<=d ; i++) list[i]=1;
1982 }
1983 }
1984
1985 /*!
1986 Get a comma separated list of numbers and split them into separate values taking into account
1987 that no value may be greater than a maximum. If a value is a range, it is expended.
1988
1989 Any duplicate value is removed.
1990
1991 \param paramname Name of the configuration parameter providing the list.
1992 \param buffer The string with the list of numbers.
1993 \param list List where to store the numbers.
1994 \param maxvalue The maximum value allowed in the list.
1995
1996 The function terminate the application with an error message if the list is invalid.
1997 */
1998 void getnumlist(const char *paramname, const char *buffer, int *list, int maxvalue)
1999 {
2000 int i, d, d0;
2001 int digitcount;
2002 int nvalues=0;
2003
2004 // skip parameter name
2005 while (*buffer && *buffer!=' ' && *buffer!='\t') buffer++;
2006 if (!*buffer)
2007 {
2008 debuga(__FILE__,__LINE__,_("Missing values for parameter \"%s\"\n"),paramname);
2009 exit(EXIT_FAILURE);
2010 }
2011
2012 // clear list
2013 for (i=0 ; i<maxvalue ; i++) list[i]=0;
2014
2015 // get values
2016 d=0;
2017 d0=-1;
2018 digitcount=0;
2019 for ( ; *buffer ; buffer++)
2020 {
2021 if (isdigit(*buffer))
2022 {
2023 d=d*10+(*buffer-'0');
2024 if (d>=maxvalue)
2025 {
2026 debuga(__FILE__,__LINE__,_("Value too big found in parameter \"%s\" (max value is %d)\n"),paramname,maxvalue-1);
2027 exit(EXIT_FAILURE);
2028 }
2029 digitcount++;
2030 }
2031 else if (*buffer=='-')
2032 {
2033 if (!digitcount)
2034 {
2035 debuga(__FILE__,__LINE__,_("Missing start value before \"-\" in parameter \"%s\"\n"),paramname);
2036 exit(EXIT_FAILURE);
2037 }
2038 d0=d;
2039 d=0;
2040 digitcount=0;
2041 }
2042 else if (*buffer==',')
2043 {
2044 if (!digitcount)
2045 {
2046 debuga(__FILE__,__LINE__,_("Missing value before \",\" in parameter \"%s\"\n"),paramname);
2047 exit(EXIT_FAILURE);
2048 }
2049 storenumlist(paramname,list,d0,d);
2050 nvalues++;
2051 d0=-1;
2052 d=0;
2053 digitcount=0;
2054 }
2055 else if (*buffer=='\r' || *buffer=='\n')
2056 {
2057 break;
2058 }
2059 else if (*buffer!=' ' && *buffer!='\t')
2060 {
2061 debuga(__FILE__,__LINE__,_("Invalid character \"%c\" found in parameter \"%s\"\n"),*buffer,paramname);
2062 exit(EXIT_FAILURE);
2063 }
2064 }
2065 if (digitcount>0)
2066 {
2067 storenumlist(paramname,list,d0,d);
2068 nvalues++;
2069 }
2070 else if (d0>=0)
2071 {
2072 debuga(__FILE__,__LINE__,_("Missing ending value in range for parameter \"%s\"\n"),paramname);
2073 exit(EXIT_FAILURE);
2074 }
2075 if (!nvalues)
2076 {
2077 debuga(__FILE__,__LINE__,_("Parameter \"%s\" is empty\n"),paramname);
2078 exit(EXIT_FAILURE);
2079 }
2080 }
2081
2082 /*!
2083 * Search if the \a list contains the \a value.
2084 *
2085 * \param list The list to search for a value.
2086 * \param maxvalue The maximum value of the list.
2087 * \param value The value to search for.
2088 *
2089 * \return \c True if the value is enabled in the list.
2090 */
2091 bool numlistcontains(const int *list, int maxvalue, int value)
2092 {
2093 if (value<0 || value>=maxvalue) return(false);
2094 return(list[value]!=0);
2095 }
2096
2097 void show_info(FILE *fp_ou)
2098 {
2099 char ftime[127];
2100
2101 if (!ShowSargInfo) return;
2102 zdate(ftime, sizeof(ftime), df);
2103 fputs("<div class=\"info\">",fp_ou);
2104 fprintf(fp_ou,_("Generated by <a href=\"%s\">%s-%s</a> on %s"),URL,PGM,VERSION,ftime);
2105 fputs("</div>\n",fp_ou);
2106 }
2107
2108 void show_sarg(FILE *fp_ou, int depth)
2109 {
2110 int i;
2111
2112 if (!ShowSargLogo) return;
2113 fputs("<div class=\"logo\"><a href=\"http://sarg.sourceforge.net\"><img src=\"",fp_ou);
2114 for (i=0 ; i<depth ; i++)
2115 fputs("../",fp_ou);
2116 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);
2117 }
2118
2119 void write_logo_image(FILE *fp_ou)
2120 {
2121 if (LogoImage[0]!='\0')
2122 fprintf(fp_ou, "<div class=\"logo\"><img src=\"%s\" width=\"%s\" height=\"%s\" alt=\"Logo\"> %s</div>\n",LogoImage,Width,Height,LogoText);
2123 }
2124
2125 void write_html_head(FILE *fp_ou, int depth, const char *page_title,int javascript)
2126 {
2127 int i;
2128
2129 fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n",fp_ou);
2130 fprintf(fp_ou, "<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n",CharSet);
2131 if (page_title) fprintf(fp_ou,"<title>%s</title>\n",page_title);
2132 css(fp_ou);
2133 if ((javascript & HTML_JS_SORTTABLE)!=0 && SortTableJs[0]) {
2134 fputs("<script type=\"text/javascript\" src=\"",fp_ou);
2135 if (strncmp(SortTableJs,"../",3)==0) {
2136 for (i=0 ; i<depth ; i++) fputs("../",fp_ou);
2137 }
2138 fputs(SortTableJs,fp_ou);
2139 fputs("\"></script>\n",fp_ou);
2140 }
2141 fputs("</head>\n<body>\n",fp_ou);
2142 }
2143
2144 void write_html_header(FILE *fp_ou, int depth, const char *page_title,int javascript)
2145 {
2146 write_html_head(fp_ou,depth,page_title,javascript);
2147 write_logo_image(fp_ou);
2148 show_sarg(fp_ou, depth);
2149 fprintf(fp_ou,"<div class=\"title\"><table cellpadding=\"0\" cellspacing=\"0\">\n<tr><th class=\"title_c\">%s</th></tr>\n",Title);
2150 }
2151
2152 void close_html_header(FILE *fp_ou)
2153 {
2154 fputs("</table></div>\n",fp_ou);
2155 }
2156
2157 void write_html_trailer(FILE *fp_ou)
2158 {
2159 show_info(fp_ou);
2160 fputs("</body>\n</html>\n",fp_ou);
2161 }
2162
2163 void output_html_string(FILE *fp_ou,const char *str,int maxlen)
2164 {
2165 int i=0;
2166
2167 while (*str && (maxlen<=0 || i<maxlen)) {
2168 switch (*str) {
2169 case '&':
2170 fputs("&",fp_ou);
2171 break;
2172 case '<':
2173 fputs("<",fp_ou);
2174 break;
2175 case '>':
2176 fputs(">",fp_ou);
2177 break;
2178 case '"':
2179 fputs(""",fp_ou);
2180 break;
2181 case '\'':
2182 fputs("'",fp_ou);
2183 break;
2184 default:
2185 fputc(*str,fp_ou);
2186 }
2187 str++;
2188 i++;
2189 }
2190 if (maxlen>0 && i>=maxlen)
2191 fputs("…",fp_ou);
2192 }
2193
2194 void output_html_url(FILE *fp_ou,const char *url)
2195 {
2196 while (*url) {
2197 if (*url=='&')
2198 fputs("&",fp_ou);
2199 else
2200 fputc(*url,fp_ou);
2201 url++;
2202 }
2203 }
2204
2205 /*!
2206 Write a host name inside an A tag of a HTML file. If the host name starts
2207 with a star, it is assumed to be an alias that cannot be put inside a link
2208 so the A tag is not written around the host name.
2209
2210 \param fp_ou The handle of the HTML file.
2211 \param url The host to display in the HTML file.
2212 \param maxlen The maximum number of characters to print into the host name.
2213 */
2214 void output_html_link(FILE *fp_ou,const char *url,int maxlen)
2215 {
2216 if (url[0]==ALIAS_PREFIX) {
2217 // this is an alias, no need for a A tag
2218 output_html_string(fp_ou,url+1,100);
2219 } else {
2220 if (skip_scheme(url)==url)
2221 fputs("<a href=\"http://",fp_ou);//no scheme in the url, assume http:// to make the link clickable
2222 else
2223 fputs("<a href=\"",fp_ou);//the scheme is in the url, no need to add one
2224 output_html_url(fp_ou,url);
2225 fputs("\">",fp_ou);
2226 output_html_string(fp_ou,url,100);
2227 fputs("</a>",fp_ou);
2228 }
2229 }
2230
2231 void url_module(const char *url, char *w2)
2232 {
2233 int x, y;
2234 char w[255];
2235
2236 y=0;
2237 for (x=strlen(url)-1; x>=0; x--) {
2238 if (url[x] == '/' || y>=sizeof(w)-1) break;
2239 w[y++]=url[x];
2240 }
2241 if (x<0) {
2242 w2[0]='\0';
2243 return;
2244 }
2245
2246 x=0;
2247 for (y=y-1; y>=0; y--) {
2248 w2[x++]=w[y];
2249 }
2250 w2[x]='\0';
2251 }
2252
2253 /*!
2254 Mangle an URL to produce a part that can be used as an anchor in
2255 a html <a name=""> tag.
2256
2257 \param url The URL to mangle.
2258 \param anchor The buffer to write the mangled URL.
2259 \param size The size of the buffer.
2260 */
2261 void url_to_anchor(const char *url,char *anchor,int size)
2262 {
2263 int i,j;
2264 bool skip;
2265
2266 // find url end
2267 for (i=0 ; url[i] && url[i]!='/' && url[i]!='?' ; i++);
2268 i--;
2269 if (i<=0) {
2270 anchor[0]='\0';
2271 return;
2272 }
2273
2274 // only keep really safe characters
2275 skip=false;
2276 j=size-1;
2277 anchor[j]='\0';
2278 while (j>0 && i>=0)
2279 {
2280 if (isalnum(url[i]) || url[i]=='-' || url[i]=='_' || url[i]=='.') {
2281 anchor[--j]=url[i];
2282 skip=false;
2283 } else {
2284 if (!skip) anchor[--j]='_';
2285 skip=true;
2286 }
2287 i--;
2288 }
2289 if (j>0)
2290 {
2291 while ( anchor[j])
2292 {
2293 *anchor=anchor[j];
2294 anchor++;
2295 }
2296 *anchor='\0';
2297 }
2298 }
2299
2300 void version(void)
2301 {
2302 printf(_("SARG Version: %s\n"),VERSION);
2303 #if defined(ENABLE_NLS) && defined(HAVE_LOCALE_H)
2304 if (debug) {
2305 printf(_("\nFor the translation to work, a valid message file should be copied to "
2306 "\"%s/<Locale>/LC_MESSAGES/%s.mo\" where <Locale> is derived from the effective locale.\n"),LOCALEDIR,PACKAGE_NAME);
2307 if (CurrentLocale) {
2308 printf(_("Currently effective locale is \"%s\".\n"),CurrentLocale);
2309 } else {
2310 printf(_("Locale is not set in the environment variable.\n"));
2311 }
2312 // TRANSLATORS: You may change this message to tell the reader that the language is correctly supported.
2313 printf(_("If this message is in English, then your language is not supported or not correctly installed.\n"));
2314 }
2315 #endif
2316 if (debug) {
2317 #ifdef HAVE_GLOB_H
2318 printf(_("File globbing compiled in.\n"));
2319 #else
2320 printf(_("File globbing NOT compiled in.\n"));
2321 #endif
2322 }
2323 exit(EXIT_SUCCESS);
2324 }
2325
2326 char *get_param_value(const char *param,char *line)
2327 {
2328 int plen;
2329
2330 while (*line==' ' || *line=='\t') line++;
2331 plen=strlen(param);
2332 if (strncasecmp(line,param,plen)) return(NULL);
2333 if (line[plen]!=' ' && line[plen]!='\t') return(NULL);
2334 line+=plen;
2335 while (*line==' ' || *line=='\t') line++;
2336 return(line);
2337 }
2338
2339 void unlinkdir(const char *dir,bool contentonly)
2340 {
2341 struct stat st;
2342 DIR *dirp;
2343 struct dirent *direntp;
2344 char dname[MAXLEN];
2345 int err;
2346
2347 dirp=opendir(dir);
2348 if (!dirp) return;
2349 while ((direntp = readdir(dirp)) != NULL) {
2350 if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' ||
2351 (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
2352 continue;
2353 if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
2354 debuga(__FILE__,__LINE__,_("Path too long: "));
2355 debuga_more("%s/%s\n",dir,direntp->d_name);
2356 exit(EXIT_FAILURE);
2357 }
2358 #ifdef HAVE_LSTAT
2359 err=lstat(dname,&st);
2360 #else
2361 err=stat(dname,&st);
2362 #endif
2363 if (err) {
2364 debuga(__FILE__,__LINE__,_("Cannot stat \"%s\": %s\n"),dname,strerror(errno));
2365 exit(EXIT_FAILURE);
2366 }
2367 if (S_ISREG(st.st_mode)) {
2368 if (unlink(dname)) {
2369 debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),dname,strerror(errno));
2370 exit(EXIT_FAILURE);
2371 }
2372 } else if (S_ISDIR(st.st_mode)) {
2373 unlinkdir(dname,0);
2374 } else {
2375 debuga(__FILE__,__LINE__,_("Don't know how to delete \"%s\" (not a regular file nor a directory)\n"),dname);
2376 }
2377 }
2378 closedir(dirp);
2379
2380 if (!contentonly) {
2381 if (rmdir(dir)) {
2382 debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),dir,strerror(errno));
2383 exit(EXIT_FAILURE);
2384 }
2385 }
2386 }
2387
2388 /*!
2389 Delete every file from the temporary directory where sarg is told to store its
2390 temporary files.
2391
2392 As any stray file left over by a previous run would be included in the report, we
2393 must delete every file from the temporary directory before we start processing the logs.
2394
2395 But the temporary directory is given by the user either in the configuration file or
2396 on the command line. We check that the user didn't give a wrong directory by looking
2397 at the files stored in the directory. If a single file is not one of ours, we abort.
2398
2399 \param dir The temporary directory to purge.
2400 */
2401 void emptytmpdir(const char *dir)
2402 {
2403 struct stat st;
2404 DIR *dirp;
2405 struct dirent *direntp;
2406 int dlen;
2407 int elen;
2408 char dname[MAXLEN];
2409 int err;
2410 int i;
2411 static const char *TmpExt[]=
2412 {
2413 ".int_unsort",
2414 ".int_log",
2415 ".day",
2416 "htmlrel.txt",
2417 ".user_unsort",
2418 ".user_log",
2419 ".utmp",
2420 ".ip",
2421 "lastlog1",
2422 "lastlog",
2423 "emailrep"
2424 };
2425
2426 dirp=opendir(dir);
2427 if (!dirp) return;
2428
2429 // make sure the temporary directory contains only our files
2430 while ((direntp = readdir(dirp)) != NULL) {
2431 if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' ||
2432 (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
2433 continue;
2434
2435 // is it one of our files
2436 dlen=strlen(direntp->d_name);
2437 for (i=sizeof(TmpExt)/sizeof(TmpExt[0])-1 ; i>=0 ; i--) {
2438 elen=strlen(TmpExt[i]);
2439 if (dlen>=elen && strcasecmp(direntp->d_name+dlen-elen,TmpExt[i])==0) break;
2440 }
2441 if (i<0) {
2442 debuga(__FILE__,__LINE__,_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2443 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2444 "directory or manually delete the content of \"%s\"\n"),direntp->d_name,dir,dir);
2445 exit(EXIT_FAILURE);
2446 }
2447
2448 if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
2449 debuga(__FILE__,__LINE__,_("Path too long: "));
2450 debuga_more("%s/%s\n",dir,direntp->d_name);
2451 exit(EXIT_FAILURE);
2452 }
2453
2454 #ifdef HAVE_LSTAT
2455 err=lstat(dname,&st);
2456 #else
2457 err=stat(dname,&st);
2458 #endif
2459 if (err) {
2460 debuga(__FILE__,__LINE__,_("Cannot stat \"%s\": %s\n"),dname,strerror(errno));
2461 exit(EXIT_FAILURE);
2462 }
2463 if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) {
2464 debuga(__FILE__,__LINE__,_("Unknown path type for \"%s\". Check temporary directory\n"),dname);
2465 exit(EXIT_FAILURE);
2466 }
2467 }
2468 rewinddir(dirp);
2469
2470 // now delete our files
2471 while ((direntp = readdir(dirp)) != NULL) {
2472 if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' ||
2473 (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
2474 continue;
2475
2476 // is it one of our files
2477 dlen=strlen(direntp->d_name);
2478 for (i=sizeof(TmpExt)/sizeof(TmpExt[0])-1 ; i>=0 ; i--) {
2479 elen=strlen(TmpExt[i]);
2480 if (dlen>=elen && strcasecmp(direntp->d_name+dlen-elen,TmpExt[i])==0) break;
2481 }
2482 if (i<0) {
2483 debuga(__FILE__,__LINE__,_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2484 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2485 "directory or manually delete the content of \"%s\"\n"),direntp->d_name,dir,dir);
2486 exit(EXIT_FAILURE);
2487 }
2488
2489 if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
2490 debuga(__FILE__,__LINE__,_("Path too long: "));
2491 debuga_more("%s/%s\n",dir,direntp->d_name);
2492 exit(EXIT_FAILURE);
2493 }
2494 #ifdef HAVE_LSTAT
2495 err=lstat(dname,&st);
2496 #else
2497 err=stat(dname,&st);
2498 #endif
2499 if (err) {
2500 debuga(__FILE__,__LINE__,_("Cannot stat \"%s\": %s\n"),dname,strerror(errno));
2501 exit(EXIT_FAILURE);
2502 }
2503 if (S_ISDIR(st.st_mode)) {
2504 unlinkdir(dname,0);
2505 } else if (S_ISREG(st.st_mode)) {
2506 if (unlink(dname)) {
2507 debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),dname,strerror(errno));
2508 exit(EXIT_FAILURE);
2509 }
2510 } else {
2511 debuga(__FILE__,__LINE__,_("Don't know how to delete \"%s\" (not a regular file)\n"),dname);
2512 }
2513 }
2514 closedir(dirp);
2515 }
2516
2517 /*!
2518 Extract an url, IPv4 or IPv6 from a buffer. The IP addresses may end with a
2519 prefix size.
2520
2521 \param buf The buffer to parse.
2522 \param text A pointer to set to the beginning of the string pattern. No terminating zero is inserted.
2523 The pointer may be NULL.
2524 \param ipv4 A 4 bytes buffer to store the bytes of the IPv4 address.
2525 \param ipv6 A 8 short integers buffer to store the values of the IPv6 address.
2526 \param nbits The number of prefix bits for an IP address.
2527 \param next The content of the line after the extracted address.
2528
2529 \retval 3 The pattern is a IPv6 address.
2530 \retval 2 The pattern is a IPv4 address.
2531 \retval 1 The patter is a string.
2532 \retval 0 Empty pattern.
2533 */
2534 int extract_address_mask(const char *buf,const char **text,unsigned char *ipv4,unsigned short int *ipv6,int *nbits,const char **next)
2535 {
2536 int i;
2537 int j;
2538 int ip_size;
2539 unsigned int value4, value6;
2540 unsigned short int addr[8];
2541 int addr_len;
2542 int nibble6_len;
2543 int mask, max_mask;
2544 int pad_pos;
2545 int pad_len;
2546 bool bracket=false;
2547 bool port=false;
2548 int port_num=0;
2549
2550 // skip leading spaces and tabs
2551 while (*buf && (*buf==' ' || *buf=='\t')) buf++;
2552
2553 // find out the nature of the pattern
2554 ip_size=0x60 | 0x04;
2555 if (*buf=='[') {
2556 bracket=true;
2557 ip_size=0x60;
2558 buf++;
2559 }
2560 value4=0U;
2561 value6=0U;
2562 addr_len=0;
2563 nibble6_len=0;
2564 pad_pos=-1;
2565 for (i=0 ; (unsigned char)buf[i]>' ' && buf[i]!='/' && buf[i]!='?' && (!bracket || buf[i]!=']') && ip_size ; i++) {
2566 if (ip_size & 0x04) {
2567 if (isdigit(buf[i])) {
2568 if (port) {
2569 port_num=port_num*10+(buf[i]-'0');
2570 if (port_num>65535) ip_size&=~0x04;
2571 } else {
2572 value4=value4*10+(buf[i]-'0');
2573 if (value4>0xFFU) ip_size&=~0x04;
2574 }
2575 } else if (buf[i]=='.' && addr_len<4) {
2576 addr[addr_len++]=(unsigned short)(value4 & 0xFFU);
2577 value4=0U;
2578 } else if (!port && buf[i]==':') {
2579 port=true;
2580 } else {
2581 ip_size&=~0x04;
2582 }
2583 }
2584 if (ip_size & 0x60) {
2585 if (isdigit(buf[i])) {
2586 value6=(value6<<4)+(buf[i]-'0');
2587 nibble6_len++;
2588 if (value6>0xFFFFU) ip_size&=~0x60;
2589 } else if (toupper(buf[i])>='A' && toupper(buf[i])<='F') {
2590 value6=(value6<<4)+(toupper(buf[i])-'A'+10);
2591 nibble6_len++;
2592 if (value6>0xFFFFU) ip_size&=~0x60;
2593 } else if (buf[i]==':' && addr_len<8) {
2594 if (nibble6_len>0) {
2595 addr[addr_len++]=(unsigned short)(value6 & 0xFFFFU);
2596 nibble6_len=0;
2597 }
2598 value6=0U;
2599 if (buf[i+1]==':') {
2600 pad_pos=addr_len;
2601 i++;
2602 }
2603 } else {
2604 ip_size&=~0x60;
2605 }
2606 }
2607 }
2608 if (i==0) return(0);
2609 if (ip_size & 0x04) {
2610 if (addr_len!=3)
2611 ip_size&=~0x04;
2612 else
2613 addr[addr_len++]=(unsigned short)(value4 & 0xFFU);
2614 }
2615 if (ip_size & 0x60) {
2616 if (pad_pos<0 && addr_len!=7) {
2617 ip_size&=~0x60;
2618 } else if (pad_pos>=0 && addr_len>=7)
2619 ip_size&=~0x60;
2620 else if (nibble6_len>0)
2621 addr[addr_len++]=(unsigned short)(value6 & 0xFFFFU);
2622 }
2623 if (!ip_size) {
2624 if (text) {
2625 *text=buf;
2626 if (bracket) (*text)--;
2627 }
2628 while ((unsigned char)buf[i]>' ') i++;
2629 if (next) *next=buf+i;
2630 return(1);
2631 }
2632 max_mask=(ip_size & 0x04) ? 4*8 : 8*16;
2633 if (buf[i]=='/') {
2634 i++;
2635 mask=atoi(buf+i);
2636 while (isdigit(buf[i])) i++;
2637 if (mask<0 || mask>max_mask) mask=max_mask;
2638 } else
2639 mask=max_mask;
2640 if (ip_size & 0x60 && bracket && buf[i]==']') i++;
2641 if (next) *next=buf+i;
2642 if (ip_size & 0x04) {
2643 if (nbits) *nbits=mask;
2644 for (i=0 ; i<addr_len ; i++)
2645 ipv4[i]=(unsigned char)addr[i];
2646 return(2);
2647 }
2648
2649 // IPv6 address
2650 if (nbits) *nbits=mask;
2651 i=0;
2652 j=0;
2653 if (pad_pos>=0) {
2654 while (i<pad_pos)
2655 ipv6[j++]=(unsigned short int)addr[i++];
2656 pad_len=8-addr_len;
2657 while (j<pad_pos+pad_len)
2658 ipv6[j++]=0;
2659 }
2660 while (i<addr_len)
2661 ipv6[j++]=(unsigned short int)addr[i++];
2662 return(3);
2663 }
2664
2665 int format_path(const char *file, int line, char *output_buffer, int buffer_size, const char *format,...)
2666 {
2667 va_list ap;
2668 int output_length;
2669
2670 va_start(ap, format);
2671 output_length = vsnprintf(output_buffer, buffer_size, format, ap);
2672 if (output_length >= buffer_size) {
2673 debuga(file, line, _("Path too long: "));
2674 vfprintf(stderr, format, ap);
2675 exit(EXIT_FAILURE);
2676 }
2677 va_end(ap);
2678 return output_length;
2679 }
2680
2681 void append_to_path(char *base_path, int base_path_size, const char *append)
2682 {
2683 int length = strlen(base_path);
2684 int append_length;
2685
2686 if (append[0] == '/') append++;
2687 if (length > 0 && base_path[length-1] != '/') {
2688 if (length+1 >= base_path_size) {
2689 debuga(__FILE__, __LINE__, _("Path too long: "));
2690 fprintf(stderr, "%s/%s", base_path, append);
2691 exit(EXIT_FAILURE);
2692 }
2693 base_path[length++] = '/';
2694 }
2695 append_length = strlen(append);
2696 if (length+append_length >= base_path_size) {
2697 debuga(__FILE__, __LINE__, _("Path too long: "));
2698 base_path[length] = '\0';
2699 fprintf(stderr, "%s%s", base_path, append);
2700 exit(EXIT_FAILURE);
2701 }
2702 strcpy(base_path + length, append);
2703 }