A hint: This file contains one or more very long lines, so maybe it is better readable using the pure text view mode that shows the contents as wrapped lines within the browser window.
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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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(¤t); 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 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 }