"Fossies" - the Fresh Open Source Software Archive

Member "vnstat-2.9/src/vnstati.c" (23 Jan 2022, 25831 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.

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 /*
    2 vnStat image output - Copyright (C) 2007-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 "iflist.h"
   20 #include "dbsql.h"
   21 #include "image.h"
   22 #include "cfg.h"
   23 #include "misc.h"
   24 #include "vnstati.h"
   25 
   26 int main(int argc, char *argv[])
   27 {
   28     int currentarg;
   29     IPARAMS p;
   30     IMAGECONTENT ic;
   31 
   32     initiparams(&p);
   33     initimagecontent(&ic);
   34 
   35     /* early check for debug and config parameter */
   36     if (argc > 1) {
   37         for (currentarg = 1; currentarg < argc; currentarg++) {
   38             if ((strcmp(argv[currentarg], "-D") == 0) || (strcmp(argv[currentarg], "--debug") == 0)) {
   39                 debug = 1;
   40                 printf("Debug enabled, vnstati %s, LibGD %d.%d.%d\n", VERSION, GD_MAJOR_VERSION, GD_MINOR_VERSION, GD_RELEASE_VERSION);
   41             } else if (strcmp(argv[currentarg], "--config") == 0) {
   42                 if (currentarg + 1 < argc) {
   43                     strncpy_nt(p.cfgfile, argv[currentarg + 1], 512);
   44                     if (debug)
   45                         printf("Used config file: %s\n", p.cfgfile);
   46                     currentarg++;
   47                 } else {
   48                     printf("Error: File for --config missing.\n");
   49                     return 1;
   50                 }
   51             }
   52         }
   53     }
   54 
   55     /* load config if available */
   56     if (!loadcfg(p.cfgfile, CT_Image)) {
   57         return 1;
   58     }
   59     cfg.qmode = 0;
   60 
   61     configlocale();
   62     strncpy_nt(p.interface, cfg.iface, 32);
   63     ic.current = time(NULL);
   64 
   65     parseargs(&p, &ic, argc, argv);
   66     validateinput(&p);
   67     validateoutput(&p);
   68     handlecaching(&p, &ic);
   69     handledatabase(&p, &ic);
   70 
   71     if (debug)
   72         printf("Qmode: %d\n", cfg.qmode);
   73 
   74     drawimage(&ic);
   75     db_close();
   76 
   77     if (ic.im == NULL) {
   78         return 1;
   79     }
   80 
   81 #if HAVE_DECL_GD_NEAREST_NEIGHBOUR
   82     scaleimage(&ic);
   83 #endif
   84     writeoutput(&p, &ic);
   85 
   86     if (debug)
   87         printf("all done\n");
   88 
   89     return 0;
   90 }
   91 
   92 void initiparams(IPARAMS *p)
   93 {
   94     db = NULL;
   95     noexit = 0;        /* allow functions to exit in case of error */
   96     debug = 0;         /* debug disabled by default */
   97     disableprints = 0; /* let prints be visible */
   98 
   99     p->interface[0] = '\0';
  100     p->filename[0] = '\0';
  101     p->cfgfile[0] = '\0';
  102     p->cache = 0;
  103     p->help = 0;
  104     p->limit = -1;
  105 }
  106 
  107 void showihelp(IPARAMS *p)
  108 {
  109     printf("vnStat image output %s by Teemu Toivola <tst at iki dot fi>\n\n", getversion());
  110 
  111     printf("      -5,  --fiveminutes [limit]         output 5 minutes\n");
  112     printf("      -5g, --fivegraph [limit] [height]  output 5 minutes graph\n");
  113     printf("      -h,  --hours [limit]               output hours\n");
  114     printf("      -hg, --hoursgraph                  output hours graph\n");
  115     printf("      -d,  --days [limit]                output days\n");
  116     printf("      -m,  --months [limit]              output months\n");
  117     printf("      -y,  --years [limit]               output years\n");
  118     printf("      -t,  --top [limit]                 output top days\n");
  119     printf("      -s,  --summary                     output summary\n");
  120     printf("      -hs, --hsummary [graph]            output horizontal summary with graph\n");
  121     printf("      -vs, --vsummary [graph]            output vertical summary with graph\n\n");
  122 
  123     printf("      -nh, --noheader                    remove header from output\n");
  124     printf("      -ne, --noedge                      remove edge from output\n");
  125     printf("      -nl, --nolegend                    remove legend from output\n");
  126     printf("      -ru, --rateunit [mode]             swap configured rate unit\n");
  127     printf("      -S,  --small                       use small fonts");
  128     if (!cfg.largefonts) {
  129         printf(" (default)");
  130     }
  131     printf("\n");
  132     printf("      -L,  --large                       use large fonts");
  133     if (cfg.largefonts) {
  134         printf(" (default)");
  135     }
  136     printf("\n");
  137     printf("      -o,  --output <file>               select output filename\n");
  138     printf("      -c,  --cache <minutes>             update output only when too old\n");
  139     printf("      -i,  --iface <interface>           select interface");
  140     if (strlen(p->interface)) {
  141         printf(" (default: %s)", p->interface);
  142     }
  143     printf("\n");
  144     printf("      -b,  --begin <date>                set list begin date\n");
  145     printf("      -e,  --end <date>                  set list end date\n");
  146     printf("      -?,  --help                        this help\n");
  147     printf("      -D,  --debug                       show some additional debug information\n");
  148     printf("      -v,  --version                     show version\n");
  149     printf("      --limit <limit>                    set list entry limit\n");
  150     printf("      --dbdir <directory>                select database directory\n");
  151     printf("      --style <mode>                     select output style (0-3)\n");
  152     printf("      --locale <locale>                  set locale\n");
  153     printf("      --config <config file>             select config file\n");
  154     printf("      --altdate                          use alternative date location\n");
  155     printf("      --headertext <text>                specify header text string\n");
  156 #if HAVE_DECL_GD_NEAREST_NEIGHBOUR
  157     printf("      --scale <percent>                  change image size by scaling it\n");
  158 #endif
  159     printf("      --transparent [enabled]            toggle background transparency\n\n");
  160 
  161     printf("See also \"man vnstati\".\n");
  162 }
  163 
  164 void parseargs(IPARAMS *p, IMAGECONTENT *ic, int argc, char **argv)
  165 {
  166     int currentarg;
  167 
  168     /* parse parameters */
  169     for (currentarg = 1; currentarg < argc; currentarg++) {
  170         if (debug)
  171             printf("arg %d: \"%s\"\n", currentarg, argv[currentarg]);
  172         if ((strcmp(argv[currentarg], "-?") == 0) || (strcmp(argv[currentarg], "--help")) == 0) {
  173             p->help = 1;
  174         } else if ((strcmp(argv[currentarg], "-i") == 0) || (strcmp(argv[currentarg], "--iface")) == 0 || (strcmp(argv[currentarg], "--interface") == 0)) {
  175             if (currentarg + 1 < argc) {
  176                 if (strlen(argv[currentarg + 1]) > 31) {
  177                     printf("Error: Interface name is limited to 31 characters.\n");
  178                     exit(EXIT_FAILURE);
  179                 }
  180                 strncpy_nt(p->interface, argv[currentarg + 1], 32);
  181                 if (debug)
  182                     printf("Used interface: \"%s\"\n", p->interface);
  183                 currentarg++;
  184             } else {
  185                 printf("Error: Interface for %s missing.\n", argv[currentarg]);
  186                 exit(EXIT_FAILURE);
  187             }
  188         } else if ((strcmp(argv[currentarg], "-o") == 0) || (strcmp(argv[currentarg], "--output")) == 0) {
  189             if (currentarg + 1 < argc) {
  190                 strncpy_nt(p->filename, argv[currentarg + 1], 512);
  191                 if (debug)
  192                     printf("Output file: \"%s\"\n", p->filename);
  193                 currentarg++;
  194             } else {
  195                 printf("Error: Filename for %s missing.\n", argv[currentarg]);
  196                 exit(EXIT_FAILURE);
  197             }
  198         } else if ((strcmp(argv[currentarg], "-c") == 0) || (strcmp(argv[currentarg], "--cache")) == 0) {
  199             if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) {
  200                 p->cache = atoi(argv[currentarg + 1]);
  201                 if (debug)
  202                     printf("Cache time: %d minutes\n", p->cache);
  203                 currentarg++;
  204             } else {
  205                 printf("Error: Parameter for %s missing or invalid.\n", argv[currentarg]);
  206                 exit(EXIT_FAILURE);
  207             }
  208         } else if ((strcmp(argv[currentarg], "--style")) == 0) {
  209             if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) {
  210                 cfg.ostyle = atoi(argv[currentarg + 1]);
  211                 if (cfg.ostyle > 3 || cfg.ostyle < 0) {
  212                     printf("Error: Invalid style parameter \"%d\" for --style.\n", cfg.ostyle);
  213                     exit(EXIT_FAILURE);
  214                 }
  215                 if (debug)
  216                     printf("Style changed: %d\n", cfg.ostyle);
  217                 currentarg++;
  218             } else {
  219                 printf("Error: Style parameter for --style missing.\n");
  220                 exit(EXIT_FAILURE);
  221             }
  222         } else if ((strcmp(argv[currentarg], "--scale")) == 0) {
  223 #if HAVE_DECL_GD_NEAREST_NEIGHBOUR
  224             if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) {
  225                 cfg.imagescale = atoi(argv[currentarg + 1]);
  226                 if (cfg.imagescale > 500 || cfg.imagescale < 50) {
  227                     printf("Error: Invalid parameter \"%d\" for --scale. Supported value range: 50 <= N <= 500\n", cfg.imagescale);
  228                     exit(EXIT_FAILURE);
  229                 }
  230                 if (debug)
  231                     printf("Scale changed: %d\n", cfg.imagescale);
  232                 currentarg++;
  233             } else {
  234                 printf("Error: Percent parameter for --scale missing.\n");
  235                 exit(EXIT_FAILURE);
  236             }
  237 #else
  238             printf("Error: Function needed by --scale is not available in used LibGD %d.%d.%d.\n", GD_MAJOR_VERSION, GD_MINOR_VERSION, GD_RELEASE_VERSION);
  239             exit(EXIT_FAILURE);
  240 #endif
  241         } else if ((strcmp(argv[currentarg], "--transparent")) == 0) {
  242             if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) {
  243                 cfg.transbg = atoi(argv[currentarg + 1]);
  244                 if (cfg.transbg > 1 || cfg.transbg < 0) {
  245                     printf("Error: Invalid parameter \"%d\" for --transparent.\n", cfg.transbg);
  246                     exit(EXIT_FAILURE);
  247                 }
  248                 if (debug)
  249                     printf("Transparency changed: %d\n", cfg.transbg);
  250                 currentarg++;
  251             } else {
  252                 cfg.transbg = !cfg.transbg;
  253                 if (debug)
  254                     printf("Transparency changed: %d\n", cfg.transbg);
  255             }
  256         } else if ((strcmp(argv[currentarg], "--dbdir")) == 0) {
  257             if (currentarg + 1 < argc) {
  258                 strncpy_nt(cfg.dbdir, argv[currentarg + 1], 512);
  259                 if (debug)
  260                     printf("DatabaseDir: \"%s\"\n", cfg.dbdir);
  261                 currentarg++;
  262             } else {
  263                 printf("Error: Directory for --dbdir missing.\n");
  264                 exit(EXIT_FAILURE);
  265             }
  266         } else if ((strcmp(argv[currentarg], "--locale")) == 0) {
  267             if (currentarg + 1 < argc) {
  268                 setlocale(LC_ALL, argv[currentarg + 1]);
  269                 if (debug)
  270                     printf("Locale: \"%s\"\n", argv[currentarg + 1]);
  271                 currentarg++;
  272             } else {
  273                 printf("Error: Locale for --locale missing.\n");
  274                 exit(EXIT_FAILURE);
  275             }
  276         } else if (strcmp(argv[currentarg], "--config") == 0) {
  277             /* config has already been parsed earlier so nothing to do here */
  278             currentarg++;
  279         } else if ((strcmp(argv[currentarg], "--headertext")) == 0) {
  280             if (currentarg + 1 < argc) {
  281                 strncpy_nt(ic->headertext, argv[currentarg + 1], 65);
  282                 if (debug)
  283                     printf("Header text: \"%s\"\n", ic->headertext);
  284                 currentarg++;
  285             } else {
  286                 printf("Error: Text string parameter for --headertext missing.\n");
  287                 exit(EXIT_FAILURE);
  288             }
  289         } else if (strcmp(argv[currentarg], "--altdate") == 0) {
  290             ic->altdate = 1;
  291         } else if ((strcmp(argv[currentarg], "-L") == 0) || (strcmp(argv[currentarg], "--large")) == 0) {
  292             cfg.largefonts = 1;
  293         } else if ((strcmp(argv[currentarg], "-S") == 0) || (strcmp(argv[currentarg], "--small")) == 0) {
  294             cfg.largefonts = 0;
  295         } else if ((strcmp(argv[currentarg], "-D") == 0) || (strcmp(argv[currentarg], "--debug")) == 0) {
  296             debug = 1;
  297         } else if ((strcmp(argv[currentarg], "-d") == 0) || (strcmp(argv[currentarg], "--days")) == 0) {
  298             cfg.qmode = 1;
  299             if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) {
  300                 cfg.listdays = atoi(argv[currentarg + 1]);
  301                 if (cfg.listdays < 0) {
  302                     printf("Error: Invalid limit parameter \"%s\" for %s. Only a zero and positive numbers are allowed.\n", argv[currentarg + 1], argv[currentarg]);
  303                     exit(EXIT_FAILURE);
  304                 }
  305                 currentarg++;
  306             }
  307         } else if ((strcmp(argv[currentarg], "-m") == 0) || (strcmp(argv[currentarg], "--months")) == 0) {
  308             cfg.qmode = 2;
  309             if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) {
  310                 cfg.listmonths = atoi(argv[currentarg + 1]);
  311                 if (cfg.listmonths < 0) {
  312                     printf("Error: Invalid limit parameter \"%s\" for %s. Only a zero and positive numbers are allowed.\n", argv[currentarg + 1], argv[currentarg]);
  313                     exit(EXIT_FAILURE);
  314                 }
  315                 currentarg++;
  316             }
  317         } else if ((strcmp(argv[currentarg], "-t") == 0) || (strcmp(argv[currentarg], "--top")) == 0) {
  318             cfg.qmode = 3;
  319             if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) {
  320                 cfg.listtop = atoi(argv[currentarg + 1]);
  321                 if (cfg.listtop < 0) {
  322                     printf("Error: Invalid limit parameter \"%s\" for %s. Only a zero and positive numbers are allowed.\n", argv[currentarg + 1], argv[currentarg]);
  323                     exit(EXIT_FAILURE);
  324                 }
  325                 currentarg++;
  326             }
  327         } else if ((strcmp(argv[currentarg], "-y") == 0) || (strcmp(argv[currentarg], "--years")) == 0) {
  328             cfg.qmode = 4;
  329             if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) {
  330                 cfg.listyears = atoi(argv[currentarg + 1]);
  331                 if (cfg.listyears < 0) {
  332                     printf("Error: Invalid limit parameter \"%s\" for %s. Only a zero and positive numbers are allowed.\n", argv[currentarg + 1], argv[currentarg]);
  333                     exit(EXIT_FAILURE);
  334                 }
  335                 currentarg++;
  336             }
  337         } else if ((strcmp(argv[currentarg], "-h") == 0) || (strcmp(argv[currentarg], "--hours")) == 0) {
  338             cfg.qmode = 8;
  339             if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) {
  340                 cfg.listhours = atoi(argv[currentarg + 1]);
  341                 if (cfg.listhours < 0) {
  342                     printf("Error: Invalid limit parameter \"%s\" for %s. Only a zero and positive numbers are allowed.\n", argv[currentarg + 1], argv[currentarg]);
  343                     exit(EXIT_FAILURE);
  344                 }
  345                 currentarg++;
  346             }
  347         } else if ((strcmp(argv[currentarg], "-5") == 0) || (strcmp(argv[currentarg], "--fiveminutes")) == 0) {
  348             cfg.qmode = 9;
  349             if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) {
  350                 cfg.listfivemins = atoi(argv[currentarg + 1]);
  351                 if (cfg.listfivemins < 0) {
  352                     printf("Error: Invalid limit parameter \"%s\" for %s. Only a zero and positive numbers are allowed.\n", argv[currentarg + 1], argv[currentarg]);
  353                     exit(EXIT_FAILURE);
  354                 }
  355                 currentarg++;
  356             }
  357         } else if ((strcmp(argv[currentarg], "-s") == 0) || (strcmp(argv[currentarg], "--summary")) == 0) {
  358             cfg.qmode = 5;
  359         } else if ((strcmp(argv[currentarg], "-hg") == 0) || (strcmp(argv[currentarg], "--hoursgraph") == 0) || (strcmp(argv[currentarg], "--hourlygraph")) == 0) {
  360             cfg.qmode = 7;
  361             if (currentarg + 1 < argc && (strlen(argv[currentarg + 1]) == 1 || ishelprequest(argv[currentarg + 1]))) {
  362                 if (!isdigit(argv[currentarg + 1][0]) || atoi(argv[currentarg + 1]) > 1 || atoi(argv[currentarg + 1]) < 0) {
  363                     if (!ishelprequest(argv[currentarg + 1]))
  364                         printf("Error: Invalid mode selection \"%s\".\n", argv[currentarg + 1]);
  365                     printf(" Valid modes for %s:\n", argv[currentarg]);
  366                     printf("    0 - 24 hour sliding windows\n");
  367                     printf("    1 - graph start from midnight\n");
  368                     exit(EXIT_FAILURE);
  369                 }
  370                 cfg.hourlygmode = atoi(argv[currentarg + 1]);
  371                 if (debug)
  372                     printf("Hourly graph mode changed: %d\n", cfg.hourlygmode);
  373                 currentarg++;
  374             }
  375         } else if ((strcmp(argv[currentarg], "-5g") == 0) || (strcmp(argv[currentarg], "--fivegraph")) == 0) {
  376             cfg.qmode = 10;
  377             if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) {
  378                 cfg.fivegresultcount = atoi(argv[currentarg + 1]);
  379                 if (cfg.fivegresultcount < FIVEGMINRESULTCOUNT) {
  380                     printf("Error: Invalid limit parameter \"%s\" for %s. A value equal or over %d is expected.\n", argv[currentarg + 1], argv[currentarg], FIVEGMINRESULTCOUNT);
  381                     exit(EXIT_FAILURE);
  382                 } else if (cfg.fivegresultcount > cfg.fiveminutehours * 12) {
  383                     printf("Error: Invalid limit parameter \"%s\" for %s. Value cannot be larger than configured data retention (5MinuteHours %d * 12 = %d).\n", argv[currentarg + 1], argv[currentarg], cfg.fiveminutehours, cfg.fiveminutehours * 12);
  384                     exit(EXIT_FAILURE);
  385                 }
  386                 currentarg++;
  387             }
  388             if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) {
  389                 cfg.fivegheight = atoi(argv[currentarg + 1]);
  390                 if (cfg.fivegheight < FIVEGMINHEIGHT) {
  391                     printf("Error: Invalid height parameter \"%s\" for %s. A value equal or over %d is expected.\n", argv[currentarg + 1], argv[currentarg], FIVEGMINHEIGHT);
  392                     exit(EXIT_FAILURE);
  393                 }
  394                 currentarg++;
  395             }
  396         } else if ((strcmp(argv[currentarg], "-hs") == 0) || (strcmp(argv[currentarg], "--hsummary")) == 0) {
  397             cfg.qmode = 51;
  398             if (currentarg + 1 < argc && (strlen(argv[currentarg + 1]) == 1 || ishelprequest(argv[currentarg + 1]))) {
  399                 if (!isdigit(argv[currentarg + 1][0]) || atoi(argv[currentarg + 1]) > 1 || atoi(argv[currentarg + 1]) < 0) {
  400                     if (!ishelprequest(argv[currentarg + 1]))
  401                         printf("Error: Invalid graph selection \"%s\".\n", argv[currentarg + 1]);
  402                     printf(" Valid graphs for %s:\n", argv[currentarg]);
  403                     printf("    0 - hours\n");
  404                     printf("    1 - 5 minutes\n");
  405                     exit(EXIT_FAILURE);
  406                 }
  407                 cfg.summarygraph = atoi(argv[currentarg + 1]);
  408                 if (debug)
  409                     printf("Summary graph changed: %d\n", cfg.summarygraph);
  410                 currentarg++;
  411             }
  412         } else if ((strcmp(argv[currentarg], "-vs") == 0) || (strcmp(argv[currentarg], "--vsummary")) == 0) {
  413             cfg.qmode = 52;
  414             if (currentarg + 1 < argc && (strlen(argv[currentarg + 1]) == 1 || ishelprequest(argv[currentarg + 1]))) {
  415                 if (!isdigit(argv[currentarg + 1][0]) || atoi(argv[currentarg + 1]) > 1 || atoi(argv[currentarg + 1]) < 0) {
  416                     if (!ishelprequest(argv[currentarg + 1]))
  417                         printf("Error: Invalid graph selection \"%s\".\n", argv[currentarg + 1]);
  418                     printf(" Valid graphs for %s:\n", argv[currentarg]);
  419                     printf("    0 - hours\n");
  420                     printf("    1 - 5 minutes\n");
  421                     exit(EXIT_FAILURE);
  422                 }
  423                 cfg.summarygraph = atoi(argv[currentarg + 1]);
  424                 if (debug)
  425                     printf("Summary graph changed: %d\n", cfg.summarygraph);
  426                 currentarg++;
  427             }
  428         } else if ((strcmp(argv[currentarg], "-nh") == 0) || (strcmp(argv[currentarg], "--noheader")) == 0) {
  429             ic->showheader = 0;
  430         } else if ((strcmp(argv[currentarg], "-ne") == 0) || (strcmp(argv[currentarg], "--noedge")) == 0) {
  431             ic->showedge = 0;
  432         } else if ((strcmp(argv[currentarg], "-nl") == 0) || (strcmp(argv[currentarg], "--nolegend")) == 0) {
  433             ic->showlegend = 0;
  434         } else if ((strcmp(argv[currentarg], "-ru") == 0) || (strcmp(argv[currentarg], "--rateunit")) == 0) {
  435             if (currentarg + 1 < argc && (strlen(argv[currentarg + 1]) == 1 || ishelprequest(argv[currentarg + 1]))) {
  436                 if (!isdigit(argv[currentarg + 1][0]) || atoi(argv[currentarg + 1]) > 1 || atoi(argv[currentarg + 1]) < 0) {
  437                     if (!ishelprequest(argv[currentarg + 1]))
  438                         printf("Error: Invalid parameter \"%s\".\n", argv[currentarg + 1]);
  439                     printf(" Valid parameters for %s:\n", argv[currentarg]);
  440                     printf("    0 - bytes\n");
  441                     printf("    1 - bits\n");
  442                     exit(EXIT_FAILURE);
  443                 }
  444                 cfg.rateunit = atoi(argv[currentarg + 1]);
  445                 if (debug)
  446                     printf("Rateunit changed: %d\n", cfg.rateunit);
  447                 currentarg++;
  448             } else {
  449                 cfg.rateunit = !cfg.rateunit;
  450                 if (debug)
  451                     printf("Rateunit changed: %d\n", cfg.rateunit);
  452             }
  453         } else if ((strcmp(argv[currentarg], "-b") == 0) || (strcmp(argv[currentarg], "--begin") == 0)) {
  454             if (currentarg + 1 < argc) {
  455                 if (!validatedatetime(argv[currentarg + 1])) {
  456                     printf("Error: Invalid date format, expected YYYY-MM-DD HH:MM, YYYY-MM-DD or \"today\".\n");
  457                     exit(EXIT_FAILURE);
  458                 }
  459                 strncpy_nt(ic->databegin, argv[currentarg + 1], 18);
  460                 currentarg++;
  461             } else {
  462                 printf("Error: Date of format YYYY-MM-DD HH:MM, YYYY-MM-DD or \"today\" for %s missing.\n", argv[currentarg]);
  463                 exit(EXIT_FAILURE);
  464             }
  465         } else if ((strcmp(argv[currentarg], "-e") == 0) || (strcmp(argv[currentarg], "--end") == 0)) {
  466             if (currentarg + 1 < argc) {
  467                 if (!validatedatetime(argv[currentarg + 1])) {
  468                     printf("Error: Invalid date format, expected YYYY-MM-DD HH:MM or YYYY-MM-DD.\n");
  469                     exit(EXIT_FAILURE);
  470                 }
  471                 strncpy_nt(ic->dataend, argv[currentarg + 1], 18);
  472                 currentarg++;
  473             } else {
  474                 printf("Error: Date of format YYYY-MM-DD HH:MM or YYYY-MM-DD for %s missing.\n", argv[currentarg]);
  475                 exit(EXIT_FAILURE);
  476             }
  477         } else if (strcmp(argv[currentarg], "--limit") == 0) {
  478             if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) {
  479                 p->limit = atoi(argv[currentarg + 1]);
  480                 if (p->limit < 0) {
  481                     printf("Error: Invalid limit parameter \"%s\" for %s. Only a zero and positive numbers are allowed.\n", argv[currentarg + 1], argv[currentarg]);
  482                     exit(EXIT_FAILURE);
  483                 }
  484                 currentarg++;
  485             } else {
  486                 printf("Error: Invalid or missing parameter for %s.\n", argv[currentarg]);
  487                 exit(EXIT_FAILURE);
  488             }
  489         } else if ((strcmp(argv[currentarg], "-v") == 0) || (strcmp(argv[currentarg], "--version")) == 0) {
  490             printf("vnStat image output %s by Teemu Toivola <tst at iki dot fi> (LibGD %d.%d.%d)\n", getversion(), GD_MAJOR_VERSION, GD_MINOR_VERSION, GD_RELEASE_VERSION);
  491             exit(EXIT_SUCCESS);
  492         } else {
  493             if (argv[currentarg][0] == '-') {
  494                 printf("Unknown parameter \"%s\". Use --help for help.\n", argv[currentarg]);
  495                 exit(EXIT_FAILURE);
  496             } else {
  497                 if (strlen(argv[currentarg]) > 31) {
  498                     printf("Error: Interface name is limited to 31 characters.\n");
  499                     exit(EXIT_FAILURE);
  500                 }
  501                 strncpy_nt(p->interface, argv[currentarg], 32);
  502                 if (debug)
  503                     printf("Used interface: \"%s\"\n", p->interface);
  504             }
  505         }
  506     }
  507 
  508     if (p->help || argc == 1) {
  509         showihelp(p);
  510         exit(EXIT_SUCCESS);
  511     }
  512 
  513     if (p->limit != -1) {
  514         cfg.listfivemins = cfg.listhours = cfg.listdays = cfg.listmonths = cfg.listyears = cfg.listtop = cfg.listjsonxml = p->limit;
  515     }
  516 
  517     if (cfg.largefonts) {
  518         ic->font = gdFontGetLarge();
  519         ic->lineheight = 16;
  520         ic->large = 1;
  521     } else {
  522         ic->font = gdFontGetSmall();
  523         ic->lineheight = 12;
  524         ic->large = 0;
  525     }
  526 }
  527 
  528 void validateinput(IPARAMS *p)
  529 {
  530     if (!cfg.qmode || !strlen(p->filename)) {
  531         printf("At least output mode and file parameter needs to be given. ");
  532         printf("Use -? or --help for getting short help.\n");
  533         exit(EXIT_FAILURE);
  534     }
  535 }
  536 
  537 void handlecaching(IPARAMS *p, IMAGECONTENT *ic)
  538 {
  539     struct stat filestat;
  540 
  541     if (p->cache == 0 || p->filename[0] == '-') {
  542         return;
  543     }
  544 
  545     if (stat(p->filename, &filestat) == 0) {
  546         if ((ic->current - filestat.st_mtime) < (p->cache * 60)) {
  547             if (debug)
  548                 printf("Using cached file (%d<%d).\n", (int)(ic->current - filestat.st_mtime), p->cache * 60);
  549             exit(EXIT_SUCCESS);
  550         }
  551     } else {
  552         /* abort if error is something else than file not found */
  553         if (errno != ENOENT) {
  554             printf("Error: Getting status for file \"%s\" failed: %s (%d)\n", p->filename, strerror(errno), errno);
  555             exit(EXIT_FAILURE);
  556         }
  557     }
  558 }
  559 
  560 void handledatabase(IPARAMS *p, IMAGECONTENT *ic)
  561 {
  562     int i, found = 0;
  563     iflist *dbifl = NULL;
  564 
  565     if (!db_open_ro()) {
  566         printf("Error: Failed to open database \"%s/%s\" in read-only mode.\n", cfg.dbdir, DATABASEFILE);
  567         exit(EXIT_FAILURE);
  568     }
  569     if (strlen(p->interface)) {
  570         if (!db_getinterfacecountbyname(p->interface)) {
  571             if (strchr(p->interface, '+') == NULL) {
  572                 for (i = 1; i <= cfg.ifacematchmethod; i++) {
  573                     found = db_setinterfacebyalias(p->interface, p->interface, i);
  574                     if (found) {
  575                         if (debug) {
  576                             printf("Found \"%s\" with method %d\n", p->interface, i);
  577                         }
  578                         break;
  579                     }
  580                 }
  581                 if (!found) {
  582                     printf("Error: No interface matching \"%s\" found in database.\n", p->interface);
  583                     exit(EXIT_FAILURE);
  584                 }
  585             } else {
  586                 printf("Error: Not all requested interfaces found in database or given interfaces aren't unique.\n");
  587                 exit(EXIT_FAILURE);
  588             }
  589         }
  590     } else {
  591         if (db_getiflist_sorted(&dbifl, 1) <= 0) {
  592             printf("Error: Unable to discover suitable interface from database.\n");
  593             exit(EXIT_FAILURE);
  594         }
  595         strncpy_nt(p->interface, dbifl->interface, 32);
  596         iflistfree(&dbifl);
  597         if (debug)
  598             printf("Automatically selected interface: \"%s\"\n", p->interface);
  599     }
  600     if (!db_getinterfaceinfo(p->interface, &ic->interface)) {
  601         printf("Error: Failed to fetch interface \"%s\" details from database.\n", p->interface);
  602         exit(EXIT_FAILURE);
  603     }
  604 }
  605 
  606 void validateoutput(IPARAMS *p)
  607 {
  608 #if HAVE_DECL_GDIMAGEFILE
  609     /* not output to stdout */
  610     if (!(strlen(p->filename) == 1 && p->filename[0] == '-')) {
  611         if (!gdSupportsFileType(p->filename, 1)) {
  612             printf("Error: Image format file extension for \"%s\" is not supported or recognized\n\n", p->filename);
  613             showsupportedfileextensions();
  614             exit(EXIT_FAILURE);
  615         }
  616     }
  617 #else
  618     /* show warning if given filename doesn't end with .png when gdImageFile() isn't available */
  619     if (!(strlen(p->filename) >= 4 && strcmp(p->filename + strlen(p->filename) - 4, ".png") == 0)) {
  620         printf("Warning: Image format selection based on file extension is not available in used LibGD %d.%d.%d, \"%s\" will be written as png.\n", GD_MAJOR_VERSION, GD_MINOR_VERSION, GD_RELEASE_VERSION, p->filename);
  621     }
  622 #endif
  623 }
  624 
  625 void writeoutput(IPARAMS *p, IMAGECONTENT *ic)
  626 {
  627     if (ic->im == NULL) {
  628         return;
  629     }
  630 
  631     /* output to stdout is always png */
  632     if (strlen(p->filename) == 1 && p->filename[0] == '-') {
  633         if ((p->pngout = fdopen(1, "w")) == NULL) {
  634             printf("Error: Opening stdout for output failed: %s\n", strerror(errno));
  635             exit(EXIT_FAILURE);
  636         }
  637         gdImagePng(ic->im, p->pngout);
  638         fclose(p->pngout);
  639     } else {
  640 #if HAVE_DECL_GDIMAGEFILE
  641         /* avoid "Palette image not supported by webp" */
  642         if (strlen(p->filename) >= 5 && strcmp(p->filename + strlen(p->filename) - 5, ".webp") == 0) {
  643             gdImagePaletteToTrueColor(ic->im);
  644         }
  645         if (!gdImageFile(ic->im, p->filename)) {
  646             printf("Error: Writing output to \"%s\" failed: %s\n", p->filename, strerror(errno));
  647             exit(EXIT_FAILURE);
  648         }
  649 #else
  650         if ((p->pngout = fopen(p->filename, "w")) == NULL) {
  651             printf("Error: Opening file \"%s\" for output failed: %s\n", p->filename, strerror(errno));
  652             exit(EXIT_FAILURE);
  653         }
  654         gdImagePng(ic->im, p->pngout);
  655         fclose(p->pngout);
  656 #endif
  657     }
  658 
  659     gdImageDestroy(ic->im);
  660 }
  661 
  662 #if HAVE_DECL_GDIMAGEFILE
  663 void showsupportedfileextensions(void)
  664 {
  665     int i;
  666     const char *extensions[] = {".avif", ".bmp", ".gif", ".heif", ".heix", ".jpeg", ".jpg", ".png", ".tga", ".tif", ".tiff", ".wbmp", ".webp", ".xbm", ".xpm"};
  667 
  668     printf("Supported image format file extensions in current environment:\n");
  669 
  670     for (i = 0; i < 15; i++) {
  671         if (gdSupportsFileType(extensions[i], 1)) {
  672             printf("%s ", extensions[i]);
  673         }
  674     }
  675     printf("\n");
  676 }
  677 #endif