1 #include "common.h"
2 #include "misc.h"
3 #include "iflist.h"
4 #include "dbsql.h"
5
6 /* global db */
7 sqlite3 *db;
8 int db_errcode;
9 int db_intransaction;
10
db_open_ro(void)11 int db_open_ro(void)
12 {
13 return db_open(0, 1);
14 }
15
db_open_rw(const int createifnotfound)16 int db_open_rw(const int createifnotfound)
17 {
18 return db_open(createifnotfound, 0);
19 }
20
db_open(const int createifnotfound,const int readonly)21 int db_open(const int createifnotfound, const int readonly)
22 {
23 int rc, createdb = 0;
24 char dbfilename[530];
25
26 #ifdef CHECK_VNSTAT
27 /* use ram based database when testing for shorter test execution times by reducing disk i/o */
28 snprintf(dbfilename, 530, ":memory:");
29 createdb = 1;
30 #else
31 struct stat filestat;
32
33 if (db != NULL) {
34 return 1;
35 }
36
37 snprintf(dbfilename, 530, "%s/%s", cfg.dbdir, DATABASEFILE);
38
39 /* create database if file doesn't exist */
40 if (stat(dbfilename, &filestat) != 0) {
41 if (errno == ENOENT && createifnotfound && !readonly) {
42 createdb = 1;
43 } else {
44 if (debug)
45 printf("Error (debug): Handling database \"%s\" failed: %s\n", dbfilename, strerror(errno));
46 return 0;
47 }
48 } else {
49 if (filestat.st_size == 0) {
50 if (createifnotfound) {
51 createdb = 1;
52 } else {
53 printf("Error: Database \"%s\" contains 0 bytes and isn't a valid database, exiting.\n", dbfilename);
54 exit(EXIT_FAILURE);
55 }
56 }
57 }
58 #endif
59 db_errcode = 0;
60 db_intransaction = 0;
61 if (readonly) {
62 rc = sqlite3_open_v2(dbfilename, &db, SQLITE_OPEN_READONLY, NULL);
63 } else {
64 rc = sqlite3_open_v2(dbfilename, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
65 }
66
67 if (rc) {
68 db_errcode = rc;
69 if (debug)
70 printf("Error (debug): Can't open database \"%s\": %s\n", dbfilename, sqlite3_errmsg(db));
71 return 0;
72 } else {
73 if (debug)
74 printf("Database \"%s\" open (ro: %d)\n", dbfilename, readonly);
75 }
76
77 if (createdb) {
78 #ifndef CHECK_VNSTAT
79 if (!spacecheck(cfg.dbdir)) {
80 printf("Error: Not enough free diskspace available in \"%s\", exiting.\n", cfg.dbdir);
81 db_close();
82 exit(EXIT_FAILURE);
83 }
84 #endif
85 if (!db_create()) {
86 if (debug)
87 printf("Error (debug): Creating database \"%s\" structure failed\n", dbfilename);
88 db_close();
89 return 0;
90 } else {
91 if (debug)
92 printf("Database \"%s\" structure created\n", dbfilename);
93 if (!db_setinfo("dbversion", SQLDBVERSION, 1)) {
94 if (debug)
95 printf("Error (debug): Writing version info to database \"%s\" failed\n", dbfilename);
96 db_close();
97 return 0;
98 }
99 }
100 }
101
102 /* set pragmas */
103 if (!readonly) {
104 sqlite3_busy_timeout(db, cfg.updateinterval * 1000);
105 if (!db_setpragmas()) {
106 db_close();
107 return 0;
108 }
109 } else {
110 /* set busy timeout when database is open in read-only mode */
111 sqlite3_busy_timeout(db, DBREADTIMEOUTSECS * 1000);
112 }
113
114 if (!createdb) {
115 if (!db_validate(readonly)) {
116 db_close();
117 return 0;
118 }
119 }
120
121 if (createifnotfound && !readonly) {
122 if (!db_setinfo("vnstatversion", getversion(), 1)) {
123 db_close();
124 return 0;
125 }
126 }
127
128 return 1;
129 }
130
db_validate(const int readonly)131 int db_validate(const int readonly)
132 {
133 int dbversion, currentversion;
134
135 db_errcode = 0;
136 dbversion = atoi(db_getinfo("dbversion"));
137 if (db_errcode) {
138 return 0;
139 }
140
141 currentversion = atoi(SQLDBVERSION);
142
143 if (debug) {
144 printf("Database version \"%d\", current version \"%d\"\n", dbversion, currentversion);
145 }
146
147 if (dbversion == currentversion) {
148 return 1;
149
150 } else if (dbversion == 0) {
151 printf("Error: Database version \"%d\" suggests error situation in database, exiting.\n", dbversion);
152 return 0;
153
154 } else if (dbversion > currentversion) {
155 printf("Error: Database version \"%d\" is not supported. Support is available up to version \"%d\", exiting.\n", dbversion, currentversion);
156 return 0;
157
158 } else if (dbversion < currentversion) {
159 if (readonly) {
160 /* database upgrade actions should be performed here once needed */
161 printf("Error: Unable to upgrade read-only database from version \"%d\" to \"%d\", exiting.\n", dbversion, currentversion);
162 return 0;
163 }
164 /* database upgrade actions should be performed here once needed, then return 1 */
165 /* however, since this is the first database version, always return 0 */
166 }
167
168 return 0;
169 }
170
db_setpragmas(void)171 int db_setpragmas(void)
172 {
173 int rc;
174 char sql[25];
175 sqlite3_stmt *sqlstmt;
176
177 /* enable use of foreign keys */
178 if (!db_exec("PRAGMA foreign_keys = ON")) {
179 return 0;
180 }
181
182 rc = sqlite3_prepare_v2(db, "PRAGMA foreign_keys", -1, &sqlstmt, NULL);
183 if (rc != SQLITE_OK) {
184 db_errcode = rc;
185 snprintf(errorstring, 1024, "Exec prepare \"PRAGMA foreign_keys;\" failed (%d): %s", rc, sqlite3_errmsg(db));
186 printe(PT_Error);
187 return 0;
188 }
189
190 /* PRAGMA foreign_keys; is expected to return one row if the feature is supported */
191 rc = sqlite3_step(sqlstmt);
192 if (rc != SQLITE_ROW) {
193 db_errcode = rc;
194 snprintf(errorstring, 1024, "PRAGMA foreign_keys returned no row (%d): %s", rc, sqlite3_errmsg(db));
195 printe(PT_Error);
196 sqlite3_finalize(sqlstmt);
197 return 0;
198 }
199
200 rc = sqlite3_finalize(sqlstmt);
201 if (rc) {
202 db_errcode = rc;
203 snprintf(errorstring, 1024, "Exec finalize \"PRAGMA foreign_keys;\" failed (%d): %s", rc, sqlite3_errmsg(db));
204 printe(PT_Error);
205 return 0;
206 }
207
208 #if HAVE_DECL_SQLITE_CHECKPOINT_RESTART
209 /* set journal_mode */
210 if (cfg.waldb) {
211 if (!db_exec("PRAGMA journal_mode = WAL")) {
212 return 0;
213 }
214 } else {
215 if (!db_exec("PRAGMA journal_mode = DELETE")) {
216 return 0;
217 }
218 }
219 #endif
220
221 /* set synchronous */
222 if (cfg.dbsynchronous == -1) {
223 #if HAVE_DECL_SQLITE_CHECKPOINT_RESTART
224 if (cfg.waldb) {
225 if (!db_exec("PRAGMA synchronous = 1")) {
226 return 0;
227 }
228 } else {
229 if (!db_exec("PRAGMA synchronous = 2")) {
230 return 0;
231 }
232 }
233 #else
234 if (!db_exec("PRAGMA synchronous = 2")) {
235 return 0;
236 }
237 #endif
238 } else {
239 snprintf(sql, 25, "PRAGMA synchronous = %d", cfg.dbsynchronous);
240 if (!db_exec(sql)) {
241 return 0;
242 }
243 }
244
245 return 1;
246 }
247
db_close(void)248 int db_close(void)
249 {
250 int rc;
251
252 if (db == NULL) {
253 return 1;
254 }
255
256 rc = sqlite3_close(db);
257 if (rc == SQLITE_OK) {
258 db = NULL;
259 if (debug)
260 printf("Database closed\n");
261 return 1;
262 } else {
263 db_errcode = rc;
264 if (debug)
265 printf("Error (debug): Closing database failed (%d): %s\n", rc, sqlite3_errmsg(db));
266 return 0;
267 }
268 }
269
db_exec(const char * sql)270 int db_exec(const char *sql)
271 {
272 int rc;
273 sqlite3_stmt *sqlstmt;
274
275 rc = sqlite3_prepare_v2(db, sql, -1, &sqlstmt, NULL);
276 if (rc != SQLITE_OK) {
277 db_errcode = rc;
278 snprintf(errorstring, 1024, "Exec prepare failed (%d: %s): \"%s\"", rc, sqlite3_errmsg(db), sql);
279 printe(PT_Error);
280 return 0;
281 }
282
283 rc = sqlite3_step(sqlstmt);
284 if (rc != SQLITE_DONE && rc != SQLITE_ROW) {
285 db_errcode = rc;
286 snprintf(errorstring, 1024, "Exec step failed (%d: %s): \"%s\"", rc, sqlite3_errmsg(db), sql);
287 printe(PT_Error);
288 sqlite3_finalize(sqlstmt);
289 return 0;
290 }
291
292 rc = sqlite3_finalize(sqlstmt);
293 if (rc) {
294 db_errcode = rc;
295 snprintf(errorstring, 1024, "Exec finalize failed (%d: %s): \"%s\"", rc, sqlite3_errmsg(db), sql);
296 printe(PT_Error);
297 return 0;
298 }
299
300 return 1;
301 }
302
db_create(void)303 int db_create(void)
304 {
305 int i;
306 const char *constsql;
307 char *sql;
308 char buffer[32];
309 const char *datatables[] = {"fiveminute", "hour", "day", "month", "year", "top"};
310
311 if (!db_begintransaction()) {
312 return 0;
313 }
314
315 constsql = "CREATE TABLE info(\n"
316 " id INTEGER PRIMARY KEY,\n"
317 " name TEXT UNIQUE NOT NULL,\n"
318 " value TEXT NOT NULL)";
319
320 if (!db_exec(constsql)) {
321 db_rollbacktransaction();
322 return 0;
323 }
324
325 constsql = "CREATE TABLE interface(\n"
326 " id INTEGER PRIMARY KEY,\n"
327 " name TEXT UNIQUE NOT NULL,\n"
328 " alias TEXT,\n"
329 " active INTEGER NOT NULL,\n"
330 " created DATE NOT NULL,\n"
331 " updated DATE NOT NULL,\n"
332 " rxcounter INTEGER NOT NULL,\n"
333 " txcounter INTEGER NOT NULL,\n"
334 " rxtotal INTEGER NOT NULL,\n"
335 " txtotal INTEGER NOT NULL)";
336
337 if (!db_exec(constsql)) {
338 db_rollbacktransaction();
339 return 0;
340 }
341
342 sql = malloc(sizeof(char) * 512);
343 for (i = 0; i < 6; i++) {
344 sqlite3_snprintf(512, sql, "CREATE TABLE %s(\n"
345 " id INTEGER PRIMARY KEY,\n"
346 " interface INTEGER REFERENCES interface(id) ON DELETE CASCADE,\n"
347 " date DATE NOT NULL,\n"
348 " rx INTEGER NOT NULL,\n"
349 " tx INTEGER NOT NULL,\n"
350 " CONSTRAINT u UNIQUE (interface, date))",
351 datatables[i]);
352
353 if (!db_exec(sql)) {
354 free(sql);
355 db_rollbacktransaction();
356 return 0;
357 }
358 }
359 free(sql);
360
361 snprintf(buffer, 32, "%" PRIu64 "", (uint64_t)MAX32);
362 if (!db_setinfo("btime", buffer, 1)) {
363 db_rollbacktransaction();
364 return 0;
365 }
366
367 return db_committransaction();
368 }
369
db_addinterface(const char * iface)370 int db_addinterface(const char *iface)
371 {
372 char sql[256];
373
374 if (!strlen(iface)) {
375 return 0;
376 }
377
378 sqlite3_snprintf(256, sql, "insert into interface (name, active, created, updated, rxcounter, txcounter, rxtotal, txtotal) values ('%q', 1, datetime('now'%s), datetime('now'%s), 0, 0, 0, 0)", iface, cfg.dbtzmodifier, cfg.dbtzmodifier);
379 return db_exec(sql);
380 }
381
db_removeinterface(const char * iface)382 int db_removeinterface(const char *iface)
383 {
384 char sql[64];
385 sqlite3_int64 ifaceid = 0;
386
387 ifaceid = db_getinterfaceid(iface, 0);
388 if (ifaceid == 0) {
389 return 0;
390 }
391
392 sqlite3_snprintf(64, sql, "delete from interface where id=%" PRId64 "", (int64_t)ifaceid);
393 return db_exec(sql);
394 }
395
db_renameinterface(const char * iface,const char * newifname)396 int db_renameinterface(const char *iface, const char *newifname)
397 {
398 char sql[128];
399 sqlite3_int64 ifaceid = 0;
400
401 if (!strlen(newifname)) {
402 return 0;
403 }
404
405 ifaceid = db_getinterfaceid(iface, 0);
406 if (ifaceid == 0) {
407 return 0;
408 }
409
410 sqlite3_snprintf(128, sql, "update interface set name='%q' where id=%" PRId64 "", newifname, (int64_t)ifaceid);
411 return db_exec(sql);
412 }
413
db_getinterfacecount(void)414 uint64_t db_getinterfacecount(void)
415 {
416 return db_getinterfacecountbyname("");
417 }
418
db_getinterfacecountbyname(const char * iface)419 uint64_t db_getinterfacecountbyname(const char *iface)
420 {
421 int rc;
422 uint64_t result = 0;
423 char sql[128], *inquery = NULL;
424 sqlite3_stmt *sqlstmt;
425
426 if (strchr(iface, '+') == NULL) {
427 if (strlen(iface) > 0) {
428 sqlite3_snprintf(128, sql, "select count(*) from interface where name='%q'", iface);
429 } else {
430 sqlite3_snprintf(128, sql, "select count(*) from interface");
431 }
432 } else {
433 inquery = getifaceinquery(iface);
434 if (inquery == NULL) {
435 return 0;
436 }
437 sqlite3_snprintf(128, sql, "select count(*) from interface where name in (%q)", inquery);
438 free(inquery);
439 }
440
441 rc = sqlite3_prepare_v2(db, sql, -1, &sqlstmt, NULL);
442 if (rc != SQLITE_OK) {
443 db_errcode = rc;
444 snprintf(errorstring, 1024, "Failed to get interface count from database (%d): %s", rc, sqlite3_errmsg(db));
445 printe(PT_Error);
446 return 0;
447 }
448 if (sqlite3_column_count(sqlstmt) != 1) {
449 return 0;
450 }
451 if (sqlite3_step(sqlstmt) == SQLITE_ROW) {
452 result = (uint64_t)sqlite3_column_int64(sqlstmt, 0);
453 }
454 sqlite3_finalize(sqlstmt);
455
456 /* consider merge query as invalid if not all requested interfaces are found or are not unique */
457 if (strchr(iface, '+') != NULL) {
458 if (result != getqueryinterfacecount(iface)) {
459 result = 0;
460 }
461 }
462
463 return result;
464 }
465
db_getinterfaceid(const char * iface,const int createifnotfound)466 sqlite3_int64 db_getinterfaceid(const char *iface, const int createifnotfound)
467 {
468 int rc;
469 char sql[128];
470 sqlite3_int64 ifaceid = 0;
471 sqlite3_stmt *sqlstmt;
472
473 sqlite3_snprintf(128, sql, "select id from interface where name='%q'", iface);
474 rc = sqlite3_prepare_v2(db, sql, -1, &sqlstmt, NULL);
475 if (rc == SQLITE_OK) {
476 if (sqlite3_step(sqlstmt) == SQLITE_ROW) {
477 ifaceid = sqlite3_column_int64(sqlstmt, 0);
478 }
479 sqlite3_finalize(sqlstmt);
480 } else {
481 db_errcode = rc;
482 snprintf(errorstring, 1024, "Failed to get interface id from database (%d): %s", rc, sqlite3_errmsg(db));
483 printe(PT_Error);
484 }
485
486 if (ifaceid == 0 && createifnotfound) {
487 if (!db_addinterface(iface)) {
488 return 0;
489 }
490 ifaceid = sqlite3_last_insert_rowid(db);
491 }
492
493 return ifaceid;
494 }
495
db_getinterfaceidin(const char * iface)496 char *db_getinterfaceidin(const char *iface)
497 {
498 int rc;
499 char sql[256], *result, *inquery;
500 sqlite3_stmt *sqlstmt;
501
502 result = NULL;
503 inquery = getifaceinquery(iface);
504 if (inquery == NULL) {
505 return NULL;
506 }
507
508 sqlite3_snprintf(256, sql, "select group_concat(id) from interface where name in (%q)", inquery);
509 free(inquery);
510 rc = sqlite3_prepare_v2(db, sql, -1, &sqlstmt, NULL);
511 if (rc == SQLITE_OK) {
512 if (sqlite3_step(sqlstmt) == SQLITE_ROW) {
513 if (sqlite3_column_text(sqlstmt, 0) != NULL) {
514 result = strdup((const char *)sqlite3_column_text(sqlstmt, 0));
515 }
516 }
517 sqlite3_finalize(sqlstmt);
518 } else {
519 db_errcode = rc;
520 snprintf(errorstring, 1024, "Failed to get interface id from database (%d): %s", rc, sqlite3_errmsg(db));
521 printe(PT_Error);
522 }
523
524 return result;
525 }
526
db_setactive(const char * iface,const int active)527 int db_setactive(const char *iface, const int active)
528 {
529 char sql[64];
530 sqlite3_int64 ifaceid = 0;
531
532 ifaceid = db_getinterfaceid(iface, 0);
533 if (ifaceid == 0) {
534 return 0;
535 }
536
537 sqlite3_snprintf(64, sql, "update interface set active=%d where id=%" PRId64 "", active, (int64_t)ifaceid);
538 return db_exec(sql);
539 }
540
db_setupdated(const char * iface,const time_t timestamp)541 int db_setupdated(const char *iface, const time_t timestamp)
542 {
543 char sql[256];
544 sqlite3_int64 ifaceid = 0;
545
546 ifaceid = db_getinterfaceid(iface, 0);
547 if (ifaceid == 0) {
548 return 0;
549 }
550
551 sqlite3_snprintf(256, sql, "update interface set updated=datetime(%" PRIu64 ", 'unixepoch'%s) where id=%" PRId64 "", (uint64_t)timestamp, cfg.dbtzmodifier, (int64_t)ifaceid);
552 return db_exec(sql);
553 }
554
db_setcounters(const char * iface,const uint64_t rxcounter,const uint64_t txcounter)555 int db_setcounters(const char *iface, const uint64_t rxcounter, const uint64_t txcounter)
556 {
557 char sql[256];
558 sqlite3_int64 ifaceid = 0;
559
560 ifaceid = db_getinterfaceid(iface, 0);
561 if (ifaceid == 0) {
562 return 0;
563 }
564
565 sqlite3_snprintf(256, sql, "update interface set rxcounter=%" PRIu64 ", txcounter=%" PRIu64 " where id=%" PRId64 "", rxcounter, txcounter, (int64_t)ifaceid);
566 return db_exec(sql);
567 }
568
db_getcounters(const char * iface,uint64_t * rxcounter,uint64_t * txcounter)569 int db_getcounters(const char *iface, uint64_t *rxcounter, uint64_t *txcounter)
570 {
571 int rc;
572 char sql[128];
573 sqlite3_int64 ifaceid = 0;
574 sqlite3_stmt *sqlstmt;
575
576 *rxcounter = *txcounter = 0;
577
578 ifaceid = db_getinterfaceid(iface, 0);
579 if (ifaceid == 0) {
580 return 0;
581 }
582
583 sqlite3_snprintf(128, sql, "select rxcounter, txcounter from interface where id=%" PRId64 "", (int64_t)ifaceid);
584 rc = sqlite3_prepare_v2(db, sql, -1, &sqlstmt, NULL);
585 if (rc != SQLITE_OK) {
586 db_errcode = rc;
587 snprintf(errorstring, 1024, "Failed to get interface counters from database (%d): %s", rc, sqlite3_errmsg(db));
588 printe(PT_Error);
589 return 0;
590 }
591 if (sqlite3_column_count(sqlstmt) != 2) {
592 sqlite3_finalize(sqlstmt);
593 return 0;
594 }
595 if (sqlite3_step(sqlstmt) == SQLITE_ROW) {
596 *rxcounter = (uint64_t)sqlite3_column_int64(sqlstmt, 0);
597 *txcounter = (uint64_t)sqlite3_column_int64(sqlstmt, 1);
598 }
599 sqlite3_finalize(sqlstmt);
600
601 return 1;
602 }
603
db_getinterfaceinfo(const char * iface,interfaceinfo * info)604 int db_getinterfaceinfo(const char *iface, interfaceinfo *info)
605 {
606 int rc;
607 char sql[512], *ifaceidin = NULL;
608 sqlite3_int64 ifaceid;
609 sqlite3_stmt *sqlstmt;
610
611 if (strchr(iface, '+') == NULL) {
612 ifaceid = db_getinterfaceid(iface, 0);
613 if (ifaceid == 0) {
614 return 0;
615 }
616 sqlite3_snprintf(512, sql, "select name, alias, active, strftime('%%s', created, 'utc'), strftime('%%s', updated, 'utc'), rxcounter, txcounter, rxtotal, txtotal from interface where id=%" PRId64 "", (int64_t)ifaceid);
617 } else {
618 ifaceidin = db_getinterfaceidin(iface);
619 if (ifaceidin == NULL || strlen(ifaceidin) < 1) {
620 free(ifaceidin);
621 return 0;
622 }
623 sqlite3_snprintf(512, sql, "select \"%q\", NULL, max(active), max(strftime('%%s', created, 'utc')), min(strftime('%%s', updated, 'utc')), 0, 0, sum(rxtotal), sum(txtotal) from interface where id in (%q)", iface, ifaceidin);
624 free(ifaceidin);
625 }
626
627 rc = sqlite3_prepare_v2(db, sql, -1, &sqlstmt, NULL);
628 if (rc != SQLITE_OK) {
629 db_errcode = rc;
630 snprintf(errorstring, 1024, "Failed to get interface information from database (%d): %s", rc, sqlite3_errmsg(db));
631 printe(PT_Error);
632 return 0;
633 }
634 if (sqlite3_column_count(sqlstmt) != 9) {
635 return 0;
636 }
637 if (sqlite3_step(sqlstmt) == SQLITE_ROW) {
638 if (sqlite3_column_text(sqlstmt, 0) != NULL) {
639 strncpy_nt(info->name, (const char *)sqlite3_column_text(sqlstmt, 0), 32);
640 } else {
641 info->name[0] = '\0';
642 }
643 if (sqlite3_column_text(sqlstmt, 1) != NULL) {
644 strncpy_nt(info->alias, (const char *)sqlite3_column_text(sqlstmt, 1), 32);
645 } else {
646 info->alias[0] = '\0';
647 }
648 info->active = sqlite3_column_int(sqlstmt, 2);
649 info->created = (time_t)sqlite3_column_int64(sqlstmt, 3);
650 info->updated = (time_t)sqlite3_column_int64(sqlstmt, 4);
651 info->rxcounter = (uint64_t)sqlite3_column_int64(sqlstmt, 5);
652 info->txcounter = (uint64_t)sqlite3_column_int64(sqlstmt, 6);
653 info->rxtotal = (uint64_t)sqlite3_column_int64(sqlstmt, 7);
654 info->txtotal = (uint64_t)sqlite3_column_int64(sqlstmt, 8);
655 }
656 sqlite3_finalize(sqlstmt);
657
658 return 1;
659 }
660
db_setalias(const char * iface,const char * alias)661 int db_setalias(const char *iface, const char *alias)
662 {
663 char sql[128];
664 sqlite3_int64 ifaceid = 0;
665
666 ifaceid = db_getinterfaceid(iface, 0);
667 if (ifaceid == 0) {
668 return 0;
669 }
670
671 sqlite3_snprintf(128, sql, "update interface set alias='%q' where id=%" PRId64 "", alias, (int64_t)ifaceid);
672 return db_exec(sql);
673 }
674
db_setinfo(const char * name,const char * value,const int createifnotfound)675 int db_setinfo(const char *name, const char *value, const int createifnotfound)
676 {
677 int rc;
678 char sql[128];
679
680 sqlite3_snprintf(128, sql, "update info set value='%q' where name='%q'", value, name);
681 rc = db_exec(sql);
682 if (!rc || (!sqlite3_changes(db) && !createifnotfound)) {
683 return 0;
684 }
685 if (!sqlite3_changes(db) && createifnotfound) {
686 sqlite3_snprintf(512, sql, "insert into info (name, value) values ('%q', '%q')", name, value);
687 rc = db_exec(sql);
688 }
689 return rc;
690 }
691
db_getinfo(const char * name)692 char *db_getinfo(const char *name)
693 {
694 int rc;
695 char sql[128];
696 static char buffer[64];
697 sqlite3_stmt *sqlstmt;
698
699 buffer[0] = '\0';
700
701 sqlite3_snprintf(128, sql, "select value from info where name='%q'", name);
702 rc = sqlite3_prepare_v2(db, sql, -1, &sqlstmt, NULL);
703 if (rc != SQLITE_OK) {
704 db_errcode = rc;
705 snprintf(errorstring, 1024, "Failed to get info value for \"%s\" from database (%d): %s", name, rc, sqlite3_errmsg(db));
706 printe(PT_Error);
707 return buffer;
708 }
709 if (sqlite3_step(sqlstmt) == SQLITE_ROW) {
710 if (sqlite3_column_text(sqlstmt, 0) != NULL) {
711 strncpy_nt(buffer, (const char *)sqlite3_column_text(sqlstmt, 0), 64);
712 }
713 }
714 sqlite3_finalize(sqlstmt);
715
716 return buffer;
717 }
718
db_getiflist(iflist ** ifl)719 int db_getiflist(iflist **ifl)
720 {
721 return db_getiflist_sorted(ifl, 0);
722 }
723
db_getiflist_sorted(iflist ** ifl,const int orderbytraffic)724 int db_getiflist_sorted(iflist **ifl, const int orderbytraffic)
725 {
726 int rc;
727 const char *constsql;
728 sqlite3_stmt *sqlstmt;
729
730 if (!orderbytraffic) {
731 constsql = "select name from interface order by name asc";
732 } else {
733 constsql = "select name from interface order by rxtotal+txtotal desc";
734 }
735
736 rc = sqlite3_prepare_v2(db, constsql, -1, &sqlstmt, NULL);
737 if (rc != SQLITE_OK) {
738 db_errcode = rc;
739 snprintf(errorstring, 1024, "Failed to get interface list from database (%d): %s", rc, sqlite3_errmsg(db));
740 printe(PT_Error);
741 return -1;
742 }
743
744 rc = 0;
745 while (sqlite3_step(sqlstmt) == SQLITE_ROW) {
746 if (sqlite3_column_text(sqlstmt, 0) == NULL) {
747 continue;
748 }
749 if (!iflistadd(ifl, (const char *)sqlite3_column_text(sqlstmt, 0), 0)) {
750 break;
751 }
752 rc++;
753 }
754
755 sqlite3_finalize(sqlstmt);
756
757 return rc;
758 }
759
db_get_date_generator(const int range,const short direct,const char * nowdate)760 char *db_get_date_generator(const int range, const short direct, const char *nowdate)
761 {
762 static char dgen[512];
763 dgen[0] = '\0';
764
765 switch (range) {
766 case 0: /* 5min */
767 snprintf(dgen, 512, "datetime(%s, ('-' || (strftime('%%M', %s)) || ' minutes'), ('-' || (strftime('%%S', %s)) || ' seconds'), ('+' || (round(strftime('%%M', %s)/5,0)*5) || ' minutes')%s)", nowdate, nowdate, nowdate, nowdate, cfg.dbtzmodifier);
768 break;
769 case 1: /* hour */
770 snprintf(dgen, 512, "strftime('%%Y-%%m-%%d %%H:00:00', %s%s)", nowdate, cfg.dbtzmodifier);
771 break;
772 case 2: /* day */
773 case 5: /* top */
774 snprintf(dgen, 512, "date(%s%s)", nowdate, cfg.dbtzmodifier);
775 break;
776 case 3: /* month */
777 if (direct || cfg.monthrotate == 1) {
778 snprintf(dgen, 512, "strftime('%%Y-%%m-01', %s%s)", nowdate, cfg.dbtzmodifier);
779 } else {
780 snprintf(dgen, 512, "strftime('%%Y-%%m-01', datetime(%s, '-%d days')%s)", nowdate, cfg.monthrotate - 1, cfg.dbtzmodifier);
781 }
782 break;
783 case 4: /* year */
784 if (direct || cfg.monthrotate == 1 || cfg.monthrotateyears == 0) {
785 snprintf(dgen, 512, "strftime('%%Y-01-01', %s%s)", nowdate, cfg.dbtzmodifier);
786 } else {
787 snprintf(dgen, 512, "strftime('%%Y-01-01', datetime(%s, '-%d days')%s)", nowdate, cfg.monthrotate - 1, cfg.dbtzmodifier);
788 }
789 break;
790 default:
791 break;
792 }
793 return dgen;
794 }
795
db_addtraffic(const char * iface,const uint64_t rx,const uint64_t tx)796 int db_addtraffic(const char *iface, const uint64_t rx, const uint64_t tx)
797 {
798 return db_addtraffic_dated(iface, rx, tx, 0);
799 }
800
db_addtraffic_dated(const char * iface,const uint64_t rx,const uint64_t tx,const uint64_t timestamp)801 int db_addtraffic_dated(const char *iface, const uint64_t rx, const uint64_t tx, const uint64_t timestamp)
802 {
803 int i, intransaction = db_intransaction;
804 char sql[1024], nowdate[64];
805 sqlite3_int64 ifaceid = 0;
806
807 const char *datatables[] = {"fiveminute", "hour", "day", "month", "year", "top"};
808 int32_t *featurecfg[] = {&cfg.fiveminutehours, &cfg.hourlydays, &cfg.dailydays, &cfg.monthlymonths, &cfg.yearlyyears, &cfg.topdayentries};
809
810 ifaceid = db_getinterfaceid(iface, 1);
811 if (ifaceid == 0) {
812 return 0;
813 }
814
815 if (timestamp > 0) {
816 snprintf(nowdate, 64, "datetime(%" PRIu64 ", 'unixepoch')", timestamp);
817 } else {
818 snprintf(nowdate, 64, "'now'");
819 }
820
821 if (debug)
822 printf("db add %s (%" PRId64 ") %" PRIu64 ": rx %" PRIu64 " - tx %" PRIu64 "\n", iface, (int64_t)ifaceid, timestamp, rx, tx);
823
824 if (!intransaction) {
825 if (!db_begintransaction()) {
826 return 0;
827 }
828 }
829
830 /* total */
831 if (rx > 0 || tx > 0) {
832 sqlite3_snprintf(1024, sql, "update interface set rxtotal=rxtotal+%" PRIu64 ", txtotal=txtotal+%" PRIu64 " where id=%" PRId64 "", rx, tx, (int64_t)ifaceid);
833 if (!db_exec(sql)) {
834 db_rollbacktransaction();
835 return 0;
836 }
837 }
838
839 /* time specific */
840 for (i = 0; i < 6; i++) {
841 if (featurecfg[i] == 0) {
842 continue;
843 }
844 sqlite3_snprintf(1024, sql, "insert or ignore into %s (interface, date, rx, tx) values (%" PRId64 ", %s, 0, 0)", datatables[i], (int64_t)ifaceid, db_get_date_generator(i, 0, nowdate));
845 if (!db_exec(sql)) {
846 db_rollbacktransaction();
847 return 0;
848 }
849 sqlite3_snprintf(1024, sql, "update %s set rx=rx+%" PRIu64 ", tx=tx+%" PRIu64 " where interface=%" PRId64 " and date=%s", datatables[i], rx, tx, (int64_t)ifaceid, db_get_date_generator(i, 0, nowdate));
850 if (!db_exec(sql)) {
851 db_rollbacktransaction();
852 return 0;
853 }
854 }
855
856 if (!intransaction) {
857 return db_committransaction();
858 }
859 return 1;
860 }
861
db_setcreation(const char * iface,const time_t timestamp)862 int db_setcreation(const char *iface, const time_t timestamp)
863 {
864 char sql[256];
865 sqlite3_int64 ifaceid = 0;
866
867 ifaceid = db_getinterfaceid(iface, 0);
868 if (ifaceid == 0) {
869 return 0;
870 }
871
872 sqlite3_snprintf(256, sql, "update interface set created=datetime(%" PRIu64 ", 'unixepoch'%s) where id=%" PRId64 "", (uint64_t)timestamp, cfg.dbtzmodifier, (int64_t)ifaceid);
873 return db_exec(sql);
874 }
875
db_settotal(const char * iface,const uint64_t rx,const uint64_t tx)876 int db_settotal(const char *iface, const uint64_t rx, const uint64_t tx)
877 {
878 char sql[256];
879 sqlite3_int64 ifaceid = 0;
880
881 ifaceid = db_getinterfaceid(iface, 0);
882 if (ifaceid == 0) {
883 return 0;
884 }
885
886 sqlite3_snprintf(256, sql, "update interface set rxtotal=%" PRIu64 ", txtotal=%" PRIu64 " where id=%" PRId64 "", rx, tx, (int64_t)ifaceid);
887 return db_exec(sql);
888 }
889
890 /* used only for legacy data import */
db_insertdata(const char * table,const char * iface,const uint64_t rx,const uint64_t tx,const uint64_t timestamp)891 int db_insertdata(const char *table, const char *iface, const uint64_t rx, const uint64_t tx, const uint64_t timestamp)
892 {
893 int i, index = -1;
894 char sql[1024], nowdate[64];
895 sqlite3_int64 ifaceid = 0;
896
897 const char *datatables[] = {"hour", "day", "month", "year", "top"};
898
899 for (i = 0; i < 5; i++) {
900 if (strcmp(table, datatables[i]) == 0) {
901 index = i;
902 break;
903 }
904 }
905
906 if (index == -1) {
907 return 0;
908 }
909
910 ifaceid = db_getinterfaceid(iface, 0);
911 if (ifaceid == 0) {
912 return 0;
913 }
914
915 /* legacy data is always local timezone and needs to be enforced here as a result */
916 if (cfg.useutc) {
917 snprintf(nowdate, 64, "datetime(%" PRIu64 ", 'unixepoch', 'localtime')", timestamp);
918 } else {
919 snprintf(nowdate, 64, "datetime(%" PRIu64 ", 'unixepoch')", timestamp);
920 }
921
922 sqlite3_snprintf(1024, sql, "insert or ignore into %s (interface, date, rx, tx) values (%" PRId64 ", %s, %" PRIu64 ", %" PRIu64 ")", table, (int64_t)ifaceid, db_get_date_generator(index + 1, 1, nowdate), rx, tx);
923 return db_exec(sql);
924 }
925
db_removeoldentries(void)926 int db_removeoldentries(void)
927 {
928 char sql[256];
929
930 if (debug) {
931 printf("db: removing old entries\n");
932 }
933
934 if (!db_begintransaction()) {
935 return 0;
936 }
937
938 if (!db_removeoldentries_top()) {
939 db_rollbacktransaction();
940 return 0;
941 }
942
943 if (cfg.fiveminutehours > 0) {
944 if (debug) {
945 printf("db: fiveminute cleanup (%dh)\n", cfg.fiveminutehours);
946 }
947 sqlite3_snprintf(256, sql, "delete from fiveminute where date < datetime('now', '-%d hours'%s)", cfg.fiveminutehours, cfg.dbtzmodifier);
948 if (!db_exec(sql)) {
949 db_rollbacktransaction();
950 return 0;
951 }
952 }
953
954 if (cfg.hourlydays > 0) {
955 if (debug) {
956 printf("db: hour cleanup (%dd)\n", cfg.hourlydays);
957 }
958 sqlite3_snprintf(256, sql, "delete from hour where date < datetime('now', '-%d days'%s)", cfg.hourlydays, cfg.dbtzmodifier);
959 if (!db_exec(sql)) {
960 db_rollbacktransaction();
961 return 0;
962 }
963 }
964
965 if (cfg.dailydays > 0) {
966 if (debug) {
967 printf("db: day cleanup (%dd)\n", cfg.dailydays);
968 }
969 sqlite3_snprintf(256, sql, "delete from day where date < date('now', '-%d days'%s)", cfg.dailydays, cfg.dbtzmodifier);
970 if (!db_exec(sql)) {
971 db_rollbacktransaction();
972 return 0;
973 }
974 }
975
976 if (cfg.monthlymonths > 0) {
977 if (debug) {
978 printf("db: month cleanup (%dm)\n", cfg.monthlymonths);
979 }
980 sqlite3_snprintf(256, sql, "delete from month where date < date('now', '-%d months'%s)", cfg.monthlymonths, cfg.dbtzmodifier);
981 if (!db_exec(sql)) {
982 db_rollbacktransaction();
983 return 0;
984 }
985 }
986
987 if (cfg.yearlyyears > 0) {
988 if (debug) {
989 printf("db: year cleanup (%dy)\n", cfg.yearlyyears);
990 }
991 sqlite3_snprintf(256, sql, "delete from year where date < date('now', '-%d years'%s)", cfg.yearlyyears, cfg.dbtzmodifier);
992 if (!db_exec(sql)) {
993 db_rollbacktransaction();
994 return 0;
995 }
996 }
997
998 return db_committransaction();
999 }
1000
db_removeoldentries_top(void)1001 int db_removeoldentries_top(void)
1002 {
1003 int errorcount = 0;
1004 char sql[512];
1005 iflist *dbifl = NULL, *dbifl_iterator = NULL;
1006 sqlite3_int64 ifaceid;
1007
1008 if (cfg.topdayentries <= 0) {
1009 return 1;
1010 }
1011
1012 if (db_getiflist(&dbifl) < 0) {
1013 return 0;
1014 }
1015
1016 dbifl_iterator = dbifl;
1017
1018 while (dbifl_iterator != NULL) {
1019 if (debug) {
1020 printf("db: top cleanup: %s (%d)\n", dbifl_iterator->interface, cfg.topdayentries);
1021 }
1022
1023 ifaceid = db_getinterfaceid(dbifl_iterator->interface, 0);
1024 if (ifaceid == 0) {
1025 errorcount++;
1026 dbifl_iterator = dbifl_iterator->next;
1027 continue;
1028 }
1029
1030 sqlite3_snprintf(512, sql, "delete from top where id in ( select id from top where interface=%" PRId64 " and date!=date('now'%s) order by rx+tx desc, date asc limit -1 offset %d )", (int64_t)ifaceid, cfg.dbtzmodifier, cfg.topdayentries);
1031
1032 if (!db_exec(sql)) {
1033 errorcount++;
1034 dbifl_iterator = dbifl_iterator->next;
1035 continue;
1036 }
1037
1038 dbifl_iterator = dbifl_iterator->next;
1039 }
1040
1041 iflistfree(&dbifl);
1042
1043 if (errorcount) {
1044 return 0;
1045 }
1046
1047 return 1;
1048 }
1049
db_vacuum(void)1050 int db_vacuum(void)
1051 {
1052 if (debug) {
1053 printf("db: vacuum\n");
1054 }
1055 return db_exec("VACUUM");
1056 }
1057
db_begintransaction(void)1058 int db_begintransaction(void)
1059 {
1060 int rc;
1061
1062 if (debug) {
1063 printf("db: begin transaction\n");
1064 }
1065
1066 rc = sqlite3_exec(db, "BEGIN IMMEDIATE", 0, 0, 0);
1067 if (rc) {
1068 db_errcode = rc;
1069 snprintf(errorstring, 1024, "Begin transaction to database failed (%d): %s", rc, sqlite3_errmsg(db));
1070 printe(PT_Error);
1071 return 0;
1072 }
1073 db_intransaction = 1;
1074 return 1;
1075 }
1076
db_committransaction(void)1077 int db_committransaction(void)
1078 {
1079 int rc;
1080
1081 if (debug) {
1082 printf("db: commit transaction\n");
1083 }
1084
1085 db_intransaction = 0;
1086
1087 rc = sqlite3_exec(db, "COMMIT", 0, 0, 0);
1088 if (rc) {
1089 snprintf(errorstring, 1024, "Commit transaction to database failed (%d): %s", rc, sqlite3_errmsg(db));
1090 printe(PT_Error);
1091 /* execute rollback if commit failure left the transaction open */
1092 if (!sqlite3_get_autocommit(db)) {
1093 db_rollbacktransaction();
1094 }
1095 db_errcode = rc;
1096 return 0;
1097 }
1098 return 1;
1099 }
1100
db_rollbacktransaction(void)1101 int db_rollbacktransaction(void)
1102 {
1103 int rc;
1104
1105 if (debug) {
1106 printf("db: rollback transaction\n");
1107 }
1108
1109 db_intransaction = 0;
1110
1111 rc = sqlite3_exec(db, "ROLLBACK", 0, 0, 0);
1112 if (rc) {
1113 db_errcode = rc;
1114 snprintf(errorstring, 1024, "Transaction rollback failed (%d): %s", rc, sqlite3_errmsg(db));
1115 printe(PT_Error);
1116 return 0;
1117 }
1118 return 1;
1119 }
1120
db_iserrcodefatal(int errcode)1121 int db_iserrcodefatal(int errcode)
1122 {
1123 switch (errcode) {
1124 case SQLITE_OK:
1125 case SQLITE_FULL:
1126 case SQLITE_IOERR:
1127 case SQLITE_LOCKED:
1128 case SQLITE_BUSY:
1129 return 0;
1130 default:
1131 return 1;
1132 }
1133 }
1134
db_isdiskfull(int errcode)1135 int db_isdiskfull(int errcode)
1136 {
1137 if (errcode == SQLITE_FULL) {
1138 return 1;
1139 } else {
1140 return 0;
1141 }
1142 }
1143
1144 #if HAVE_DECL_SQLITE_CHECKPOINT_RESTART
db_walcheckpoint(void)1145 void db_walcheckpoint(void)
1146 {
1147 double used_secs = 0.0;
1148
1149 timeused(__func__, 1);
1150 #if HAVE_DECL_SQLITE_CHECKPOINT_TRUNCATE
1151 sqlite3_wal_checkpoint_v2(db, NULL, SQLITE_CHECKPOINT_TRUNCATE, NULL, NULL);
1152 #else
1153 sqlite3_wal_checkpoint_v2(db, NULL, SQLITE_CHECKPOINT_RESTART, NULL, NULL);
1154 #endif
1155 timeused(__func__, 0);
1156
1157 used_secs = timeused(__func__, 0);
1158 if (used_secs > SLOWDBWARNLIMIT) {
1159 snprintf(errorstring, 1024, "Write-Ahead Logging checkpoint took %.1f seconds.", used_secs);
1160 printe(PT_Warning);
1161 }
1162 }
1163 #endif
1164
db_getdata(dbdatalist ** dbdata,dbdatalistinfo * listinfo,const char * iface,const char * table,const uint32_t resultlimit)1165 int db_getdata(dbdatalist **dbdata, dbdatalistinfo *listinfo, const char *iface, const char *table, const uint32_t resultlimit)
1166 {
1167 return db_getdata_range(dbdata, listinfo, iface, table, resultlimit, "", "");
1168 }
1169
db_getdata_range(dbdatalist ** dbdata,dbdatalistinfo * listinfo,const char * iface,const char * table,const uint32_t resultlimit,const char * databegin,const char * dataend)1170 int db_getdata_range(dbdatalist **dbdata, dbdatalistinfo *listinfo, const char *iface, const char *table, const uint32_t resultlimit, const char *databegin, const char *dataend)
1171 {
1172 int ret, i, rc;
1173 const char *datatables[] = {"fiveminute", "hour", "day", "month", "year", "top"};
1174 char sql[512], limit[64], dbegin[32], dend[44], *ifaceidin = NULL;
1175 sqlite3_stmt *sqlstmt;
1176 time_t timestamp;
1177 int64_t rowid;
1178 uint64_t rx, tx;
1179
1180 listinfo->count = 0;
1181
1182 ret = 0;
1183 for (i = 0; i < 6; i++) {
1184 if (strcmp(table, datatables[i]) == 0) {
1185 ret = 1;
1186 break;
1187 }
1188 }
1189 if (!ret) {
1190 return 0;
1191 }
1192
1193 ifaceidin = db_getinterfaceidin(iface);
1194 if (ifaceidin == NULL) {
1195 return 0;
1196 }
1197
1198 dbegin[0] = '\0';
1199 if (strlen(databegin)) {
1200 snprintf(dbegin, 32, "and date >= '%s'", databegin);
1201 }
1202
1203 dend[0] = '\0';
1204 if (strlen(dataend)) {
1205 if (strchr(dataend, ':')) {
1206 snprintf(dend, 44, "and date <= datetime('%s')", dataend);
1207 } else {
1208 snprintf(dend, 44, "and date <= datetime('%s 23:59:59')", dataend);
1209 }
1210 }
1211
1212 limit[0] = '\0';
1213 if (resultlimit > 0 && (!strlen(dbegin) || !strlen(dend))) {
1214 snprintf(limit, 64, "limit %" PRIu32 "", resultlimit);
1215 }
1216
1217 /* note that using the linked list reverses the order */
1218 /* most recent last in the linked list is considered the normal order */
1219 if (strcmp(table, "top") == 0) {
1220 /* 'top' entries, requires different query due to rx+tx ordering */
1221 if (strlen(dbegin)) {
1222 if (resultlimit > 0) {
1223 snprintf(limit, 64, "limit %" PRIu32 "", resultlimit);
1224 }
1225 sqlite3_snprintf(512, sql, "select * from (select id, strftime('%%s', date, 'utc') as unixdate, sum(rx) as rx, sum(tx) as tx from day where interface in (%q) %s %s group by date order by rx+tx desc, unixdate asc %s) order by rx+tx asc, unixdate desc", ifaceidin, dbegin, dend, limit);
1226 } else {
1227 sqlite3_snprintf(512, sql, "select * from (select id, strftime('%%s', date, 'utc') as unixdate, sum(rx) as rx, sum(tx) as tx from top where interface in (%q) group by date order by rx+tx desc, unixdate asc %s) order by rx+tx asc, unixdate desc", ifaceidin, limit);
1228 }
1229 } else {
1230 if (strlen(dbegin) && strlen(limit)) {
1231 sqlite3_snprintf(512, sql, "select * from (select id, strftime('%%s', date, 'utc') as unixdate, sum(rx), sum(tx) from %s where interface in (%q) %s %s group by date order by unixdate asc %s) order by unixdate desc", table, ifaceidin, dbegin, dend, limit);
1232 } else {
1233 sqlite3_snprintf(512, sql, "select id, strftime('%%s', date, 'utc') as unixdate, sum(rx), sum(tx) from %s where interface in (%q) %s %s group by date order by unixdate desc %s", table, ifaceidin, dbegin, dend, limit);
1234 }
1235 }
1236 free(ifaceidin);
1237
1238 rc = sqlite3_prepare_v2(db, sql, -1, &sqlstmt, NULL);
1239 if (rc != SQLITE_OK) {
1240 db_errcode = rc;
1241 snprintf(errorstring, 1024, "Get data prepare failed (%d: %s): \"%s\"", rc, sqlite3_errmsg(db), sql);
1242 printe(PT_Error);
1243 return 0;
1244 }
1245
1246 rc = sqlite3_column_count(sqlstmt);
1247 if (rc != 4) {
1248 snprintf(errorstring, 1024, "Get data returned unexpected column count %d instead of 4: \"%s\"", rc, sql);
1249 printe(PT_Error);
1250 sqlite3_finalize(sqlstmt);
1251 return 0;
1252 }
1253
1254 while (sqlite3_step(sqlstmt) == SQLITE_ROW) {
1255 rowid = (int64_t)sqlite3_column_int64(sqlstmt, 0);
1256 timestamp = (time_t)sqlite3_column_int64(sqlstmt, 1);
1257 rx = (uint64_t)sqlite3_column_int64(sqlstmt, 2);
1258 tx = (uint64_t)sqlite3_column_int64(sqlstmt, 3);
1259 if (!dbdatalistadd(dbdata, rx, tx, timestamp, rowid)) {
1260 snprintf(errorstring, 1024, "Storing data for processing failed: %s", strerror(errno));
1261 printe(PT_Error);
1262 ret = 0;
1263 break;
1264 }
1265 updatelistinfo(listinfo, rx, tx, timestamp);
1266 }
1267 sqlite3_finalize(sqlstmt);
1268
1269 /* clean list on failure */
1270 if (!ret) {
1271 dbdatalistfree(dbdata);
1272 listinfo->count = 0;
1273 }
1274
1275 return ret;
1276 }
1277
updatelistinfo(dbdatalistinfo * listinfo,const uint64_t rx,const uint64_t tx,const time_t timestamp)1278 void updatelistinfo(dbdatalistinfo *listinfo, const uint64_t rx, const uint64_t tx, const time_t timestamp)
1279 {
1280 if (listinfo->count == 0) {
1281 listinfo->maxtime = timestamp;
1282 listinfo->mintime = timestamp;
1283 listinfo->maxrx = rx;
1284 listinfo->minrx = rx;
1285 listinfo->maxtx = tx;
1286 listinfo->mintx = tx;
1287 listinfo->min = rx + tx;
1288 listinfo->max = rx + tx;
1289 listinfo->sumrx = rx;
1290 listinfo->sumtx = tx;
1291 } else {
1292 if (timestamp > listinfo->maxtime) {
1293 listinfo->maxtime = timestamp;
1294 }
1295 if (timestamp < listinfo->mintime) {
1296 listinfo->mintime = timestamp;
1297 }
1298 if (rx < listinfo->minrx) {
1299 listinfo->minrx = rx;
1300 }
1301 if (tx < listinfo->mintx) {
1302 listinfo->mintx = tx;
1303 }
1304 if (rx > listinfo->maxrx) {
1305 listinfo->maxrx = rx;
1306 }
1307 if (tx > listinfo->maxtx) {
1308 listinfo->maxtx = tx;
1309 }
1310 if (rx + tx > listinfo->max) {
1311 listinfo->max = rx + tx;
1312 }
1313 if (rx + tx < listinfo->min) {
1314 listinfo->min = rx + tx;
1315 }
1316 listinfo->sumrx += rx;
1317 listinfo->sumtx += tx;
1318 }
1319 listinfo->count++;
1320 }
1321
dbdatalistadd(dbdatalist ** dbdata,const uint64_t rx,const uint64_t tx,const time_t timestamp,const int64_t rowid)1322 int dbdatalistadd(dbdatalist **dbdata, const uint64_t rx, const uint64_t tx, const time_t timestamp, const int64_t rowid)
1323 {
1324 dbdatalist *newdata;
1325
1326 newdata = malloc(sizeof(dbdatalist));
1327 if (newdata == NULL) {
1328 return 0;
1329 }
1330
1331 newdata->next = *dbdata;
1332 *dbdata = newdata;
1333
1334 newdata->rowid = rowid;
1335 newdata->timestamp = timestamp;
1336 newdata->rx = rx;
1337 newdata->tx = tx;
1338
1339 return 1;
1340 }
1341
dbdatalistfree(dbdatalist ** dbdata)1342 void dbdatalistfree(dbdatalist **dbdata)
1343 {
1344 dbdatalist *dbdata_prev;
1345
1346 while (*dbdata != NULL) {
1347 dbdata_prev = *dbdata;
1348 *dbdata = (*dbdata)->next;
1349 free(dbdata_prev);
1350 }
1351 }
1352
getqueryinterfacecount(const char * input)1353 unsigned int getqueryinterfacecount(const char *input)
1354 {
1355 unsigned int i, ifacecount = 1;
1356
1357 if (!strlen(input) || input[0] == '+' || input[strlen(input) - 1] == '+') {
1358 return 0;
1359 }
1360
1361 for (i = 0; i < (unsigned int)strlen(input); i++) {
1362 if (input[i] == '+') {
1363 if (i > 0 && input[i - 1] == '+') {
1364 return 0;
1365 } else {
1366 ifacecount++;
1367 }
1368 }
1369 }
1370
1371 return ifacecount;
1372 }
1373
getifaceinquery(const char * input)1374 char *getifaceinquery(const char *input)
1375 {
1376 unsigned int i, j, ifacecount;
1377 char *result;
1378
1379 ifacecount = getqueryinterfacecount(input);
1380
1381 if (ifacecount == 0) {
1382 return NULL;
1383 }
1384
1385 /* each interface requires two quotes and comma or \0 so 3 extra chars */
1386 j = (unsigned int)strlen(input) + ifacecount * 3;
1387 result = malloc(sizeof(char) * j);
1388 if (result == NULL) {
1389 panicexit(__FILE__, __LINE__);
1390 }
1391
1392 memset(result, '\0', j);
1393
1394 result[0] = '"';
1395 j = 1;
1396 for (i = 0; i < (unsigned int)strlen(input); i++) {
1397 if (input[i] == '+') {
1398 strcat(result, "\",\"");
1399 j += 3;
1400 } else {
1401 result[j] = input[i];
1402 j++;
1403 }
1404 }
1405 result[j] = '"';
1406
1407 return result;
1408 }
1409