]> granicus.if.org Git - vnstat/commitdiff
add support for database restore (--dumpdb import) based on patch by Tilmann Bubeck
authorTeemu Toivola <git@humdi.net>
Thu, 6 Mar 2014 21:07:11 +0000 (23:07 +0200)
committerTeemu Toivola <git@humdi.net>
Thu, 6 Mar 2014 21:07:11 +0000 (23:07 +0200)
man/vnstat.1
src/dbaccess.c
src/dbaccess.h
src/vnstat.c
tests/database_tests.c

index 55f01c3653d4857148de7bb9aff6546408f24273..0f7a6005520b3ef8b1a2d2c5aae9da8ce5352825 100644 (file)
@@ -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
index a7e17cdfd9143c2f8af1685ea3d658aee28107bc..6cb7ea664f7c187182f19c27bcfe121bb958918a 100644 (file)
@@ -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;
+                       }
+               }
+       }
+}
index 928bb007e0337f9e49918b514e08a480d626195e..150d3df22387dc3e4c93181d7295e848251bc5ea 100644 (file)
@@ -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 {
index deb6d5c7c8e8388f7b62ae55eeb8c7d524794e9c..d74ef0034481eb7b1439e4ac88358ec5ae17df76 100644 (file)
@@ -29,7 +29,7 @@ vnStat - Copyright (c) 2002-2014 Teemu Toivola <tst@iki.fi>
 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) {
index 337c3d60178a9aa0197763f82e8e560757c0cc18..bb2ec252d3487228ab5660d01d936a48fe28fb16 100644 (file)
@@ -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);
 }