From: Teemu Toivola Date: Wed, 14 Aug 2019 19:02:58 +0000 (+0300) Subject: implement --rename for renaming interfaces already existing the database X-Git-Tag: v2.4~1 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=68572e81ba5b9797703440491b28fdaab5ff0e7d;p=vnstat implement --rename for renaming interfaces already existing the database --- diff --git a/CHANGES b/CHANGES index 1ef2391..d0996f8 100644 --- a/CHANGES +++ b/CHANGES @@ -8,6 +8,8 @@ - Daemon didn't fork() even when requested to with --daemon when started by PID 1 (issue seen at least in Docker containers) - Move vnstatd man page from section 1 to section 8 + - New + - Add --rename for renaming interfaces already existing the database 2.3 / 10-Jul-2019 diff --git a/man/vnstat.1 b/man/vnstat.1 index 151b291..647b92c 100644 --- a/man/vnstat.1 +++ b/man/vnstat.1 @@ -46,6 +46,8 @@ vnstat \- a console-based network traffic monitor .RB [ \-\-rateunit .RI [ mode ]] .RB [ \-\-remove ] +.RB [ \-\-rename +.IR name ] .RB [ \-ru .RI [ mode ]] .RB [ \-\-setalias @@ -97,7 +99,8 @@ Create database entry for interface specified with .B \-i or .B \-\-iface -option. +option. The daemon can be running during this operation but will not +automatically detect the addition without a restart. .TP .BI "-b, --begin " date @@ -283,7 +286,19 @@ Delete the database entry for the interface specified with .B \-i or .B \-\-iface -and stop monitoring it. +and stop monitoring it. The daemon can be running during this operation +and will automatically detect the change. + +.TP +.BI "--rename " name +Rename the interface specified with +.B \-i +or +.B \-\-iface +in the database with new name +.BR name . +The new name cannot already exist in the database. This operation doesn't +cause any data loss. The daemon should not be running during this operation. .TP .BI "-ru, --rateunit " [mode] @@ -299,7 +314,8 @@ select between bytes (0) and bits (1) regardless of the configuration file setti .BI "--setalias " alias Set the selected interface .I alias -as an alias that will be displayed in queries. +as an alias that will be displayed in queries. The daemon can be running during +this operation. .TP .B "-s, --short" diff --git a/src/dbsql.c b/src/dbsql.c index f0681d0..9fb8135 100644 --- a/src/dbsql.c +++ b/src/dbsql.c @@ -392,6 +392,24 @@ int db_removeinterface(const char *iface) return db_exec(sql); } +int db_renameinterface(const char *iface, const char *newifname) +{ + char sql[128]; + sqlite3_int64 ifaceid = 0; + + if (!strlen(newifname)) { + return 0; + } + + ifaceid = db_getinterfaceid(iface, 0); + if (ifaceid == 0) { + return 0; + } + + sqlite3_snprintf(128, sql, "update interface set name='%q' where id=%" PRId64 "", newifname, (int64_t)ifaceid); + return db_exec(sql); +} + uint64_t db_getinterfacecount(void) { return db_getinterfacecountbyname(""); diff --git a/src/dbsql.h b/src/dbsql.h index 8b2da67..e534650 100644 --- a/src/dbsql.h +++ b/src/dbsql.h @@ -38,6 +38,7 @@ int db_exec(const char *sql); int db_create(void); int db_addinterface(const char *iface); int db_removeinterface(const char *iface); +int db_renameinterface(const char *iface, const char *newifname); uint64_t db_getinterfacecount(void); uint64_t db_getinterfacecountbyname(const char *iface); sqlite3_int64 db_getinterfaceid(const char *iface, const int createifnotfound); diff --git a/src/vnstat.c b/src/vnstat.c index f3181c8..ed7f693 100644 --- a/src/vnstat.c +++ b/src/vnstat.c @@ -361,6 +361,19 @@ int main(int argc, char *argv[]) } else if (strcmp(argv[currentarg], "--remove") == 0) { p.removeiface = 1; p.query = 0; + } else if (strcmp(argv[currentarg], "--rename") == 0) { + if (currentarg + 1 < argc) { + strncpy_nt(p.newifname, argv[currentarg + 1], 32); + if (debug) + printf("Given new interface name: \"%s\"\n", p.newifname); + p.renameiface = 1; + p.query = 0; + currentarg++; + continue; + } else { + printf("Error: New interface name for %s missing.\n", argv[currentarg]); + return 1; + } } else if ((strcmp(argv[currentarg], "-b") == 0) || (strcmp(argv[currentarg], "--begin") == 0)) { if (currentarg + 1 < argc) { if (!validatedatetime(argv[currentarg + 1])) { @@ -442,6 +455,7 @@ int main(int argc, char *argv[]) /* parameter handlers */ handleremoveinterface(&p); + handlerenameinterface(&p); handleaddinterface(&p); handlesetalias(&p); handleshowdatabases(&p); @@ -491,8 +505,14 @@ void initparams(PARAMS *p) p->livetraffic = 0; p->defaultiface = 1; p->removeiface = 0; + p->renameiface = 0; p->livemode = 0; p->ifacelist = NULL; + p->interface[0] = '\0'; + p->alias[0] = '\0'; + p->newifname[0] = '\0'; + p->filename[0] = '\0'; + p->definterface[0] = '\0'; p->cfgfile[0] = '\0'; p->jsonmode = 'a'; p->xmlmode = 'a'; @@ -555,6 +575,7 @@ void showlonghelp(PARAMS *p) printf(" --add add interface to database\n"); printf(" --remove remove interface from database\n"); + printf(" --rename rename interface in database\n"); printf(" --setalias set alias for interface\n\n"); printf("Misc:\n"); @@ -587,6 +608,11 @@ void handleremoveinterface(PARAMS *p) return; } + if (p->defaultiface) { + printf("Error: Use -i parameter to specify an interface.\n"); + exit(EXIT_FAILURE); + } + if (!db_getinterfacecountbyname(p->interface)) { printf("Error: Interface \"%s\" not found in database.\n", p->interface); exit(EXIT_FAILURE); @@ -614,6 +640,52 @@ void handleremoveinterface(PARAMS *p) } } +void handlerenameinterface(PARAMS *p) +{ + if (!p->renameiface) { + return; + } + + if (p->defaultiface) { + printf("Error: Use -i parameter to specify an interface.\n"); + exit(EXIT_FAILURE); + } + + if (!strlen(p->newifname)) { + printf("Error: New interface name must be at least one character long.\n"); + exit(EXIT_FAILURE); + } + + if (!db_getinterfacecountbyname(p->interface)) { + printf("Error: Interface \"%s\" not found in database.\n", p->interface); + exit(EXIT_FAILURE); + } + + if (db_getinterfacecountbyname(p->newifname)) { + printf("Error: Interface \"%s\" already exists in database.\n", p->interface); + exit(EXIT_FAILURE); + } + + if (!p->force) { + printf("Warning:\nThe current option would rename\ninterface \"%s\" -> \"%s\" in the database.\n", p->interface, p->newifname); + printf("Use --force in order to really do that.\n"); + exit(EXIT_FAILURE); + } + + if (!db_close() || !db_open_rw(0)) { + printf("Error: Handling database \"%s/%s\" failing: %s\n", cfg.dbdir, DATABASEFILE, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (db_renameinterface(p->interface, p->newifname)) { + printf("Interface \"%s\" has been renamed \"%s\".\n", p->interface, p->newifname); + exit(EXIT_SUCCESS); + } else { + printf("Error: Renaming interface \"%s\" -> \"%s\" failed.\n", p->interface, p->newifname); + exit(EXIT_FAILURE); + } +} + void handleaddinterface(PARAMS *p) { if (!p->addiface) { @@ -657,7 +729,7 @@ void handleaddinterface(PARAMS *p) printf("\nRestart the vnStat daemon if it is currently running in order to start monitoring \"%s\".\n", p->interface); exit(EXIT_SUCCESS); } else { - printf("Error: Adding interface \"%s\" to database failed: %s\n", p->interface, strerror(errno)); + printf("Error: Adding interface \"%s\" to database failed.\n", p->interface); exit(EXIT_FAILURE); } } @@ -687,7 +759,7 @@ void handlesetalias(PARAMS *p) printf("Alias of interface \"%s\" set to \"%s\".\n", p->interface, p->alias); exit(EXIT_SUCCESS); } else { - printf("Error: Changing interface \"%s\" alias failed: %s\n", p->interface, strerror(errno)); + printf("Error: Setting interface \"%s\" alias failed.\n", p->interface); exit(EXIT_FAILURE); } } @@ -832,7 +904,7 @@ void handleifselection(PARAMS *p) iflist *ifl = NULL; iflist *dbifl = NULL, *dbifl_iterator = NULL; - if (!p->defaultiface) { + if (!p->defaultiface || !p->query) { return; } diff --git a/src/vnstat.h b/src/vnstat.h index 3e345a8..92645d7 100644 --- a/src/vnstat.h +++ b/src/vnstat.h @@ -4,9 +4,9 @@ typedef struct { int query, setalias; int addiface, force, traffic; - int livetraffic, defaultiface, removeiface, livemode; + int livetraffic, defaultiface, removeiface, renameiface, livemode; uint64_t dbifcount; - char interface[32], alias[32], filename[512]; + char interface[32], alias[32], newifname[32], filename[512]; char definterface[32], cfgfile[512], *ifacelist, jsonmode, xmlmode; char databegin[18], dataend[18]; } PARAMS; @@ -15,6 +15,7 @@ void initparams(PARAMS *p); void showhelp(PARAMS *p); void showlonghelp(PARAMS *p); void handleremoveinterface(PARAMS *p); +void handlerenameinterface(PARAMS *p); void handleaddinterface(PARAMS *p); void handlesetalias(PARAMS *p); void handleshowdatabases(PARAMS *p); diff --git a/tests/dbsql_tests.c b/tests/dbsql_tests.c index 94f68b8..165805b 100644 --- a/tests/dbsql_tests.c +++ b/tests/dbsql_tests.c @@ -488,6 +488,71 @@ START_TEST(db_removeinterface_can_remove_interfaces) } END_TEST +START_TEST(db_renameinterface_knows_if_interface_exists) +{ + int ret; + + defaultcfg(); + + ret = db_open_rw(1); + ck_assert_int_eq(ret, 1); + + ret = db_renameinterface("eth0", "eth1"); + ck_assert_int_eq(ret, 0); + ret = db_renameinterface("nothing", "something"); + ck_assert_int_eq(ret, 0); + ret = db_renameinterface("", ""); + ck_assert_int_eq(ret, 0); + + ret = db_close(); + ck_assert_int_eq(ret, 1); +} +END_TEST + +START_TEST(db_renameinterface_can_rename_interfaces) +{ + int ret; + + defaultcfg(); + + ret = db_open_rw(1); + ck_assert_int_eq(ret, 1); + + ret = db_addinterface("eth0"); + ck_assert_int_eq(ret, 1); + ret = db_addinterface("eth1"); + ck_assert_int_eq(ret, 1); + ret = db_addinterface("eth2"); + ck_assert_int_eq(ret, 1); + + ck_assert_int_eq(db_getinterfacecount(), 3); + ck_assert_int_eq(db_getinterfacecountbyname("eth0"), 1); + ck_assert_int_eq(db_getinterfacecountbyname("eth1"), 1); + ck_assert_int_eq(db_getinterfacecountbyname("eth2"), 1); + ck_assert_int_eq(db_getinterfacecountbyname("eth3"), 0); + + ret = db_renameinterface("eth0", "eth1"); + ck_assert_int_eq(ret, 0); + ret = db_renameinterface("eth2", "eth3"); + ck_assert_int_eq(ret, 1); + ret = db_renameinterface("eth1", "eth2"); + ck_assert_int_eq(ret, 1); + ret = db_renameinterface("eth0", ""); + ck_assert_int_eq(ret, 0); + ret = db_renameinterface("eth0", "eth1"); + ck_assert_int_eq(ret, 1); + + ck_assert_int_eq(db_getinterfacecount(), 3); + ck_assert_int_eq(db_getinterfacecountbyname("eth0"), 0); + ck_assert_int_eq(db_getinterfacecountbyname("eth1"), 1); + ck_assert_int_eq(db_getinterfacecountbyname("eth2"), 1); + ck_assert_int_eq(db_getinterfacecountbyname("eth3"), 1); + + ret = db_close(); + ck_assert_int_eq(ret, 1); +} +END_TEST + START_TEST(db_getinterfacecount_counts_interfaces) { int ret; @@ -2216,6 +2281,8 @@ void add_dbsql_tests(Suite *s) tcase_add_test(tc_dbsql, db_addinterface_can_not_add_same_interface_twice); tcase_add_test(tc_dbsql, db_removeinterface_knows_if_interface_exists); tcase_add_test(tc_dbsql, db_removeinterface_can_remove_interfaces); + tcase_add_test(tc_dbsql, db_renameinterface_knows_if_interface_exists); + tcase_add_test(tc_dbsql, db_renameinterface_can_rename_interfaces); tcase_add_test(tc_dbsql, db_getcounters_with_no_interface); tcase_add_test(tc_dbsql, db_setcounters_with_no_interface); tcase_add_test(tc_dbsql, db_interface_info_manipulation);