From da881d6e3b215c25ede6d8fd41c07efddbe5d9f4 Mon Sep 17 00:00:00 2001 From: Teemu Toivola Date: Sat, 16 Mar 2019 22:24:31 +0200 Subject: [PATCH] enforce the existence and uniqueness of all interfaces in a merge query --- man/vnstat.1 | 3 ++- man/vnstati.1 | 3 ++- src/dbsql.c | 31 +++++++++++++++++++++++++------ src/dbsql.h | 1 + src/vnstat.c | 2 +- src/vnstati.c | 6 +++++- tests/dbsql_tests.c | 24 +++++++++++++++++++++++- 7 files changed, 59 insertions(+), 11 deletions(-) diff --git a/man/vnstat.1 b/man/vnstat.1 index 0b1b1bc..2ddf7d6 100644 --- a/man/vnstat.1 +++ b/man/vnstat.1 @@ -188,7 +188,8 @@ Select one specific and apply actions to only it. For queries, it is possible to merge the information of two or more interfaces using the .I interface1+interface2+... -syntax. +syntax. All provided interfaces must be unique and must exist in the database +when the merge syntax is used. .TP .B "--iflist" diff --git a/man/vnstati.1 b/man/vnstati.1 index a6e5433..4678dc2 100644 --- a/man/vnstati.1 +++ b/man/vnstati.1 @@ -188,7 +188,8 @@ Use instead of default or configured interface. It is also possible to merge the information of two or more interfaces using the .I interface1+interface2+... -syntax. +syntax. All provided interfaces must be unique and must exist in the database +when the merge syntax is used. .TP .BI "--locale " locale diff --git a/src/dbsql.c b/src/dbsql.c index 91b18d4..f60159a 100644 --- a/src/dbsql.c +++ b/src/dbsql.c @@ -354,7 +354,6 @@ uint64_t db_getinterfacecountbyname(const char *iface) sqlite3_snprintf(512, sql, "select count(*) from interface"); } } else { - /* TODO: possibly verify all given interfaces exist in the database */ inquery = getifaceinquery(iface); if (inquery == NULL) { return 0; @@ -378,6 +377,13 @@ uint64_t db_getinterfacecountbyname(const char *iface) } sqlite3_finalize(sqlstmt); + /* consider merge query as invalid if not all requested interfaces are found or are not unique */ + if (strchr(iface, '+') != NULL) { + if (result != getqueryinterfacecount(iface)) { + result = 0; + } + } + return result; } @@ -1241,25 +1247,38 @@ void dbdatalistfree(dbdatalist **dbdata) } -char *getifaceinquery(const char *input) +unsigned int getqueryinterfacecount(const char *input) { - unsigned int i, j, ifacecount = 1; - char *result; + unsigned int i, ifacecount = 1; if (input[0] == '+' || input[strlen(input)-1] == '+' || !strlen(input)) { - return NULL; + return 0; } for (i = 0; i < (unsigned int)strlen(input); i++) { if (input[i] == '+') { if (i > 0 && input[i-1] == '+') { - return NULL; + return 0; } else { ifacecount++; } } } + return ifacecount; +} + +char *getifaceinquery(const char *input) +{ + unsigned int i, j, ifacecount = 1; + char *result; + + ifacecount = getqueryinterfacecount(input); + + if (ifacecount == 0) { + return NULL; + } + /* each interface requires two quotes and comma or \0 so 3 extra chars */ j = (unsigned int)strlen(input) + ifacecount * 3; result = malloc(sizeof(char) * j); diff --git a/src/dbsql.h b/src/dbsql.h index 0b8950f..67455aa 100644 --- a/src/dbsql.h +++ b/src/dbsql.h @@ -78,6 +78,7 @@ void updatelistinfo(dbdatalistinfo *listinfo, const uint64_t rx, const uint64_t int dbdatalistadd(dbdatalist **dbdata, const uint64_t rx, const uint64_t tx, const time_t timestamp, const int64_t rowid); void dbdatalistfree(dbdatalist **dbdata); +unsigned int getqueryinterfacecount(const char *input); char *getifaceinquery(const char *input); /* global db */ diff --git a/src/vnstat.c b/src/vnstat.c index 1c9eb91..78e80ab 100644 --- a/src/vnstat.c +++ b/src/vnstat.c @@ -766,7 +766,7 @@ void showoneinterface(PARAMS *p, const char *interface) if (strchr(p->interface, '+') == NULL) { printf("Error: Interface \"%s\" not found in database.\n", p->interface); } else { - printf("Error: Not all requested interfaces found in database.\n"); + printf("Error: Not all requested interfaces found in database or given interfaces aren't unique.\n"); } exit(EXIT_FAILURE); } diff --git a/src/vnstati.c b/src/vnstati.c index d236586..6c2a024 100644 --- a/src/vnstati.c +++ b/src/vnstati.c @@ -415,7 +415,11 @@ void handledatabase(IPARAMS *p, IMAGECONTENT *ic) exit(EXIT_FAILURE); } if (!db_getinterfacecountbyname(p->interface)) { - printf("Error: Interface \"%s\" not found in database.\n", p->interface); + if (strchr(p->interface, '+') == NULL) { + printf("Error: Interface \"%s\" not found in database.\n", p->interface); + } else { + printf("Error: Not all requested interfaces found in database or given interfaces aren't unique.\n"); + } exit(EXIT_FAILURE); } if (!db_getinterfaceinfo(p->interface, &ic->interface)) { diff --git a/tests/dbsql_tests.c b/tests/dbsql_tests.c index e5e27ea..e853181 100644 --- a/tests/dbsql_tests.c +++ b/tests/dbsql_tests.c @@ -563,7 +563,7 @@ START_TEST(db_getinterfacecountbyname_counts_interfaces) ck_assert_int_eq(ret, 3); ret = (int)db_getinterfacecountbyname("eth0+eth1+eth2"); - ck_assert_int_eq(ret, 2); + ck_assert_int_eq(ret, 0); ret = db_close(); ck_assert_int_eq(ret, 1); @@ -2183,6 +2183,27 @@ START_TEST(db_getinterfaceinfo_can_handle_invalid_input) } END_TEST +START_TEST(getqueryinterfacecount_can_count) +{ + ck_assert_int_eq(getqueryinterfacecount("eth0"), 1); + ck_assert_int_eq(getqueryinterfacecount("eth1"), 1); + ck_assert_int_eq(getqueryinterfacecount("eth1+eth2"), 2); + ck_assert_int_eq(getqueryinterfacecount("eth1+eth2+eth3"), 3); + ck_assert_int_eq(getqueryinterfacecount("eth1+eth2+eth3+eth1"), 4); + ck_assert_int_eq(getqueryinterfacecount("eth0+eth0"), 2); + ck_assert_int_eq(getqueryinterfacecount("eth0++eth1"), 0); + ck_assert_int_eq(getqueryinterfacecount(""), 0); + ck_assert_int_eq(getqueryinterfacecount("1"), 1); + ck_assert_int_eq(getqueryinterfacecount("+"), 0); + ck_assert_int_eq(getqueryinterfacecount("++"), 0); + ck_assert_int_eq(getqueryinterfacecount("+ +"), 0); + ck_assert_int_eq(getqueryinterfacecount("+ethsomething"), 0); + ck_assert_int_eq(getqueryinterfacecount("ethnothing+"), 0); + ck_assert_int_eq(getqueryinterfacecount("eth+nothing"), 2); + ck_assert_int_eq(getqueryinterfacecount("ethlongcanbelong+ethnotsoshort+ethdoesnotcare"), 3); +} +END_TEST + void add_dbsql_tests(Suite *s) { TCase *tc_dbsql = tcase_create("DB SQL"); @@ -2259,5 +2280,6 @@ void add_dbsql_tests(Suite *s) tcase_add_test(tc_dbsql, db_getinterfaceidin_can_handle_error_situations); tcase_add_test(tc_dbsql, db_getinterfaceinfo_can_handle_interface_merges); tcase_add_test(tc_dbsql, db_getinterfaceinfo_can_handle_invalid_input); + tcase_add_test(tc_dbsql, getqueryinterfacecount_can_count); suite_add_tcase(s, tc_dbsql); } -- 2.40.0