"Fossies" - the Fresh Open Source Software Archive

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

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 "cfg.h"
    3 
    4 int loadcfg(const char *cfgfile, const ConfigType type)
    5 {
    6     FILE *fd;
    7     int i;
    8     unsigned int linelen, cfglen;
    9 
   10     char value[512], cfgline[512];
   11 
   12     struct cfgsetting cset[] =
   13         {/* cfg string, char var name, int var name, char len, fill status */
   14          {"Interface", cfg.iface, 0, 32, 0},
   15          {"DatabaseDir", cfg.dbdir, 0, 512, 0},
   16          {"Locale", cfg.locale, 0, 32, 0},
   17          {"MonthRotate", 0, &cfg.monthrotate, 0, 0},
   18          {"MonthRotateAffectsYears", 0, &cfg.monthrotateyears, 0, 0},
   19          {"DayFormat", cfg.dformat, 0, 64, 0},
   20          {"MonthFormat", cfg.mformat, 0, 64, 0},
   21          {"TopFormat", cfg.tformat, 0, 64, 0},
   22          {"RXCharacter", cfg.rxchar, 0, 2, 0},
   23          {"TXCharacter", cfg.txchar, 0, 2, 0},
   24          {"RXHourCharacter", cfg.rxhourchar, 0, 2, 0},
   25          {"TXHourCharacter", cfg.txhourchar, 0, 2, 0},
   26          {"UnitMode", 0, &cfg.unitmode, 0, 0},
   27          {"RateUnitMode", 0, &cfg.rateunitmode, 0, 0},
   28          {"OutputStyle", 0, &cfg.ostyle, 0, 0},
   29          {"EstimateBarVisible", 0, &cfg.estimatebarvisible, 0, 0},
   30          {"RateUnit", 0, &cfg.rateunit, 0, 0},
   31          {"DefaultDecimals", 0, &cfg.defaultdecimals, 0, 0},
   32          {"HourlyDecimals", 0, &cfg.hourlydecimals, 0, 0},
   33          {"HourlySectionStyle", 0, &cfg.hourlystyle, 0, 0},
   34          {"BandwidthDetection", 0, &cfg.bwdetection, 0, 0},
   35          {"MaxBandwidth", 0, &cfg.maxbw, 0, 0},
   36          {"Sampletime", 0, &cfg.sampletime, 0, 0},
   37          {"QueryMode", 0, &cfg.qmode, 0, 0},
   38          {"CheckDiskSpace", 0, &cfg.spacecheck, 0, 0},
   39          {"BootVariation", 0, &cfg.bvar, 0, 0},
   40          {"TrafficlessEntries", 0, &cfg.trafficlessentries, 0, 0},
   41          {"List5Mins", 0, &cfg.listfivemins, 0, 0},
   42          {"ListHours", 0, &cfg.listhours, 0, 0},
   43          {"ListDays", 0, &cfg.listdays, 0, 0},
   44          {"ListMonths", 0, &cfg.listmonths, 0, 0},
   45          {"ListYears", 0, &cfg.listyears, 0, 0},
   46          {"ListTop", 0, &cfg.listtop, 0, 0},
   47          {"InterfaceMatchMethod", 0, &cfg.ifacematchmethod, 0, 0},
   48          {"5MinuteHours", 0, &cfg.fiveminutehours, 0, 0},
   49          {"HourlyDays", 0, &cfg.hourlydays, 0, 0},
   50          {"DailyDays", 0, &cfg.dailydays, 0, 0},
   51          {"MonthlyMonths", 0, &cfg.monthlymonths, 0, 0},
   52          {"YearlyYears", 0, &cfg.yearlyyears, 0, 0},
   53          {"TopDayEntries", 0, &cfg.topdayentries, 0, 0},
   54          {"DaemonUser", cfg.daemonuser, 0, 33, 0},
   55          {"DaemonGroup", cfg.daemongroup, 0, 33, 0},
   56          {"TimeSyncWait", 0, &cfg.timesyncwait, 0, 0},
   57          {"UpdateInterval", 0, &cfg.updateinterval, 0, 0},
   58          {"PollInterval", 0, &cfg.pollinterval, 0, 0},
   59          {"SaveInterval", 0, &cfg.saveinterval, 0, 0},
   60          {"OfflineSaveInterval", 0, &cfg.offsaveinterval, 0, 0},
   61          {"RescanDatabaseOnSave", 0, &cfg.rescanonsave, 0, 0},
   62          {"AlwaysAddNewInterfaces", 0, &cfg.alwaysadd, 0, 0},
   63          {"BandwidthDetectionInterval", 0, &cfg.bwdetectioninterval, 0, 0},
   64          {"SaveOnStatusChange", 0, &cfg.savestatus, 0, 0},
   65          {"UseLogging", 0, &cfg.uselogging, 0, 0},
   66          {"CreateDirs", 0, &cfg.createdirs, 0, 0},
   67          {"UpdateFileOwner", 0, &cfg.updatefileowner, 0, 0},
   68          {"LogFile", cfg.logfile, 0, 512, 0},
   69          {"PidFile", cfg.pidfile, 0, 512, 0},
   70          {"64bitInterfaceCounters", 0, &cfg.is64bit, 0, 0},
   71          {"DatabaseWriteAheadLogging", 0, &cfg.waldb, 0, 0},
   72          {"DatabaseSynchronous", 0, &cfg.dbsynchronous, 0, 0},
   73          {"UseUTC", 0, &cfg.useutc, 0, 0},
   74          {"HeaderFormat", cfg.hformat, 0, 64, 0},
   75          {"HourlyRate", 0, &cfg.hourlyrate, 0, 0},
   76          {"SummaryRate", 0, &cfg.summaryrate, 0, 0},
   77          {"TransparentBg", 0, &cfg.transbg, 0, 0},
   78          {"LargeFonts", 0, &cfg.largefonts, 0, 0},
   79          {"LineSpacingAdjustment", 0, &cfg.linespaceadjust, 0, 0},
   80          {"ImageScale", 0, &cfg.imagescale, 0, 0},
   81          {"5MinuteGraphResultCount", 0, &cfg.fivegresultcount, 0, 0},
   82          {"5MinuteGraphHeight", 0, &cfg.fivegheight, 0, 0},
   83          {"HourlyGraphMode", 0, &cfg.hourlygmode, 0, 0},
   84          {"SummaryGraph", 0, &cfg.summarygraph, 0, 0},
   85          {"EstimateStyle", 0, &cfg.estimatestyle, 0, 0},
   86          {"BarColumnShowsRate", 0, &cfg.barshowsrate, 0, 0},
   87          {"CBackground", cfg.cbg, 0, 8, 0},
   88          {"CEdge", cfg.cedge, 0, 8, 0},
   89          {"CHeader", cfg.cheader, 0, 8, 0},
   90          {"CHeaderTitle", cfg.cheadertitle, 0, 8, 0},
   91          {"CHeaderDate", cfg.cheaderdate, 0, 8, 0},
   92          {"CText", cfg.ctext, 0, 8, 0},
   93          {"CLine", cfg.cline, 0, 8, 0},
   94          {"CLineL", cfg.clinel, 0, 8, 0},
   95          {"CRx", cfg.crx, 0, 8, 0},
   96          {"CRxD", cfg.crxd, 0, 8, 0},
   97          {"CTx", cfg.ctx, 0, 8, 0},
   98          {"CTxD", cfg.ctxd, 0, 8, 0},
   99          {"Experimental", 0, &cfg.experimental, 0, 0},
  100          {0, 0, 0, 0, 0}};
  101 
  102     /* load default config */
  103     defaultcfg();
  104 
  105     i = opencfgfile(cfgfile, &fd);
  106     if (i != 2)
  107         return i;
  108 
  109     rewind(fd);
  110 
  111     /* parse every config file line */
  112     while (!feof(fd)) {
  113 
  114         cfgline[0] = '\0';
  115         if (fgets(cfgline, 512, fd) == NULL) {
  116             break;
  117         }
  118 
  119         linelen = (unsigned int)strlen(cfgline);
  120         if (linelen <= 2 || cfgline[0] == '#' || cfgline[0] == ';') {
  121             continue;
  122         }
  123 
  124         for (i = 0; cset[i].name != 0; i++) {
  125 
  126             if (cset[i].found) {
  127                 continue;
  128             }
  129 
  130             cfglen = (unsigned int)strlen(cset[i].name);
  131             if ((linelen < (cfglen + 2)) || (strncasecmp(cfgline, cset[i].name, cfglen) != 0)) {
  132                 continue;
  133             }
  134 
  135             if (!extractcfgvalue(value, 512, cfgline, cfglen)) {
  136                 if (debug)
  137                     printf("  c: %s   -> \"%s\" with no value, keeping default.\n", cfgline, cset[i].name);
  138                 cset[i].found = 1;
  139                 break;
  140             }
  141 
  142             if (!setcfgvalue(&cset[i], value, cfgline)) {
  143                 continue;
  144             }
  145 
  146             cset[i].found = 1;
  147             break;
  148         }
  149 
  150         if ((debug) && (!cset[i].found) && (strncasecmp(cfgline, "MaxBW", 5) != 0))
  151             printf("Unknown configuration line: %s", cfgline);
  152     }
  153 
  154     fclose(fd);
  155 
  156     /* validate config */
  157     validatecfg(type);
  158 
  159     return 1;
  160 }
  161 
  162 void validatebool(const char *cfgname, int32_t *cfgptr, const int32_t defaultvalue)
  163 {
  164     validateint(cfgname, cfgptr, defaultvalue, 0, 1);
  165 }
  166 
  167 void validateint(const char *cfgname, int32_t *cfgptr, const int32_t defaultvalue, const int32_t minvalue, const int32_t maxvalue)
  168 {
  169     if (maxvalue > minvalue) {
  170         if (*cfgptr < minvalue || *cfgptr > maxvalue) {
  171             snprintf(errorstring, 1024, "Invalid value \"%d\" for %s. Value needs to be between %d and %d. Using default value %d.", *cfgptr, cfgname, minvalue, maxvalue, defaultvalue);
  172             printe(PT_Config);
  173             *cfgptr = defaultvalue;
  174         }
  175     } else {
  176         if (*cfgptr < minvalue) {
  177             snprintf(errorstring, 1024, "Invalid value \"%d\" for %s. Value needs to be at least %d. Using default value %d.", *cfgptr, cfgname, minvalue, defaultvalue);
  178             printe(PT_Config);
  179             *cfgptr = defaultvalue;
  180         }
  181     }
  182 }
  183 
  184 void validatecfg(const ConfigType type)
  185 {
  186     uint32_t rolloversecs;
  187     const char *invalidvalue = "Invalid value for";
  188     const char *resettingto = "using default value";
  189     const char *noslashstart = "doesn't start with \"/\", using default value instead.";
  190 
  191     validateint("UnitMode", &cfg.unitmode, UNITMODE, 0, 2);
  192     validatebool("RateUnitMode", &cfg.rateunitmode, RATEUNITMODE);
  193     validateint("OutputStyle", &cfg.ostyle, OSTYLE, 0, 3);
  194     validatebool("EstimateBarVisible", &cfg.estimatebarvisible, ESTIMATEBARVISIBLE);
  195     validateint("DefaultDecimals", &cfg.defaultdecimals, DEFAULTDECIMALS, 0, 2);
  196     validateint("HourlyDecimals", &cfg.hourlydecimals, HOURLYDECIMALS, 0, 2);
  197     validateint("HourlySectionStyle", &cfg.hourlystyle, HOURLYSTYLE, 0, 3);
  198     validateint("BootVariation", &cfg.bvar, BVAR, 0, 300);
  199     validateint("Sampletime", &cfg.sampletime, DEFSAMPTIME, 2, 600);
  200     validateint("MonthRotate", &cfg.monthrotate, MONTHROTATE, 1, 28);
  201     validatebool("MonthRotateAffectsYears", &cfg.monthrotateyears, MONTHROTATEYEARS);
  202     validateint("MaxBandwidth", &cfg.maxbw, DEFMAXBW, 0, BWMAX);
  203     validatebool("CheckDiskSpace", &cfg.spacecheck, USESPACECHECK);
  204     validateint("TimeSyncWait", &cfg.timesyncwait, TIMESYNCWAIT, 0, 60);
  205     validateint("PollInterval", &cfg.pollinterval, POLLINTERVAL, 2, 60);
  206     validatebool("SaveOnStatusChange", &cfg.savestatus, SAVESTATUS);
  207     validateint("UseLogging", &cfg.uselogging, USELOGGING, 0, 2);
  208     validateint("CreateDirs", &cfg.createdirs, CREATEDIRS, 0, 2);
  209     validateint("UpdateFileOwner", &cfg.updatefileowner, UPDATEFILEOWNER, 0, 2);
  210     validateint("64bitInterfaceCounters", &cfg.is64bit, IS64BIT, -2, 1);
  211     validatebool("DatabaseWriteAheadLogging", &cfg.waldb, WALDB);
  212     validateint("DatabaseSynchronous", &cfg.dbsynchronous, DBSYNCHRONOUS, -1, 3);
  213     validatebool("UseUTC", &cfg.useutc, USEUTC);
  214     if (type == CT_Image || type == CT_All) {
  215         validatebool("TransparentBg", &cfg.transbg, TRANSBG);
  216         validatebool("LargeFonts", &cfg.largefonts, LARGEFONTS);
  217         validateint("LineSpacingAdjustment", &cfg.linespaceadjust, LINESPACEADJUST, -5, 10);
  218         validateint("ImageScale", &cfg.imagescale, IMAGESCALE, 50, 500);
  219         validateint("5MinuteGraphResultCount", &cfg.fivegresultcount, FIVEGRESULTCOUNT, FIVEGMINRESULTCOUNT, 2000);
  220         validateint("5MinuteGraphHeight", &cfg.fivegheight, FIVEGHEIGHT, FIVEGMINHEIGHT, 2000);
  221         validateint("HourlyGraphMode", &cfg.hourlygmode, HOURLYGMODE, 0, 1);
  222         validatebool("SummaryGraph", &cfg.summarygraph, SUMMARYGRAPH);
  223         validateint("EstimateStyle", &cfg.estimatestyle, ESTIMATESTYLE, 0, 2);
  224         validatebool("BarColumnShowsRate", &cfg.barshowsrate, BARSHOWSRATE);
  225         validatebool("HourlyRate", &cfg.hourlyrate, HOURLYRATE);
  226         validatebool("SummaryRate", &cfg.summaryrate, SUMMARYRATE);
  227     }
  228     validatebool("TrafficlessEntries", &cfg.trafficlessentries, TRAFFICLESSENTRIES);
  229     validateint("List5Mins", &cfg.listfivemins, LISTFIVEMINS, 0, 0);
  230     validateint("ListHours", &cfg.listhours, LISTHOURS, 0, 0);
  231     validateint("ListDays", &cfg.listdays, LISTDAYS, 0, 0);
  232     validateint("ListMonths", &cfg.listmonths, LISTMONTHS, 0, 0);
  233     validateint("ListYears", &cfg.listyears, LISTYEARS, 0, 0);
  234     validateint("ListTop", &cfg.listtop, LISTTOP, 0, 0);
  235     validateint("InterfaceMatchMethod", &cfg.ifacematchmethod, IFACEMATCHMETHOD, 0, 3);
  236     validateint("5MinuteHours", &cfg.fiveminutehours, FIVEMINUTEHOURS, -1, -1);
  237     validateint("HourlyDays", &cfg.hourlydays, HOURLYDAYS, -1, -1);
  238     validateint("DailyDays", &cfg.dailydays, DAILYDAYS, -1, -1);
  239     validateint("MonthlyMonths", &cfg.monthlymonths, MONTHLYMONTHS, -1, -1);
  240     validateint("YearlyYears", &cfg.yearlyyears, YEARLYYEARS, -1, -1);
  241     validateint("TopDayEntries", &cfg.topdayentries, TOPDAYENTRIES, -1, -1);
  242     validatebool("BandwidthDetection", &cfg.bwdetection, BWDETECT);
  243     validateint("BandwidthDetectionInterval", &cfg.bwdetectioninterval, BWDETECTINTERVAL, 0, 30);
  244     validatebool("Experimental", &cfg.experimental, 0);
  245 
  246     if (cfg.useutc) {
  247         strncpy_nt(cfg.dbtzmodifier, "", 14);
  248     } else {
  249         strncpy_nt(cfg.dbtzmodifier, DATABASELOCALTIMEMODIFIER, 14);
  250     }
  251 
  252     if (cfg.dbdir[0] != '/') {
  253         strncpy_nt(cfg.dbdir, DATABASEDIR, 512);
  254         snprintf(errorstring, 1024, "DatabaseDir %s", noslashstart);
  255         printe(PT_Config);
  256     }
  257 
  258     if (cfg.logfile[0] != '/') {
  259         strncpy_nt(cfg.logfile, LOGFILE, 512);
  260         snprintf(errorstring, 1024, "LogFile %s", noslashstart);
  261         printe(PT_Config);
  262     }
  263 
  264     if (cfg.pidfile[0] != '/') {
  265         strncpy_nt(cfg.pidfile, PIDFILE, 512);
  266         snprintf(errorstring, 1024, "PidFile %s", noslashstart);
  267         printe(PT_Config);
  268     }
  269 
  270     if (type == CT_Daemon || type == CT_All) {
  271         validatebool("RescanDatabaseOnSave", &cfg.rescanonsave, RESCANONSAVE);
  272         validatebool("AlwaysAddNewInterfaces", &cfg.alwaysadd, ALWAYSADD);
  273 
  274         if (cfg.updateinterval < cfg.pollinterval || cfg.updateinterval > 300) {
  275             if (cfg.pollinterval > UPDATEINTERVAL) {
  276                 cfg.updateinterval = cfg.pollinterval;
  277             } else {
  278                 cfg.updateinterval = UPDATEINTERVAL;
  279             }
  280             snprintf(errorstring, 1024, "%s UpdateInterval, %s %d.", invalidvalue, resettingto, cfg.updateinterval);
  281             printe(PT_Config);
  282         }
  283 
  284         if ((cfg.saveinterval * 60) < cfg.updateinterval || cfg.saveinterval > 60) {
  285             if (cfg.updateinterval > (SAVEINTERVAL * 60)) {
  286                 cfg.saveinterval = cfg.updateinterval;
  287             } else {
  288                 cfg.saveinterval = SAVEINTERVAL;
  289             }
  290             snprintf(errorstring, 1024, "%s SaveInterval, %s %d.", invalidvalue, resettingto, cfg.saveinterval);
  291             printe(PT_Config);
  292         }
  293 
  294         if (cfg.offsaveinterval < cfg.saveinterval || cfg.offsaveinterval > 60) {
  295             if (cfg.saveinterval > OFFSAVEINTERVAL) {
  296                 cfg.offsaveinterval = cfg.saveinterval;
  297             } else {
  298                 cfg.offsaveinterval = OFFSAVEINTERVAL;
  299             }
  300             snprintf(errorstring, 1024, "%s OfflineSaveInterval, %s %d.", invalidvalue, resettingto, cfg.offsaveinterval);
  301             printe(PT_Config);
  302         }
  303 
  304         /* enforce update interval to be short enough that 32-bit interface counter rollover can be detected */
  305         /* 1.02 is the same 2% safety buffer as used in processifinfo() in daemon.c */
  306         if (cfg.maxbw > 0) {
  307             rolloversecs = (uint32_t)((float)MAX32 / ((float)cfg.maxbw * 1024 * 1024 * (float)1.02 / 8));
  308             if (rolloversecs <= (uint32_t)cfg.updateinterval) {
  309                 cfg.updateinterval = UPDATEINTERVAL;
  310                 if (rolloversecs <= (uint32_t)cfg.updateinterval) {
  311                     cfg.updateinterval /= 2;
  312                 }
  313                 snprintf(errorstring, 1024, "UpdateInterval has been reset to %d seconds in order to ensure correct counter rollover detection at %d Mbit.", cfg.updateinterval, cfg.maxbw);
  314                 printe(PT_Config);
  315             }
  316         }
  317     }
  318 
  319     /* affects only image output */
  320     if (type == CT_Image || type == CT_All) {
  321         if (cfg.barshowsrate && cfg.estimatebarvisible) {
  322             cfg.estimatestyle = 0;
  323             if (debug) {
  324                 printf("BarColumnShowsRate and EstimateBarVisible both enabled -> EstimateStyle set to 0\n");
  325             }
  326         }
  327 
  328         if (cfg.fiveminutehours > 0 && cfg.fivegresultcount > cfg.fiveminutehours * 12) {
  329             if (cfg.fiveminutehours * 12 < FIVEGMINRESULTCOUNT) {
  330                 snprintf(errorstring, 1024, "Value \"%d\" for 5MinuteHours is too small for 5MinuteGraphResultCount with value \"%d\" (smallest supported value: %d). Value for 5MinuteHours needs to be at least %d if 5MinuteGraphResultCount is set to %d.", cfg.fiveminutehours, cfg.fivegresultcount, FIVEGMINRESULTCOUNT, FIVEGMINRESULTCOUNT / 12, FIVEGMINRESULTCOUNT);
  331                 cfg.fivegresultcount = FIVEGMINRESULTCOUNT;
  332             } else {
  333                 snprintf(errorstring, 1024, "5MinuteGraphResultCount has been adjusted to %d because requested \"%d\" requires more data than can be available with value %d for 5MinuteHours.", cfg.fiveminutehours * 12, cfg.fivegresultcount, cfg.fiveminutehours);
  334                 cfg.fivegresultcount = cfg.fiveminutehours * 12;
  335             }
  336             printe(PT_Config);
  337         }
  338     }
  339 }
  340 
  341 void defaultcfg(void)
  342 {
  343     ifacebw = NULL;
  344 
  345     cfg.bvar = BVAR;
  346     cfg.qmode = DEFQMODE;
  347     cfg.sampletime = DEFSAMPTIME;
  348     cfg.monthrotate = MONTHROTATE;
  349     cfg.monthrotateyears = MONTHROTATEYEARS;
  350     cfg.unitmode = UNITMODE;
  351     cfg.rateunitmode = RATEUNITMODE;
  352     cfg.ostyle = OSTYLE;
  353     cfg.estimatebarvisible = ESTIMATEBARVISIBLE;
  354     cfg.rateunit = RATEUNIT;
  355     cfg.defaultdecimals = DEFAULTDECIMALS;
  356     cfg.hourlydecimals = HOURLYDECIMALS;
  357     cfg.hourlystyle = HOURLYSTYLE;
  358     cfg.bwdetection = BWDETECT;
  359     cfg.bwdetectioninterval = BWDETECTINTERVAL;
  360     cfg.maxbw = DEFMAXBW;
  361     cfg.spacecheck = USESPACECHECK;
  362     cfg.hourlyrate = HOURLYRATE;
  363     cfg.summaryrate = SUMMARYRATE;
  364     cfg.trafficlessentries = TRAFFICLESSENTRIES;
  365     cfg.utflocale = UTFLOCALE;
  366     cfg.ifacematchmethod = IFACEMATCHMETHOD;
  367 
  368     cfg.listfivemins = LISTFIVEMINS;
  369     cfg.listhours = LISTHOURS;
  370     cfg.listdays = LISTDAYS;
  371     cfg.listmonths = LISTMONTHS;
  372     cfg.listyears = LISTYEARS;
  373     cfg.listtop = LISTTOP;
  374     cfg.listjsonxml = LISTJSONXML;
  375 
  376     cfg.fiveminutehours = FIVEMINUTEHOURS;
  377     cfg.hourlydays = HOURLYDAYS;
  378     cfg.dailydays = DAILYDAYS;
  379     cfg.monthlymonths = MONTHLYMONTHS;
  380     cfg.yearlyyears = YEARLYYEARS;
  381     cfg.topdayentries = TOPDAYENTRIES;
  382 
  383     strncpy_nt(cfg.dbdir, DATABASEDIR, 512);
  384     strncpy_nt(cfg.dbtzmodifier, DATABASELOCALTIMEMODIFIER, 14);
  385     strncpy_nt(cfg.iface, DEFIFACE, 32);
  386     strncpy_nt(cfg.locale, LOCALE, 32);
  387     strncpy_nt(cfg.dformat, DFORMAT, 64);
  388     strncpy_nt(cfg.mformat, MFORMAT, 64);
  389     strncpy_nt(cfg.tformat, TFORMAT, 64);
  390     strncpy_nt(cfg.hformat, HFORMAT, 64);
  391     strncpy_nt(cfg.rxchar, RXCHAR, 2);
  392     strncpy_nt(cfg.txchar, TXCHAR, 2);
  393     strncpy_nt(cfg.rxhourchar, RXHOURCHAR, 2);
  394     strncpy_nt(cfg.txhourchar, TXHOURCHAR, 2);
  395 
  396     cfg.daemonuser[0] = '\0';
  397     cfg.daemongroup[0] = '\0';
  398     cfg.timesyncwait = TIMESYNCWAIT;
  399     cfg.updateinterval = UPDATEINTERVAL;
  400     cfg.pollinterval = POLLINTERVAL;
  401     cfg.saveinterval = SAVEINTERVAL;
  402     cfg.offsaveinterval = OFFSAVEINTERVAL;
  403     cfg.rescanonsave = RESCANONSAVE;
  404     cfg.alwaysadd = ALWAYSADD;
  405     cfg.savestatus = SAVESTATUS;
  406     cfg.uselogging = USELOGGING;
  407     cfg.createdirs = CREATEDIRS;
  408     cfg.updatefileowner = UPDATEFILEOWNER;
  409     strncpy_nt(cfg.logfile, LOGFILE, 512);
  410     strncpy_nt(cfg.pidfile, PIDFILE, 512);
  411     cfg.is64bit = IS64BIT;
  412     cfg.waldb = WALDB;
  413     cfg.dbsynchronous = DBSYNCHRONOUS;
  414     cfg.useutc = USEUTC;
  415 
  416     cfg.transbg = TRANSBG;
  417     cfg.largefonts = LARGEFONTS;
  418     cfg.linespaceadjust = LINESPACEADJUST;
  419     cfg.imagescale = IMAGESCALE;
  420     cfg.fivegresultcount = FIVEGRESULTCOUNT;
  421     cfg.fivegheight = FIVEGHEIGHT;
  422     cfg.hourlygmode = HOURLYGMODE;
  423     cfg.summarygraph = SUMMARYGRAPH;
  424     cfg.estimatestyle = ESTIMATESTYLE;
  425     cfg.barshowsrate = BARSHOWSRATE;
  426     strncpy_nt(cfg.cbg, CBACKGROUND, 8);
  427     strncpy_nt(cfg.cedge, CEDGE, 8);
  428     strncpy_nt(cfg.cheader, CHEADER, 8);
  429     strncpy_nt(cfg.cheadertitle, CHEADERTITLE, 8);
  430     strncpy_nt(cfg.cheaderdate, CHEADERDATE, 8);
  431     strncpy_nt(cfg.ctext, CTEXT, 8);
  432     strncpy_nt(cfg.cline, CLINE, 8);
  433     strncpy_nt(cfg.clinel, CLINEL, 8);
  434     strncpy_nt(cfg.crx, CRX, 8);
  435     strncpy_nt(cfg.crxd, CRXD, 8);
  436     strncpy_nt(cfg.ctx, CTX, 8);
  437     strncpy_nt(cfg.ctxd, CTXD, 8);
  438 
  439     cfg.timestampprints = 0;
  440     cfg.experimental = 0;
  441 }
  442 
  443 int opencfgfile(const char *cfgfile, FILE **fd)
  444 {
  445     char buffer[512];
  446     int i, tryhome;
  447 
  448     /* clear buffer */
  449     for (i = 0; i < 512; i++) {
  450         buffer[i] = '\0';
  451     }
  452     cfg.cfgfile[0] = '\0';
  453 
  454     /* possible config files: 1) --config   2) $HOME/.vnstatrc   3) /etc/vnstat.conf   4) none */
  455 
  456     if (cfgfile[0] != '\0') {
  457 
  458         /* try to open given file */
  459         if ((*fd = fopen(cfgfile, "r")) != NULL) {
  460             strncpy_nt(cfg.cfgfile, cfgfile, 512);
  461             if (debug)
  462                 printf("Config file: --config\n");
  463         } else {
  464             snprintf(errorstring, 1024, "Unable to open given config file \"%s\": %s", cfgfile, strerror(errno));
  465             printe(PT_Error);
  466             return 0;
  467         }
  468 
  469     } else {
  470 
  471         if (getenv("HOME")) {
  472             strncpy_nt(buffer, getenv("HOME"), 500);
  473             strcat(buffer, "/.vnstatrc");
  474             tryhome = 1;
  475         } else {
  476             tryhome = 0;
  477         }
  478 
  479         /* try to open first available config file */
  480         if (tryhome && (*fd = fopen(buffer, "r")) != NULL) {
  481             strncpy_nt(cfg.cfgfile, buffer, 512);
  482         } else if ((*fd = fopen("/etc/vnstat.conf", "r")) != NULL) {
  483             snprintf(cfg.cfgfile, 512, "/etc/vnstat.conf");
  484         } else if ((*fd = fopen("/usr/local/etc/vnstat.conf", "r")) != NULL) {
  485             snprintf(cfg.cfgfile, 512, "/usr/local/etc/vnstat.conf");
  486         } else {
  487             if (debug)
  488                 printf("Config file: none\n");
  489             return 1;
  490         }
  491         if (debug)
  492             printf("Config file: %s\n", cfg.cfgfile);
  493     }
  494 
  495     return 2;
  496 }
  497 
  498 int extractcfgvalue(char *value, const unsigned int valuelen, const char *cfgline, const unsigned int cfglen)
  499 {
  500 
  501     unsigned int i, j, linelen;
  502 
  503     linelen = (unsigned int)strlen(cfgline);
  504 
  505     for (i = 0; i < valuelen; i++) {
  506         value[i] = '\0';
  507     }
  508 
  509     i = 0;
  510     for (j = cfglen; j < linelen; j++) {
  511         if (cfgline[j] == '\n' || cfgline[j] == '\r') {
  512             break;
  513         } else if (cfgline[j] == '\"') {
  514             if (i == 0) {
  515                 continue;
  516             } else {
  517                 break;
  518             }
  519         } else {
  520             if (i == 0 && (cfgline[j] == ' ' || cfgline[j] == '=' || cfgline[j] == '\t')) {
  521                 continue;
  522             } else {
  523                 value[i] = cfgline[j];
  524                 i++;
  525             }
  526         }
  527     }
  528 
  529     return (int)strlen(value);
  530 }
  531 
  532 int setcfgvalue(const struct cfgsetting *cset, const char *value, const char *cfgline)
  533 {
  534     if (cset->namelen > 0) {
  535         strncpy_nt(cset->locc, value, (size_t)cset->namelen);
  536         if (debug)
  537             printf("  c: %s   -> \"%s\": \"%s\"\n", cfgline, cset->name, cset->locc);
  538     } else if ((strlen(value) > 1 && isdigit(value[1])) || isdigit(value[0])) {
  539         *cset->loci = (int32_t)strtol(value, (char **)NULL, 0);
  540         if (debug)
  541             printf("  i: %s   -> \"%s\": %d\n", cfgline, cset->name, *cset->loci);
  542     } else {
  543         return 0;
  544     }
  545 
  546     return 1;
  547 }
  548 
  549 void configlocale(void)
  550 {
  551     const char *env = getenv("LC_ALL");
  552 
  553     if (cfg.locale[0] != '-' && strlen(cfg.locale) > 0) {
  554         setlocale(LC_ALL, cfg.locale);
  555     } else {
  556         if (env) {
  557             setlocale(LC_ALL, env);
  558         } else {
  559             setlocale(LC_ALL, "");
  560         }
  561     }
  562     if (env) {
  563         if (strstr(env, "UTF") != NULL) {
  564             cfg.utflocale = 1;
  565         } else {
  566             cfg.utflocale = 0;
  567         }
  568     }
  569 }