-.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
] [
.B \-\-reset
] [
+.B \-\-restoredb
+] [
.B \-ru
] [
.B \-\-savemerged
.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
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;
+ }
+ }
+ }
+}
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 {
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];
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");
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)) {
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) {
}
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 */
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);
}