"Fossies" - the Fresh Open Source Software Archive

Member "vnstat-2.9/src/daemon.c" (27 Aug 2021, 27512 Bytes) of package /linux/misc/vnstat-2.9.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "daemon.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.7_vs_2.8.

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(&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 
 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 }