"Fossies" - the Fresh Open Source Software Archive

Member "vnstat-2.9/src/vnstatd.c" (23 Jan 2022, 11462 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 "vnstatd.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.8_vs_2.9.

    1 /*
    2 vnStat daemon - Copyright (C) 2008-2022 Teemu Toivola <tst@iki.fi>
    3 
    4    This program is free software; you can redistribute it and/or modify
    5    it under the terms of the GNU General Public License as published by
    6    the Free Software Foundation; version 2 dated June, 1991.
    7 
    8    This program is distributed in the hope that it will be useful,
    9    but WITHOUT ANY WARRANTY; without even the implied warranty of
   10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   11    GNU General Public License for more details.
   12 
   13    You should have received a copy of the GNU General Public License along
   14    with this program; if not, write to the Free Software Foundation, Inc.,
   15    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   16 */
   17 
   18 #include "common.h"
   19 #include "datacache.h"
   20 #include "dbsql.h"
   21 #include "cfg.h"
   22 #include "ibw.h"
   23 #include "id.h"
   24 #include "misc.h"
   25 #include "daemon.h"
   26 #include "vnstatd.h"
   27 
   28 int main(int argc, char *argv[])
   29 {
   30     int currentarg;
   31     uint32_t previflisthash;
   32     uint64_t temp;
   33     DSTATE s;
   34 
   35     initdstate(&s);
   36 
   37     /* early check for debug and config parameter */
   38     if (argc > 1) {
   39         for (currentarg = 1; currentarg < argc; currentarg++) {
   40             if ((strcmp(argv[currentarg], "-D") == 0) || (strcmp(argv[currentarg], "--debug") == 0)) {
   41                 debug = 1;
   42                 printf("Debug enabled, vnstatd %s\n", VERSION);
   43             } else if (strcmp(argv[currentarg], "--config") == 0) {
   44                 if (currentarg + 1 < argc) {
   45                     strncpy_nt(s.cfgfile, argv[currentarg + 1], 512);
   46                     if (debug)
   47                         printf("Used config file: %s\n", s.cfgfile);
   48                     currentarg++;
   49                 } else {
   50                     printf("Error: File for --config missing.\n");
   51                     return 1;
   52                 }
   53             }
   54         }
   55     }
   56 
   57     timeused_debug("daemon_startup", 1);
   58 
   59     /* load config if available */
   60     if (!loadcfg(s.cfgfile, CT_Daemon)) {
   61         return 1;
   62     }
   63     if (!ibwloadcfg(s.cfgfile)) {
   64         return 1;
   65     }
   66 
   67     /* init config settings */
   68     strncpy_nt(s.user, cfg.daemonuser, 33);
   69     strncpy_nt(s.group, cfg.daemongroup, 33);
   70     s.updateinterval = cfg.updateinterval;
   71     s.saveinterval = cfg.saveinterval * 60;
   72 
   73     parseargs(&s, argc, argv);
   74 
   75     preparedirs(&s);
   76 
   77     /* set user and/or group if requested */
   78     setgroup(s.group);
   79     setuser(s.user);
   80 
   81     if (!db_open_rw(1)) {
   82         printf("Error: Failed to open database \"%s/%s\" in read/write mode.\n", cfg.dbdir, DATABASEFILE);
   83         printf("Exiting...\n");
   84         exit(EXIT_FAILURE);
   85     }
   86 
   87     if (s.initdb) {
   88         db_close();
   89         if (debug) {
   90             printf("--initdb complete, exiting...\n");
   91         }
   92         exit(EXIT_SUCCESS);
   93     }
   94 
   95     detectboot(&s);
   96     preparedatabase(&s);
   97 
   98     if (!db_removeoldentries()) {
   99         printf("Error: Database \"%s/%s\" cleanup failed: %s\n", cfg.dbdir, DATABASEFILE, strerror(errno));
  100         printf("Exiting...\n");
  101         exit(EXIT_FAILURE);
  102     }
  103 
  104     setsignaltraps();
  105 
  106     /* start as daemon if requested, debug can't be enabled at the same time */
  107     if (s.rundaemon && !debug) {
  108         if (!db_close()) {
  109             printf("Error: Failed to close database \"%s/%s\" before starting daemon: %s\n", cfg.dbdir, DATABASEFILE, strerror(errno));
  110             printf("Exiting...\n");
  111             exit(EXIT_FAILURE);
  112         }
  113         noexit++;
  114         daemonize();
  115         if (!db_open_rw(0)) {
  116             snprintf(errorstring, 1024, "Failed to reopen database \"%s/%s\": %s", cfg.dbdir, DATABASEFILE, strerror(errno));
  117             printe(PT_Error);
  118             exit(EXIT_FAILURE);
  119         }
  120     }
  121 
  122     timeused_debug("daemon_startup", 0);
  123     s.running = 1;
  124 
  125 #if defined(__linux__) && HAVE_LINUX_RTNETLINK_H
  126 #if HAVE_DECL_IFLA_STATS64
  127     snprintf(errorstring, 1024, "vnStat daemon %s started. (pid:%d uid:%d gid:%d 64-bit)", getversion(), (int)getpid(), (int)getuid(), (int)getgid());
  128 #else
  129     snprintf(errorstring, 1024, "vnStat daemon %s started. (pid:%d uid:%d gid:%d 32-bit)", getversion(), (int)getpid(), (int)getuid(), (int)getgid());
  130 #endif
  131 #else
  132     snprintf(errorstring, 1024, "vnStat daemon %s started. (pid:%d uid:%d gid:%d)", getversion(), (int)getpid(), (int)getuid(), (int)getgid());
  133 #endif
  134     printe(PT_Info);
  135 
  136 #if !HAVE_DECL_SQLITE_CHECKPOINT_RESTART
  137     if (cfg.waldb) {
  138         snprintf(errorstring, 1024, "DatabaseWriteAheadLogging is enabled but used libsqlite3 does not support it");
  139         printe(PT_Warning);
  140     }
  141 #endif
  142 
  143     /* warmup */
  144     if (s.dbifcount == 0) {
  145         filldatabaselist(&s);
  146         s.prevdbsave = 0;
  147     }
  148     while (s.running && s.dbifcount && waittimesync(&s)) {
  149         if (intsignal) {
  150             handleintsignals(&s);
  151         } else {
  152             sleep(5);
  153         }
  154     }
  155 
  156     /* main loop */
  157     while (s.running) {
  158 
  159         s.current = time(NULL);
  160 
  161         /* track interface status only if at least one database exists */
  162         if (s.dbifcount != 0) {
  163             previflisthash = s.iflisthash;
  164             interfacechangecheck(&s);
  165             if (cfg.alwaysadd && s.iflisthash != previflisthash && previflisthash != 0) {
  166                 temp = s.dbifcount;
  167                 s.dbifcount += addinterfaces(&s);
  168                 if (temp != s.dbifcount) {
  169                     datacache_status(&s.dcache);
  170                 }
  171             }
  172         }
  173 
  174         /* do update only if enough time has passed since the previous update */
  175         if ((s.current - s.prevdbupdate) >= s.updateinterval) {
  176 
  177             s.updateinterval = cfg.updateinterval;
  178 
  179             if (debug) {
  180                 debugtimestamp();
  181                 datacache_debug(&s.dcache);
  182                 ibwlist();
  183             }
  184 
  185             /* fill database list if cache is empty */
  186             if (s.dbifcount == 0) {
  187                 filldatabaselist(&s);
  188 
  189                 /* update data cache */
  190             } else {
  191                 s.prevdbupdate = s.current - (s.current % s.updateinterval);
  192 
  193                 adjustsaveinterval(&s);
  194                 checkdbsaveneed(&s);
  195 
  196                 processdatacache(&s);
  197 
  198 #if HAVE_DECL_SQLITE_CHECKPOINT_RESTART
  199                 if (cfg.waldb && (s.current - s.prevwaldbcheckpoint) >= WALDBCHECKPOINTINTERVALMINS * 60) {
  200                     db_walcheckpoint();
  201                     s.prevwaldbcheckpoint = s.current;
  202                 }
  203 #endif
  204 
  205                 if (debug) {
  206                     printf("\n");
  207                 }
  208             }
  209         }
  210 
  211         if (s.running && intsignal == 0) {
  212             sleep((unsigned int)(cfg.pollinterval - (time(NULL) % cfg.pollinterval)));
  213         }
  214 
  215         if (intsignal) {
  216             handleintsignals(&s);
  217         }
  218     }
  219 
  220     flushcachetodisk(&s);
  221     db_close();
  222 
  223     datacache_clear(&s.dcache);
  224     ibwflush();
  225 
  226     if (s.rundaemon && !debug) {
  227         close(pidfile);
  228         unlink(cfg.pidfile);
  229     }
  230 
  231     return 0;
  232 }
  233 
  234 void showhelp(void)
  235 {
  236     printf("vnStat daemon %s by Teemu Toivola <tst at iki dot fi>\n\n", getversion());
  237 
  238     printf("      -d, --daemon             fork process to background\n");
  239     printf("      -n, --nodaemon           stay in foreground attached to the terminal\n\n");
  240 
  241     printf("      -s, --sync               sync interface counters on first update\n");
  242     printf("      -D, --debug              show additional debug and disable daemon\n");
  243     printf("      -?, --help               show this help\n");
  244     printf("      -v, --version            show version\n");
  245     printf("      -p, --pidfile <file>     select used pid file\n");
  246     printf("      -u, --user <user>        set daemon process user\n");
  247     printf("      -g, --group <group>      set daemon process group\n");
  248     printf("      -t, --timestamp          add timestamp to prints when running in foreground\n");
  249     printf("      --config <config file>   select used config file\n");
  250     printf("      --noadd                  prevent startup if database has no interfaces\n");
  251     printf("      --alwaysadd [mode]       automatically start monitoring all new interfaces\n");
  252     printf("      --initdb                 create empty database and exit\n\n");
  253 
  254     printf("See also \"man vnstatd\".\n");
  255 }
  256 
  257 void parseargs(DSTATE *s, int argc, char **argv)
  258 {
  259     int currentarg, pidfiledefined = 0;
  260 
  261     /* parse parameters, maybe not the best way but... */
  262     for (currentarg = 1; currentarg < argc; currentarg++) {
  263         if (debug)
  264             printf("arg %d: \"%s\"\n", currentarg, argv[currentarg]);
  265         if ((strcmp(argv[currentarg], "-?") == 0) || (strcmp(argv[currentarg], "--help") == 0)) {
  266             break;
  267         } else if (strcmp(argv[currentarg], "--config") == 0) {
  268             /* config has already been parsed earlier so nothing to do here */
  269             currentarg++;
  270         } else if ((strcmp(argv[currentarg], "-D") == 0) || (strcmp(argv[currentarg], "--debug") == 0)) {
  271             debug = 1;
  272         } else if ((strcmp(argv[currentarg], "-d") == 0) || (strcmp(argv[currentarg], "--daemon") == 0)) {
  273             s->rundaemon = 1;
  274             s->showhelp = 0;
  275         } else if ((strcmp(argv[currentarg], "-n") == 0) || (strcmp(argv[currentarg], "--nodaemon") == 0)) {
  276             s->showhelp = 0;
  277         } else if ((strcmp(argv[currentarg], "-s") == 0) || (strcmp(argv[currentarg], "--sync") == 0)) {
  278             s->sync = 1;
  279         } else if ((strcmp(argv[currentarg], "-t") == 0) || (strcmp(argv[currentarg], "--timestamp") == 0)) {
  280             cfg.timestampprints = 1;
  281         } else if ((strcmp(argv[currentarg], "-u") == 0) || (strcmp(argv[currentarg], "--user") == 0)) {
  282             if (currentarg + 1 < argc) {
  283                 strncpy_nt(s->user, argv[currentarg + 1], 33);
  284                 if (debug)
  285                     printf("Requested user: \"%s\"\n", s->user);
  286                 currentarg++;
  287             } else {
  288                 printf("Error: User for --user missing.\n");
  289                 exit(EXIT_FAILURE);
  290             }
  291         } else if ((strcmp(argv[currentarg], "-g") == 0) || (strcmp(argv[currentarg], "--group") == 0)) {
  292             if (currentarg + 1 < argc) {
  293                 strncpy_nt(s->group, argv[currentarg + 1], 33);
  294                 if (debug)
  295                     printf("Requested group: \"%s\"\n", s->group);
  296                 currentarg++;
  297             } else {
  298                 printf("Error: Group for --group missing.\n");
  299                 exit(EXIT_FAILURE);
  300             }
  301         } else if (strcmp(argv[currentarg], "--noadd") == 0) {
  302             s->noadd = 1;
  303         } else if (strcmp(argv[currentarg], "--alwaysadd") == 0) {
  304             if (currentarg + 1 < argc && (strlen(argv[currentarg + 1]) == 1 || ishelprequest(argv[currentarg + 1]))) {
  305                 if (!isdigit(argv[currentarg + 1][0]) || atoi(argv[currentarg + 1]) > 1 || atoi(argv[currentarg + 1]) < 0) {
  306                     if (!ishelprequest(argv[currentarg + 1]))
  307                         printf("Error: Invalid mode parameter \"%s\".\n", argv[currentarg + 1]);
  308                     printf(" Valid parameters for %s:\n", argv[currentarg]);
  309                     printf("    0 - disabled");
  310                     if (!cfg.alwaysadd) {
  311                         printf(" (default)");
  312                     }
  313                     printf("\n    1 - enabled");
  314                     if (cfg.alwaysadd) {
  315                         printf(" (default)");
  316                     }
  317                     printf("\n No mode parameter results in feature being enabled.\n");
  318                     exit(EXIT_FAILURE);
  319                 }
  320                 cfg.alwaysadd = atoi(argv[currentarg + 1]);
  321                 currentarg++;
  322             } else {
  323                 cfg.alwaysadd = 1;
  324             }
  325         } else if (strcmp(argv[currentarg], "--initdb") == 0) {
  326             s->initdb = 1;
  327             s->showhelp = 0;
  328         } else if ((strcmp(argv[currentarg], "-v") == 0) || (strcmp(argv[currentarg], "--version") == 0)) {
  329             printf("vnStat daemon %s by Teemu Toivola <tst at iki dot fi>\n", getversion());
  330             exit(EXIT_SUCCESS);
  331         } else if ((strcmp(argv[currentarg], "-p") == 0) || (strcmp(argv[currentarg], "--pidfile") == 0)) {
  332             if (currentarg + 1 < argc) {
  333                 strncpy_nt(cfg.pidfile, argv[currentarg + 1], 512);
  334                 cfg.pidfile[511] = '\0';
  335                 if (debug)
  336                     printf("Used pid file: %s\n", cfg.pidfile);
  337                 currentarg++;
  338                 pidfiledefined = 1;
  339             } else {
  340                 printf("Error: File for --pidfile missing.\n");
  341                 exit(EXIT_FAILURE);
  342             }
  343         } else {
  344             printf("Unknown arg \"%s\". Use --help for help.\n", argv[currentarg]);
  345             exit(EXIT_FAILURE);
  346         }
  347     }
  348 
  349     if (s->noadd && cfg.alwaysadd) {
  350         printf("Warning: --noadd and --alwaysadd can't both be enabled at the same time. --alwaysadd has been disabled.\n");
  351         cfg.alwaysadd = 0;
  352     }
  353 
  354     if (s->rundaemon && debug) {
  355         printf("Error: --daemon and --debug can't both be used at the same time.\n");
  356         exit(EXIT_FAILURE);
  357     }
  358 
  359     if (s->rundaemon && s->initdb) {
  360         printf("Error: --daemon and --initdb can't both be used at the same time.\n");
  361         exit(EXIT_FAILURE);
  362     }
  363 
  364     /* show help if nothing else was asked to be done */
  365     if (s->showhelp) {
  366         showhelp();
  367         exit(EXIT_SUCCESS);
  368     }
  369 
  370     if (!s->rundaemon && pidfiledefined) {
  371         printf("Error: --pidfile can only be used together with --daemon\n");
  372         exit(EXIT_FAILURE);
  373     }
  374 }