Branch data Line data Source code
1 : : // $Id: util.cc 6916 2009-09-24 20:48:36Z vern $
2 : : //
3 : : // See the file "COPYING" in the main distribution directory for copyright.
4 : :
5 : : #include "config.h"
6 : :
7 : : #ifdef TIME_WITH_SYS_TIME
8 : : # include <sys/time.h>
9 : : # include <time.h>
10 : : #else
11 : : # ifdef HAVE_SYS_TIME_H
12 : : # include <sys/time.h>
13 : : # else
14 : : # include <time.h>
15 : : # endif
16 : : #endif
17 : :
18 : : #include <ctype.h>
19 : : #include <stdio.h>
20 : : #include <stdlib.h>
21 : : #include <unistd.h>
22 : : #include <sys/types.h>
23 : : #include <sys/stat.h>
24 : : #include <sys/resource.h>
25 : : #include <fcntl.h>
26 : : #include <stdarg.h>
27 : : #include <errno.h>
28 : : #include <signal.h>
29 : :
30 : : #ifdef HAVE_MALLINFO
31 : : # include <malloc.h>
32 : : #endif
33 : :
34 : : #include "input.h"
35 : : #include "util.h"
36 : : #include "Obj.h"
37 : : #include "md5.h"
38 : : #include "Val.h"
39 : : #include "NetVar.h"
40 : : #include "Net.h"
41 : :
42 : 73119 : char* copy_string(const char* s)
43 : : {
44 : 73119 : char* c = new char[strlen(s)+1];
45 : 73119 : strcpy(c, s);
46 : 73119 : return c;
47 : : }
48 : :
49 : 418531 : int streq(const char* s1, const char* s2)
50 : : {
51 : 418531 : return ! strcmp(s1, s2);
52 : : }
53 : :
54 : 2470 : int expand_escape(const char*& s)
55 : : {
56 [ - - + + + : 2470 : switch ( *(s++) ) {
- - + + + ]
57 : 0 : case 'b': return '\b';
58 : 0 : case 'f': return '\f';
59 : 640 : case 'n': return '\n';
60 : 4 : case 'r': return '\r';
61 : 22 : case 't': return '\t';
62 : 0 : case 'a': return '\a';
63 : 0 : case 'v': return '\v';
64 : :
65 : : case '0': case '1': case '2': case '3': case '4':
66 : : case '5': case '6': case '7':
67 : : { // \<octal>{1,3}
68 : 2 : --s; // put back the first octal digit
69 : 2 : const char* start = s;
70 : :
71 : : // Don't increment inside loop control
72 : : // because if isdigit() is a macro it might
73 : : // expand into multiple increments ...
74 : :
75 : : // Here we define a maximum length for escape sequence
76 : : // to allow easy handling of string like: "^H0" as
77 : : // "\0100".
78 : :
79 [ + + ][ + - ]: 8 : for ( int len = 0; len < 3 && isascii(*s) && isdigit(*s);
[ + - ]
80 : : ++s, ++len)
81 : : ;
82 : :
83 : : int result;
84 [ - + ]: 2 : if ( sscanf(start, "%3o", &result) != 1 )
85 : : {
86 : 0 : warn("bad octal escape: ", start);
87 : 0 : result = 0;
88 : : }
89 : :
90 : 2 : return result;
91 : : }
92 : :
93 : : case 'x':
94 : : { /* \x<hex> */
95 : 13 : const char* start = s;
96 : :
97 : : // Look at most 2 characters, so that "\x0ddir" -> "^Mdir".
98 [ + + ][ + - ]: 39 : for ( int len = 0; len < 2 && isascii(*s) && isxdigit(*s);
[ + - ]
99 : : ++s, ++len)
100 : : ;
101 : :
102 : : int result;
103 [ - + ]: 13 : if ( sscanf(start, "%2x", &result) != 1 )
104 : : {
105 : 0 : warn("bad hexadecimal escape: ", start);
106 : 0 : result = 0;
107 : : }
108 : :
109 : 13 : return result;
110 : : }
111 : :
112 : : default:
113 : 2470 : return s[-1];
114 : : }
115 : : }
116 : :
117 : 436 : char* skip_whitespace(char* s)
118 : : {
119 [ + + ][ - + ]: 872 : while ( *s == ' ' || *s == '\t' )
120 : 436 : ++s;
121 : 436 : return s;
122 : : }
123 : :
124 : 966 : const char* skip_whitespace(const char* s)
125 : : {
126 [ + + ][ - + ]: 985 : while ( *s == ' ' || *s == '\t' )
127 : 19 : ++s;
128 : 966 : return s;
129 : : }
130 : :
131 : 0 : char* skip_whitespace(char* s, char* end_of_s)
132 : : {
133 [ # # ][ # # ]: 0 : while ( s < end_of_s && (*s == ' ' || *s == '\t') )
[ # # ]
134 : 0 : ++s;
135 : 0 : return s;
136 : : }
137 : :
138 : 2775 : const char* skip_whitespace(const char* s, const char* end_of_s)
139 : : {
140 [ + + ][ + + ]: 4536 : while ( s < end_of_s && (*s == ' ' || *s == '\t') )
[ - + ]
141 : 1761 : ++s;
142 : 2775 : return s;
143 : : }
144 : :
145 : 0 : char* skip_digits(char* s)
146 : : {
147 [ # # ][ # # ]: 0 : while ( *s && isdigit(*s) )
148 : 0 : ++s;
149 : 0 : return s;
150 : : }
151 : :
152 : 0 : char* get_word(char*& s)
153 : : {
154 : 0 : char* w = s;
155 [ # # ][ # # ]: 0 : while ( *s && ! isspace(*s) )
156 : 0 : ++s;
157 : :
158 [ # # ]: 0 : if ( *s )
159 : : {
160 : 0 : *s = '\0'; // terminate the word
161 : 0 : s = skip_whitespace(s+1);
162 : : }
163 : :
164 : 0 : return w;
165 : : }
166 : :
167 : 0 : void get_word(int length, const char* s, int& pwlen, const char*& pw)
168 : : {
169 : 0 : pw = s;
170 : :
171 : 0 : int len = 0;
172 [ # # ][ # # ]: 0 : while ( len < length && *s && ! isspace(*s) )
[ # # ]
173 : : {
174 : 0 : ++s;
175 : 0 : ++len;
176 : : }
177 : :
178 : 0 : pwlen = len;
179 : 0 : }
180 : :
181 : 0 : void to_upper(char* s)
182 : : {
183 [ # # ]: 0 : while ( *s )
184 : : {
185 [ # # ]: 0 : if ( islower(*s) )
186 : 0 : *s = toupper(*s);
187 : 0 : ++s;
188 : : }
189 : 0 : }
190 : :
191 : 0 : const char* strchr_n(const char* s, const char* end_of_s, char ch)
192 : : {
193 [ # # ]: 0 : for ( ; s < end_of_s; ++s )
194 [ # # ]: 0 : if ( *s == ch )
195 : 0 : return s;
196 : :
197 : 0 : return 0;
198 : : }
199 : :
200 : 0 : const char* strrchr_n(const char* s, const char* end_of_s, char ch)
201 : : {
202 [ # # ]: 0 : for ( --end_of_s; end_of_s >= s; --end_of_s )
203 [ # # ]: 0 : if ( *end_of_s == ch )
204 : 0 : return end_of_s;
205 : :
206 : 0 : return 0;
207 : : }
208 : :
209 : 4408 : int decode_hex(char ch)
210 : : {
211 [ + - ][ + + ]: 4408 : if ( ch >= '0' && ch <= '9' )
212 : 2778 : return ch - '0';
213 : :
214 [ + - ][ + + ]: 1630 : if ( ch >= 'A' && ch <= 'F' )
215 : 1294 : return ch - 'A' + 10;
216 : :
217 [ + - ][ + - ]: 336 : if ( ch >= 'a' && ch <= 'f' )
218 : 336 : return ch - 'a' + 10;
219 : :
220 : 4408 : return -1;
221 : : }
222 : :
223 : 0 : unsigned char encode_hex(int h)
224 : : {
225 : : static const char hex[16] = {
226 : : '0', '1', '2', '3', '4', '5', '6', '7', '8',
227 : : '9', 'A', 'B', 'C', 'D', 'E', 'F'
228 : : };
229 : :
230 [ # # ][ # # ]: 0 : if ( h < 0 || h >= 16 )
231 : : {
232 : 0 : internal_error("illegal value for encode_hex: %d", h);
233 : : return 'X';
234 : : }
235 : :
236 : 0 : return hex[h];
237 : : }
238 : :
239 : : // Same as strpbrk except that s is not NUL-terminated, but limited by
240 : : // len. Note that '\0' is always implicitly contained in charset.
241 : 0 : const char* strpbrk_n(size_t len, const char* s, const char* charset)
242 : : {
243 [ # # ]: 0 : for ( const char* p = s; p < s + len; ++p )
244 [ # # ]: 0 : if ( strchr(charset, *p) )
245 : 0 : return p;
246 : :
247 : 0 : return 0;
248 : : }
249 : :
250 : 52656 : int strcasecmp_n(int b_len, const char* b, const char* t)
251 : : {
252 [ - + ]: 52656 : if ( ! b )
253 : 0 : return -1;
254 : :
255 : : int i;
256 [ + + ]: 111733 : for ( i = 0; i < b_len; ++i )
257 : : {
258 [ + + ]: 109173 : char c1 = islower(b[i]) ? toupper(b[i]) : b[i];
259 [ + + ]: 109173 : char c2 = islower(t[i]) ? toupper(t[i]) : t[i];
260 : :
261 [ + + ]: 109173 : if ( c1 < c2 )
262 : 25047 : return -1;
263 : :
264 [ + + ]: 84126 : if ( c1 > c2 )
265 : 25049 : return 1;
266 : : }
267 : :
268 : 52656 : return t[i] != '\0';
269 : : }
270 : :
271 : : #ifndef HAVE_STRCASESTR
272 : : // This code is derived from software contributed to BSD by Chris Torek.
273 : : char* strcasestr(const char* s, const char* find)
274 : : {
275 : : char c = *find++;
276 : : if ( c )
277 : : {
278 : : c = tolower((unsigned char) c);
279 : :
280 : : size_t len = strlen(find);
281 : :
282 : : do {
283 : : char sc;
284 : : do {
285 : : sc = *s++;
286 : : if ( sc == 0 )
287 : : return 0;
288 : : } while ( char(tolower((unsigned char) sc)) != c );
289 : : } while ( strcasecmp_n(len, s, find) != 0 );
290 : :
291 : : --s;
292 : : }
293 : :
294 : : return (char*) s;
295 : : }
296 : : #endif
297 : :
298 : 494 : int atoi_n(int len, const char* s, const char** end, int base, int& result)
299 : : {
300 : 494 : int n = 0;
301 : 494 : int neg = 0;
302 : :
303 [ + - ][ - + ]: 494 : if ( len > 0 && *s == '-' )
304 : : {
305 : 0 : neg = 1;
306 : 0 : --len; ++s;
307 : : }
308 : :
309 : : int i;
310 [ + + ]: 2091 : for ( i = 0; i < len; ++i )
311 : : {
312 : : unsigned int d;
313 : :
314 [ + + ]: 1610 : if ( isdigit(s[i]) )
315 : 1510 : d = s[i] - '0';
316 : :
317 [ + + ][ + - ]: 100 : else if ( s[i] >= 'a' && s[i] < 'a' - 10 + base )
318 : 87 : d = s[i] - 'a' + 10;
319 : :
320 [ - + ][ # # ]: 13 : else if ( s[i] >= 'A' && s[i] < 'A' - 10 + base )
321 : 0 : d = s[i] - 'A' + 10;
322 : :
323 [ + - ]: 13 : else if ( i > 0 )
324 : 13 : break;
325 : :
326 : : else
327 : 0 : return 0;
328 : :
329 : 1597 : n = n * base + d;
330 : : }
331 : :
332 [ - + ]: 494 : if ( neg )
333 : 0 : result = -n;
334 : : else
335 : 494 : result = n;
336 : :
337 [ - + ]: 494 : if ( end )
338 : 0 : *end = s + i;
339 : :
340 : 494 : return 1;
341 : : }
342 : :
343 : : int strstr_n(const int big_len, const u_char* big,
344 : 18039 : const int little_len, const u_char* little)
345 : : {
346 [ - + ]: 18039 : if ( little_len > big_len )
347 : 0 : return -1;
348 : :
349 [ + + ]: 295442 : for ( int i = 0; i <= big_len - little_len; ++i )
350 : : {
351 [ + + ]: 278372 : if ( ! memcmp(big + i, little, little_len) )
352 : 969 : return i;
353 : : }
354 : :
355 : 18039 : return -1;
356 : : }
357 : :
358 : 0 : int fputs(int len, const char* s, FILE* fp)
359 : : {
360 [ # # ]: 0 : for ( int i = 0; i < len; ++i )
361 [ # # ]: 0 : if ( fputc(s[i], fp) == EOF )
362 : 0 : return EOF;
363 : 0 : return 0;
364 : : }
365 : :
366 : 0 : bool is_printable(const char* s, int len)
367 : : {
368 [ # # ]: 0 : while ( --len >= 0 )
369 [ # # ]: 0 : if ( ! isprint(*s++) )
370 : 0 : return false;
371 : 0 : return true;
372 : : }
373 : :
374 : 50345 : const char* fmt_bytes(const char* data, int len)
375 : : {
376 : : static char buf[1024];
377 : 50345 : char* p = buf;
378 : :
379 [ + + ][ + - ]: 1768854 : for ( int i = 0; i < len && p - buf < int(sizeof(buf)); ++i )
380 : : {
381 [ + + ]: 1718509 : if ( isprint(data[i]) )
382 : 903295 : *p++ = data[i];
383 : : else
384 : : p += snprintf(p, sizeof(buf) - (p - buf),
385 : 815214 : "\\x%02x", (unsigned char) data[i]);
386 : : }
387 : :
388 [ + - ]: 50345 : if ( p - buf < int(sizeof(buf)) )
389 : 50345 : *p = '\0';
390 : : else
391 : 0 : buf[sizeof(buf) - 1] = '\0';
392 : :
393 : 50345 : return buf;
394 : : }
395 : :
396 : 71980 : const char* fmt(const char* format, ...)
397 : : {
398 : : static char* buf = 0;
399 : : static unsigned int buf_len = 1024;
400 : :
401 [ + + ]: 71980 : if ( ! buf )
402 : 3 : buf = (char*) malloc(buf_len);
403 : :
404 : : va_list al;
405 : 71980 : va_start(al, format);
406 : 71980 : int n = safe_vsnprintf(buf, buf_len, format, al);
407 : 71980 : va_end(al);
408 : :
409 [ - + ]: 71980 : if ( (unsigned int) n >= buf_len )
410 : : { // Not enough room, grow the buffer.
411 : 0 : buf_len = n + 32;
412 : 0 : buf = (char*) realloc(buf, buf_len);
413 : :
414 : : // Is it portable to restart?
415 : 0 : va_start(al, format);
416 : 0 : n = safe_vsnprintf(buf, buf_len, format, al);
417 : 0 : va_end(al);
418 : :
419 [ # # ]: 0 : if ( (unsigned int) n >= buf_len )
420 : 0 : internal_error("confusion reformatting in fmt()");
421 : : }
422 : :
423 : 71980 : return buf;
424 : : }
425 : :
426 : 0 : const char* fmt_access_time(double t)
427 : : {
428 : : static char buf[256];
429 : 0 : time_t time = (time_t) t;
430 : 0 : strftime(buf, sizeof(buf), "%d/%m-%H:%M", localtime(&time));
431 : 0 : return buf;
432 : : }
433 : :
434 : 2 : bool ensure_dir(const char *dirname)
435 : : {
436 : : struct stat st;
437 [ - + ]: 2 : if ( stat(dirname, &st) < 0 )
438 : : {
439 [ # # ]: 0 : if ( errno != ENOENT )
440 : : {
441 : : warn(fmt("can't stat directory %s: %s",
442 : 0 : dirname, strerror(errno)));
443 : 0 : return false;
444 : : }
445 : :
446 [ # # ]: 0 : if ( mkdir(dirname, 0700) < 0 )
447 : : {
448 : : warn(fmt("can't create directory %s: %s",
449 : 0 : dirname, strerror(errno)));
450 : 0 : return false;
451 : : }
452 : : }
453 : :
454 [ - + ]: 2 : else if ( ! S_ISDIR(st.st_mode) )
455 : : {
456 : 0 : warn(fmt("%s exists but is not a directory", dirname));
457 : 0 : return false;
458 : : }
459 : :
460 : 2 : return true;
461 : : }
462 : :
463 : 215 : bool is_dir(const char* path)
464 : : {
465 : : struct stat st;
466 [ - + ]: 215 : if ( stat(path, &st) < 0 )
467 : : {
468 [ # # ]: 0 : if ( errno != ENOENT )
469 : 0 : warn(fmt("can't stat %s: %s", path, strerror(errno)));
470 : :
471 : 0 : return false;
472 : : }
473 : :
474 : 215 : return S_ISDIR(st.st_mode);
475 : : }
476 : :
477 : 46089 : void hash_md5(size_t size, const unsigned char* bytes, unsigned char digest[16])
478 : : {
479 : : md5_state_s h;
480 : 46089 : md5_init(&h);
481 : 46089 : md5_append(&h, bytes, size);
482 : 46089 : md5_finish(&h, digest);
483 : 46089 : }
484 : :
485 : 0 : const char* md5_digest_print(const unsigned char digest[16])
486 : : {
487 : : static char digest_print[256];
488 : :
489 [ # # ]: 0 : for ( int i = 0; i < 16; ++i )
490 : 0 : snprintf(digest_print + i * 2, 3, "%02x", digest[i]);
491 : :
492 : 0 : return digest_print;
493 : : }
494 : :
495 : : int hmac_key_set = 0;
496 : : uint8 shared_hmac_md5_key[16];
497 : :
498 : 23043 : void hmac_md5(size_t size, const unsigned char* bytes, unsigned char digest[16])
499 : : {
500 [ - + ]: 23043 : if ( ! hmac_key_set )
501 : 0 : internal_error("HMAC-MD5 invoked before the HMAC key is set");
502 : :
503 : 23043 : hash_md5(size, bytes, digest);
504 : :
505 [ + + ]: 391731 : for ( int i = 0; i < 16; ++i )
506 : 368688 : digest[i] ^= shared_hmac_md5_key[i];
507 : :
508 : 23043 : hash_md5(16, digest, digest);
509 : 23043 : }
510 : :
511 : : static bool read_random_seeds(const char* read_file, uint32* seed,
512 : 0 : uint32* buf, int bufsiz)
513 : : {
514 : : struct stat st;
515 : 0 : FILE* f = 0;
516 : :
517 [ # # ]: 0 : if ( stat(read_file, &st) < 0 )
518 : : {
519 : : warn(fmt("Seed file '%s' does not exist: %s",
520 : 0 : read_file, strerror(errno)));
521 : 0 : return false;
522 : : }
523 : :
524 [ # # ]: 0 : if ( ! (f = fopen(read_file, "r")) )
525 : : {
526 : : warn(fmt("Could not open seed file '%s': %s",
527 : 0 : read_file, strerror(errno)));
528 : 0 : return false;
529 : : }
530 : :
531 : : // Read seed for srandom().
532 [ # # ]: 0 : if ( fscanf(f, "%u", seed) != 1 )
533 : : {
534 : 0 : fclose(f);
535 : 0 : return false;
536 : : }
537 : :
538 : : // Read seeds for MD5.
539 [ # # ]: 0 : for ( int i = 0; i < bufsiz; ++i )
540 : : {
541 : : int tmp;
542 [ # # ]: 0 : if ( fscanf(f, "%u", &tmp) != 1 )
543 : : {
544 : 0 : fclose(f);
545 : 0 : return false;
546 : : }
547 : :
548 : 0 : buf[i] = tmp;
549 : : }
550 : :
551 : 0 : fclose(f);
552 : 0 : return true;
553 : : }
554 : :
555 : : static bool write_random_seeds(const char* write_file, uint32 seed,
556 : 0 : uint32* buf, int bufsiz)
557 : : {
558 : 0 : FILE* f = 0;
559 : :
560 [ # # ]: 0 : if ( ! (f = fopen(write_file, "w+")) )
561 : : {
562 : : warn(fmt("Could not create seed file '%s': %s",
563 : 0 : write_file, strerror(errno)));
564 : 0 : return false;
565 : : }
566 : :
567 : 0 : fprintf(f, "%u\n", seed);
568 : :
569 [ # # ]: 0 : for ( int i = 0; i < bufsiz; ++i )
570 : 0 : fprintf(f, "%u\n", buf[i]);
571 : :
572 : 0 : fclose(f);
573 : 0 : return true;
574 : : }
575 : :
576 : 3 : void init_random_seed(uint32 seed, const char* read_file, const char* write_file)
577 : : {
578 : : static const int bufsiz = 16;
579 : : uint32 buf[bufsiz];
580 : 3 : int pos = 0; // accumulates entropy
581 : 3 : bool seeds_done = false;
582 : :
583 [ - + ]: 3 : if ( read_file )
584 : : {
585 [ # # ]: 0 : if ( ! read_random_seeds(read_file, &seed, buf, bufsiz) )
586 : : fprintf(stderr, "Could not load seeds from file '%s'.\n",
587 : 0 : read_file);
588 : : else
589 : 0 : seeds_done = true;
590 : : }
591 : :
592 [ + - ]: 3 : if ( ! seeds_done )
593 : : {
594 : : // Gather up some entropy.
595 : 3 : gettimeofday((struct timeval *)(buf + pos), 0);
596 : 3 : pos += sizeof(struct timeval) / sizeof(uint32);
597 : :
598 : : #if defined(O_NONBLOCK)
599 : 3 : int fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
600 : : #elif defined(O_NDELAY)
601 : : int fd = open("/dev/random", O_RDONLY | O_NDELAY);
602 : : #else
603 : : int fd = open("/dev/random", O_RDONLY);
604 : : #endif
605 : :
606 [ + - ]: 3 : if ( fd >= 0 )
607 : : {
608 : : int amt = read(fd, buf + pos,
609 : 3 : sizeof(uint32) * (bufsiz - pos));
610 : 3 : close(fd);
611 : :
612 [ + - ]: 3 : if ( amt > 0 )
613 : 3 : pos += amt / sizeof(uint32);
614 : : else
615 : : // Clear errno, which can be set on some
616 : : // systems due to a lack of entropy.
617 : 0 : errno = 0;
618 : : }
619 : :
620 [ - + ]: 3 : if ( pos < bufsiz )
621 : : {
622 : 0 : buf[pos++] = getpid();
623 : :
624 [ # # ]: 0 : if ( pos < bufsiz )
625 : 0 : buf[pos++] = getuid();
626 : : }
627 : :
628 [ + - ]: 3 : if ( ! seed )
629 : : {
630 [ + + ]: 51 : for ( int i = 0; i < pos; ++i )
631 : : {
632 : 48 : seed ^= buf[i];
633 : 48 : seed = (seed << 1) | (seed >> 31);
634 : : }
635 : : }
636 : : }
637 : :
638 : 3 : srandom(seed);
639 : :
640 [ + - ]: 3 : if ( ! hmac_key_set )
641 : : {
642 : 3 : hash_md5(sizeof(buf), (u_char*) buf, shared_hmac_md5_key);
643 : 3 : hmac_key_set = 1;
644 : : }
645 : :
646 [ - + ][ # # ]: 3 : if ( write_file && ! write_random_seeds(write_file, seed, buf, bufsiz) )
[ - + ]
647 : : fprintf(stderr, "Could not write seeds to file '%s'.\n",
648 : 0 : write_file);
649 : 3 : }
650 : :
651 : :
652 : : // Returns a 64-bit random string.
653 : 0 : uint64 rand64bit()
654 : : {
655 : 0 : uint64 base = 0;
656 : : int i;
657 : :
658 [ # # ]: 0 : for ( i = 1; i <= 4; ++i )
659 : 0 : base = (base<<16) | random();
660 : 0 : return base;
661 : : }
662 : :
663 : 0 : void message(const char* msg)
664 : : {
665 : 0 : pinpoint();
666 : 0 : fprintf(stderr, "%s\n", msg);
667 : 0 : }
668 : :
669 : 0 : void warn(const char* msg)
670 : : {
671 : 0 : pinpoint();
672 : 0 : fprintf(stderr, "warning: %s\n", msg);
673 : 0 : ++nwarn;
674 : 0 : }
675 : :
676 : 0 : void warn(const char* msg, const char* addl)
677 : : {
678 : 0 : pinpoint();
679 : 0 : fprintf(stderr, "warning: %s %s\n", msg, addl);
680 : 0 : ++nwarn;
681 : 0 : }
682 : :
683 : 0 : void error(const char* msg)
684 : : {
685 : 0 : pinpoint();
686 : 0 : fprintf(stderr, "error: %s\n", msg);
687 : 0 : ++nerr;
688 : 0 : }
689 : :
690 : 2 : void error(const char* msg, const char* addl)
691 : : {
692 : 2 : pinpoint();
693 : 2 : fprintf(stderr, "error: %s %s\n", msg, addl);
694 : 2 : ++nerr;
695 : 2 : }
696 : :
697 : 0 : void error(const char* msg, uint32 addl)
698 : : {
699 : 0 : pinpoint();
700 : 0 : fprintf(stderr, "error: %s - %u\n", msg, addl);
701 : 0 : ++nerr;
702 : 0 : }
703 : :
704 : 0 : void run_time(const char* msg)
705 : : {
706 : 0 : pinpoint();
707 : 0 : fprintf(stderr, "run-time error: %s\n", msg);
708 : 0 : ++nruntime;
709 : 0 : }
710 : :
711 : 0 : void run_time(const char* fmt, BroObj* obj)
712 : : {
713 : 0 : ODesc d;
714 : 0 : obj->Describe(&d);
715 : 0 : run_time(fmt, d.Description());
716 : 0 : }
717 : :
718 : 0 : void run_time(const char* fmt, const char* arg)
719 : : {
720 : 0 : pinpoint();
721 : 0 : fprintf(stderr, "run-time error: ");
722 : 0 : fprintf(stderr, fmt, arg);
723 : 0 : fprintf(stderr, "\n");
724 : 0 : ++nruntime;
725 : 0 : }
726 : :
727 : 0 : void run_time(const char* fmt, const char* arg1, const char* arg2)
728 : : {
729 : 0 : pinpoint();
730 : 0 : fprintf(stderr, "run-time error: ");
731 : 0 : fprintf(stderr, fmt, arg1, arg2);
732 : 0 : fprintf(stderr, "\n");
733 : 0 : ++nruntime;
734 : 0 : }
735 : :
736 : 0 : void internal_error(const char* fmt, ...)
737 : : {
738 : : va_list al;
739 : :
740 : 0 : pinpoint();
741 : 0 : fprintf(stderr, "internal error: ");
742 : 0 : va_start(al, fmt);
743 : 0 : vfprintf(stderr, fmt, al);
744 : 0 : va_end(al);
745 : 0 : fprintf(stderr, "\n");
746 : 0 : set_processing_status("TERMINATED", "internal_error");
747 : 0 : abort();
748 : : }
749 : :
750 : 2 : void pinpoint()
751 : : {
752 [ - + ]: 2 : if ( network_time > 0.0 )
753 : 0 : fprintf(stderr, "%.6f ", network_time);
754 : : else
755 : : {
756 [ - + ]: 2 : if ( filename )
757 : 0 : fprintf(stderr, "%s, ", filename);
758 : 2 : fprintf(stderr, "line %d: ", line_number);
759 : : }
760 : 2 : }
761 : :
762 : 16792 : int int_list_cmp(const void* v1, const void* v2)
763 : : {
764 : 16792 : ptr_compat_int i1 = *(ptr_compat_int*) v1;
765 : 16792 : ptr_compat_int i2 = *(ptr_compat_int*) v2;
766 : :
767 [ + + ]: 16792 : if ( i1 < i2 )
768 : 9226 : return -1;
769 [ - + ]: 7566 : else if ( i1 == i2 )
770 : 0 : return 0;
771 : : else
772 : 16792 : return 1;
773 : : }
774 : :
775 : 350 : const char* bro_path()
776 : : {
777 : 350 : const char* path = getenv("BROPATH");
778 [ - + ]: 350 : if ( ! path )
779 : : path = ".:"
780 : : POLICYDEST ":"
781 : : POLICYDEST "/sigs:"
782 : : POLICYDEST "/time-machine:"
783 : 0 : POLICYDEST "/site";
784 : :
785 : 350 : return path;
786 : : }
787 : :
788 : 0 : const char* bro_prefixes()
789 : : {
790 : 0 : int len = 1; // room for \0
791 [ # # ]: 0 : loop_over_list(prefixes, i)
792 : 0 : len += strlen(prefixes[i]) + 1;
793 : :
794 : 0 : char* p = new char[len];
795 : :
796 [ # # ]: 0 : loop_over_list(prefixes, j)
797 [ # # ]: 0 : if ( j == 0 )
798 : 0 : strcpy(p, prefixes[j]);
799 : : else
800 : : {
801 : 0 : strcat(p, ":");
802 : 0 : strcat(p, prefixes[j]);
803 : : }
804 : :
805 : 0 : return p;
806 : : }
807 : :
808 : 215 : FILE* open_file(const char* filename, const char** full_filename)
809 : : {
810 [ + + ]: 215 : if ( full_filename )
811 : 214 : *full_filename = copy_string(filename);
812 : :
813 : 215 : FILE* f = fopen(filename, "r");
814 : :
815 : 215 : return f;
816 : : }
817 : :
818 : : FILE* search_for_file(const char* filename, const char* ext,
819 : 350 : const char** full_filename)
820 : : {
821 [ + - ][ - + ]: 350 : if ( filename[0] == '/' || filename[0] == '.' )
822 : 0 : return open_file(filename, full_filename);
823 : :
824 : : char path[1024], full_filename_buf[1024];
825 : 350 : safe_strncpy(path, bro_path(), sizeof(path));
826 : :
827 : 350 : char* dir_beginning = path;
828 : 350 : char* dir_ending = path;
829 : 350 : int more = *dir_beginning != '\0';
830 : :
831 [ + + ]: 1692 : while ( more )
832 : : {
833 [ + + ][ + + ]: 45741 : while ( *dir_ending && *dir_ending != ':' )
834 : 44184 : ++dir_ending;
835 : :
836 [ + + ]: 1557 : if ( *dir_ending == ':' )
837 : 1422 : *dir_ending = '\0';
838 : : else
839 : 135 : more = 0;
840 : :
841 : : safe_snprintf(full_filename_buf, sizeof(full_filename_buf),
842 : 1557 : "%s/%s.%s", dir_beginning, filename, ext);
843 [ + + + - ]: 1557 : if ( access(full_filename_buf, R_OK) == 0 &&
[ + + ]
844 : : ! is_dir(full_filename_buf) )
845 : 174 : return open_file(full_filename_buf, full_filename);
846 : :
847 : : safe_snprintf(full_filename_buf, sizeof(full_filename_buf),
848 : 1383 : "%s/%s", dir_beginning, filename);
849 [ + + + - ]: 1383 : if ( access(full_filename_buf, R_OK) == 0 &&
[ + + ]
850 : : ! is_dir(full_filename_buf) )
851 : 41 : return open_file(full_filename_buf, full_filename);
852 : :
853 : 1342 : dir_beginning = ++dir_ending;
854 : : }
855 : :
856 [ + + ]: 135 : if ( full_filename )
857 : 134 : *full_filename = copy_string(filename);
858 : :
859 : 350 : return 0;
860 : : }
861 : :
862 : 0 : FILE* rotate_file(const char* name, RecordVal* rotate_info)
863 : : {
864 : : // Build file names.
865 : 0 : const int buflen = strlen(name) + 128;
866 : :
867 : 0 : char tmpname[buflen], newname[buflen+4];
868 : :
869 : : safe_snprintf(newname, buflen, "%s.%d.%.06f.tmp",
870 : 0 : name, getpid(), network_time);
871 : 0 : newname[buflen-1] = '\0';
872 : 0 : strcpy(tmpname, newname);
873 : 0 : strcat(tmpname, ".tmp");
874 : :
875 : : // First open the new file using a temporary name.
876 : 0 : FILE* newf = fopen(tmpname, "w");
877 [ # # ]: 0 : if ( ! newf )
878 : : {
879 : 0 : run_time(fmt("rotate_file: can't open %s: %s", tmpname, strerror(errno)));
880 : 0 : return 0;
881 : : }
882 : :
883 : : // Then move old file to "<name>.<pid>.<timestamp>" and make sure
884 : : // it really gets created.
885 : : struct stat dummy;
886 [ # # ][ # # ]: 0 : if ( link(name, newname) < 0 || stat(newname, &dummy) < 0 )
[ # # ]
887 : : {
888 : 0 : run_time(fmt("rotate_file: can't move %s to %s: %s", name, newname, strerror(errno)));
889 : 0 : fclose(newf);
890 : 0 : unlink(newname);
891 : 0 : unlink(tmpname);
892 : 0 : return 0;
893 : : }
894 : :
895 : : // Close current file, and move the tmp to its place.
896 [ # # ][ # # ]: 0 : if ( unlink(name) < 0 || link(tmpname, name) < 0 || unlink(tmpname) < 0 )
[ # # ][ # # ]
897 : : {
898 : 0 : run_time(fmt("rotate_file: can't move %s to %s: %s", tmpname, name, strerror(errno)));
899 : 0 : exit(1); // hard to fix, but shouldn't happen anyway...
900 : : }
901 : :
902 : : // Init rotate_info.
903 [ # # ]: 0 : if ( rotate_info )
904 : : {
905 : 0 : rotate_info->Assign(0, new StringVal(name));
906 : 0 : rotate_info->Assign(1, new StringVal(newname));
907 : 0 : rotate_info->Assign(2, new Val(network_time, TYPE_TIME));
908 : 0 : rotate_info->Assign(3, new Val(network_time, TYPE_TIME));
909 : : }
910 : :
911 : 0 : return newf;
912 : : }
913 : :
914 : 3 : const char* log_file_name(const char* tag)
915 : : {
916 : 3 : const char* env = getenv("BRO_LOG_SUFFIX");
917 [ - + ]: 3 : return fmt("%s.%s", tag, (env ? env : "log"));
918 : : }
919 : :
920 : 0 : double calc_next_rotate(double interval, const char* rotate_base_time)
921 : : {
922 : 0 : double current = network_time;
923 : :
924 : : // Calculate start of day.
925 : 0 : time_t teatime = time_t(current);
926 : :
927 : : struct tm t;
928 : 0 : t = *localtime(&teatime);
929 : 0 : t.tm_hour = t.tm_min = t.tm_sec = 0;
930 : 0 : double startofday = mktime(&t);
931 : :
932 : 0 : double base = -1;
933 : :
934 [ # # # # ]: 0 : if ( rotate_base_time && rotate_base_time[0] != '\0' )
935 : : {
936 : : struct tm t;
937 [ # # ]: 0 : if ( ! strptime(rotate_base_time, "%H:%M", &t) )
938 : 0 : run_time("calc_next_rotate(): can't parse rotation base time");
939 : : else
940 : 0 : base = t.tm_min * 60 + t.tm_hour * 60 * 60;
941 : : }
942 : :
943 [ # # ]: 0 : if ( base < 0 )
944 : : // No base time given. To get nice timestamps, we round
945 : : // the time up to the next multiple of the rotation interval.
946 : : return floor(current / interval) * interval
947 : 0 : + interval - current;
948 : :
949 : : // current < startofday + base + i * interval <= current + interval
950 : : return startofday + base +
951 : : ceil((current - startofday - base) / interval) * interval -
952 : 0 : current;
953 : : }
954 : :
955 : :
956 : : RETSIGTYPE sig_handler(int signo);
957 : :
958 : 0 : void terminate_processing()
959 : : {
960 [ # # ]: 0 : if ( ! terminating )
961 : 0 : sig_handler(SIGTERM);
962 : 0 : }
963 : :
964 : : extern const char* proc_status_file;
965 : 11 : void _set_processing_status(const char* status)
966 : : {
967 [ + - ]: 11 : if ( ! proc_status_file )
968 : 11 : return;
969 : :
970 : : // This function can be called from a signal context, so we have to
971 : : // make sure to only call reentrant functions and to restore errno
972 : : // afterwards.
973 : :
974 : 0 : int old_errno = errno;
975 : :
976 : 0 : int fd = open(proc_status_file, O_CREAT | O_WRONLY | O_TRUNC, 0700);
977 : :
978 : 0 : int len = strlen(status);
979 [ # # ]: 0 : while ( len )
980 : : {
981 : 0 : int n = write(fd, status, len);
982 : :
983 [ # # # # ]: 0 : if ( n < 0 && errno != EINTR && errno != EAGAIN )
[ # # ][ # # ]
984 : : // Ignore errors, as they're too difficult to
985 : : // safely report here.
986 : 0 : break;
987 : :
988 : 0 : status += n;
989 : 0 : len -= n;
990 : : }
991 : :
992 : 0 : close(fd);
993 : :
994 : 11 : errno = old_errno;
995 : : }
996 : :
997 : 21464 : double current_time(bool real)
998 : : {
999 : : struct timeval tv;
1000 [ - + ]: 21464 : if ( gettimeofday(&tv, 0) < 0 )
1001 : 0 : internal_error("gettimeofday failed in current_time()");
1002 : :
1003 : 21464 : double t = double(tv.tv_sec) + double(tv.tv_usec) / 1e6;
1004 : :
1005 [ - + ][ # # ]: 21464 : if ( ! pseudo_realtime || real || pkt_srcs.length() == 0 )
[ # # ][ + - ]
1006 : 21464 : return t;
1007 : :
1008 : : // This obviously only works for a single source ...
1009 : 0 : PktSrc* src = pkt_srcs[0];
1010 : :
1011 [ # # ]: 0 : if ( net_is_processing_suspended() )
1012 : 0 : return src->CurrentPacketTimestamp();
1013 : :
1014 : : // We don't scale with pseudo_realtime here as that would give us a
1015 : : // jumping real-time.
1016 : : return src->CurrentPacketTimestamp() +
1017 : 21464 : (t - src->CurrentPacketWallClock());
1018 : : }
1019 : :
1020 : 0 : struct timeval double_to_timeval(double t)
1021 : : {
1022 : : struct timeval tv;
1023 : :
1024 : 0 : double t1 = floor(t);
1025 : 0 : tv.tv_sec = int(t1);
1026 : 0 : tv.tv_usec = int((t - t1) * 1e6 + 0.5);
1027 : :
1028 : 0 : return tv;
1029 : : }
1030 : :
1031 : 0 : int time_compare(struct timeval* tv_a, struct timeval* tv_b)
1032 : : {
1033 [ # # ]: 0 : if ( tv_a->tv_sec == tv_b->tv_sec )
1034 : 0 : return tv_a->tv_usec - tv_b->tv_usec;
1035 : : else
1036 : 0 : return tv_a->tv_sec - tv_b->tv_sec;
1037 : : }
1038 : :
1039 : 0 : void out_of_memory(const char* where)
1040 : : {
1041 : 0 : fprintf( stderr, "bro: out of memory in %s.\n", where );
1042 : 0 : abort();
1043 : : }
1044 : :
1045 : 2 : void get_memory_usage(unsigned int* total, unsigned int* malloced)
1046 : : {
1047 : : unsigned int ret_total;
1048 : :
1049 : : #ifdef HAVE_MALLINFO
1050 : : // For memory, getrusage() gives bogus results on Linux. Grmpf.
1051 : : struct mallinfo mi = mallinfo();
1052 : :
1053 : : if ( malloced )
1054 : : *malloced = mi.uordblks;
1055 : :
1056 : : ret_total = mi.arena;
1057 : :
1058 : : if ( total )
1059 : : *total = ret_total;
1060 : : #else
1061 : : struct rusage r;
1062 : 2 : getrusage(RUSAGE_SELF, &r);
1063 : :
1064 [ - + ]: 2 : if ( malloced )
1065 : 0 : *malloced = 0;
1066 : :
1067 : : // At least on FreeBSD it's in KB.
1068 : 2 : ret_total = r.ru_maxrss * 1024;
1069 : :
1070 [ + - ]: 2 : if ( total )
1071 : 2 : *total = ret_total;
1072 : : #endif
1073 : :
1074 : : // return ret_total;
1075 [ + - ][ + - ]: 8 : }
1076 : 3 :
1077 : : #ifdef malloc
1078 : :
1079 : : #undef malloc
1080 : : #undef realloc
1081 : : #undef free
1082 : :
1083 : : extern "C" {
1084 : : void* malloc(size_t);
1085 : : void* realloc(void*, size_t);
1086 : : void free(void*);
1087 : : }
1088 : :
1089 : : static int malloc_debug = 0;
1090 : :
1091 : : void* debug_malloc(size_t t)
1092 : : {
1093 : : void* v = malloc(t);
1094 : : if ( malloc_debug )
1095 : : printf("%.6f malloc %x %d\n", network_time, v, t);
1096 : : return v;
1097 : : }
1098 : :
1099 : : void* debug_realloc(void* v, size_t t)
1100 : : {
1101 : : v = realloc(v, t);
1102 : : if ( malloc_debug )
1103 : : printf("%.6f realloc %x %d\n", network_time, v, t);
1104 : : return v;
1105 : : }
1106 : :
1107 : : void debug_free(void* v)
1108 : : {
1109 : : if ( malloc_debug )
1110 : : printf("%.6f free %x\n", network_time, v);
1111 : : free(v);
1112 : : }
1113 : :
1114 : : void* operator new(size_t t)
1115 : : {
1116 : : void* v = malloc(t);
1117 : : if ( malloc_debug )
1118 : : printf("%.6f new %x %d\n", network_time, v, t);
1119 : : return v;
1120 : : }
1121 : :
1122 : : void* operator new[](size_t t)
1123 : : {
1124 : : void* v = malloc(t);
1125 : : if ( malloc_debug )
1126 : : printf("%.6f new[] %x %d\n", network_time, v, t);
1127 : : return v;
1128 : : }
1129 : :
1130 : : void operator delete(void* v)
1131 : : {
1132 : : if ( malloc_debug )
1133 : : printf("%.6f delete %x\n", network_time, v);
1134 : : free(v);
1135 : : }
1136 : :
1137 : : void operator delete[](void* v)
1138 : : {
1139 : : if ( malloc_debug )
1140 : : printf("%.6f delete %x\n", network_time, v);
1141 : : free(v);
1142 : : }
1143 : :
1144 : : #endif
|