From: Teemu Toivola Date: Thu, 6 Mar 2014 21:07:11 +0000 (+0200) Subject: add support for database restore (--dumpdb import) based on patch by Tilmann Bubeck X-Git-Tag: v1.12~67 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=de422564b34fca20b6d646695d8ef28ecb8bc890;p=vnstat add support for database restore (--dumpdb import) based on patch by Tilmann Bubeck --- diff --git a/man/vnstat.1 b/man/vnstat.1 index 55f01c3..0f7a600 100644 --- a/man/vnstat.1 +++ b/man/vnstat.1 @@ -1,4 +1,4 @@ -.TH VNSTAT 1 "JUNE 2011" "version 1.11" "User Manuals" +.TH VNSTAT 1 "MARCH 2014" "version 1.12" "User Manuals" .SH NAME vnStat \- a console-based network traffic monitor @@ -64,6 +64,8 @@ vnStat \- a console-based network traffic monitor ] [ .B \-\-reset ] [ +.B \-\-restoredb +] [ .B \-ru ] [ .B \-\-savemerged @@ -265,6 +267,17 @@ otherwise that interface will get some extra traffic to its database. .BI "--rebuildtotal" Reset the total traffic counters and recount those using recorded months. +.TP +.BI "--restoredb" +Restore a database which was previously dumped using the +.BI "--dumpdb" +option. This can be used to transfer a database between different architectures and +machines, as the database is architecture dependant and not compatible between +different architectures. First dump the database on one machine, e.g. with +.B "vnstat -i ppp0 --dumpdb > ppp0-dump" +and then restore that dump on a different machine using +.B "vnstat -i ppp0 --restoredb < ppp0-dump" + .TP .BI "-ru, --rateunit" Swap the configured rate unit. If rate has been configured to be shown in diff --git a/src/dbaccess.c b/src/dbaccess.c index a7e17cd..6cb7ea6 100644 --- a/src/dbaccess.c +++ b/src/dbaccess.c @@ -800,3 +800,159 @@ void rebuilddbtotal(const char *iface, const char *dirname) writedb(iface, dirname, 0); printf("Total transfer rebuild completed for interface \"%s\".\n", data.interface); } + +int validatedb(void) +{ + int i, used; + uint64_t rxsum, txsum; + + if (data.version!=DBVERSION) { + return 0; + } + + if (data.active<0 || data.active>1) + return 0; + + if (!strlen(data.interface)) + return 0; + + if (!data.created || !data.lastupdated || !data.btime) + return 0; + + rxsum = txsum = 0; + used = 1; + for (i=0; i<30; i++) { + if (data.day[i].used<0 || data.day[i].used>1) + return 0; + if (data.day[i].rxk<0 || data.day[i].txk<0) + return 0; + if (data.day[i].used && !used) { + return 0; + } else if (!data.day[i].used) { + used = 0; + } + if (data.day[i].used) { + rxsum += data.day[i].rx; + txsum += data.day[i].tx; + } + } + + if (data.totalrx < rxsum) + return 0; + + if (data.totaltx < txsum) + return 0; + + rxsum = txsum = 0; + used = 1; + for (i=0; i<12; i++) { + if (data.month[i].used<0 || data.month[i].used>1) + return 0; + if (data.month[i].rxk<0 || data.month[i].txk<0) + return 0; + if (data.month[i].used && !used) { + return 0; + } else if (!data.month[i].used) { + used = 0; + } + if (data.month[i].used) { + rxsum += data.month[i].rx; + txsum += data.month[i].tx; + } + } + + if (data.totalrx < rxsum) + return 0; + + if (data.totaltx < txsum) + return 0; + + used = 1; + for (i=0; i<10; i++) { + if (data.top10[i].used<0 || data.top10[i].used>1) + return 0; + if (data.top10[i].rxk<0 || data.top10[i].txk<0) + return 0; + if (data.top10[i].used && !used) { + return 0; + } else if (!data.top10[i].used) { + used = 0; + } + } + + return 1; +} + +void restoredb(FILE *input) +{ + char line[512]; + int i, count; + uint64_t tempint; + DAY day; + MONTH month; + HOUR hour; + + while (fgets(line, sizeof(line), input) != NULL) { + if (debug) { + printf("parsing %s", line); + } + + if (strlen(line)<9) { + continue; + } + + sscanf(line, "version;%d", &data.version); + sscanf(line, "active;%d", &data.active); + sscanf(line, "interface;%511s", data.interface); + sscanf(line, "nick;%511s", data.nick); + if (sscanf(line, "created;%"PRIu64, &tempint)) { + data.created = (time_t)tempint; + } + if (sscanf(line, "updated;%"PRIu64, &tempint)) { + data.lastupdated = (time_t)tempint; + } + sscanf(line, "totalrx;%"PRIu64, &data.totalrx); + sscanf(line, "totaltx;%"PRIu64, &data.totaltx); + sscanf(line, "currx;%"PRIu64, &data.currx); + sscanf(line, "curtx;%"PRIu64, &data.curtx); + sscanf(line, "totalrxk;%d", &data.totalrxk); + sscanf(line, "totaltxk;%d", &data.totaltxk); + sscanf(line, "btime;%"PRIu64, &data.btime); + + count = sscanf(line, "d;%d;%"PRIu64";%"PRIu64";%"PRIu64";%d;%d;%d", + &i, &tempint, &day.rx, &day.tx, &day.rxk, &day.txk, &day.used); + if (count == 7) { + if (i >= 0 && i < (int)sizeof(data.day) / (int)sizeof(DAY)) { + day.date = (time_t)tempint; + data.day[i] = day; + } + } + + count = sscanf(line, "m;%d;%"PRIu64";%"PRIu64";%"PRIu64";%d;%d;%d", + &i, &tempint, &month.rx, &month.tx, &month.rxk, &month.txk, &month.used); + if (count == 7) { + if ( i >= 0 && i < (int)sizeof(data.month) / (int)sizeof(MONTH) ) { + month.month = (time_t)tempint; + data.month[i] = month; + } + } + + count = sscanf(line, "t;%d;%"PRIu64";%"PRIu64";%"PRIu64";%d;%d;%d", + &i, &tempint, &day.rx, &day.tx, &day.rxk, &day.txk, &day.used); + if (count == 7) { + if ( i >= 0 && i < (int)sizeof(data.top10) / (int)sizeof(DAY) ) { + day.date = (time_t)tempint; + data.top10[i] = day; + } + } + + count = sscanf(line, "h;%d;%"PRIu64";%"PRIu64";%"PRIu64, + &i, &tempint, &hour.rx, &hour.tx); + if (count == 4) { + if ( i >= 0 && i < (int)sizeof(data.hour) / (int)sizeof(HOUR) ) { + hour.date = (time_t)tempint; + data.hour[i] = hour; + } + } + } +} diff --git a/src/dbaccess.h b/src/dbaccess.h index 928bb00..150d3df 100644 --- a/src/dbaccess.h +++ b/src/dbaccess.h @@ -14,7 +14,8 @@ void rotatedays(void); void rotatemonths(void); void cleartop10(const char *iface, const char *dirname); void rebuilddbtotal(const char *iface, const char *dirname); - +int validatedb(void); +void restoredb(FILE *input); /* version 1.0 database format aka db v1 */ typedef struct { diff --git a/src/vnstat.c b/src/vnstat.c index deb6d5c..d74ef00 100644 --- a/src/vnstat.c +++ b/src/vnstat.c @@ -29,7 +29,7 @@ vnStat - Copyright (c) 2002-2014 Teemu Toivola int main(int argc, char *argv[]) { int i; - int currentarg, update=0, query=1, newdb=0, reset=0, sync=0, merged=0, savemerged=0; + int currentarg, update=0, query=1, newdb=0, reset=0, sync=0, merged=0, savemerged=0, restore_db=0; int active=-1, files=0, force=0, cleartop=0, rebuildtotal=0, traffic=0; int livetraffic=0, defaultiface=1, delete=0, livemode=0; char interface[32], dirname[512], nick[32]; @@ -112,6 +112,7 @@ int main(int argc, char *argv[]) { printf(" -ru, --rateunit swap configured rate unit\n"); printf(" --oneline show simple parseable format\n"); printf(" --dumpdb show database in parseable format\n"); + printf(" --restoredb restore database from previous --dumpdb\n"); printf(" --xml show database in xml format\n"); printf(" Misc:\n"); @@ -240,6 +241,8 @@ int main(int argc, char *argv[]) { query=0; if (debug) printf("Updating database...\n"); + } else if (strcmp(argv[currentarg],"--restoredb")==0) { + restore_db=1; } else if ((strcmp(argv[currentarg],"-q")==0) || (strcmp(argv[currentarg],"--query")==0)) { query=1; } else if ((strcmp(argv[currentarg],"-D")==0) || (strcmp(argv[currentarg],"--debug")==0)) { @@ -414,6 +417,34 @@ int main(int argc, char *argv[]) { printf("Counters reseted for \"%s\"\n", data.interface); } + /* restore database from previous dumpdb output */ + if (restore_db) { + if (defaultiface) { + printf("Error: Specify interface to be restored using the -i parameter.\n"); + return 1; + } + if (!spacecheck(dirname) && !force) { + printf("Error: Not enough free diskspace available.\n"); + return 1; + } + if (checkdb(interface, dirname) && !force) { + printf("Error: Database file for interface \"%s\" already exists.\n", interface); + printf("Add --force parameter to overwrite it.\n"); + return 1; + } + initdb(); + restoredb(fdopen(STDIN_FILENO,"r")); + if (!validatedb()) { + printf("Error: validation of restored database fails.\n"); + return 1; + } + strncpy(data.interface, interface, 32); + if (writedb(interface, dirname, 1)) { + printf("Database restore for \"%s\" completed.\n", data.interface); + } + return 0; + } + /* counter sync */ if (sync) { if (!spacecheck(dirname) && !force) { diff --git a/tests/database_tests.c b/tests/database_tests.c index 337c3d6..bb2ec25 100644 --- a/tests/database_tests.c +++ b/tests/database_tests.c @@ -607,6 +607,35 @@ START_TEST(rebuilddbtotal_with_nonexisting_file) } END_TEST +START_TEST(validatedb_with_initdb) +{ + initdb(); + strcpy(data.interface, "ethtest"); + ck_assert_int_eq(validatedb(), 1); +} +END_TEST + +START_TEST(validatedb_with_invalid_totals) +{ + initdb(); + strcpy(data.interface, "ethtest"); + data.day[0].rx++; + ck_assert_int_eq(validatedb(), 0); +} +END_TEST + +START_TEST(validatedb_with_top10_use) +{ + initdb(); + strcpy(data.interface, "ethtest"); + data.top10[0].used = 1; + data.top10[1].used = 1; + data.top10[2].used = 1; + data.top10[5].used = 1; + ck_assert_int_eq(validatedb(), 0); +} +END_TEST + void add_database_tests(Suite *s) { /* Database test cases */ @@ -646,5 +675,8 @@ void add_database_tests(Suite *s) tcase_add_exit_test(tc_db, cleartop10_with_nonexisting_file, 1); tcase_add_test(tc_db, rebuilddbtotal_rebuilds_total); tcase_add_exit_test(tc_db, rebuilddbtotal_with_nonexisting_file, 1); + tcase_add_test(tc_db, validatedb_with_initdb); + tcase_add_test(tc_db, validatedb_with_invalid_totals); + tcase_add_test(tc_db, validatedb_with_top10_use); suite_add_tcase(s, tc_db); }