diff --git a/CHANGES b/CHANGES index 6d93705..08a4a55 100644 --- a/CHANGES +++ b/CHANGES @@ -5,6 +5,7 @@ example cgi (examples/vnstat.cgi) - New - Add database data merge support as --merge (work in progress) + - Add --db for specifying database file for queries (vnstat and vnstati) - Add exit status 2 options to --alert for making it possible to differentiate alerts from errors (exit status 1) - Add --dbiflist also to vnstati command diff --git a/man/vnstat.1 b/man/vnstat.1 index 421d450..9f1aad4 100644 --- a/man/vnstat.1 +++ b/man/vnstat.1 @@ -1,5 +1,5 @@ '\" t -.TH VNSTAT 1 "AUGUST 2024" "version 2.13" "User Manuals" +.TH VNSTAT 1 "JANUARY 2025" "version 2.13" "User Manuals" .SH NAME vnstat \- a console-based network traffic monitor @@ -17,6 +17,8 @@ vnstat \- a console-based network traffic monitor .IR file ] .RB [ \-\-days .RI [ limit ]] +.RB [ \-\-db +.IR file ] .RB [ \-\-dbdir .IR directory ] .RB [ \-\-dbiflist @@ -236,12 +238,24 @@ parameter is used. All entries stored in the database will be shown if .I limit is set to 0. +.TP +.BI "--db " file +Use +.I file +as database file instead of searching for a database from the directory specified in +the configuration file or the hardcoded default if no configuration file is available. +This option overrides +.BR "--dbdir" . + .TP .BI "--dbdir " directory Use .I directory as database directory instead of using the directory specified in the configuration -file or the hardcoded default if no configuration file is available. +file or the hardcoded default if no configuration file is available. This option is +ignored if +.B "--db" +is also defined. .TP .BI "--dbiflist " [mode] diff --git a/man/vnstati.1 b/man/vnstati.1 index 17d8ffa..35ef39a 100644 --- a/man/vnstati.1 +++ b/man/vnstati.1 @@ -1,4 +1,4 @@ -.TH VNSTATI 1 "APRIL 2024" "version 2.13" "User Manuals" +.TH VNSTATI 1 "JANUARY 2025" "version 2.13" "User Manuals" .SH NAME vnstati \- image output support for vnStat @@ -20,6 +20,8 @@ vnstati \- image output support for vnStat .IR file ] .RB [ \-\-days .RI [ limit ]] +.RB [ \-\-db +.IR file ] .RB [ \-\-dbdir .IR directory ] .RB [ \-\-dbiflist @@ -166,12 +168,24 @@ parameter is used. All entries stored in the database will be shown if .I limit is set to 0. +.TP +.BI "--db " file +Use +.I file +as database file instead of searching for a database from the directory specified in +the configuration file or the hardcoded default if no configuration file is available. +This option overrides +.BR "--dbdir" . + .TP .BI "--dbdir " directory Use .I directory as database directory instead of using the directory specified in the configuration -file or the hardcoded default if no configuration file is available. +file or the hardcoded default if no configuration file is available. This option is +ignored if +.B "--db" +is also defined. .TP .BI "--dbiflist " [mode] diff --git a/src/cfg.c b/src/cfg.c index 52ab90b..038a0fa 100644 --- a/src/cfg.c +++ b/src/cfg.c @@ -378,6 +378,7 @@ void defaultcfg(void) cfg.yearlyyears = YEARLYYEARS; cfg.topdayentries = TOPDAYENTRIES; + cfg.dbfile[0] = '\0'; strncpy_nt(cfg.dbdir, DATABASEDIR, 512); strncpy_nt(cfg.dbtzmodifier, DATABASELOCALTIMEMODIFIER, 14); strncpy_nt(cfg.iface, DEFIFACE, MAXIFPARAMLEN); diff --git a/src/clicommon.c b/src/clicommon.c index c1dd1f7..81312e8 100644 --- a/src/clicommon.c +++ b/src/clicommon.c @@ -9,7 +9,7 @@ void showdbiflist(const int mode) iflist *dbifl = NULL, *dbifl_i = NULL; if (db == NULL && !db_open_ro()) { - printf("Error: Failed to open database \"%s/%s\" in read-only mode.\n", cfg.dbdir, DATABASEFILE); + printf("Error: Failed to open database \"%s\" in read-only mode: %s\n", cfg.dbfile, strerror(errno)); exit(EXIT_FAILURE); } @@ -22,7 +22,7 @@ void showdbiflist(const int mode) dbifcount = db_getiflist(&dbifl); if (dbifcount < 0) { - printf("Error: Failed to get interface list from database \"%s/%s\".\n", cfg.dbdir, DATABASEFILE); + printf("Error: Failed to get interface list from database \"%s\".\n", cfg.dbfile); exit(EXIT_FAILURE); } diff --git a/src/common.h b/src/common.h index c528a5d..6d8f3be 100644 --- a/src/common.h +++ b/src/common.h @@ -340,7 +340,7 @@ typedef struct { char dformat[64], mformat[64], tformat[64], hformat[64]; char iface[MAXIFPARAMLEN]; char locale[32]; - char dbdir[512], dbtzmodifier[14]; + char dbfile[530], dbdir[512], dbtzmodifier[14]; char rxchar[2], txchar[2], rxhourchar[2], txhourchar[2], estimatetext[10]; char cbg[8], cedge[8], cheader[8], cheadertitle[8], cheaderdate[8], ctext[8]; char cline[8], clinel[8], cpercentileline[8], cvnstat[8], crx[8], crxd[8], ctx[8], ctxd[8], ctotal[8]; diff --git a/src/dbsql.c b/src/dbsql.c index ef25cb8..fa2871b 100644 --- a/src/dbsql.c +++ b/src/dbsql.c @@ -22,12 +22,17 @@ int db_open(const int createifnotfound, const int readonly) { char dbfilename[530]; + if (strlen(cfg.dbfile) > 0) { + strncpy_nt(dbfilename, cfg.dbfile, 530); + } else { #ifdef CHECK_VNSTAT - /* use ram based database when testing for shorter test execution times by reducing disk i/o */ - snprintf(dbfilename, 530, ":memory:"); + /* use ram based database when testing for shorter test execution times by reducing disk i/o */ + snprintf(dbfilename, 530, ":memory:"); #else - snprintf(dbfilename, 530, "%s/%s", cfg.dbdir, DATABASEFILE); + snprintf(dbfilename, 530, "%s/%s", cfg.dbdir, DATABASEFILE); + strncpy_nt(cfg.dbfile, dbfilename, 530); #endif + } return db_open_filename(dbfilename, createifnotfound, readonly); } diff --git a/src/vnstat.c b/src/vnstat.c index 4ff324c..2c9ea49 100644 --- a/src/vnstat.c +++ b/src/vnstat.c @@ -25,7 +25,7 @@ vnStat - Copyright (C) 2002-2025 Teemu Toivola int main(int argc, char *argv[]) { - int currentarg; + int currentarg, dbfiledefined = 0; DIR *dir = NULL; PARAMS p; @@ -82,13 +82,18 @@ int main(int argc, char *argv[]) /* open database and see if it contains any interfaces */ if (!p.traffic && !p.livetraffic) { - if ((dir = opendir(cfg.dbdir)) != NULL) { - if (debug) - printf("Dir OK\n"); - closedir(dir); + if (strlen(cfg.dbfile) > 0) { + dbfiledefined = 1; + } + if (dbfiledefined || (dir = opendir(cfg.dbdir)) != NULL) { + if (dir != NULL) { + if (debug) + printf("Dir OK\n"); + closedir(dir); + } if (!db_open_ro()) { - printf("Error: Failed to open database \"%s/%s\" in read-only mode.\n", cfg.dbdir, DATABASEFILE); - if (errno == ENOENT) { + printf("Error: Failed to open database \"%s\" in read-only mode: %s\n", cfg.dbfile, strerror(errno)); + if (!dbfiledefined && errno == ENOENT) { printf("The vnStat daemon should have created the database when started.\n"); printf("Check that it is configured and running. See also \"man vnstatd\".\n"); } diff --git a/src/vnstat_func.c b/src/vnstat_func.c index ef9d99d..0b0ba4b 100644 --- a/src/vnstat_func.c +++ b/src/vnstat_func.c @@ -38,7 +38,6 @@ void initparams(PARAMS *p) 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'; @@ -143,8 +142,9 @@ void showlonghelp(const PARAMS *p) printf(" --limit set output entry limit\n"); printf(" --style select output style (0-4)\n"); printf(" --iflist [mode] show list of available interfaces\n"); + printf(" --db select database file\n"); printf(" --dbiflist [mode] show list of interfaces in database\n"); - printf(" --dbdir select database directory\n"); // TODO: --db / --dbfile + printf(" --dbdir select database directory\n"); printf(" --locale set locale\n"); printf(" --config select config file\n"); printf(" --showconfig dump config file with current settings\n"); @@ -210,7 +210,7 @@ void parseargs(PARAMS *p, const int argc, char **argv) printf("Error: Alias for %s missing.\n", argv[currentarg]); exit(EXIT_FAILURE); } - } else if ((strcmp(argv[currentarg], "--style")) == 0) { + } else if (strcmp(argv[currentarg], "--style") == 0) { if (currentarg + 1 < argc && isdigit(argv[currentarg + 1][0])) { cfg.ostyle = atoi(argv[currentarg + 1]); if (cfg.ostyle > 4 || cfg.ostyle < 0) { @@ -226,7 +226,17 @@ void parseargs(PARAMS *p, const int argc, char **argv) showstylehelp(); exit(EXIT_FAILURE); } - } else if ((strcmp(argv[currentarg], "--dbdir")) == 0) { + } else if ((strcmp(argv[currentarg], "--db") == 0) || (strcmp(argv[currentarg], "--dbfile") == 0)) { + if (currentarg + 1 < argc) { + strncpy_nt(cfg.dbfile, argv[currentarg + 1], 530); + if (debug) + printf("DatabaseFile: \"%s\"\n", cfg.dbfile); + currentarg++; + } else { + printf("Error: File for %s missing.\n", argv[currentarg]); + exit(EXIT_FAILURE); + } + } else if (strcmp(argv[currentarg], "--dbdir") == 0) { if (currentarg + 1 < argc) { strncpy_nt(cfg.dbdir, argv[currentarg + 1], 512); if (debug) @@ -236,7 +246,7 @@ void parseargs(PARAMS *p, const int argc, char **argv) printf("Error: Directory for %s missing.\n", argv[currentarg]); exit(EXIT_FAILURE); } - } else if ((strcmp(argv[currentarg], "--locale")) == 0) { + } else if (strcmp(argv[currentarg], "--locale") == 0) { if (currentarg + 1 < argc) { setlocale(LC_ALL, argv[currentarg + 1]); if (debug) @@ -1042,7 +1052,7 @@ void handleremoveinterface(const PARAMS *p) #ifndef CHECK_VNSTAT if (!db_close() || !db_open_rw(0)) { - printf("Error: Handling database \"%s/%s\" failing: %s\n", cfg.dbdir, DATABASEFILE, strerror(errno)); + printf("Error: Handling database \"%s\" failing: %s\n", cfg.dbfile, strerror(errno)); exit(EXIT_FAILURE); } #endif @@ -1094,7 +1104,7 @@ void handlerenameinterface(const PARAMS *p) #ifndef CHECK_VNSTAT if (!db_close() || !db_open_rw(0)) { - printf("Error: Handling database \"%s/%s\" failing: %s\n", cfg.dbdir, DATABASEFILE, strerror(errno)); + printf("Error: Handling database \"%s\" failing: %s\n", cfg.dbfile, strerror(errno)); exit(EXIT_FAILURE); } #endif @@ -1146,7 +1156,7 @@ void handleaddinterface(PARAMS *p) #ifndef CHECK_VNSTAT if (!db_close() || !db_open_rw(0)) { - printf("Error: Handling database \"%s/%s\" failing: %s\n", cfg.dbdir, DATABASEFILE, strerror(errno)); + printf("Error: Handling database \"%s\" failing: %s\n", cfg.dbfile, strerror(errno)); exit(EXIT_FAILURE); } #endif @@ -1187,7 +1197,7 @@ void handlesetalias(const PARAMS *p) #ifndef CHECK_VNSTAT if (!db_close() || !db_open_rw(0)) { - printf("Error: Handling database \"%s/%s\" failing: %s\n", cfg.dbdir, DATABASEFILE, strerror(errno)); + printf("Error: Handling database \"%s\" failing: %s\n", cfg.dbfile, strerror(errno)); exit(EXIT_FAILURE); } #endif diff --git a/src/vnstat_func.h b/src/vnstat_func.h index 54a0734..5694103 100644 --- a/src/vnstat_func.h +++ b/src/vnstat_func.h @@ -7,7 +7,7 @@ typedef struct { int livetraffic, defaultiface, removeiface, renameiface, livemode; int32_t limit; uint64_t dbifcount; - char interface[MAXIFPARAMLEN], alias[32], newifname[MAXIFLEN], filename[512]; + char interface[MAXIFPARAMLEN], alias[32], newifname[MAXIFLEN]; char definterface[MAXIFPARAMLEN], cfgfile[512], *ifacelist, jsonmode, xmlmode; char databegin[18], dataend[18]; unsigned int alert, alertoutput, alertexit, alerttype, alertcondition; diff --git a/src/vnstati.c b/src/vnstati.c index 7286f36..af4cec2 100644 --- a/src/vnstati.c +++ b/src/vnstati.c @@ -159,6 +159,8 @@ void showihelp(const IPARAMS *p) printf(" -D, --debug show some additional debug information\n"); printf(" -v, --version show version\n"); printf(" --limit set list entry limit\n"); + printf(" --db select database file\n"); + printf(" --dbiflist [mode] show list of interfaces in database\n"); printf(" --dbdir select database directory\n"); printf(" --style select output style (0-3)\n"); printf(" --locale set locale\n"); @@ -272,7 +274,17 @@ void parseargs(IPARAMS *p, IMAGECONTENT *ic, int argc, char **argv) if (debug) printf("Transparency changed: %d\n", cfg.transbg); } - } else if ((strcmp(argv[currentarg], "--dbdir")) == 0) { + } else if ((strcmp(argv[currentarg], "--db") == 0) || (strcmp(argv[currentarg], "--dbfile") == 0)) { + if (currentarg + 1 < argc) { + strncpy_nt(cfg.dbfile, argv[currentarg + 1], 530); + if (debug) + printf("DatabaseFile: \"%s\"\n", cfg.dbfile); + currentarg++; + } else { + fprintf(stderr, "Error: File for %s missing.\n", argv[currentarg]); + exit(EXIT_FAILURE); + } + } else if (strcmp(argv[currentarg], "--dbdir") == 0) { if (currentarg + 1 < argc) { strncpy_nt(cfg.dbdir, argv[currentarg + 1], 512); if (debug) @@ -282,7 +294,7 @@ void parseargs(IPARAMS *p, IMAGECONTENT *ic, int argc, char **argv) fprintf(stderr, "Error: Directory for --dbdir missing.\n"); exit(EXIT_FAILURE); } - } else if ((strcmp(argv[currentarg], "--locale")) == 0) { + } else if (strcmp(argv[currentarg], "--locale") == 0) { if (currentarg + 1 < argc) { setlocale(LC_ALL, argv[currentarg + 1]); if (debug) @@ -295,7 +307,7 @@ void parseargs(IPARAMS *p, IMAGECONTENT *ic, int argc, char **argv) } else if (strcmp(argv[currentarg], "--config") == 0) { /* config has already been parsed earlier so nothing to do here */ currentarg++; - } else if ((strcmp(argv[currentarg], "--headertext")) == 0) { + } else if (strcmp(argv[currentarg], "--headertext") == 0) { if (currentarg + 1 < argc) { strncpy_nt(ic->headertext, argv[currentarg + 1], 65); if (debug) @@ -650,7 +662,7 @@ void handledatabase(IPARAMS *p, IMAGECONTENT *ic) iflist *dbifl = NULL; if (!db_open_ro()) { - fprintf(stderr, "Error: Failed to open database \"%s/%s\" in read-only mode.\n", cfg.dbdir, DATABASEFILE); + fprintf(stderr, "Error: Failed to open database \"%s\" in read-only mode: %s\n", cfg.dbfile, strerror(errno)); exit(EXIT_FAILURE); } if (strlen(p->interface)) {