1 #include "common.h"
2 #include "ifinfo.h"
3 #include "iflist.h"
4 #include "dbsql.h"
5 #include "dbaccess.h"
6 #include "datacache.h"
7 #include "misc.h"
8 #include "cfg.h"
9 #include "ibw.h"
10 #include "fs.h"
11 #include "id.h"
12 #include "daemon.h"
13 
daemonize(void)14 void daemonize(void)
15 {
16 	int i;
17 	char str[10];
18 
19 	i = (int)fork();
20 
21 	if (i < 0) { /* fork error */
22 		perror("Error: fork");
23 		exit(EXIT_FAILURE);
24 	}
25 	if (i > 0) { /* parent exits */
26 		exit(EXIT_SUCCESS);
27 	}
28 	/* child (daemon) continues */
29 
30 	setsid(); /* obtain a new process group */
31 
32 	if (!verifylogaccess()) {
33 		printf("Error: Unable to use logfile. Exiting.\n");
34 		exit(EXIT_FAILURE);
35 	}
36 
37 	/* lock / pid file */
38 	pidfile = open(cfg.pidfile, O_RDWR | O_CREAT, 0644);
39 	if (pidfile < 0) {
40 		perror("Error: pidfile");
41 		snprintf(errorstring, 1024, "opening pidfile \"%s\" failed (%s), exiting.", cfg.pidfile, strerror(errno));
42 		printe(PT_Error);
43 		exit(EXIT_FAILURE); /* can't open */
44 	}
45 	if (lockf(pidfile, F_TLOCK, 0) < 0) {
46 		perror("Error: pidfile lock");
47 		snprintf(errorstring, 1024, "pidfile \"%s\" lock failed (%s), exiting.", cfg.pidfile, strerror(errno));
48 		printe(PT_Error);
49 		exit(EXIT_FAILURE); /* can't lock */
50 	}
51 
52 	/* close all descriptors except lock file */
53 	for (i = getdtablesize(); i >= 0; --i) {
54 		if (i != pidfile) {
55 			close(i);
56 		}
57 	}
58 
59 	/* redirect standard i/o to null */
60 	i = open("/dev/null", O_RDWR); /* stdin */
61 
62 	if (i < 0) {
63 		perror("Error: open() /dev/null");
64 		snprintf(errorstring, 1024, "open() /dev/null failed, exiting.");
65 		printe(PT_Error);
66 		exit(EXIT_FAILURE);
67 	}
68 
69 	/* stdout */
70 	if (dup(i) < 0) {
71 		perror("Error: dup(stdout)");
72 		snprintf(errorstring, 1024, "dup(stdout) failed, exiting.");
73 		printe(PT_Error);
74 		exit(EXIT_FAILURE);
75 	}
76 	/* stderr */
77 	if (dup(i) < 0) {
78 		perror("Error: dup(stderr)");
79 		snprintf(errorstring, 1024, "dup(stderr) failed, exiting.");
80 		printe(PT_Error);
81 		exit(EXIT_FAILURE);
82 	}
83 
84 	close(i);
85 
86 	umask(027); /* set newly created file permissions */
87 
88 	/* change running directory */
89 	if (chdir("/") < 0) {
90 		perror("Error: chdir(/)");
91 		snprintf(errorstring, 1024, "directory change to / failed, exiting.");
92 		printe(PT_Error);
93 		exit(EXIT_FAILURE);
94 	}
95 
96 	/* first instance continues */
97 	snprintf(str, 10, "%d\n", (int)getpid());
98 
99 	/* record pid to pidfile */
100 	if (write(pidfile, str, strlen(str)) < 0) {
101 		perror("Error: write(pidfile)");
102 		snprintf(errorstring, 1024, "writing to pidfile \"%s\" failed (%s), exiting.", cfg.pidfile, strerror(errno));
103 		printe(PT_Error);
104 		exit(EXIT_FAILURE);
105 	}
106 
107 	signal(SIGCHLD, SIG_IGN); /* ignore child */
108 	signal(SIGTSTP, SIG_IGN); /* ignore tty signals */
109 	signal(SIGTTOU, SIG_IGN);
110 	signal(SIGTTIN, SIG_IGN);
111 }
112 
addinterfaces(DSTATE * s)113 unsigned int addinterfaces(DSTATE *s)
114 {
115 	iflist *ifl = NULL, *ifl_iterator = NULL;
116 	unsigned int count = 0;
117 	uint32_t bwlimit = 0;
118 
119 	timeused_debug(__func__, 1);
120 
121 	/* get list of currently visible interfaces */
122 	if (getiflist(&ifl, 0, 1) == 0) {
123 		iflistfree(&ifl);
124 		return 0;
125 	}
126 
127 	if (ifl == NULL) {
128 		return 0;
129 	}
130 
131 	if (debug) {
132 		printf("Interface list:");
133 		ifl_iterator = ifl;
134 		while (ifl_iterator != NULL) {
135 			printf(" \"%s\"", ifl_iterator->interface);
136 			ifl_iterator = ifl_iterator->next;
137 		}
138 		printf("\n");
139 	}
140 
141 	ifl_iterator = ifl;
142 	while (ifl_iterator != NULL) {
143 		if (debug)
144 			printf("Processing: \"%s\"\n", ifl_iterator->interface);
145 
146 		/* skip already known interfaces */
147 		if (db_getinterfacecountbyname(ifl_iterator->interface)) {
148 			if (debug)
149 				printf("already known\n");
150 			ifl_iterator = ifl_iterator->next;
151 			continue;
152 		}
153 
154 		/* create database for interface */
155 		if (!db_addinterface(ifl_iterator->interface)) {
156 			if (debug)
157 				printf("add failed, skip\n");
158 			ifl_iterator = ifl_iterator->next;
159 			continue;
160 		}
161 
162 		if (!getifinfo(ifl_iterator->interface)) {
163 			if (debug)
164 				printf("getifinfo failed, skip\n");
165 			/* remove empty entry from database since the interface can't provide data */
166 			db_removeinterface(ifl_iterator->interface);
167 			ifl_iterator = ifl_iterator->next;
168 			continue;
169 		}
170 
171 		db_setcounters(ifl_iterator->interface, ifinfo.rx, ifinfo.tx);
172 
173 		count++;
174 		ibwget(ifl_iterator->interface, &bwlimit);
175 		if (bwlimit > 0) {
176 			snprintf(errorstring, 1024, "Interface \"%s\" added with %" PRIu32 " Mbit bandwidth limit.", ifl_iterator->interface, bwlimit);
177 		} else {
178 			snprintf(errorstring, 1024, "Interface \"%s\" added. Warning: no bandwidth limit has been set.", ifl_iterator->interface);
179 		}
180 		printe(PT_Infoless);
181 		if (s->running) {
182 			datacache_add(&s->dcache, ifl_iterator->interface, 1);
183 		}
184 		ifl_iterator = ifl_iterator->next;
185 	}
186 
187 	if (count && !s->running) {
188 		if (count == 1) {
189 			printf("-> %u new interface found.\n", count);
190 		} else {
191 			printf("-> %u new interfaces found.\n", count);
192 		}
193 
194 		printf("Limits can be modified using the configuration file. See \"man vnstat.conf\".\n");
195 		printf("Unwanted interfaces can be removed from monitoring with \"vnstat --remove\".\n");
196 	}
197 
198 	iflistfree(&ifl);
199 	timeused_debug(__func__, 0);
200 	return count;
201 }
202 
detectboot(DSTATE * s)203 void detectboot(DSTATE *s)
204 {
205 	char buffer[32];
206 	char *btime_buffer;
207 	uint64_t current_btime, db_btime;
208 
209 	current_btime = getbtime();
210 	btime_buffer = db_getinfo("btime");
211 
212 	if (current_btime == 0) {
213 		return;
214 	} else if (strlen(btime_buffer) == 0) {
215 		snprintf(buffer, 32, "%" PRIu64 "", current_btime);
216 		db_setinfo("btime", buffer, 1);
217 		return;
218 	}
219 	db_btime = strtoull(btime_buffer, (char **)NULL, 0);
220 
221 	if (db_btime < (current_btime - (uint32_t)cfg.bvar)) {
222 		s->bootdetected = 1;
223 		if (debug)
224 			printf("System has been booted, %" PRIu64 " < %" PRIu64 " - %d\n", db_btime, current_btime, cfg.bvar);
225 	}
226 
227 	snprintf(buffer, 32, "%" PRIu64 "", current_btime);
228 	db_setinfo("btime", buffer, 1);
229 }
230 
debugtimestamp(void)231 void debugtimestamp(void)
232 {
233 	time_t now;
234 	char timestamp[22];
235 
236 	now = time(NULL);
237 	strftime(timestamp, 22, DATETIMEFORMAT, localtime(&now));
238 	printf("%s\n", timestamp);
239 }
240 
initdstate(DSTATE * s)241 void initdstate(DSTATE *s)
242 {
243 	db = NULL;
244 	noexit = 1;		   /* disable exits in functions */
245 	debug = 0;		   /* debug disabled by default */
246 	disableprints = 0; /* let prints be visible */
247 	s->rundaemon = 0;  /* daemon disabled by default */
248 
249 	s->running = 0;
250 	s->dbsaved = 1;
251 	s->showhelp = 1;
252 	s->sync = 0;
253 	s->forcesave = 0;
254 	s->noadd = 0;
255 	s->initdb = 0;
256 	s->iflisthash = 0;
257 	s->cfgfile[0] = '\0';
258 	s->user[0] = '\0';
259 	s->group[0] = '\0';
260 	s->prevdbupdate = 0;
261 	s->prevdbsave = 0;
262 	s->dbifcount = 0;
263 	s->dodbsave = 0;
264 	s->bootdetected = 0;
265 	s->cleanuphour = getcurrenthour();
266 	s->dbretrycount = 0;
267 	s->dcache = NULL;
268 	s->prevwaldbcheckpoint = time(NULL);
269 }
270 
preparedatabase(DSTATE * s)271 void preparedatabase(DSTATE *s)
272 {
273 	s->dbifcount = db_getinterfacecount();
274 
275 	if (s->dbifcount > 0 && !cfg.alwaysadd) {
276 		s->dbifcount = 0;
277 		return;
278 	}
279 
280 	if (debug) {
281 		printf("db if count: %" PRIu64 "\n", s->dbifcount);
282 	}
283 
284 	if (s->noadd) {
285 		printf("No interfaces found in database, exiting.\n");
286 		exit(EXIT_FAILURE);
287 	}
288 
289 	if (!spacecheck(cfg.dbdir)) {
290 		printf("Error: Not enough free diskspace available, exiting.\n");
291 		exit(EXIT_FAILURE);
292 	}
293 
294 	if (s->dbifcount == 0) {
295 		if (importlegacydbs(s) && !cfg.alwaysadd) {
296 			s->dbifcount = 0;
297 			return;
298 		}
299 		printf("No interfaces found in database, adding available interfaces...\n");
300 	}
301 
302 	if (!addinterfaces(s) && s->dbifcount == 0) {
303 		printf("Nothing to do, exiting.\n");
304 		exit(EXIT_FAILURE);
305 	}
306 
307 	/* set counter back to zero so that dbs will be cached later */
308 	s->dbifcount = 0;
309 }
310 
importlegacydbs(DSTATE * s)311 unsigned int importlegacydbs(DSTATE *s)
312 {
313 	DIR *dir;
314 	struct dirent *di;
315 	unsigned int importcount = 0;
316 
317 	if ((dir = opendir(cfg.dbdir)) == NULL) {
318 		printf("Error: Unable to open database directory \"%s\": %s\n", cfg.dbdir, strerror(errno));
319 		printf("Make sure it exists and is at least read enabled for current user.\n");
320 		printf("Exiting...\n");
321 		exit(EXIT_FAILURE);
322 	}
323 
324 	s->dbifcount = 0;
325 	while ((di = readdir(dir))) {
326 		if ((di->d_name[0] != '.') && (strncmp(di->d_name, DATABASEFILE, strlen(DATABASEFILE)) != 0)) {
327 			/* ignore already known interfaces */
328 			if (db_getinterfacecountbyname(di->d_name)) {
329 				continue;
330 			}
331 			if (importlegacydb(di->d_name, cfg.dbdir)) {
332 				importcount++;
333 			}
334 		}
335 	}
336 	closedir(dir);
337 
338 	s->dbifcount += importcount;
339 	return importcount;
340 }
341 
setsignaltraps(void)342 void setsignaltraps(void)
343 {
344 	intsignal = 0;
345 	if (signal(SIGINT, sighandler) == SIG_ERR) {
346 		perror("Error: signal SIGINT");
347 		exit(EXIT_FAILURE);
348 	}
349 	if (signal(SIGHUP, sighandler) == SIG_ERR) {
350 		perror("Error: signal SIGHUP");
351 		exit(EXIT_FAILURE);
352 	}
353 	if (signal(SIGTERM, sighandler) == SIG_ERR) {
354 		perror("Error: signal SIGTERM");
355 		exit(EXIT_FAILURE);
356 	}
357 }
358 
filldatabaselist(DSTATE * s)359 void filldatabaselist(DSTATE *s)
360 {
361 	iflist *dbifl = NULL, *dbifl_iterator = NULL;
362 
363 	timeused_debug(__func__, 1);
364 
365 	if (db_getiflist(&dbifl) < 0) {
366 		errorexitdaemon(s, 1);
367 	}
368 
369 	dbifl_iterator = dbifl;
370 
371 	while (dbifl_iterator != NULL) {
372 		if (debug) {
373 			printf("\nProcessing interface \"%s\"...\n", dbifl_iterator->interface);
374 		}
375 		if (!datacache_add(&s->dcache, dbifl_iterator->interface, s->sync)) {
376 			snprintf(errorstring, 1024, "Cache memory allocation failed (%s), exiting.", strerror(errno));
377 			printe(PT_Error);
378 			errorexitdaemon(s, 1);
379 		}
380 		s->dbifcount++;
381 		dbifl_iterator = dbifl_iterator->next;
382 	}
383 
384 	iflistfree(&dbifl);
385 	s->sync = 0;
386 
387 	/* disable update interval check for one loop if database list was refreshed */
388 	/* otherwise increase default update interval since there's nothing else to do */
389 	if (s->dbifcount) {
390 		s->updateinterval = 0;
391 		intsignal = 42;
392 		s->prevdbsave = s->current;
393 		/* list monitored interfaces to log */
394 		datacache_status(&s->dcache);
395 	} else {
396 		s->updateinterval = 120;
397 	}
398 	timeused_debug(__func__, 0);
399 }
400 
adjustsaveinterval(DSTATE * s)401 void adjustsaveinterval(DSTATE *s)
402 {
403 	/* modify active save interval if all interfaces are unavailable */
404 	if (datacache_activecount(&s->dcache) > 0) {
405 		s->saveinterval = cfg.saveinterval * 60;
406 	} else {
407 		s->saveinterval = cfg.offsaveinterval * 60;
408 	}
409 }
410 
checkdbsaveneed(DSTATE * s)411 void checkdbsaveneed(DSTATE *s)
412 {
413 	if ((s->current - s->prevdbsave) >= (s->saveinterval) || s->forcesave) {
414 		s->dodbsave = 1;
415 		s->forcesave = 0;
416 		s->prevdbsave = s->current - (s->current % s->saveinterval);
417 	} else {
418 		s->dodbsave = 0;
419 	}
420 }
421 
processdatacache(DSTATE * s)422 void processdatacache(DSTATE *s)
423 {
424 	datacache *iterator = s->dcache;
425 
426 	timeused_debug(__func__, 1);
427 
428 	while (iterator != NULL) {
429 
430 		if (debug) {
431 			printf("dc: processing %s (%d)...\n", iterator->interface, s->dodbsave);
432 		}
433 
434 		if (!iterator->filled) {
435 			if (!initcachevalues(s, &iterator)) {
436 				iterator = iterator->next;
437 				continue;
438 			}
439 			s->iflisthash = 0;
440 		}
441 
442 		if (iterator->active) {
443 			if (!getifinfo(iterator->interface)) {
444 				/* disable interface since we can't access its data */
445 				iterator->active = 0;
446 				snprintf(errorstring, 1024, "Interface \"%s\" not available, disabling.", iterator->interface);
447 				printe(PT_Info);
448 			} else {
449 				if (!processifinfo(s, &iterator)) {
450 					iterator = iterator->next;
451 					continue;
452 				}
453 			}
454 		} else {
455 			if (debug)
456 				printf("dc: interface is disabled\n");
457 		}
458 
459 		iterator = iterator->next;
460 	}
461 
462 	if (s->bootdetected) {
463 		s->bootdetected = 0;
464 	}
465 	timeused_debug(__func__, 0);
466 
467 	if (s->dodbsave) {
468 		flushcachetodisk(s);
469 		cleanremovedinterfaces(s);
470 		if (s->cleanuphour != getcurrenthour()) {
471 			db_removeoldentries();
472 			s->cleanuphour = getcurrenthour();
473 		}
474 		if (cfg.rescanonsave) {
475 			rescandatabaseforinterfaces(s);
476 		}
477 		s->dodbsave = 0;
478 	}
479 }
480 
initcachevalues(DSTATE * s,datacache ** dc)481 int initcachevalues(DSTATE *s, datacache **dc)
482 {
483 	interfaceinfo info;
484 
485 	if (!db_getinterfaceinfo((*dc)->interface, &info)) {
486 		return 0;
487 	}
488 
489 	if (s->bootdetected) {
490 		(*dc)->currx = 0;
491 		(*dc)->curtx = 0;
492 	} else {
493 		(*dc)->currx = info.rxcounter;
494 		(*dc)->curtx = info.txcounter;
495 	}
496 	(*dc)->updated = info.updated;
497 	(*dc)->filled = 1;
498 
499 	return 1;
500 }
501 
processifinfo(DSTATE * s,datacache ** dc)502 int processifinfo(DSTATE *s, datacache **dc)
503 {
504 	uint64_t rxchange, txchange;
505 	uint64_t maxtransfer;
506 	uint32_t maxbw;
507 	time_t interval;
508 	short detected64bit = 0;
509 
510 	if ((*dc)->syncneeded) { /* if --sync was used during startup */
511 		(*dc)->currx = ifinfo.rx;
512 		(*dc)->curtx = ifinfo.tx;
513 		(*dc)->syncneeded = 0;
514 		return 1;
515 	}
516 
517 	if ((*dc)->updated > ifinfo.timestamp) {
518 		/* skip update if previous update is less than a day in the future */
519 		/* otherwise exit with error message since the clock is probably messed */
520 		if ((*dc)->updated > (ifinfo.timestamp + 86400)) {
521 			snprintf(errorstring, 1024, "Interface \"%s\" has previous update date too much in the future, exiting. (%u / %u)", (*dc)->interface, (unsigned int)(*dc)->updated, (unsigned int)ifinfo.timestamp);
522 			printe(PT_Error);
523 			errorexitdaemon(s, 1);
524 		}
525 		return 0;
526 	}
527 
528 	interval = ifinfo.timestamp - (*dc)->updated;
529 	/* maximum configurable update interval is 5 minutes, limit here is set to 6 minutes (360 seconds) */
530 	/* in order to be on the safe side and avoid discarding data in case there's some random extra delay */
531 	if ((interval >= 1) && (interval <= 360)) {
532 
533 		if ((*dc)->currx > MAX32 || (*dc)->curtx > MAX32 || ifinfo.rx > MAX32 || ifinfo.tx > MAX32) {
534 			ifinfo.is64bit = 1;
535 			detected64bit = 1;
536 		}
537 
538 		rxchange = countercalc(&(*dc)->currx, &ifinfo.rx, ifinfo.is64bit);
539 		txchange = countercalc(&(*dc)->curtx, &ifinfo.tx, ifinfo.is64bit);
540 
541 		/* workaround for interface drivers using only 32-bit range with 64-bit interface counters, */
542 		/* active only when automatic detection is enabled and all values are within 32-bit range */
543 		if (cfg.is64bit == -2 || !detected64bit) {
544 			if ((rxchange / (uint64_t)interval / 1024 / 1024 * 8) > BWMAX || (txchange / (uint64_t)interval / 1024 / 1024 * 8) > BWMAX) {
545 				ifinfo.is64bit = 0;
546 				rxchange = countercalc(&(*dc)->currx, &ifinfo.rx, 0);
547 				txchange = countercalc(&(*dc)->curtx, &ifinfo.tx, 0);
548 			}
549 		}
550 
551 		/* get bandwidth limit for current interface */
552 		ibwget((*dc)->interface, &maxbw);
553 
554 		if (maxbw > 0) {
555 
556 			/* calculate maximum possible transfer since last update based on set maximum rate */
557 			/* and add 2% in order to be on the safe side */
558 			maxtransfer = (uint64_t)(ceilf(((float)maxbw / (float)8) * (float)interval * (float)1.02)) * 1024 * 1024;
559 
560 			if (debug)
561 				printf("interval: %" PRIu64 "  maxbw: %" PRIu32 "  maxrate: %" PRIu64 "  rxc: %" PRIu64 "  txc: %" PRIu64 "\n", (uint64_t)interval, maxbw, maxtransfer, rxchange, txchange);
562 
563 			/* sync counters if traffic is greater than set maximum */
564 			if ((rxchange > maxtransfer) || (txchange > maxtransfer)) {
565 				snprintf(errorstring, 1024, "Traffic rate for \"%s\" higher than set maximum %" PRIu32 " Mbit (%" PRIu64 "s->%" PRIu64 ", r%" PRIu64 " t%" PRIu64 ", 64bit:%d), syncing.", (*dc)->interface, maxbw, (uint64_t)interval, maxtransfer, rxchange, txchange, ifinfo.is64bit);
566 				printe(PT_Info);
567 				rxchange = txchange = 0;
568 			}
569 		}
570 
571 		if (rxchange || txchange || cfg.trafficlessentries) {
572 			xferlog_add(&(*dc)->log, (*dc)->updated - ((*dc)->updated % 300), rxchange, txchange);
573 		}
574 	}
575 	(*dc)->currx = ifinfo.rx;
576 	(*dc)->curtx = ifinfo.tx;
577 	(*dc)->updated = ifinfo.timestamp;
578 
579 	return 1;
580 }
581 
flushcachetodisk(DSTATE * s)582 void flushcachetodisk(DSTATE *s)
583 {
584 	int ret;
585 	double used_secs = 0.0;
586 	uint32_t logcount = 0;
587 	datacache *iterator = s->dcache;
588 	xferlog *logiterator;
589 	interfaceinfo info;
590 
591 	timeused(__func__, 1);
592 
593 	if (!db_begintransaction()) {
594 		handledatabaseerror(s);
595 		return;
596 	}
597 
598 	db_errcode = 0;
599 	while (iterator != NULL) {
600 		/* ignore interface no longer in database */
601 		if (!db_getinterfacecountbyname(iterator->interface)) {
602 			if (db_errcode) {
603 				handledatabaseerror(s);
604 				break;
605 			} else {
606 				iterator = iterator->next;
607 				continue;
608 			}
609 		}
610 
611 		/* flush interface specific log to database */
612 		logcount = 0;
613 		logiterator = iterator->log;
614 		while (logiterator != NULL) {
615 			if (!db_addtraffic_dated(iterator->interface, logiterator->rx, logiterator->tx, (uint64_t)logiterator->timestamp)) {
616 				handledatabaseerror(s);
617 				break;
618 			}
619 			logiterator = logiterator->next;
620 			logcount++;
621 		}
622 		if (db_errcode) {
623 			break;
624 		}
625 
626 		/* update database counters if new data was inserted */
627 		if (logcount) {
628 			if (!db_setcounters(iterator->interface, iterator->currx, iterator->curtx)) {
629 				handledatabaseerror(s);
630 				break;
631 			}
632 		}
633 
634 		if (!iterator->active && !logcount) {
635 			/* throw away if interface hasn't seen any data and is disabled */
636 			if (!iterator->currx && !iterator->curtx) {
637 				ret = db_getinterfaceinfo(iterator->interface, &info);
638 				if (!ret || (!info.rxtotal && !info.txtotal)) {
639 					snprintf(errorstring, 1024, "Removing interface \"%s\" from database as it is disabled and has seen no data.", iterator->interface);
640 					printe(PT_Info);
641 					if (!db_removeinterface(iterator->interface)) {
642 						if (db_errcode) {
643 							handledatabaseerror(s);
644 						}
645 					}
646 					break;
647 				}
648 			}
649 		}
650 
651 		/* update interface timestamp in database */
652 		if (!db_setupdated(iterator->interface, iterator->updated)) {
653 			handledatabaseerror(s);
654 			break;
655 		}
656 
657 		/* update interface activity status in database */
658 		if (!db_setactive(iterator->interface, iterator->active)) {
659 			handledatabaseerror(s);
660 			break;
661 		}
662 
663 		iterator = iterator->next;
664 	}
665 
666 	if (db_intransaction && !db_errcode) {
667 		if (!db_committransaction()) {
668 			handledatabaseerror(s);
669 		} else {
670 			/* clear xferlog now that everything is in database */
671 			iterator = s->dcache;
672 			while (iterator != NULL) {
673 				xferlog_clear(&iterator->log);
674 				iterator = iterator->next;
675 			}
676 			s->dbretrycount = 0;
677 		}
678 	} else {
679 		db_rollbacktransaction();
680 	}
681 	used_secs = timeused(__func__, 0);
682 	if (used_secs > SLOWDBWARNLIMIT) {
683 		snprintf(errorstring, 1024, "Writing cached data to database took %.1f seconds.", used_secs);
684 		printe(PT_Warning);
685 	}
686 }
687 
handledatabaseerror(DSTATE * s)688 void handledatabaseerror(DSTATE *s)
689 {
690 	if (db_iserrcodefatal(db_errcode)) {
691 		snprintf(errorstring, 1024, "Fatal database error detected, exiting.");
692 		printe(PT_Error);
693 		errorexitdaemon(s, 1);
694 	} else {
695 		if (db_isdiskfull(db_errcode)) {
696 			snprintf(errorstring, 1024, "Disk is full, continuing with data caching.");
697 			printe(PT_Error);
698 		} else {
699 			s->dbretrycount++;
700 			if (s->dbretrycount > DBRETRYLIMIT) {
701 				snprintf(errorstring, 1024, "Database error retry limit of %d reached, exiting.", DBRETRYLIMIT);
702 				printe(PT_Error);
703 				errorexitdaemon(s, 1);
704 			}
705 		}
706 	}
707 }
708 
cleanremovedinterfaces(DSTATE * s)709 void cleanremovedinterfaces(DSTATE *s)
710 {
711 	datacache *iterator = s->dcache;
712 	iflist *dbifl = NULL, *dbifl_iterator = NULL;
713 
714 	timeused_debug(__func__, 1);
715 
716 	while (iterator != NULL) {
717 		if (!db_getinterfacecountbyname(iterator->interface)) {
718 			iflistadd(&dbifl, iterator->interface, 0);
719 		}
720 		iterator = iterator->next;
721 	}
722 
723 	if (dbifl != NULL) {
724 		dbifl_iterator = dbifl;
725 		while (dbifl_iterator != NULL) {
726 			snprintf(errorstring, 1024, "Interface \"%s\" no longer in database, stopping monitoring.", dbifl_iterator->interface);
727 			printe(PT_Info);
728 			datacache_remove(&s->dcache, dbifl_iterator->interface);
729 			if (s->dbifcount > 0) {
730 				s->dbifcount--;
731 			}
732 			dbifl_iterator = dbifl_iterator->next;
733 		}
734 		datacache_status(&s->dcache);
735 		iflistfree(&dbifl);
736 	}
737 	timeused_debug(__func__, 0);
738 }
739 
rescandatabaseforinterfaces(DSTATE * s)740 void rescandatabaseforinterfaces(DSTATE *s)
741 {
742 	short interface_already_monitored = 0;
743 	uint64_t dbifcount = s->dbifcount;
744 	datacache *iterator = NULL;
745 	iflist *dbifl = NULL, *dbifl_iterator = NULL;
746 
747 	timeused_debug(__func__, 1);
748 
749 	if (db_getiflist(&dbifl) > 0 && dbifl != NULL) {
750 		dbifl_iterator = dbifl;
751 		while (dbifl_iterator != NULL) {
752 			iterator = s->dcache;
753 			interface_already_monitored = 0;
754 			while (iterator != NULL) {
755 				if (strcmp(iterator->interface, dbifl_iterator->interface) == 0) {
756 					interface_already_monitored = 1;
757 					break;
758 				}
759 				iterator = iterator->next;
760 			}
761 			if (!interface_already_monitored) {
762 				snprintf(errorstring, 1024, "Interface \"%s\" found from database, starting monitoring.", dbifl_iterator->interface);
763 				printe(PT_Info);
764 				if (!datacache_add(&s->dcache, dbifl_iterator->interface, 1)) {
765 					snprintf(errorstring, 1024, "Cache memory allocation failed (%s), exiting.", strerror(errno));
766 					printe(PT_Error);
767 					errorexitdaemon(s, 1);
768 				}
769 				s->dbifcount++;
770 			}
771 			dbifl_iterator = dbifl_iterator->next;
772 		}
773 		if (s->dbifcount != dbifcount) {
774 			datacache_status(&s->dcache);
775 		}
776 		iflistfree(&dbifl);
777 	}
778 
779 	timeused_debug(__func__, 0);
780 }
781 
handleintsignals(DSTATE * s)782 void handleintsignals(DSTATE *s)
783 {
784 	switch (intsignal) {
785 
786 		case SIGHUP:
787 			snprintf(errorstring, 1024, "SIGHUP received, flushing data to disk and reloading config.");
788 			printe(PT_Info);
789 			flushcachetodisk(s);
790 			datacache_clear(&s->dcache);
791 			s->dbifcount = 0;
792 			ibwflush();
793 			db_close();
794 			loadcfg(s->cfgfile, CT_Daemon);
795 			ibwloadcfg(s->cfgfile);
796 			if (!db_open_rw(1)) {
797 				snprintf(errorstring, 1024, "Opening database after SIGHUP failed (%s), exiting.", strerror(errno));
798 				printe(PT_Error);
799 				if (s->rundaemon && !debug) {
800 					close(pidfile);
801 					unlink(cfg.pidfile);
802 				}
803 				exit(EXIT_FAILURE);
804 			}
805 			break;
806 
807 		case SIGINT:
808 			snprintf(errorstring, 1024, "SIGINT received, exiting.");
809 			printe(PT_Info);
810 			s->running = 0;
811 			break;
812 
813 		case SIGTERM:
814 			snprintf(errorstring, 1024, "SIGTERM received, exiting.");
815 			printe(PT_Info);
816 			s->running = 0;
817 			break;
818 
819 		/* from filldatabaselist() */
820 		case 42:
821 			break;
822 
823 		case 0:
824 			break;
825 
826 		default:
827 			snprintf(errorstring, 1024, "Unknown signal %d received, ignoring.", intsignal);
828 			printe(PT_Info);
829 			break;
830 	}
831 
832 	intsignal = 0;
833 }
834 
preparedirs(DSTATE * s)835 void preparedirs(DSTATE *s)
836 {
837 	/* database directory */
838 	if (mkpath(cfg.dbdir, 0775)) {
839 		updatedirowner(cfg.dbdir, s->user, s->group);
840 	}
841 
842 	if (!cfg.createdirs || !s->rundaemon) {
843 		return;
844 	}
845 
846 	/* possible pid/lock and log directory */
847 	preparevnstatdir(cfg.pidfile, s->user, s->group);
848 	if (cfg.uselogging == 1) {
849 		preparevnstatdir(cfg.logfile, s->user, s->group);
850 	}
851 }
852 
datacache_status(datacache ** dc)853 void datacache_status(datacache **dc)
854 {
855 	char buffer[1024], bwtemp[32];
856 	unsigned int b = 0, count = 0;
857 	uint32_t bwlimit = 0;
858 	datacache *iterator = *dc;
859 
860 	timeused_debug(__func__, 1);
861 
862 	snprintf(buffer, 1024, "Monitoring (%d): ", datacache_count(dc));
863 	b = (unsigned int)strlen(buffer) + 1;
864 
865 	while (iterator != NULL) {
866 		if ((b + strlen(iterator->interface) + 32) < 1020) {
867 			if (!ibwget(iterator->interface, &bwlimit) || bwlimit == 0) {
868 				snprintf(bwtemp, 32, " (no limit) ");
869 			} else {
870 				snprintf(bwtemp, 32, " (%" PRIu32 " Mbit) ", bwlimit);
871 			}
872 			strcat(buffer, iterator->interface);
873 			strcat(buffer, bwtemp);
874 			b += strlen(iterator->interface) + strlen(bwtemp);
875 		} else {
876 			strcat(buffer, "...");
877 			break;
878 		}
879 		count++;
880 		iterator = iterator->next;
881 	}
882 
883 	if (count) {
884 		strncpy_nt(errorstring, buffer, 1024);
885 	} else {
886 		snprintf(errorstring, 1024, "Nothing to monitor");
887 	}
888 	printe(PT_Info);
889 	timeused_debug(__func__, 0);
890 }
891 
interfacechangecheck(DSTATE * s)892 void interfacechangecheck(DSTATE *s)
893 {
894 	char *ifacelist, interface[32];
895 	datacache *iterator = s->dcache;
896 	uint32_t newhash;
897 	int offset, found;
898 
899 	timeused_debug(__func__, 1);
900 
901 	/* get list of currently visible interfaces */
902 	if (getifliststring(&ifacelist, 0) == 0) {
903 		free(ifacelist);
904 		s->iflisthash = 0;
905 		return;
906 	}
907 
908 	newhash = simplehash(ifacelist, (int)strlen(ifacelist));
909 
910 	if (s->iflisthash == newhash) {
911 		free(ifacelist);
912 		return;
913 	}
914 
915 	/* search for changes if hash doesn't match */
916 	if (debug) {
917 		printf("ifacelist changed: '%s'    %u <> %u\n", ifacelist, s->iflisthash, newhash);
918 	}
919 
920 	while (iterator != NULL) {
921 
922 		if (!iterator->filled) {
923 			iterator = iterator->next;
924 			continue;
925 		}
926 
927 		found = offset = 0;
928 
929 		while (offset <= (int)strlen(ifacelist)) {
930 			sscanf(ifacelist + offset, "%31s", interface);
931 			if (strcmp(iterator->interface, interface) == 0) {
932 				found = 1;
933 				break;
934 			}
935 			offset += (int)strlen(interface) + 1;
936 		}
937 
938 		if (iterator->active == 1 && found == 0) {
939 			iterator->active = 0;
940 			iterator->currx = 0;
941 			iterator->curtx = 0;
942 			if (cfg.savestatus) {
943 				s->forcesave = 1;
944 			}
945 			snprintf(errorstring, 1024, "Interface \"%s\" disabled.", iterator->interface);
946 			printe(PT_Info);
947 		} else if (iterator->active == 0 && found == 1) {
948 			iterator->active = 1;
949 			iterator->currx = 0;
950 			iterator->curtx = 0;
951 			if (cfg.savestatus) {
952 				s->forcesave = 1;
953 			}
954 			snprintf(errorstring, 1024, "Interface \"%s\" enabled.", iterator->interface);
955 			printe(PT_Info);
956 		}
957 
958 		iterator = iterator->next;
959 	}
960 	free(ifacelist);
961 
962 	s->iflisthash = newhash;
963 	timeused_debug(__func__, 0);
964 }
965 
simplehash(const char * data,int len)966 uint32_t simplehash(const char *data, int len)
967 {
968 	uint32_t hash;
969 
970 	if (len <= 0 || data == NULL) {
971 		return 0;
972 	}
973 
974 	hash = (uint32_t)len;
975 
976 	for (len--; len >= 0; len--) {
977 		if (len > 0) {
978 			hash += (uint32_t)data[len] * (uint32_t)len;
979 		} else {
980 			hash += (uint32_t)data[len];
981 		}
982 	}
983 
984 	return hash;
985 }
986 
errorexitdaemon(DSTATE * s,const int fataldberror)987 __attribute__((noreturn)) void errorexitdaemon(DSTATE *s, const int fataldberror)
988 {
989 	if (!fataldberror) {
990 		flushcachetodisk(s);
991 	}
992 	db_close();
993 
994 	datacache_clear(&s->dcache);
995 	ibwflush();
996 
997 	if (s->rundaemon && !debug) {
998 		close(pidfile);
999 		unlink(cfg.pidfile);
1000 	}
1001 
1002 	exit(EXIT_FAILURE);
1003 }
1004 
getcurrenthour(void)1005 short getcurrenthour(void)
1006 {
1007 	int ret = 0;
1008 	time_t current;
1009 	struct tm *stm;
1010 	char buffer[4];
1011 
1012 	current = time(NULL);
1013 	stm = localtime(&current);
1014 	if (stm == NULL) {
1015 		return 0;
1016 	}
1017 
1018 	if (!strftime(buffer, sizeof(buffer), "%H", stm)) {
1019 		return 0;
1020 	}
1021 
1022 	ret = atoi(buffer);
1023 	if (ret > 23 || ret < 0) {
1024 		ret = 0;
1025 	}
1026 
1027 	return (short)ret;
1028 }
1029 
waittimesync(DSTATE * s)1030 int waittimesync(DSTATE *s)
1031 {
1032 	datacache *iterator = s->dcache;
1033 	char timestamp[22], timestamp2[22];
1034 
1035 	if (cfg.timesyncwait == 0) {
1036 		return 0;
1037 	}
1038 
1039 	if (s->prevdbupdate == 0 && s->prevdbsave == 0) {
1040 		while (iterator != NULL) {
1041 			if (debug) {
1042 				printf("w: processing %s...\n", iterator->interface);
1043 			}
1044 
1045 			if (!iterator->filled) {
1046 				if (!initcachevalues(s, &iterator)) {
1047 					iterator = iterator->next;
1048 					continue;
1049 				}
1050 				s->iflisthash = 0;
1051 			}
1052 
1053 			if (debug) {
1054 				strftime(timestamp, 22, DATETIMEFORMAT, localtime(&iterator->updated));
1055 				printf("w: has %s\n", timestamp);
1056 			}
1057 			if (iterator->updated > s->prevdbsave) {
1058 				s->prevdbsave = iterator->updated;
1059 			}
1060 			iterator = iterator->next;
1061 		}
1062 		if (s->prevdbsave == 0) {
1063 			snprintf(errorstring, 1024, "Couldn't define when database was last updated. Continuing, some errors may follow.");
1064 			printe(PT_Info);
1065 			return 0;
1066 		}
1067 	}
1068 
1069 	s->current = time(NULL);
1070 
1071 	if (debug) {
1072 		strftime(timestamp, 22, DATETIMEFORMAT, localtime(&s->current));
1073 		printf("current time:     %s\n", timestamp);
1074 		strftime(timestamp2, 22, DATETIMEFORMAT, localtime(&s->prevdbsave));
1075 		printf("latest db update: %s\n", timestamp2);
1076 	}
1077 
1078 	if (s->current < s->prevdbsave) {
1079 		if (s->prevdbupdate == 0) {
1080 			s->prevdbupdate = s->current;
1081 			strftime(timestamp, 22, DATETIMEFORMAT, localtime(&s->current));
1082 			strftime(timestamp2, 22, DATETIMEFORMAT, localtime(&s->prevdbsave));
1083 			snprintf(errorstring, 1024, "Latest database update is in the future (db: %s > now: %s). Giving the system clock up to %d minutes to sync before continuing.", timestamp2, timestamp, cfg.timesyncwait);
1084 			printe(PT_Info);
1085 		}
1086 		if (s->current - s->prevdbupdate >= cfg.timesyncwait * 60) {
1087 			strftime(timestamp, 22, DATETIMEFORMAT, localtime(&s->current));
1088 			strftime(timestamp2, 22, DATETIMEFORMAT, localtime(&s->prevdbsave));
1089 			snprintf(errorstring, 1024, "Latest database update is still in the future (db: %s > now: %s), continuing. Some errors may follow.", timestamp2, timestamp);
1090 			printe(PT_Info);
1091 			return 0;
1092 		}
1093 	} else {
1094 		if (s->prevdbupdate != 0) {
1095 			strftime(timestamp, 22, DATETIMEFORMAT, localtime(&s->current));
1096 			strftime(timestamp2, 22, DATETIMEFORMAT, localtime(&s->prevdbsave));
1097 			snprintf(errorstring, 1024, "Latest database update is no longer in the future (db: %s <= now: %s), continuing.", timestamp2, timestamp);
1098 			printe(PT_Info);
1099 		}
1100 		s->prevdbsave = s->current;
1101 		s->prevdbupdate = 0;
1102 		if (debug) {
1103 			printf("time sync ok\n\n");
1104 		}
1105 		return 0;
1106 	}
1107 
1108 	return 1;
1109 }
1110