vnstat  2.9
About: vnStat is a console-based network traffic monitor (using the /proc filesystem).
  Fossies Dox: vnstat-2.9.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

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