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)  

dbaccess.c
Go to the documentation of this file.
1#include "common.h"
2#include "dbsql.h"
3#include "dbaccess.h"
4
5int importlegacydb(const char *iface, const char *dirname)
6{
7 DATA data;
8
9 snprintf(errorstring, 1024, "Importing data from legacy database \"%s\".", iface);
11
12 if (db_getinterfacecountbyname(iface)) {
13 return 0;
14 }
15
16 if (readdb(&data, iface, dirname, 0) != 0) {
17 return 0;
18 }
19
20 if (!db_addinterface(iface)) {
21 return 0;
22 }
23
24 if (!insertlegacydata(&data, iface)) {
25 return 0;
26 }
27
28 return 1;
29}
30
31int insertlegacydata(DATA *data, const char *iface)
32{
33 int i, year;
34 time_t yeartime;
35 struct tm *stm;
36 uint64_t rx, tx;
37
38 if (!db_begintransaction()) {
39 return 0;
40 }
41
42 if (!db_setactive(iface, data->active)) {
44 return 0;
45 }
46 if (strcmp(iface, data->nick) != 0) {
47 if (!db_setalias(iface, data->nick)) {
49 return 0;
50 }
51 }
52 if (!db_setcounters(iface, data->currx, data->curtx)) {
54 return 0;
55 }
56 if (!db_setcreation(iface, data->created)) {
58 return 0;
59 }
60
61 for (i = 23; i >= 0; i--) {
62 if (data->hour[i].date > 0 && (data->hour[i].rx > 0 || data->hour[i].tx > 0)) {
63 if (!db_insertdata("hour", iface, data->hour[i].rx * 1024, data->hour[i].tx * 1024, (uint64_t)data->hour[i].date)) {
65 return 0;
66 }
67 }
68 }
69 for (i = 29; i >= 0; i--) {
70 if (data->day[i].used) {
71 if (!db_insertdata("day", iface, data->day[i].rx * 1024 * 1024 + (uint64_t)data->day[i].rxk * 1024, data->day[i].tx * 1024 * 1024 + (uint64_t)data->day[i].txk * 1024, (uint64_t)data->day[i].date)) {
73 return 0;
74 }
75 }
76 }
77 for (i = 11; i >= 0; i--) {
78 if (data->month[i].used) {
79 if (!db_insertdata("month", iface, data->month[i].rx * 1024 * 1024 + (uint64_t)data->month[i].rxk * 1024, data->month[i].tx * 1024 * 1024 + (uint64_t)data->month[i].txk * 1024, (uint64_t)data->month[i].month)) {
81 return 0;
82 }
83 }
84 }
85 for (i = 9; i >= 0; i--) {
86 if (data->top10[i].used) {
87 if (!db_insertdata("top", iface, data->top10[i].rx * 1024 * 1024 + (uint64_t)data->top10[i].rxk * 1024, data->top10[i].tx * 1024 * 1024 + (uint64_t)data->top10[i].txk * 1024, (uint64_t)data->top10[i].date)) {
89 return 0;
90 }
91 }
92 }
93
94 /* construct yearly data from legacy monthly data */
95 rx = 0;
96 tx = 0;
97 year = 0;
98 yeartime = 0;
99 for (i = 11; i >= 0; i--) {
100 if (!data->month[i].used) {
101 continue;
102 }
103 stm = localtime(&data->month[i].month);
104 /* sanity check for possible invalid data */
105 if (stm->tm_year + 1900 <= 1980 || stm->tm_year + 1900 >= 2050) {
106 continue;
107 }
108 if (stm->tm_year + 1900 != year) {
109 if (year != 0 && (rx > 0 || tx > 0)) {
110 if (!db_insertdata("year", iface, rx, tx, (uint64_t)yeartime)) {
112 return 0;
113 }
114 }
115 year = stm->tm_year + 1900;
116 yeartime = data->month[i].month;
117 rx = 0;
118 tx = 0;
119 }
120 rx += data->month[i].rx * 1024 * 1024 + (uint64_t)data->month[i].rxk * 1024;
121 tx += data->month[i].tx * 1024 * 1024 + (uint64_t)data->month[i].txk * 1024;
122 }
123 if (year != 0 && (rx > 0 || tx > 0)) {
124 if (!db_insertdata("year", iface, rx, tx, (uint64_t)yeartime)) {
126 return 0;
127 }
128 }
129
130 if (!db_settotal(iface, data->totalrx * 1024 * 1024 + (uint64_t)data->totalrxk * 1024, data->totaltx * 1024 * 1024 + (uint64_t)data->totaltxk * 1024)) {
132 return 0;
133 }
134
135 return db_committransaction();
136}
137
138int readdb(DATA *data, const char *iface, const char *dirname, const int force)
139{
140 FILE *legacydb;
141 char file[512], backup[512];
142
143 snprintf(file, 512, "%s/%s", dirname, iface);
144 snprintf(backup, 512, "%s/.%s", dirname, iface);
145
146 if ((legacydb = fopen(file, "r")) == NULL) {
147 snprintf(errorstring, 1024, "Unable to read database \"%s\": %s", file, strerror(errno));
149
150 /* create new database template */
151 initdb(data);
152 strncpy_nt(data->interface, iface, 32);
153 strncpy_nt(data->nick, data->interface, 32);
154 return 1;
155 }
156
157 if (fread(data, sizeof(DATA), 1, legacydb) != 1 || ferror(legacydb)) {
158 data->version = -1;
159 if (debug) {
160 printf("db: Database read failed for file \"%s\".\n", file);
161 }
162 } else {
163 if (debug) {
164 data->interface[sizeof(data->interface) - 1] = '\0';
165 printf("db: Database loaded for interface \"%s\"...\n", data->interface);
166 }
167 }
168 data->interface[sizeof(data->interface) - 1] = '\0';
169 data->nick[sizeof(data->nick) - 1] = '\0';
170
171 if (data->version == LEGACYDBVERSION) {
172 if (!validatedb(data) && !force) {
173 data->version = -1;
174 if (debug) {
175 printf("db: Database for interface \"%s\" fails to validate, trying with backup\n", data->interface);
176 }
177 }
178 }
179
180 /* convert old database to new format if necessary */
181 if (data->version < LEGACYDBVERSION) {
182 if (data->version == -1) {
183
184 /* close current db and try using backup if database conversion failed */
185 fclose(legacydb);
186 if ((legacydb = fopen(backup, "r")) == NULL) {
187 snprintf(errorstring, 1024, "Unable to open backup database \"%s\": %s", backup, strerror(errno));
189 if (noexit) {
190 return -1;
191 } else {
192 exit(EXIT_FAILURE);
193 }
194 }
195
196 if (fread(data, sizeof(DATA), 1, legacydb) != 1 || ferror(legacydb)) {
197 snprintf(errorstring, 1024, "Database load failed even when using backup (%s). Aborting.", strerror(errno));
199 fclose(legacydb);
200
201 if (noexit) {
202 return -1;
203 } else {
204 exit(EXIT_FAILURE);
205 }
206 } else {
207 if (debug) {
208 data->interface[sizeof(data->interface) - 1] = '\0';
209 printf("db: Backup database loaded for interface \"%s\"...\n", data->interface);
210 }
211 }
212 data->interface[sizeof(data->interface) - 1] = '\0';
213 data->nick[sizeof(data->nick) - 1] = '\0';
214
215 if (data->version == LEGACYDBVERSION) {
216 if (!validatedb(data)) {
217 data->version = -1;
218 if (debug) {
219 printf("db: Backup database for interface \"%s\" fails to validate\n", data->interface);
220 }
221 }
222 }
223
224 if (data->version != LEGACYDBVERSION) {
225 if (data->version == -1) {
226 snprintf(errorstring, 1024, "Unable to use database \"%s\" or its backup.", file);
228 fclose(legacydb);
229
230 if (noexit) {
231 return -1;
232 } else {
233 exit(EXIT_FAILURE);
234 }
235 }
236 }
237 snprintf(errorstring, 1024, "Database possibly corrupted, using backup instead.");
239 }
240
241 } else if (data->version > LEGACYDBVERSION) {
242 snprintf(errorstring, 1024, "Downgrading database \"%s\" (v%d) is not supported.", file, data->version);
244 fclose(legacydb);
245
246 if (noexit) {
247 return -1;
248 } else {
249 exit(EXIT_FAILURE);
250 }
251 }
252
253 fclose(legacydb);
254
255 if (strcmp(data->interface, iface)) {
256 snprintf(errorstring, 1024, "Warning:\nThe previous interface for this file was \"%s\".", data->interface);
258 snprintf(errorstring, 1024, "It has now been replaced with \"%s\".", iface);
260 snprintf(errorstring, 1024, "You can ignore this message if you renamed the filename.");
262 snprintf(errorstring, 1024, "Interface name mismatch, renamed \"%s\" -> \"%s\"", data->interface, iface);
264 if (strcmp(data->interface, data->nick) == 0) {
265 strncpy_nt(data->nick, iface, 32);
266 }
267 strncpy_nt(data->interface, iface, 32);
268 }
269
270 return 0;
271}
272
273void initdb(DATA *data)
274{
275 int i;
276 time_t current;
277 struct tm *d;
278
279 current = time(NULL);
280 d = localtime(&current);
281
282 /* set default values for a new database */
283 data->version = LEGACYDBVERSION;
284 data->active = 1;
285 data->totalrx = 0;
286 data->totaltx = 0;
287 data->currx = 0;
288 data->curtx = 0;
289 data->totalrxk = 0;
290 data->totaltxk = 0;
291 data->lastupdated = current;
292 data->created = current;
293
294 /* days */
295 for (i = 0; i <= 29; i++) {
296 data->day[i].rx = 0;
297 data->day[i].tx = 0;
298 data->day[i].rxk = 0;
299 data->day[i].txk = 0;
300 data->day[i].date = 0;
301 data->day[i].used = 0;
302 }
303
304 /* months */
305 for (i = 0; i <= 11; i++) {
306 data->month[i].rx = 0;
307 data->month[i].tx = 0;
308 data->month[i].rxk = 0;
309 data->month[i].txk = 0;
310 data->month[i].month = 0;
311 data->month[i].used = 0;
312 }
313
314 /* top10 */
315 for (i = 0; i <= 9; i++) {
316 data->top10[i].rx = 0;
317 data->top10[i].tx = 0;
318 data->top10[i].rxk = 0;
319 data->top10[i].txk = 0;
320 data->top10[i].date = 0;
321 data->top10[i].used = 0;
322 }
323
324 /* hours */
325 for (i = 0; i <= 23; i++) {
326 data->hour[i].rx = 0;
327 data->hour[i].tx = 0;
328 data->hour[i].date = 0;
329 }
330
331 data->day[0].used = data->month[0].used = 1;
332 data->day[0].date = current;
333
334 /* calculate new date for current month if current day is less
335 than the set monthrotate value so that new databases begin
336 from the right month */
337 if (d->tm_mday < cfg.monthrotate) {
338 d->tm_mday = cfg.monthrotate;
339 d->tm_mon--;
340 data->month[0].month = mktime(d);
341 } else {
342 data->month[0].month = current;
343 }
344
345 data->btime = MAX32;
346}
347
348int validatedb(DATA *data)
349{
350 int i, used;
351 uint64_t rxsum, txsum;
352 const char *invaliddb = "Invalid database";
353
354 if (debug) {
355 printf("validating loaded database\n");
356 }
357
358 /* enforce string termination */
359 data->interface[sizeof(data->interface) - 1] = '\0';
360 data->nick[sizeof(data->nick) - 1] = '\0';
361
362 if (data->version > LEGACYDBVERSION) {
363 snprintf(errorstring, 1024, "%s: %s version: %d", data->interface, invaliddb, data->version);
365 return 0;
366 }
367
368 if (data->active < 0 || data->active > 1) {
369 snprintf(errorstring, 1024, "%s: %s activity status: %d", data->interface, invaliddb, data->active);
371 return 0;
372 }
373
374 if (!strlen(data->interface)) {
375 snprintf(errorstring, 1024, "%s interface string: %s", invaliddb, data->interface);
377 return 0;
378 }
379
380 if (!data->created || !data->lastupdated || !data->btime) {
381 snprintf(errorstring, 1024, "%s: %s timestamp.", data->interface, invaliddb);
383 return 0;
384 }
385
386 rxsum = txsum = 0;
387 used = 1;
388 for (i = 0; i < 30; i++) {
389 if (data->day[i].used < 0 || data->day[i].used > 1) {
390 snprintf(errorstring, 1024, "%s: %s daily use information: %d %d", data->interface, invaliddb, i, data->day[i].used);
392 return 0;
393 }
394 if (data->day[i].rxk < 0 || data->day[i].txk < 0) {
395 snprintf(errorstring, 1024, "%s: %s daily traffic: %d", data->interface, invaliddb, i);
397 return 0;
398 }
399 if (data->day[i].used && !used) {
400 snprintf(errorstring, 1024, "%s: %s daily use order: %d", data->interface, invaliddb, i);
402 return 0;
403 } else if (!data->day[i].used) {
404 used = 0;
405 }
406 if (data->day[i].used) {
407 rxsum += data->day[i].rx;
408 txsum += data->day[i].tx;
409 }
410 }
411
412 for (i = 1; i < 30; i++) {
413 if (!data->day[i].used) {
414 break;
415 }
416 if (data->day[i - 1].date < data->day[i].date) {
417 snprintf(errorstring, 1024, "%s: %s daily date order: %u (%d) < %u (%d)", data->interface, invaliddb, (unsigned int)data->day[i - 1].date, i - 1, (unsigned int)data->day[i].date, i);
419 return 0;
420 }
421 }
422
423 if (data->totalrx < rxsum || data->totaltx < txsum) {
424 snprintf(errorstring, 1024, "%s: %s total traffic compared to daily usage.", data->interface, invaliddb);
426 return 0;
427 }
428
429 rxsum = txsum = 0;
430 used = 1;
431 for (i = 0; i < 12; i++) {
432 if (data->month[i].used < 0 || data->month[i].used > 1) {
433 snprintf(errorstring, 1024, "%s: %s monthly use information: %d %d", data->interface, invaliddb, i, data->month[i].used);
435 return 0;
436 }
437 if (data->month[i].rxk < 0 || data->month[i].txk < 0) {
438 snprintf(errorstring, 1024, "%s: %s monthly traffic: %d", data->interface, invaliddb, i);
440 return 0;
441 }
442 if (data->month[i].used && !used) {
443 snprintf(errorstring, 1024, "%s: %s monthly use order: %d", data->interface, invaliddb, i);
445 return 0;
446 } else if (!data->month[i].used) {
447 used = 0;
448 }
449 if (data->month[i].used) {
450 rxsum += data->month[i].rx;
451 txsum += data->month[i].tx;
452 }
453 }
454
455 for (i = 1; i < 12; i++) {
456 if (!data->month[i].used) {
457 break;
458 }
459 if (data->month[i - 1].month < data->month[i].month) {
460 snprintf(errorstring, 1024, "%s: %s monthly date order: %u (%d) < %u (%d)", data->interface, invaliddb, (unsigned int)data->month[i - 1].month, i - 1, (unsigned int)data->month[i].month, i);
462 return 0;
463 }
464 }
465
466 if (data->totalrx < rxsum || data->totaltx < txsum) {
467 snprintf(errorstring, 1024, "%s: %s total traffic compared to monthly usage.", data->interface, invaliddb);
469 return 0;
470 }
471
472 used = 1;
473 for (i = 0; i < 10; i++) {
474 if (data->top10[i].used < 0 || data->top10[i].used > 1) {
475 snprintf(errorstring, 1024, "%s: %s top10 use information: %d %d", data->interface, invaliddb, i, data->top10[i].used);
477 return 0;
478 }
479 if (data->top10[i].rxk < 0 || data->top10[i].txk < 0) {
480 snprintf(errorstring, 1024, "%s: %s top10 traffic: %d", data->interface, invaliddb, i);
482 return 0;
483 }
484 if (data->top10[i].used && !used) {
485 snprintf(errorstring, 1024, "%s: %s top10 use order: %d", data->interface, invaliddb, i);
487 return 0;
488 } else if (!data->top10[i].used) {
489 used = 0;
490 }
491 }
492
493 return 1;
494}
int noexit
Definition: common.c:9
char errorstring[1024]
Definition: common.c:6
int printe(const PrintType type)
Definition: common.c:14
int debug
Definition: common.c:8
CFG cfg
Definition: common.c:4
char * strncpy_nt(char *dest, const char *src, size_t n)
Definition: common.c:253
#define MAX32
Definition: common.h:214
@ PT_ShortMultiline
Definition: common.h:356
@ PT_Info
Definition: common.h:350
@ PT_Error
Definition: common.h:353
@ PT_Multiline
Definition: common.h:355
@ PT_Infoless
Definition: common.h:351
int insertlegacydata(DATA *data, const char *iface)
Definition: dbaccess.c:31
void initdb(DATA *data)
Definition: dbaccess.c:273
int validatedb(DATA *data)
Definition: dbaccess.c:348
int readdb(DATA *data, const char *iface, const char *dirname, const int force)
Definition: dbaccess.c:138
int importlegacydb(const char *iface, const char *dirname)
Definition: dbaccess.c:5
#define LEGACYDBVERSION
Definition: dbaccess.h:7
int db_setcreation(const char *iface, const time_t timestamp)
Definition: dbsql.c:909
int db_settotal(const char *iface, const uint64_t rx, const uint64_t tx)
Definition: dbsql.c:923
int db_setalias(const char *iface, const char *alias)
Definition: dbsql.c:708
int db_insertdata(const char *table, const char *iface, const uint64_t rx, const uint64_t tx, const uint64_t timestamp)
Definition: dbsql.c:938
int db_addinterface(const char *iface)
Definition: dbsql.c:370
int db_setactive(const char *iface, const int active)
Definition: dbsql.c:574
uint64_t db_getinterfacecountbyname(const char *iface)
Definition: dbsql.c:419
int db_begintransaction(void)
Definition: dbsql.c:1105
int db_setcounters(const char *iface, const uint64_t rxcounter, const uint64_t txcounter)
Definition: dbsql.c:602
int db_rollbacktransaction(void)
Definition: dbsql.c:1148
int db_committransaction(void)
Definition: dbsql.c:1124
int32_t monthrotate
Definition: common.h:315
Definition: dbaccess.h:36
char nick[32]
Definition: dbaccess.h:39
HOUR hour[24]
Definition: dbaccess.h:47
int totalrxk
Definition: dbaccess.h:42
uint64_t totalrx
Definition: dbaccess.h:41
int totaltxk
Definition: dbaccess.h:42
int version
Definition: dbaccess.h:37
DAY day[30]
Definition: dbaccess.h:44
char interface[32]
Definition: dbaccess.h:38
uint64_t currx
Definition: dbaccess.h:41
uint64_t curtx
Definition: dbaccess.h:41
time_t lastupdated
Definition: dbaccess.h:43
DAY top10[10]
Definition: dbaccess.h:46
uint64_t btime
Definition: dbaccess.h:48
MONTH month[12]
Definition: dbaccess.h:45
time_t created
Definition: dbaccess.h:43
uint64_t totaltx
Definition: dbaccess.h:41
int active
Definition: dbaccess.h:40
time_t date
Definition: dbaccess.h:22
uint64_t rx
Definition: dbaccess.h:23
int txk
Definition: dbaccess.h:24
int used
Definition: dbaccess.h:25
int rxk
Definition: dbaccess.h:24
uint64_t tx
Definition: dbaccess.h:23
uint64_t tx
Definition: dbaccess.h:18
uint64_t rx
Definition: dbaccess.h:18
time_t date
Definition: dbaccess.h:17
uint64_t rx
Definition: dbaccess.h:30
uint64_t tx
Definition: dbaccess.h:30
time_t month
Definition: dbaccess.h:29
int used
Definition: dbaccess.h:32
int rxk
Definition: dbaccess.h:31
int txk
Definition: dbaccess.h:31