vnstat  2.9
About: vnStat is a console-based network traffic monitor (using the /proc filesystem).
  Fossies Dox: vnstat-2.9.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

daemon.c
Go to the documentation of this file.
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
14void 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));
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));
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.");
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.");
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.");
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.");
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));
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
113unsigned int addinterfaces(DSTATE *s)
114{
115 iflist *ifl = NULL, *ifl_iterator = NULL;
116 unsigned int count = 0;
117 uint32_t bwlimit = 0;
118
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 }
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);
200 return count;
201}
202
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
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
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;
266 s->dbretrycount = 0;
267 s->dcache = NULL;
268 s->prevwaldbcheckpoint = time(NULL);
269}
270
272{
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
311unsigned 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
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
360{
361 iflist *dbifl = NULL, *dbifl_iterator = NULL;
362
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));
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 */
395 } else {
396 s->updateinterval = 120;
397 }
399}
400
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 {
408 }
409}
410
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
423{
424 datacache *iterator = s->dcache;
425
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);
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 }
466
467 if (s->dodbsave) {
470 if (s->cleanuphour != getcurrenthour()) {
473 }
474 if (cfg.rescanonsave) {
476 }
477 s->dodbsave = 0;
478 }
479}
480
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
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);
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);
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
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()) {
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) {
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)) {
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)) {
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);
641 if (!db_removeinterface(iterator->interface)) {
642 if (db_errcode) {
644 }
645 }
646 break;
647 }
648 }
649 }
650
651 /* update interface timestamp in database */
652 if (!db_setupdated(iterator->interface, iterator->updated)) {
654 break;
655 }
656
657 /* update interface activity status in database */
658 if (!db_setactive(iterator->interface, iterator->active)) {
660 break;
661 }
662
663 iterator = iterator->next;
664 }
665
667 if (!db_committransaction()) {
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 {
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);
685 }
686}
687
689{
691 snprintf(errorstring, 1024, "Fatal database error detected, exiting.");
693 errorexitdaemon(s, 1);
694 } else {
696 snprintf(errorstring, 1024, "Disk is full, continuing with data caching.");
698 } else {
699 s->dbretrycount++;
700 if (s->dbretrycount > DBRETRYLIMIT) {
701 snprintf(errorstring, 1024, "Database error retry limit of %d reached, exiting.", DBRETRYLIMIT);
703 errorexitdaemon(s, 1);
704 }
705 }
706 }
707}
708
710{
711 datacache *iterator = s->dcache;
712 iflist *dbifl = NULL, *dbifl_iterator = NULL;
713
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);
728 datacache_remove(&s->dcache, dbifl_iterator->interface);
729 if (s->dbifcount > 0) {
730 s->dbifcount--;
731 }
732 dbifl_iterator = dbifl_iterator->next;
733 }
735 iflistfree(&dbifl);
736 }
738}
739
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
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);
764 if (!datacache_add(&s->dcache, dbifl_iterator->interface, 1)) {
765 snprintf(errorstring, 1024, "Cache memory allocation failed (%s), exiting.", strerror(errno));
767 errorexitdaemon(s, 1);
768 }
769 s->dbifcount++;
770 }
771 dbifl_iterator = dbifl_iterator->next;
772 }
773 if (s->dbifcount != dbifcount) {
775 }
776 iflistfree(&dbifl);
777 }
778
780}
781
783{
784 switch (intsignal) {
785
786 case SIGHUP:
787 snprintf(errorstring, 1024, "SIGHUP received, flushing data to disk and reloading config.");
791 s->dbifcount = 0;
792 ibwflush();
793 db_close();
796 if (!db_open_rw(1)) {
797 snprintf(errorstring, 1024, "Opening database after SIGHUP failed (%s), exiting.", strerror(errno));
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.");
810 s->running = 0;
811 break;
812
813 case SIGTERM:
814 snprintf(errorstring, 1024, "SIGTERM received, exiting.");
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);
829 break;
830 }
831
832 intsignal = 0;
833}
834
836{
837 /* database directory */
838 if (mkpath(cfg.dbdir, 0775)) {
840 }
841
842 if (!cfg.createdirs || !s->rundaemon) {
843 return;
844 }
845
846 /* possible pid/lock and log directory */
848 if (cfg.uselogging == 1) {
850 }
851}
852
854{
855 char buffer[1024], bwtemp[32];
856 unsigned int b = 0, count = 0;
857 uint32_t bwlimit = 0;
858 datacache *iterator = *dc;
859
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 }
890}
891
893{
894 char *ifacelist, interface[32];
895 datacache *iterator = s->dcache;
896 uint32_t newhash;
897 int offset, found;
898
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);
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);
956 }
957
958 iterator = iterator->next;
959 }
960 free(ifacelist);
961
962 s->iflisthash = newhash;
964}
965
966uint32_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
987__attribute__((noreturn)) void errorexitdaemon(DSTATE *s, const int fataldberror)
988{
989 if (!fataldberror) {
991 }
992 db_close();
993
995 ibwflush();
996
997 if (s->rundaemon && !debug) {
998 close(pidfile);
999 unlink(cfg.pidfile);
1000 }
1001
1002 exit(EXIT_FAILURE);
1003}
1004
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
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}
int loadcfg(const char *cfgfile, const ConfigType type)
Definition: cfg.c:4
@ CT_Daemon
Definition: cfg.h:15
int noexit
Definition: common.c:9
double timeused(const char *func, const int reset)
Definition: common.c:298
int intsignal
Definition: common.c:10
int disableprints
Definition: common.c:12
uint64_t countercalc(const uint64_t *a, const uint64_t *b, const short is64bit)
Definition: common.c:227
IFINFO ifinfo
Definition: common.c:5
int verifylogaccess(void)
Definition: common.c:163
void timeused_debug(const char *func, const int reset)
Definition: common.c:322
char errorstring[1024]
Definition: common.c:6
int printe(const PrintType type)
Definition: common.c:14
int debug
Definition: common.c:8
CFG cfg
Definition: common.c:4
char * strncpy_nt(char *dest, const char *src, size_t n)
Definition: common.c:253
int pidfile
Definition: common.c:11
#define SLOWDBWARNLIMIT
Definition: common.h:248
#define MAX32
Definition: common.h:214
#define __func__
Definition: common.h:51
#define DATABASEFILE
Definition: common.h:72
#define DATETIMEFORMAT
Definition: common.h:89
#define DBRETRYLIMIT
Definition: common.h:303
@ PT_Info
Definition: common.h:350
@ PT_Error
Definition: common.h:353
@ PT_Infoless
Definition: common.h:351
@ PT_Warning
Definition: common.h:352
#define BWMAX
Definition: common.h:147
void preparedatabase(DSTATE *s)
Definition: daemon.c:271
void setsignaltraps(void)
Definition: daemon.c:342
void rescandatabaseforinterfaces(DSTATE *s)
Definition: daemon.c:740
short getcurrenthour(void)
Definition: daemon.c:1005
void daemonize(void)
Definition: daemon.c:14
void datacache_status(datacache **dc)
Definition: daemon.c:853
void filldatabaselist(DSTATE *s)
Definition: daemon.c:359
void errorexitdaemon(DSTATE *s, const int fataldberror)
Definition: daemon.c:987
uint32_t simplehash(const char *data, int len)
Definition: daemon.c:966
int waittimesync(DSTATE *s)
Definition: daemon.c:1030
void interfacechangecheck(DSTATE *s)
Definition: daemon.c:892
void cleanremovedinterfaces(DSTATE *s)
Definition: daemon.c:709
void debugtimestamp(void)
Definition: daemon.c:231
void adjustsaveinterval(DSTATE *s)
Definition: daemon.c:401
int processifinfo(DSTATE *s, datacache **dc)
Definition: daemon.c:502
void initdstate(DSTATE *s)
Definition: daemon.c:241
void handleintsignals(DSTATE *s)
Definition: daemon.c:782
void preparedirs(DSTATE *s)
Definition: daemon.c:835
void detectboot(DSTATE *s)
Definition: daemon.c:203
unsigned int importlegacydbs(DSTATE *s)
Definition: daemon.c:311
void checkdbsaveneed(DSTATE *s)
Definition: daemon.c:411
void flushcachetodisk(DSTATE *s)
Definition: daemon.c:582
int initcachevalues(DSTATE *s, datacache **dc)
Definition: daemon.c:481
void processdatacache(DSTATE *s)
Definition: daemon.c:422
unsigned int addinterfaces(DSTATE *s)
Definition: daemon.c:113
void handledatabaseerror(DSTATE *s)
Definition: daemon.c:688
int datacache_count(datacache **dc)
Definition: datacache.c:78
int xferlog_add(xferlog **log, const time_t timestamp, const uint64_t rx, const uint64_t tx)
Definition: datacache.c:125
int datacache_activecount(datacache **dc)
Definition: datacache.c:90
void xferlog_clear(xferlog **log)
Definition: datacache.c:148
int datacache_remove(datacache **dc, const char *interface)
Definition: datacache.c:27
void datacache_clear(datacache **dc)
Definition: datacache.c:66
int datacache_add(datacache **dc, const char *interface, const short sync)
Definition: datacache.c:4
int importlegacydb(const char *iface, const char *dirname)
Definition: dbaccess.c:5
int db_close(void)
Definition: dbsql.c:248
int db_getiflist(iflist **ifl)
Definition: dbsql.c:766
int db_addtraffic_dated(const char *iface, const uint64_t rx, const uint64_t tx, const uint64_t timestamp)
Definition: dbsql.c:848
int db_open_rw(const int createifnotfound)
Definition: dbsql.c:16
int db_removeinterface(const char *iface)
Definition: dbsql.c:382
int db_errcode
Definition: dbsql.c:8
int db_addinterface(const char *iface)
Definition: dbsql.c:370
uint64_t db_getinterfacecount(void)
Definition: dbsql.c:414
int db_setactive(const char *iface, const int active)
Definition: dbsql.c:574
uint64_t db_getinterfacecountbyname(const char *iface)
Definition: dbsql.c:419
char * db_getinfo(const char *name)
Definition: dbsql.c:739
int db_removeoldentries(void)
Definition: dbsql.c:973
int db_isdiskfull(int errcode)
Definition: dbsql.c:1182
int db_begintransaction(void)
Definition: dbsql.c:1105
int db_setcounters(const char *iface, const uint64_t rxcounter, const uint64_t txcounter)
Definition: dbsql.c:602
int db_iserrcodefatal(int errcode)
Definition: dbsql.c:1168
int db_setupdated(const char *iface, const time_t timestamp)
Definition: dbsql.c:588
int db_setinfo(const char *name, const char *value, const int createifnotfound)
Definition: dbsql.c:722
int db_rollbacktransaction(void)
Definition: dbsql.c:1148
sqlite3 * db
Definition: dbsql.c:7
int db_intransaction
Definition: dbsql.c:9
int db_getinterfaceinfo(const char *iface, interfaceinfo *info)
Definition: dbsql.c:651
int db_committransaction(void)
Definition: dbsql.c:1124
void updatedirowner(const char *dir, const char *user, const char *group)
Definition: fs.c:143
int mkpath(const char *dir, const mode_t mode)
Definition: fs.c:24
void preparevnstatdir(const char *dir, const char *user, const char *group)
Definition: fs.c:88
void ibwflush(void)
Definition: ibw.c:182
int ibwloadcfg(const char *cfgfile)
Definition: ibw.c:6
int ibwget(const char *iface, uint32_t *limit)
Definition: ibw.c:97
int getiflist(iflist **ifl, const int getspeed, const int validate)
Definition: ifinfo.c:108
int getifliststring(char **ifacelist, int showspeed)
Definition: ifinfo.c:64
int getifinfo(const char *iface)
Definition: ifinfo.c:5
void iflistfree(iflist **ifl)
Definition: iflist.c:43
int iflistadd(iflist **ifl, const char *iface, const uint32_t bandwidth)
Definition: iflist.c:4
uint64_t getbtime(void)
Definition: misc.c:89
void sighandler(int sig)
Definition: misc.c:61
int spacecheck(const char *path)
Definition: misc.c:20
int32_t alwaysadd
Definition: common.h:318
char dbdir[512]
Definition: common.h:310
char pidfile[512]
Definition: common.h:319
int32_t saveinterval
Definition: common.h:321
int32_t trafficlessentries
Definition: common.h:315
int32_t rescanonsave
Definition: common.h:321
int32_t createdirs
Definition: common.h:322
int32_t bvar
Definition: common.h:314
int32_t savestatus
Definition: common.h:321
int32_t timesyncwait
Definition: common.h:321
int32_t uselogging
Definition: common.h:322
int32_t is64bit
Definition: common.h:316
char logfile[512]
Definition: common.h:319
int32_t offsaveinterval
Definition: common.h:321
Definition: daemon.h:4
short initdb
Definition: daemon.h:7
short dbsaved
Definition: daemon.h:7
short showhelp
Definition: daemon.h:7
time_t prevdbsave
Definition: daemon.h:13
short running
Definition: daemon.h:6
short cleanuphour
Definition: daemon.h:8
int updateinterval
Definition: daemon.h:5
int saveinterval
Definition: daemon.h:5
short dodbsave
Definition: daemon.h:6
uint64_t dbifcount
Definition: daemon.h:10
time_t current
Definition: daemon.h:13
short dbretrycount
Definition: daemon.h:8
time_t prevdbupdate
Definition: daemon.h:13
short rundaemon
Definition: daemon.h:6
char cfgfile[512]
Definition: daemon.h:11
datacache * dcache
Definition: daemon.h:14
short sync
Definition: daemon.h:7
time_t prevwaldbcheckpoint
Definition: daemon.h:13
char group[33]
Definition: daemon.h:12
char user[33]
Definition: daemon.h:12
short bootdetected
Definition: daemon.h:8
short noadd
Definition: daemon.h:7
short forcesave
Definition: daemon.h:7
uint32_t iflisthash
Definition: daemon.h:9
time_t timestamp
Definition: common.h:337
short is64bit
Definition: common.h:332
uint64_t rx
Definition: common.h:333
uint64_t tx
Definition: common.h:334
short filled
Definition: datacache.h:7
short active
Definition: datacache.h:6
uint64_t currx
Definition: datacache.h:9
time_t updated
Definition: datacache.h:10
struct xferlog * log
Definition: datacache.h:11
struct datacache * next
Definition: datacache.h:12
uint64_t curtx
Definition: datacache.h:9
char interface[32]
Definition: datacache.h:5
Definition: iflist.h:4
uint64_t rxcounter
Definition: dbsql.h:27
time_t updated
Definition: dbsql.h:26
uint64_t txtotal
Definition: dbsql.h:28
uint64_t rxtotal
Definition: dbsql.h:28
uint64_t txcounter
Definition: dbsql.h:27
struct xferlog * next
Definition: datacache.h:18
time_t timestamp
Definition: datacache.h:16
uint64_t tx
Definition: datacache.h:17
uint64_t rx
Definition: datacache.h:17