From 1c5c15a8f8c5e7bc715344c1e8018aca053e3c40 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 3 Oct 2021 18:00:59 +0200 Subject: [PATCH] add config override path --- src/ebusd/main.cpp | 52 ++++++++++++++++++++++++++++++++++++---------- src/ebusd/main.h | 1 + 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/src/ebusd/main.cpp b/src/ebusd/main.cpp index de92a487..176601ef 100644 --- a/src/ebusd/main.cpp +++ b/src/ebusd/main.cpp @@ -82,6 +82,7 @@ static struct options opt = { 0, // extraLatency CONFIG_PATH, // configPath + "", // overridePath false, // scanConfig 0, // initialScan getenv("LANG"), // preferLanguage @@ -135,6 +136,9 @@ static MainLoop* s_mainLoop = nullptr; /** the path prefix (including trailing "/") for retrieving configuration files from local files (empty for HTTP). */ static string s_configLocalPrefix; +/** the path prefix (including trailing "/") for overriding configuration files from local files (empty if unset). */ +static string s_configOverridePrefix; + /** the URI prefix (including trailing "/") for retrieving configuration files from HTTP (empty for local files). */ static string s_configUriPrefix; @@ -191,6 +195,7 @@ static const struct argp_option argpoptions[] = { {nullptr, 0, nullptr, 0, "Message configuration options:", 2 }, {"configpath", 'c', "PATH", 0, "Read CSV config files from PATH (local folder or HTTP URL) [" CONFIG_PATH "]", 0 }, + {"overridepath", 'o', "PATH", 0, "Read override CSV config files from PATH (local folder only) []", 0 }, {"scanconfig", 's', "ADDR", OPTION_ARG_OPTIONAL, "Pick CSV config files matching initial scan (ADDR=" "\"none\" or empty for no initial scan message, \"full\" for full scan, or a single hex address to scan, " "default is broadcast ident message). If combined with --checkconfig, you can add scan message data as " @@ -315,6 +320,13 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) { } opt->configPath = arg; break; + case 'o': // --overridepath=/etc/ebusd/ + if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) { + argp_error(state, "invalid overridepath"); + return EINVAL; + } + opt->overridePath = arg; + break; case 's': // --scanconfig[=ADDR] (ADDR=|full|) opt->scanConfig = true; if (opt->pollInterval == 0) { @@ -764,10 +776,11 @@ void signalHandler(int sig) { * @return the result code. */ static result_t collectConfigFiles(const string& relPath, const string& prefix, const string& extension, - vector* files, const bool ignoreAddressPrefix = false, const string& query = "", - vector* dirs = nullptr, bool* hasTemplates = nullptr) { + bool fromOverride, vector* files, + bool ignoreAddressPrefix = false, const string& query = "", + vector* dirs = nullptr, bool* hasTemplates = nullptr) { const string relPathWithSlash = relPath.empty() ? "" : relPath + "/"; - if (!s_configUriPrefix.empty()) { + if (!fromOverride && !s_configUriPrefix.empty()) { string uri = s_configUriPrefix + relPathWithSlash + "?t=" + extension.substr(1) + query; string names; if (!s_configHttpClient.get(uri, "", &names)) { @@ -792,7 +805,7 @@ static result_t collectConfigFiles(const string& relPath, const string& prefix, } return RESULT_OK; } - const string path = s_configLocalPrefix + relPathWithSlash; + const string path = (fromOverride ? s_configOverridePrefix : s_configLocalPrefix) + relPathWithSlash; DIR* dir = opendir(path.c_str()); if (dir == nullptr) { return RESULT_ERR_NOTFOUND; @@ -901,16 +914,17 @@ static bool readTemplates(const string relPath, const string extension, bool ava * @param relPath the relative path from which to read the files (without trailing "/"). * @param extension the filename extension of the files to read. * @param messages the @a MessageMap to load the messages into. + * @param fromOverride whether to load from the override path. * @param recursive whether to load all files recursively. * @param verbose whether to verbosely log problems. * @param errorDescription a string in which to store the error description in case of error. * @return the result code. */ -static result_t readConfigFiles(const string& relPath, const string& extension, const bool recursive, - const bool verbose, string* errorDescription, MessageMap* messages) { +static result_t readConfigFiles(const string& relPath, const string& extension, bool fromOverride, bool recursive, + bool verbose, string* errorDescription, MessageMap* messages) { vector files, dirs; bool hasTemplates = false; - result_t result = collectConfigFiles(relPath, "", extension, &files, false, "", &dirs, &hasTemplates); + result_t result = collectConfigFiles(relPath, "", extension, fromOverride, &files, false, "", &dirs, &hasTemplates); if (result != RESULT_OK) { return result; } @@ -926,7 +940,7 @@ static result_t readConfigFiles(const string& relPath, const string& extension, if (recursive) { for (const auto& name : dirs) { logInfo(lf_main, "reading dir %s", name.c_str()); - result = readConfigFiles(name, extension, true, verbose, errorDescription, messages); + result = readConfigFiles(name, extension, fromOverride, true, verbose, errorDescription, messages); if (result != RESULT_OK) { return result; } @@ -1008,7 +1022,7 @@ result_t loadConfigFiles(MessageMap* messages, bool verbose, bool denyRecursive) s_templatesByPath.clear(); string errorDescription; - result_t result = readConfigFiles("", ".csv", + result_t result = readConfigFiles("", ".csv", false, (!opt.scanConfig || opt.checkConfig) && !denyRecursive, verbose, &errorDescription, messages); if (result == RESULT_OK) { logInfo(lf_main, "read config files"); @@ -1016,6 +1030,17 @@ result_t loadConfigFiles(MessageMap* messages, bool verbose, bool denyRecursive) logError(lf_main, "error reading config files from %s: %s, last error: %s", opt.configPath, getResultCode(result), errorDescription.c_str()); } + if (s_configOverridePrefix.length() > 0) { + logInfo(lf_main, "loading override config files from %s", opt.overridePath); + result = readConfigFiles("", ".csv", true, + (!opt.scanConfig || opt.checkConfig) && !denyRecursive, verbose, &errorDescription, messages); + if (result == RESULT_OK) { + logInfo(lf_main, "read override config files"); + } else { + logError(lf_main, "error reading config files from %s: %s, last error: %s", opt.overridePath, + getResultCode(result), errorDescription.c_str()); + } + } messages->unlock(); return opt.checkConfig ? result : RESULT_OK; } @@ -1098,7 +1123,7 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, bool verbose out.str(""); out.clear(); } - result = collectConfigFiles(manufStr, addrStr + ".", ".csv", &files, false, query, nullptr, &hasTemplates); + result = collectConfigFiles(manufStr, addrStr + ".", ".csv", false, &files, false, query, nullptr, &hasTemplates); if (result != RESULT_OK) { logError(lf_main, "unable to load scan config %2.2x: list files in %s %s", address, manufStr.c_str(), getResultCode(result)); @@ -1161,7 +1186,7 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, bool verbose // found the right file. load the templates if necessary, then load the file itself bool readCommon = readTemplates(manufStr, ".csv", hasTemplates, opt.checkConfig); if (readCommon) { - result = collectConfigFiles(manufStr, "", ".csv", &files, true, "&a=-"); + result = collectConfigFiles(manufStr, "", ".csv", false, &files, true, "&a=-"); if (result == RESULT_OK && !files.empty()) { for (const auto& name : files) { string baseName = name.substr(manufStr.length()+1, name.length()-manufStr.length()-strlen(".csv")); // *. @@ -1267,6 +1292,11 @@ int main(int argc, char* argv[]) { } s_configHttpClient.disconnect(); } + configPath = string(opt.overridePath); + if (configPath.length() > 0) { + configPath[configPath.length()-1] == '/' ? configPath : configPath + "/"; + } + s_configOverridePrefix = configPath; if (!opt.readOnly && opt.scanConfig && opt.initialScan == 0) { opt.initialScan = BROADCAST; } diff --git a/src/ebusd/main.h b/src/ebusd/main.h index 7e1146cd..9edea3c7 100644 --- a/src/ebusd/main.h +++ b/src/ebusd/main.h @@ -42,6 +42,7 @@ struct options { unsigned int extraLatency; //!< extra transfer latency in ms [0 for USB, 10 for IP] const char* configPath; //!< path to CSV configuration files [http://ebusd.eu/config/] + const char* overridePath; //!< path to CSV configuration files to override the main files with bool scanConfig; //!< pick configuration files matching initial scan /** the initial address to scan for scanconfig * (@a ESC=none, 0xfe=broadcast ident, @a SYN=full scan, else: single slave address). */