1 #include "common.h"
2 #include "ifinfo.h"
3 #include "iflist.h"
4 #include "traffic.h"
5 #include "dbsql.h"
6 #include "dbxml.h"
7 #include "dbjson.h"
8 #include "dbshow.h"
9 #include "misc.h"
10 #include "cfg.h"
11 #include "cfgoutput.h"
12 #include "vnstat_func.h"
13 
initparams(PARAMS * p)14 void initparams(PARAMS *p)
15 {
16 	db = NULL;
17 	noexit = 0;		   /* allow functions to exit in case of error */
18 	debug = 0;		   /* debug disabled by default */
19 	disableprints = 0; /* let prints be visible */
20 
21 	p->addiface = 0;
22 	p->query = 1;
23 	p->setalias = 0;
24 	p->dbifcount = 0;
25 	p->force = 0;
26 	p->traffic = 0;
27 	p->livetraffic = 0;
28 	p->defaultiface = 1;
29 	p->removeiface = 0;
30 	p->renameiface = 0;
31 	p->livemode = 0;
32 	p->limit = -1;
33 	p->ifacelist = NULL;
34 	p->interface[0] = '\0';
35 	p->alias[0] = '\0';
36 	p->newifname[0] = '\0';
37 	p->filename[0] = '\0';
38 	p->definterface[0] = '\0';
39 	p->cfgfile[0] = '\0';
40 	p->jsonmode = 'a';
41 	p->xmlmode = 'a';
42 	p->databegin[0] = '\0';
43 	p->dataend[0] = '\0';
44 }
45 
showhelp(PARAMS * p)46 void showhelp(PARAMS *p)
47 {
48 	printf("vnStat %s by Teemu Toivola <tst at iki dot fi>\n\n", getversion());
49 
50 	printf("      -5,  --fiveminutes [limit]   show 5 minutes\n");
51 	printf("      -h,  --hours [limit]         show hours\n");
52 	printf("      -hg, --hoursgraph            show hours graph\n");
53 	printf("      -d,  --days [limit]          show days\n");
54 	printf("      -m,  --months [limit]        show months\n");
55 	printf("      -y,  --years [limit]         show years\n");
56 	printf("      -t,  --top [limit]           show top days\n\n");
57 
58 	printf("      -b, --begin <date>           set list begin date\n");
59 	printf("      -e, --end <date>             set list end date\n\n");
60 
61 	printf("      --oneline [mode]             show simple parsable format\n");
62 	printf("      --json [mode] [limit]        show database in json format\n");
63 	printf("      --xml [mode] [limit]         show database in xml format\n\n");
64 
65 	printf("      -tr, --traffic [time]        calculate traffic\n");
66 	printf("      -l,  --live [mode]           show transfer rate in real time\n");
67 	printf("      -i,  --iface <interface>     select interface");
68 	if (strlen(p->definterface)) {
69 		printf(" (default: %s)", p->definterface);
70 	}
71 	printf("\n\n");
72 
73 	printf("Use \"--longhelp\" or \"man vnstat\" for complete list of options.\n");
74 }
75 
showlonghelp(PARAMS * p)76 void showlonghelp(PARAMS *p)
77 {
78 	printf("vnStat %s by Teemu Toivola <tst at iki dot fi>\n\n", getversion());
79 
80 	printf("Query:\n");
81 
82 	printf("      -q,  --query                 query database\n");
83 	printf("      -s,  --short                 use short output\n");
84 	printf("      -5,  --fiveminutes [limit]   show 5 minutes\n");
85 	printf("      -h,  --hours [limit]         show hours\n");
86 	printf("      -hg, --hoursgraph            show hours graph\n");
87 	printf("      -d,  --days [limit]          show days\n");
88 	printf("      -m,  --months [limit]        show months\n");
89 	printf("      -y,  --years [limit]         show years\n");
90 	printf("      -t,  --top [limit]           show top days\n");
91 	printf("      -b,  --begin <date>          set list begin date\n");
92 	printf("      -e,  --end <date>            set list end date\n");
93 	printf("      --oneline [mode]             show simple parsable format\n");
94 	printf("      --json [mode] [limit]        show database in json format\n");
95 	printf("      --xml [mode] [limit]         show database in xml format\n\n");
96 
97 	printf("Modify:\n");
98 
99 	printf("      --add                        add interface to database\n");
100 	printf("      --remove                     remove interface from database\n");
101 	printf("      --rename <name>              rename interface in database\n");
102 	printf("      --setalias <alias>           set alias for interface\n\n");
103 
104 	printf("Misc:\n");
105 
106 	printf("      -i,  --iface <interface>     select interface");
107 	if (strlen(p->definterface)) {
108 		printf(" (default: %s)", p->definterface);
109 	}
110 	printf("\n");
111 	printf("      -?,  --help                  show short help\n");
112 	printf("      -D,  --debug                 show some additional debug information\n");
113 	printf("      -v,  --version               show version\n");
114 	printf("      -tr, --traffic [time]        calculate traffic\n");
115 	printf("      -l,  --live [mode]           show transfer rate in real time\n");
116 	printf("      -ru, --rateunit [mode]       swap configured rate unit\n");
117 	printf("      --limit <limit>              set output entry limit\n");
118 	printf("      --style <mode>               select output style (0-4)\n");
119 	printf("      --iflist [mode]              show list of available interfaces\n");
120 	printf("      --dbiflist [mode]            show list of interfaces in database\n");
121 	printf("      --dbdir <directory>          select database directory\n");
122 	printf("      --locale <locale>            set locale\n");
123 	printf("      --config <config file>       select config file\n");
124 	printf("      --showconfig                 dump config file with current settings\n");
125 	printf("      --longhelp                   show this help\n\n");
126 
127 	printf("See also \"man vnstat\" for longer descriptions of each option.\n");
128 }
129 
parseargs(PARAMS * p,int argc,char ** argv)130 void parseargs(PARAMS *p, int argc, char **argv)
131 {
132 	int currentarg;
133 
134 	/* parse parameters, maybe not the best way but... */
135 	for (currentarg = 1; currentarg < argc; currentarg++) {
136 		if (debug)
137 			printf("arg %d: \"%s\"\n", currentarg, argv[currentarg]);
138 		if (strcmp(argv[currentarg], "--longhelp") == 0) {
139 			showlonghelp(p);
140 			exit(EXIT_SUCCESS);
141 		} else if ((strcmp(argv[currentarg], "-?") == 0) || (strcmp(argv[currentarg], "--help") == 0)) {
142 			showhelp(p);
143 			exit(EXIT_SUCCESS);
144 		} else if ((strcmp(argv[currentarg], "-i") == 0) || (strcmp(argv[currentarg], "--iface") == 0) || (strcmp(argv[currentarg], "--interface") == 0)) {
145 			if (currentarg + 1 < argc) {
146 				if (strlen(argv[currentarg + 1]) > 31) {
147 					printf("Error: Interface name is limited to 31 characters.\n");
148 					exit(EXIT_FAILURE);
149 				}
150 				strncpy_nt(p->interface, argv[currentarg + 1], 32);
151 				if (strlen(p->interface)) {
152 					p->defaultiface = 0;
153 				} else {
154 					strncpy_nt(p->definterface, p->interface, 32);
155 				}
156 				if (debug)
157 					printf("Used interface: \"%s\"\n", p->interface);
158 				currentarg++;
159 			} else {
160 				printf("Error: Interface for %s missing.\n", argv[currentarg]);
161 				exit(EXIT_FAILURE);
162 			}
163 		} else if (strcmp(argv[currentarg], "--config") == 0) {
164 			/* config has already been parsed earlier so nothing to do here */
165 			currentarg++;
166 		} else if (strcmp(argv[currentarg], "--setalias") == 0 || strcmp(argv[currentarg], "--nick") == 0) {
167 			if (strcmp(argv[currentarg], "--nick") == 0) {
168 				printf("Warning: --nick is deprecated and will be removed in a future release. Use --setalias instead.\n");
169 			}
170 			if (currentarg + 1 < argc) {
171 				strncpy_nt(p->alias, argv[currentarg + 1], 32);
172 				if (debug)
173 					printf("Used alias: \"%s\"\n", p->alias);
174 				p->setalias = 1;
175 				currentarg++;
176 			} else {
177 				printf("Error: Alias for %s missing.\n", argv[currentarg]);
178 				exit(EXIT_FAILURE);
179 			}
180 		} else if ((strcmp(argv[currentarg], "--style")) == 0) {
181 			if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) {
182 				cfg.ostyle = atoi(argv[currentarg + 1]);
183 				if (cfg.ostyle > 4 || cfg.ostyle < 0) {
184 					printf("Error: Invalid style parameter \"%d\"\n", cfg.ostyle);
185 					showstylehelp();
186 					exit(EXIT_FAILURE);
187 				}
188 				if (debug)
189 					printf("Style changed: %d\n", cfg.ostyle);
190 				currentarg++;
191 			} else {
192 				printf("Error: Style parameter for --style missing.\n");
193 				showstylehelp();
194 				exit(EXIT_FAILURE);
195 			}
196 		} else if ((strcmp(argv[currentarg], "--dbdir")) == 0) {
197 			if (currentarg + 1 < argc) {
198 				strncpy_nt(cfg.dbdir, argv[currentarg + 1], 512);
199 				if (debug)
200 					printf("DatabaseDir: \"%s\"\n", cfg.dbdir);
201 				currentarg++;
202 			} else {
203 				printf("Error: Directory for %s missing.\n", argv[currentarg]);
204 				exit(EXIT_FAILURE);
205 			}
206 		} else if ((strcmp(argv[currentarg], "--locale")) == 0) {
207 			if (currentarg + 1 < argc) {
208 				setlocale(LC_ALL, argv[currentarg + 1]);
209 				if (debug)
210 					printf("Locale: \"%s\"\n", argv[currentarg + 1]);
211 				currentarg++;
212 			} else {
213 				printf("Error: Locale for %s missing.\n", argv[currentarg]);
214 				exit(EXIT_FAILURE);
215 			}
216 		} else if (strcmp(argv[currentarg], "--add") == 0) {
217 			p->addiface = 1;
218 			p->query = 0;
219 		} else if ((strcmp(argv[currentarg], "-u") == 0) || (strcmp(argv[currentarg], "--update") == 0)) {
220 			printf("Error: The \"%s\" parameter is not supported in this version.\n", argv[currentarg]);
221 			exit(EXIT_FAILURE);
222 		} else if ((strcmp(argv[currentarg], "-q") == 0) || (strcmp(argv[currentarg], "--query") == 0)) {
223 			p->query = 1;
224 		} else if ((strcmp(argv[currentarg], "-D") == 0) || (strcmp(argv[currentarg], "--debug") == 0)) {
225 			debug = 1;
226 		} else if ((strcmp(argv[currentarg], "-d") == 0) || (strcmp(argv[currentarg], "--days") == 0)) {
227 			cfg.qmode = 1;
228 			if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) {
229 				cfg.listdays = atoi(argv[currentarg + 1]);
230 				if (cfg.listdays < 0) {
231 					printf("Error: Invalid limit parameter \"%s\" for %s. Only a zero and positive numbers are allowed.\n", argv[currentarg + 1], argv[currentarg]);
232 					exit(EXIT_FAILURE);
233 				}
234 				currentarg++;
235 			}
236 		} else if ((strcmp(argv[currentarg], "-m") == 0) || (strcmp(argv[currentarg], "--months") == 0)) {
237 			cfg.qmode = 2;
238 			if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) {
239 				cfg.listmonths = atoi(argv[currentarg + 1]);
240 				if (cfg.listmonths < 0) {
241 					printf("Error: Invalid limit parameter \"%s\" for %s. Only a zero and positive numbers are allowed.\n", argv[currentarg + 1], argv[currentarg]);
242 					exit(EXIT_FAILURE);
243 				}
244 				currentarg++;
245 			}
246 		} else if ((strcmp(argv[currentarg], "-t") == 0) || (strcmp(argv[currentarg], "--top") == 0)) {
247 			cfg.qmode = 3;
248 			if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) {
249 				cfg.listtop = atoi(argv[currentarg + 1]);
250 				if (cfg.listtop < 0) {
251 					printf("Error: Invalid limit parameter \"%s\" for %s. Only a zero and positive numbers are allowed.\n", argv[currentarg + 1], argv[currentarg]);
252 					exit(EXIT_FAILURE);
253 				}
254 				currentarg++;
255 			}
256 		} else if ((strcmp(argv[currentarg], "-s") == 0) || (strcmp(argv[currentarg], "--short") == 0)) {
257 			cfg.qmode = 5;
258 		} else if ((strcmp(argv[currentarg], "-y") == 0) || (strcmp(argv[currentarg], "--years") == 0)) {
259 			cfg.qmode = 6;
260 			if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) {
261 				cfg.listyears = atoi(argv[currentarg + 1]);
262 				if (cfg.listyears < 0) {
263 					printf("Error: Invalid limit parameter \"%s\" for %s. Only a zero and positive numbers are allowed.\n", argv[currentarg + 1], argv[currentarg]);
264 					exit(EXIT_FAILURE);
265 				}
266 				currentarg++;
267 			}
268 		} else if ((strcmp(argv[currentarg], "-hg") == 0) || (strcmp(argv[currentarg], "--hoursgraph") == 0)) {
269 			cfg.qmode = 7;
270 		} else if ((strcmp(argv[currentarg], "-h") == 0) || (strcmp(argv[currentarg], "--hours") == 0)) {
271 			cfg.qmode = 11;
272 			if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) {
273 				cfg.listhours = atoi(argv[currentarg + 1]);
274 				if (cfg.listhours < 0) {
275 					printf("Error: Invalid limit parameter \"%s\" for %s. Only a zero and positive numbers are allowed.\n", argv[currentarg + 1], argv[currentarg]);
276 					exit(EXIT_FAILURE);
277 				}
278 				currentarg++;
279 			}
280 		} else if ((strcmp(argv[currentarg], "-5") == 0) || (strcmp(argv[currentarg], "--fiveminutes") == 0)) {
281 			cfg.qmode = 12;
282 			if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) {
283 				cfg.listfivemins = atoi(argv[currentarg + 1]);
284 				if (cfg.listfivemins < 0) {
285 					printf("Error: Invalid limit parameter \"%s\" for %s. Only a zero and positive numbers are allowed.\n", argv[currentarg + 1], argv[currentarg]);
286 					exit(EXIT_FAILURE);
287 				}
288 				currentarg++;
289 			}
290 		} else if (strcmp(argv[currentarg], "--oneline") == 0) {
291 			cfg.qmode = 9;
292 			if (currentarg + 1 < argc && (strlen(argv[currentarg + 1]) == 1 || ishelprequest(argv[currentarg + 1]))) {
293 				if (argv[currentarg + 1][0] == 'b') {
294 					cfg.ostyle = 4;
295 					currentarg++;
296 				} else {
297 					if (!ishelprequest(argv[currentarg + 1]))
298 						printf("Error: Invalid mode parameter \"%s\".\n", argv[currentarg + 1]);
299 					printf(" Valid parameters for --oneline:\n");
300 					printf("    (none) - automatically scaled units visible\n");
301 					printf("    b      - all values in bytes\n");
302 					exit(EXIT_FAILURE);
303 				}
304 			}
305 		} else if (strcmp(argv[currentarg], "--xml") == 0) {
306 			cfg.qmode = 8;
307 			if (currentarg + 1 < argc && (strlen(argv[currentarg + 1]) == 1 || ishelprequest(argv[currentarg + 1]))) {
308 				p->xmlmode = argv[currentarg + 1][0];
309 				if (strlen(argv[currentarg + 1]) != 1 || strchr("afhdmyt", p->xmlmode) == NULL) {
310 					if (!ishelprequest(argv[currentarg + 1]))
311 						printf("Error: Invalid mode parameter \"%s\".\n", argv[currentarg + 1]);
312 					printf(" Valid parameters for --xml:\n");
313 					printf("    a - all (default)\n");
314 					printf("    f - only 5 minutes\n");
315 					printf("    h - only hours\n");
316 					printf("    d - only days\n");
317 					printf("    m - only months\n");
318 					printf("    y - only years\n");
319 					printf("    t - only top\n");
320 					exit(EXIT_FAILURE);
321 				}
322 				currentarg++;
323 			}
324 			if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) {
325 				cfg.listjsonxml = atoi(argv[currentarg + 1]);
326 				if (cfg.listjsonxml < 0) {
327 					printf("Error: Invalid limit parameter \"%s\" for %s. Only a zero and positive numbers are allowed.\n", argv[currentarg + 1], argv[currentarg]);
328 					exit(EXIT_FAILURE);
329 				}
330 				currentarg++;
331 			}
332 		} else if (strcmp(argv[currentarg], "--json") == 0) {
333 			cfg.qmode = 10;
334 			if (currentarg + 1 < argc && (strlen(argv[currentarg + 1]) == 1 || ishelprequest(argv[currentarg + 1]))) {
335 				p->jsonmode = argv[currentarg + 1][0];
336 				if (strlen(argv[currentarg + 1]) != 1 || strchr("afhdmyt", p->jsonmode) == NULL) {
337 					if (!ishelprequest(argv[currentarg + 1]))
338 						printf("Error: Invalid mode parameter \"%s\".\n", argv[currentarg + 1]);
339 					printf(" Valid parameters for --json:\n");
340 					printf("    a - all (default)\n");
341 					printf("    f - only 5 minutes\n");
342 					printf("    h - only hours\n");
343 					printf("    d - only days\n");
344 					printf("    m - only months\n");
345 					printf("    y - only years\n");
346 					printf("    t - only top\n");
347 					exit(EXIT_FAILURE);
348 				}
349 				currentarg++;
350 			}
351 			if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) {
352 				cfg.listjsonxml = atoi(argv[currentarg + 1]);
353 				if (cfg.listjsonxml < 0) {
354 					printf("Error: Invalid limit parameter \"%s\" for %s. Only a zero and positive numbers are allowed.\n", argv[currentarg + 1], argv[currentarg]);
355 					exit(EXIT_FAILURE);
356 				}
357 				currentarg++;
358 			}
359 		} else if ((strcmp(argv[currentarg], "-ru") == 0) || (strcmp(argv[currentarg], "--rateunit")) == 0) {
360 			if (currentarg + 1 < argc && (strlen(argv[currentarg + 1]) == 1 || ishelprequest(argv[currentarg + 1]))) {
361 				if (!isdigit(argv[currentarg + 1][0]) || atoi(argv[currentarg + 1]) > 1 || atoi(argv[currentarg + 1]) < 0) {
362 					if (!ishelprequest(argv[currentarg + 1]))
363 						printf("Error: Invalid parameter \"%s\".\n", argv[currentarg + 1]);
364 					printf(" Valid parameters for %s:\n", argv[currentarg]);
365 					printf("    0 - bytes\n");
366 					printf("    1 - bits\n");
367 					exit(EXIT_FAILURE);
368 				}
369 				cfg.rateunit = atoi(argv[currentarg + 1]);
370 				if (debug)
371 					printf("Rateunit changed: %d\n", cfg.rateunit);
372 				currentarg++;
373 			} else {
374 				cfg.rateunit = !cfg.rateunit;
375 				if (debug)
376 					printf("Rateunit changed: %d\n", cfg.rateunit);
377 			}
378 		} else if ((strcmp(argv[currentarg], "-tr") == 0) || (strcmp(argv[currentarg], "--traffic") == 0)) {
379 			if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) {
380 				cfg.sampletime = atoi(argv[currentarg + 1]);
381 				currentarg++;
382 			}
383 			p->traffic = 1;
384 			p->query = 0;
385 		} else if ((strcmp(argv[currentarg], "-l") == 0) || (strcmp(argv[currentarg], "--live") == 0)) {
386 			if (currentarg + 1 < argc && (strlen(argv[currentarg + 1]) == 1 || ishelprequest(argv[currentarg + 1]))) {
387 				if (!isdigit(argv[currentarg + 1][0]) || atoi(argv[currentarg + 1]) > 1 || atoi(argv[currentarg + 1]) < 0) {
388 					if (!ishelprequest(argv[currentarg + 1]))
389 						printf("Error: Invalid mode parameter \"%s\".\n", argv[currentarg + 1]);
390 					printf(" Valid parameters for %s:\n", argv[currentarg]);
391 					printf("    0 - show packets per second (default)\n");
392 					printf("    1 - show transfer counters\n");
393 					exit(EXIT_FAILURE);
394 				}
395 				p->livemode = atoi(argv[currentarg + 1]);
396 				currentarg++;
397 			}
398 			p->livetraffic = 1;
399 			p->query = 0;
400 		} else if (strcmp(argv[currentarg], "--force") == 0) {
401 			p->force = 1;
402 		} else if (strcmp(argv[currentarg], "--showconfig") == 0) {
403 			printcfgfile();
404 			exit(EXIT_SUCCESS);
405 		} else if (strcmp(argv[currentarg], "--remove") == 0) {
406 			p->removeiface = 1;
407 			p->query = 0;
408 		} else if (strcmp(argv[currentarg], "--rename") == 0) {
409 			if (currentarg + 1 < argc) {
410 				strncpy_nt(p->newifname, argv[currentarg + 1], 32);
411 				if (debug)
412 					printf("Given new interface name: \"%s\"\n", p->newifname);
413 				p->renameiface = 1;
414 				p->query = 0;
415 				currentarg++;
416 			} else {
417 				printf("Error: New interface name for %s missing.\n", argv[currentarg]);
418 				exit(EXIT_FAILURE);
419 			}
420 		} else if ((strcmp(argv[currentarg], "-b") == 0) || (strcmp(argv[currentarg], "--begin") == 0)) {
421 			if (currentarg + 1 < argc) {
422 				if (!validatedatetime(argv[currentarg + 1])) {
423 					printf("Error: Invalid date format, expected YYYY-MM-DD HH:MM or YYYY-MM-DD.\n");
424 					exit(EXIT_FAILURE);
425 				}
426 				strncpy_nt(p->databegin, argv[currentarg + 1], 18);
427 				currentarg++;
428 			} else {
429 				printf("Error: Date of format YYYY-MM-DD HH:MM or YYYY-MM-DD for %s missing.\n", argv[currentarg]);
430 				exit(EXIT_FAILURE);
431 			}
432 		} else if ((strcmp(argv[currentarg], "-e") == 0) || (strcmp(argv[currentarg], "--end") == 0)) {
433 			if (currentarg + 1 < argc) {
434 				if (!validatedatetime(argv[currentarg + 1])) {
435 					printf("Error: Invalid date format, expected YYYY-MM-DD HH:MM or YYYY-MM-DD.\n");
436 					exit(EXIT_FAILURE);
437 				}
438 				strncpy_nt(p->dataend, argv[currentarg + 1], 18);
439 				currentarg++;
440 			} else {
441 				printf("Error: Date of format YYYY-MM-DD HH:MM or YYYY-MM-DD for %s missing.\n", argv[currentarg]);
442 				exit(EXIT_FAILURE);
443 			}
444 		} else if (strcmp(argv[currentarg], "--iflist") == 0) {
445 			p->query = 0;
446 			if (currentarg + 1 < argc && (strlen(argv[currentarg + 1]) == 1 || ishelprequest(argv[currentarg + 1]))) {
447 				if (!isdigit(argv[currentarg + 1][0]) || atoi(argv[currentarg + 1]) > 1 || atoi(argv[currentarg + 1]) < 0) {
448 					if (!ishelprequest(argv[currentarg + 1]))
449 						printf("Error: Invalid mode parameter \"%s\".\n", argv[currentarg + 1]);
450 					printf(" Valid parameters for --iflist:\n");
451 					printf("    0 - show verbose (default)\n");
452 					printf("    1 - show one interface per line\n");
453 					exit(EXIT_FAILURE);
454 				}
455 				p->query = atoi(argv[currentarg + 1]);
456 				currentarg++;
457 			}
458 			showiflist(p->query);
459 			exit(EXIT_SUCCESS);
460 		} else if (strcmp(argv[currentarg], "--dbiflist") == 0) {
461 			p->query = 0;
462 			if (currentarg + 1 < argc && (strlen(argv[currentarg + 1]) == 1 || ishelprequest(argv[currentarg + 1]))) {
463 				if (!isdigit(argv[currentarg + 1][0]) || atoi(argv[currentarg + 1]) > 1 || atoi(argv[currentarg + 1]) < 0) {
464 					if (!ishelprequest(argv[currentarg + 1]))
465 						printf("Error: Invalid mode parameter \"%s\".\n", argv[currentarg + 1]);
466 					printf(" Valid parameters for --dbiflist:\n");
467 					printf("    0 - show verbose (default)\n");
468 					printf("    1 - show one interface per line\n");
469 					exit(EXIT_FAILURE);
470 				}
471 				p->query = atoi(argv[currentarg + 1]);
472 				currentarg++;
473 			}
474 			showdbiflist(p->query);
475 			exit(EXIT_SUCCESS);
476 		} else if (strcmp(argv[currentarg], "--limit") == 0) {
477 			if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) {
478 				p->limit = atoi(argv[currentarg + 1]);
479 				if (p->limit < 0) {
480 					printf("Error: Invalid limit parameter \"%s\" for %s. Only a zero and positive numbers are allowed.\n", argv[currentarg + 1], argv[currentarg]);
481 					exit(EXIT_FAILURE);
482 				}
483 				currentarg++;
484 			} else {
485 				printf("Error: Invalid or missing parameter for %s.\n", argv[currentarg]);
486 				exit(EXIT_FAILURE);
487 			}
488 		} else if ((strcmp(argv[currentarg], "-v") == 0) || (strcmp(argv[currentarg], "--version") == 0)) {
489 			printf("vnStat %s by Teemu Toivola <tst at iki dot fi>\n", getversion());
490 			exit(EXIT_SUCCESS);
491 		} else {
492 			if (argv[currentarg][0] == '-' || strlen(argv[currentarg]) == 1) {
493 				printf("Unknown parameter \"%s\". Use --help for help.\n", argv[currentarg]);
494 				exit(EXIT_FAILURE);
495 			} else {
496 				if (strlen(argv[currentarg]) > 31) {
497 					printf("Error: Interface name is limited to 31 characters.\n");
498 					exit(EXIT_FAILURE);
499 				}
500 				strncpy_nt(p->interface, argv[currentarg], 32);
501 				if (strlen(p->interface)) {
502 					p->defaultiface = 0;
503 				} else {
504 					strncpy_nt(p->definterface, p->interface, 32);
505 				}
506 				if (debug)
507 					printf("Used interface: \"%s\"\n", p->interface);
508 			}
509 		}
510 	}
511 
512 	if (p->limit != -1) {
513 		cfg.listfivemins = cfg.listhours = cfg.listdays = cfg.listmonths = cfg.listyears = cfg.listtop = cfg.listjsonxml = p->limit;
514 	}
515 }
516 
showstylehelp(void)517 void showstylehelp(void)
518 {
519 	printf(" Valid parameters for --style.:\n");
520 	printf("    0 - a more narrow output\n");
521 	printf("    1 - enable bar column if available\n");
522 	printf("    2 - average traffic rate in summary output\n");
523 	printf("    3 - average traffic rate in all outputs if available\n");
524 	printf("    4 - disable terminal control characters in -l / --live\n");
525 	printf("        and show raw values in --oneline\n");
526 }
527 
handleremoveinterface(PARAMS * p)528 void handleremoveinterface(PARAMS *p)
529 {
530 	if (!p->removeiface) {
531 		return;
532 	}
533 
534 	if (p->defaultiface) {
535 		printf("Error: Use -i parameter to specify an interface.\n");
536 		exit(EXIT_FAILURE);
537 	}
538 
539 	if (!db_getinterfacecountbyname(p->interface)) {
540 		printf("Error: Interface \"%s\" not found in database.\n", p->interface);
541 		exit(EXIT_FAILURE);
542 	}
543 
544 	if (!p->force) {
545 		printf("Warning:\nThe current option would remove all data about interface \"%s\" from the database. ", p->interface);
546 		printf("Add --force in order to really do that.\n");
547 		exit(EXIT_FAILURE);
548 	}
549 
550 #ifndef CHECK_VNSTAT
551 	if (!db_close() || !db_open_rw(0)) {
552 		printf("Error: Handling database \"%s/%s\" failing: %s\n", cfg.dbdir, DATABASEFILE, strerror(errno));
553 		exit(EXIT_FAILURE);
554 	}
555 #endif
556 
557 	if (db_removeinterface(p->interface)) {
558 		printf("Interface \"%s\" removed from database.\n", p->interface);
559 		printf("The interface will no longer be monitored. Use --add if monitoring the interface is again needed.\n");
560 #ifndef CHECK_VNSTAT
561 		db_close();
562 		exit(EXIT_SUCCESS);
563 #endif
564 	} else {
565 		printf("Error: Removing interface \"%s\" from database failed.\n", p->interface);
566 		exit(EXIT_FAILURE);
567 	}
568 }
569 
handlerenameinterface(PARAMS * p)570 void handlerenameinterface(PARAMS *p)
571 {
572 	if (!p->renameiface) {
573 		return;
574 	}
575 
576 	if (p->defaultiface) {
577 		printf("Error: Use -i parameter to specify an interface.\n");
578 		exit(EXIT_FAILURE);
579 	}
580 
581 	if (!strlen(p->newifname)) {
582 		printf("Error: New interface name must be at least one character long.\n");
583 		exit(EXIT_FAILURE);
584 	}
585 
586 	if (!db_getinterfacecountbyname(p->interface)) {
587 		printf("Error: Interface \"%s\" not found in database.\n", p->interface);
588 		exit(EXIT_FAILURE);
589 	}
590 
591 	if (db_getinterfacecountbyname(p->newifname)) {
592 		printf("Error: Interface \"%s\" already exists in database.\n", p->newifname);
593 		exit(EXIT_FAILURE);
594 	}
595 
596 	if (!p->force) {
597 		printf("Warning:\nThe current option would rename interface \"%s\" -> \"%s\" in the database. ", p->interface, p->newifname);
598 		printf("Add --force in order to really do that.\n");
599 		exit(EXIT_FAILURE);
600 	}
601 
602 #ifndef CHECK_VNSTAT
603 	if (!db_close() || !db_open_rw(0)) {
604 		printf("Error: Handling database \"%s/%s\" failing: %s\n", cfg.dbdir, DATABASEFILE, strerror(errno));
605 		exit(EXIT_FAILURE);
606 	}
607 #endif
608 
609 	if (db_renameinterface(p->interface, p->newifname)) {
610 		printf("Interface \"%s\" has been renamed \"%s\".\n", p->interface, p->newifname);
611 #ifndef CHECK_VNSTAT
612 		db_close();
613 		exit(EXIT_SUCCESS);
614 #endif
615 	} else {
616 		printf("Error: Renaming interface \"%s\" -> \"%s\" failed.\n", p->interface, p->newifname);
617 		exit(EXIT_FAILURE);
618 	}
619 }
620 
handleaddinterface(PARAMS * p)621 void handleaddinterface(PARAMS *p)
622 {
623 	if (!p->addiface) {
624 		return;
625 	}
626 
627 	if (p->defaultiface) {
628 		printf("Error: Use -i parameter to specify an interface.\n");
629 		exit(EXIT_FAILURE);
630 	}
631 
632 	db_errcode = 0;
633 	if (db_getinterfacecountbyname(p->interface)) {
634 		printf("Error: Interface \"%s\" already exists in the database.\n", p->interface);
635 		exit(EXIT_FAILURE);
636 	}
637 	if (db_errcode) {
638 		exit(EXIT_FAILURE);
639 	}
640 
641 	if (!p->force && !getifinfo(p->interface)) {
642 		getifliststring(&p->ifacelist, 1);
643 		printf("Only available interfaces can be added for monitoring.\n\n");
644 		printf("The following interfaces are currently available:\n    %s\n", p->ifacelist);
645 		free(p->ifacelist);
646 		exit(EXIT_FAILURE);
647 	}
648 
649 	if (!p->force && !spacecheck(cfg.dbdir)) {
650 		printf("Error: Not enough free diskspace available.\n");
651 		exit(EXIT_FAILURE);
652 	}
653 
654 #ifndef CHECK_VNSTAT
655 	if (!db_close() || !db_open_rw(0)) {
656 		printf("Error: Handling database \"%s/%s\" failing: %s\n", cfg.dbdir, DATABASEFILE, strerror(errno));
657 		exit(EXIT_FAILURE);
658 	}
659 #endif
660 
661 	printf("Adding interface \"%s\" to database for monitoring.\n", p->interface);
662 	if (db_addinterface(p->interface)) {
663 		if (cfg.rescanonsave) {
664 			printf("vnStat daemon will automatically start monitoring \"%s\" within %d minutes if the daemon process is currently running.\n", p->interface, cfg.saveinterval);
665 		} else {
666 			printf("Restart vnStat daemon if it is currently running in order to start monitoring \"%s\".\n", p->interface);
667 		}
668 		handlesetalias(p);
669 #ifndef CHECK_VNSTAT
670 		db_close();
671 		exit(EXIT_SUCCESS);
672 #endif
673 	} else {
674 		printf("Error: Adding interface \"%s\" to database failed.\n", p->interface);
675 		exit(EXIT_FAILURE);
676 	}
677 }
678 
handlesetalias(PARAMS * p)679 void handlesetalias(PARAMS *p)
680 {
681 	if (!p->setalias) {
682 		return;
683 	}
684 
685 	if (p->defaultiface) {
686 		printf("Error: Use -i parameter to specify an interface.\n");
687 		exit(EXIT_FAILURE);
688 	}
689 
690 	if (!db_getinterfacecountbyname(p->interface)) {
691 		printf("Error: Interface \"%s\" not found in database.\n", p->interface);
692 		exit(EXIT_FAILURE);
693 	}
694 
695 #ifndef CHECK_VNSTAT
696 	if (!db_close() || !db_open_rw(0)) {
697 		printf("Error: Handling database \"%s/%s\" failing: %s\n", cfg.dbdir, DATABASEFILE, strerror(errno));
698 		exit(EXIT_FAILURE);
699 	}
700 #endif
701 
702 	if (db_setalias(p->interface, p->alias)) {
703 		printf("Alias of interface \"%s\" set to \"%s\".\n", p->interface, p->alias);
704 #ifndef CHECK_VNSTAT
705 		db_close();
706 		exit(EXIT_SUCCESS);
707 #endif
708 	} else {
709 		printf("Error: Setting interface \"%s\" alias failed.\n", p->interface);
710 		exit(EXIT_FAILURE);
711 	}
712 }
713 
handleshowdata(PARAMS * p)714 void handleshowdata(PARAMS *p)
715 {
716 	int ifcount = 0;
717 	iflist *dbifl = NULL, *dbifl_i = NULL;
718 
719 	if (!p->query) {
720 		return;
721 	}
722 
723 	/* show only specified file */
724 	if (!p->defaultiface) {
725 		showoneinterface(p);
726 		return;
727 	}
728 
729 	/* show all interfaces if -i isn't specified */
730 	if (p->dbifcount == 0) {
731 		p->query = 0;
732 	} else if ((cfg.qmode == 0 || cfg.qmode == 8 || cfg.qmode == 10) && (p->dbifcount > 1)) {
733 
734 		if (cfg.qmode == 0) {
735 			if (cfg.ostyle != 0) {
736 				printf("\n                      rx      /      tx      /     total    /   estimated\n");
737 			} else {
738 				printf("\n                      rx      /      tx      /     total\n");
739 			}
740 		} else if (cfg.qmode == 8) {
741 			xmlheader();
742 		} else if (cfg.qmode == 10) {
743 			jsonheader();
744 		}
745 
746 		if (db_getiflist(&dbifl) <= 0) {
747 			return;
748 		}
749 
750 		dbifl_i = dbifl;
751 
752 		while (dbifl_i != NULL) {
753 			strncpy_nt(p->interface, dbifl_i->interface, 32);
754 			if (debug)
755 				printf("\nProcessing interface \"%s\"...\n", p->interface);
756 			if (cfg.qmode == 0) {
757 				showdb(p->interface, 5, "", "");
758 			} else if (cfg.qmode == 8) {
759 				showxml(p->interface, p->xmlmode, p->databegin, p->dataend);
760 			} else if (cfg.qmode == 10) {
761 				showjson(p->interface, ifcount, p->jsonmode, p->databegin, p->dataend);
762 			}
763 			ifcount++;
764 			dbifl_i = dbifl_i->next;
765 		}
766 		iflistfree(&dbifl);
767 
768 		if (cfg.qmode == 8) {
769 			xmlfooter();
770 		} else if (cfg.qmode == 10) {
771 			jsonfooter();
772 		}
773 
774 		/* show in qmode if there's only one interface or qmode!=0 */
775 	} else {
776 		showoneinterface(p);
777 	}
778 }
779 
showoneinterface(PARAMS * p)780 void showoneinterface(PARAMS *p)
781 {
782 	if (!db_getinterfacecountbyname(p->interface)) {
783 		if (strchr(p->interface, '+') == NULL) {
784 			printf("Error: Interface \"%s\" not found in database.\n", p->interface);
785 		} else {
786 			printf("Error: Not all requested interfaces found in database or given interfaces aren't unique.\n");
787 		}
788 		exit(EXIT_FAILURE);
789 	}
790 
791 	if (cfg.qmode == 5) {
792 		if (cfg.ostyle != 0) {
793 			printf("\n                      rx      /      tx      /     total    /   estimated\n");
794 		} else {
795 			printf("\n                      rx      /      tx      /     total\n");
796 		}
797 	}
798 	if (cfg.qmode != 8 && cfg.qmode != 10) {
799 		showdb(p->interface, cfg.qmode, p->databegin, p->dataend);
800 	} else if (cfg.qmode == 8) {
801 		xmlheader();
802 		showxml(p->interface, p->xmlmode, p->databegin, p->dataend);
803 		xmlfooter();
804 	} else if (cfg.qmode == 10) {
805 		jsonheader();
806 		showjson(p->interface, 0, p->jsonmode, p->databegin, p->dataend);
807 		jsonfooter();
808 	}
809 }
810 
handletrafficmeters(PARAMS * p)811 void handletrafficmeters(PARAMS *p)
812 {
813 	int i;
814 
815 	if (!p->traffic && !p->livetraffic) {
816 		return;
817 	}
818 
819 	if (strchr(p->interface, '+') != NULL) {
820 		printf("This feature doesn't support interface merges (\"%s\"), ", p->interface);
821 		for (i = 0; i < (int)strlen(p->interface); i++) {
822 			if (p->interface[i] == '+') {
823 				p->interface[i] = '\0';
824 				break;
825 			}
826 		}
827 		p->defaultiface = 0;
828 		printf("using \"%s\" instead.\n", p->interface);
829 	}
830 
831 	if (!isifavailable(p->interface)) {
832 		getifliststring(&p->ifacelist, 0);
833 		if (p->defaultiface) {
834 			printf("Error: Configured default interface \"%s\" isn't available.\n\n", p->interface);
835 			if (strlen(cfg.cfgfile)) {
836 				printf("Update \"Interface\" keyword value in configuration file \"%s\" to change ", cfg.cfgfile);
837 				printf("the default interface or give an alternative interface using the -i parameter.\n\n");
838 			} else {
839 				printf("An alternative interface can be given using the -i parameter.\n\n");
840 			}
841 			printf("The following interfaces are currently available:\n    %s\n", p->ifacelist);
842 
843 		} else {
844 			printf("Error: Unable to get interface \"%s\" statistics.\n\n", p->interface);
845 			printf("The following interfaces are currently available:\n    %s\n", p->ifacelist);
846 		}
847 		free(p->ifacelist);
848 		exit(EXIT_FAILURE);
849 	}
850 
851 	/* calculate traffic */
852 	if (p->traffic) {
853 		trafficmeter(p->interface, (unsigned int)cfg.sampletime);
854 	}
855 
856 	/* live traffic */
857 	if (p->livetraffic) {
858 		livetrafficmeter(p->interface, p->livemode);
859 	}
860 }
861 
handleifselection(PARAMS * p)862 void handleifselection(PARAMS *p)
863 {
864 	int ifcount, dbifcount = 0, iffound = 0, dbopened = 0;
865 	iflist *ifl = NULL;
866 	iflist *dbifl = NULL, *dbifl_iterator = NULL;
867 
868 	if (!p->defaultiface) {
869 		return;
870 	}
871 
872 	if (strlen(p->definterface)) {
873 		strncpy_nt(p->interface, p->definterface, 32);
874 		return;
875 	}
876 
877 	if (p->traffic || p->livetraffic) {
878 		ifcount = getiflist(&ifl, 0, 1);
879 
880 		/* try to open database for extra information */
881 		if (db == NULL) {
882 			if (!db_open_ro()) {
883 				db = NULL;
884 			} else {
885 				dbopened = 1;
886 			}
887 		}
888 
889 		if (db != NULL) {
890 			dbifcount = db_getiflist_sorted(&dbifl, 1);
891 			if (dbopened) {
892 				db_close();
893 			}
894 		}
895 
896 		if (dbifcount > 0 && ifcount > 0) {
897 			dbifl_iterator = dbifl;
898 			while (dbifl_iterator != NULL) {
899 				if (iflistsearch(&ifl, dbifl_iterator->interface)) {
900 					strncpy_nt(p->interface, dbifl_iterator->interface, 32);
901 					iffound = 1;
902 					if (debug)
903 						printf("Automatically selected interface with db: \"%s\"\n", p->interface);
904 					break;
905 				}
906 				dbifl_iterator = dbifl_iterator->next;
907 			}
908 		}
909 
910 		if (!iffound) {
911 			if (ifcount > 0) {
912 				strncpy_nt(p->interface, ifl->interface, 32);
913 				if (debug)
914 					printf("Automatically selected interface without db: \"%s\"\n", p->interface);
915 			} else {
916 				printf("Error: Unable to find any suitable interface.\n");
917 				iflistfree(&ifl);
918 				iflistfree(&dbifl);
919 				exit(EXIT_FAILURE);
920 			}
921 		}
922 
923 		iflistfree(&ifl);
924 	} else if (p->query) {
925 		if (db_getiflist_sorted(&dbifl, 1) <= 0) {
926 			printf("Error: Unable to discover suitable interface from database.\n");
927 			iflistfree(&dbifl);
928 			exit(EXIT_FAILURE);
929 		}
930 		strncpy_nt(p->interface, dbifl->interface, 32);
931 		if (debug)
932 			printf("Automatically selected interface from db: \"%s\"\n", p->interface);
933 	}
934 
935 	iflistfree(&dbifl);
936 }
937 
showiflist(const int parseable)938 void showiflist(const int parseable)
939 {
940 	char *ifacelist = NULL;
941 	iflist *ifl = NULL, *ifl_iterator = NULL;
942 
943 	if (!parseable) {
944 		if (!getifliststring(&ifacelist, 1)) {
945 			exit(EXIT_FAILURE);
946 		}
947 		if (strlen(ifacelist)) {
948 			printf("Available interfaces: %s\n", ifacelist);
949 		} else {
950 			printf("No usable interfaces found.\n");
951 		}
952 		free(ifacelist);
953 	} else {
954 		if (!getiflist(&ifl, 0, 1)) {
955 			exit(EXIT_FAILURE);
956 		}
957 		ifl_iterator = ifl;
958 		while (ifl_iterator != NULL) {
959 			printf("%s\n", ifl_iterator->interface);
960 			ifl_iterator = ifl_iterator->next;
961 		}
962 		iflistfree(&ifl);
963 	}
964 }
965 
showdbiflist(const int parseable)966 void showdbiflist(const int parseable)
967 {
968 	int dbifcount;
969 	iflist *dbifl = NULL, *dbifl_i = NULL;
970 
971 	if (db == NULL && !db_open_ro()) {
972 		printf("Error: Failed to open database \"%s/%s\" in read-only mode.\n", cfg.dbdir, DATABASEFILE);
973 		exit(EXIT_FAILURE);
974 	}
975 
976 	dbifcount = db_getiflist(&dbifl);
977 	if (dbifcount < 0) {
978 		printf("Error: Failed to get interface list from database \"%s/%s\".\n", cfg.dbdir, DATABASEFILE);
979 		exit(EXIT_FAILURE);
980 	}
981 
982 	if (dbifcount == 0 && !parseable) {
983 		printf("Database is empty.");
984 	} else {
985 		dbifl_i = dbifl;
986 
987 		if (!parseable) {
988 			printf("Interfaces in database:");
989 			while (dbifl_i != NULL) {
990 				printf(" %s", dbifl_i->interface);
991 				dbifl_i = dbifl_i->next;
992 			}
993 			printf("\n");
994 		} else {
995 			while (dbifl_i != NULL) {
996 				printf("%s\n", dbifl_i->interface);
997 				dbifl_i = dbifl_i->next;
998 			}
999 		}
1000 	}
1001 
1002 	iflistfree(&dbifl);
1003 	db_close();
1004 }
1005