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