corrected cleanup, var names

This commit is contained in:
John
2022-02-13 11:37:02 +01:00
parent d5f4ced49e
commit 4aa586818b
+95 -77
View File
@@ -72,13 +72,10 @@ using std::cout;
#endif #endif
/** the opened PID file, or nullptr. */ /** the opened PID file, or nullptr. */
static FILE* pidFile = nullptr; static FILE* s_pidFile = nullptr;
/** true when forked into daemon mode. */
static bool isDaemon = false;
/** the program options. */ /** the program options. */
static struct options opt = { static struct options s_opt = {
"/dev/ttyUSB0", // device "/dev/ttyUSB0", // device
false, // noDeviceCheck false, // noDeviceCheck
false, // readOnly false, // readOnly
@@ -137,14 +134,14 @@ static MessageMap* s_messageMap = nullptr;
/** the @a MainLoop instance, or nullptr. */ /** the @a MainLoop instance, or nullptr. */
static MainLoop* s_mainLoop = nullptr; static MainLoop* s_mainLoop = nullptr;
/** the path prefix (including trailing "/") for retrieving configuration files from local files (empty for HTTP). */ /** the path prefix (including trailing "/") for retrieving configuration files from local files (empty for HTTPS). */
static string s_configLocalPrefix; static string s_configLocalPrefix;
/** the URI prefix (including trailing "/") for retrieving configuration files from HTTP (empty for local files). */ /** the URI prefix (including trailing "/") for retrieving configuration files from HTTPS (empty for local files). */
static string s_configUriPrefix; static string s_configUriPrefix;
/** the @a HttpClient for retrieving configuration files from HTTP. */ /** the @a HttpClient for retrieving configuration files from HTTPS. */
static HttpClient s_configHttpClient; static HttpClient* s_configHttpClient = nullptr;
/** the documentation of the program. */ /** the documentation of the program. */
static const char argpdoc[] = static const char argpdoc[] =
@@ -636,6 +633,7 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
return 0; return 0;
} }
void shutdown(bool error = false);
void daemonize() { void daemonize() {
// fork off the parent process // fork off the parent process
@@ -672,40 +670,28 @@ void daemonize() {
close(STDERR_FILENO); close(STDERR_FILENO);
// create pid file and try to lock it // create pid file and try to lock it
pidFile = fopen(opt.pidFile, "w+"); s_pidFile = fopen(s_opt.pidFile, "w+");
umask(S_IWGRP | S_IRWXO); // set permissions of newly created files to 750 umask(S_IWGRP | S_IRWXO); // set permissions of newly created files to 750
if (pidFile != nullptr) { if (s_pidFile != nullptr) {
setbuf(pidFile, nullptr); // disable buffering setbuf(s_pidFile, nullptr); // disable buffering
if (lockf(fileno(pidFile), F_TLOCK, 0) < 0 if (lockf(fileno(s_pidFile), F_TLOCK, 0) < 0
|| fprintf(pidFile, "%d\n", getpid()) <= 0) { || fprintf(s_pidFile, "%d\n", getpid()) <= 0) {
fclose(pidFile); fclose(s_pidFile);
pidFile = nullptr; s_pidFile = nullptr;
} }
} }
if (pidFile == nullptr) { if (s_pidFile == nullptr) {
logError(lf_main, "can't open pidfile: %s, exiting", opt.pidFile); logError(lf_main, "can't open pidfile: %s, exiting", s_opt.pidFile);
exit(EXIT_FAILURE); shutdown(true);
}
isDaemon = true;
}
void closePidFile() {
if (pidFile != nullptr) {
if (fclose(pidFile) != 0) {
return;
}
remove(opt.pidFile);
} }
} }
/** /**
* Helper method performing shutdown. * Clean up all dynamically allocated and stop main loop and all dependent components.
*/ */
void shutdown(bool error = false) { void cleanup() {
// stop main loop and all dependent components
if (s_mainLoop) { if (s_mainLoop) {
delete s_mainLoop; delete s_mainLoop;
s_mainLoop = nullptr; s_mainLoop = nullptr;
@@ -721,14 +707,30 @@ void shutdown(bool error = false) {
} }
} }
s_templatesByPath.clear(); s_templatesByPath.clear();
if (s_configHttpClient) {
delete s_configHttpClient;
s_configHttpClient = nullptr;
}
}
/**
* Clean up resources and shutdown.
*/
void shutdown(bool error) {
cleanup();
// reset all signal handlers to default // reset all signal handlers to default
signal(SIGHUP, SIG_DFL); signal(SIGHUP, SIG_DFL);
signal(SIGINT, SIG_DFL); signal(SIGINT, SIG_DFL);
signal(SIGTERM, SIG_DFL); signal(SIGTERM, SIG_DFL);
// delete daemon pid file if necessary // close and delete pid file if necessary
closePidFile(); if (s_pidFile != nullptr) {
if (fclose(s_pidFile) == 0) {
remove(s_opt.pidFile);
}
s_pidFile = nullptr;
}
logNotice(lf_main, "ebusd stopped"); logNotice(lf_main, "ebusd stopped");
closeLogFile(); closeLogFile();
@@ -744,9 +746,9 @@ void signalHandler(int sig) {
switch (sig) { switch (sig) {
case SIGHUP: case SIGHUP:
logNotice(lf_main, "SIGHUP received"); logNotice(lf_main, "SIGHUP received");
if (!opt.foreground && opt.logFile && opt.logFile[0] != 0) { // for log file rotation if (!s_opt.foreground && s_opt.logFile && s_opt.logFile[0] != 0) { // for log file rotation
closeLogFile(); closeLogFile();
setLogFile(opt.logFile); setLogFile(s_opt.logFile);
} }
break; break;
case SIGINT: case SIGINT:
@@ -771,13 +773,24 @@ void signalHandler(int sig) {
} }
} }
/**
* Lazy create the s_configHttpClient if not already done.
* @return true (always).
*/
bool lazyHttpClient() {
if (!s_configHttpClient) {
s_configHttpClient = new HttpClient();
}
return true;
}
/** /**
* Collect configuration files matching the prefix and extension from the specified path. * Collect configuration files matching the prefix and extension from the specified path.
* @param relPath the relative path from which to collect the files (without trailing "/"). * @param relPath the relative path from which to collect the files (without trailing "/").
* @param prefix the filename prefix the files have to match, or empty. * @param prefix the filename prefix the files have to match, or empty.
* @param extension the filename extension the files have to match. * @param extension the filename extension the files have to match.
* @param files the @a vector to which to add the matching files. * @param files the @a vector to which to add the matching files.
* @param query the query string suffix for HTTP retrieval starting with "&", or empty. * @param query the query string suffix for HTTPS retrieval starting with "&", or empty.
* @param dirs the @a vector to which to add found directories (without any name check), or nullptr to ignore. * @param dirs the @a vector to which to add found directories (without any name check), or nullptr to ignore.
* @param hasTemplates the bool to set when the templates file was found in the path, or nullptr to ignore. * @param hasTemplates the bool to set when the templates file was found in the path, or nullptr to ignore.
* @return the result code. * @return the result code.
@@ -790,7 +803,7 @@ static result_t collectConfigFiles(const string& relPath, const string& prefix,
if (!s_configUriPrefix.empty()) { if (!s_configUriPrefix.empty()) {
string uri = s_configUriPrefix + relPathWithSlash + "?t=" + extension.substr(1) + query; string uri = s_configUriPrefix + relPathWithSlash + "?t=" + extension.substr(1) + query;
string names; string names;
if (!s_configHttpClient.get(uri, "", &names)) { if (!lazyHttpClient() || !s_configHttpClient->get(uri, "", &names)) {
return RESULT_ERR_NOTFOUND; return RESULT_ERR_NOTFOUND;
} }
istringstream stream(names); istringstream stream(names);
@@ -937,7 +950,7 @@ static result_t readConfigFiles(const string& relPath, const string& extension,
readTemplates(relPath, extension, hasTemplates, verbose); readTemplates(relPath, extension, hasTemplates, verbose);
for (const auto& name : files) { for (const auto& name : files) {
logInfo(lf_main, "reading file %s", name.c_str()); logInfo(lf_main, "reading file %s", name.c_str());
result_t result = loadDefinitionsFromConfigPath(messages, name, verbose, nullptr, errorDescription); result = loadDefinitionsFromConfigPath(messages, name, verbose, nullptr, errorDescription);
if (result != RESULT_OK) { if (result != RESULT_OK) {
return result; return result;
} }
@@ -1000,7 +1013,7 @@ result_t loadDefinitionsFromConfigPath(FileReader* reader, const string& filenam
stream = FileReader::openFile(s_configLocalPrefix + filename, errorDescription, &mtime); stream = FileReader::openFile(s_configLocalPrefix + filename, errorDescription, &mtime);
} else { } else {
string content; string content;
if (s_configHttpClient.get(s_configUriPrefix + filename, "", &content, &mtime)) { if (lazyHttpClient() && s_configHttpClient->get(s_configUriPrefix + filename, "", &content, &mtime)) {
stream = new istringstream(content); stream = new istringstream(content);
} }
} }
@@ -1015,7 +1028,7 @@ result_t loadDefinitionsFromConfigPath(FileReader* reader, const string& filenam
} }
result_t loadConfigFiles(MessageMap* messages, bool verbose, bool denyRecursive) { result_t loadConfigFiles(MessageMap* messages, bool verbose, bool denyRecursive) {
logInfo(lf_main, "loading configuration files from %s", opt.configPath); logInfo(lf_main, "loading configuration files from %s", s_opt.configPath);
messages->lock(); messages->lock();
messages->clear(); messages->clear();
s_globalTemplates.clear(); s_globalTemplates.clear();
@@ -1029,15 +1042,15 @@ result_t loadConfigFiles(MessageMap* messages, bool verbose, bool denyRecursive)
string errorDescription; string errorDescription;
result_t result = readConfigFiles("", ".csv", result_t result = readConfigFiles("", ".csv",
(!opt.scanConfig || opt.checkConfig) && !denyRecursive, verbose, &errorDescription, messages); (!s_opt.scanConfig || s_opt.checkConfig) && !denyRecursive, verbose, &errorDescription, messages);
if (result == RESULT_OK) { if (result == RESULT_OK) {
logInfo(lf_main, "read config files"); logInfo(lf_main, "read config files");
} else { } else {
logError(lf_main, "error reading config files from %s: %s, last error: %s", opt.configPath, logError(lf_main, "error reading config files from %s: %s, last error: %s", s_opt.configPath,
getResultCode(result), errorDescription.c_str()); getResultCode(result), errorDescription.c_str());
} }
messages->unlock(); messages->unlock();
return opt.checkConfig ? result : RESULT_OK; return s_opt.checkConfig ? result : RESULT_OK;
} }
result_t loadScanConfigFile(MessageMap* messages, symbol_t address, bool verbose, string* relativeFile) { result_t loadScanConfigFile(MessageMap* messages, symbol_t address, bool verbose, string* relativeFile) {
@@ -1180,7 +1193,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 // found the right file. load the templates if necessary, then load the file itself
bool readCommon = readTemplates(manufStr, ".csv", hasTemplates, opt.checkConfig); bool readCommon = readTemplates(manufStr, ".csv", hasTemplates, s_opt.checkConfig);
if (readCommon) { if (readCommon) {
result = collectConfigFiles(manufStr, "", ".csv", &files, true, "&a=-"); result = collectConfigFiles(manufStr, "", ".csv", &files, true, "&a=-");
if (result == RESULT_OK && !files.empty()) { if (result == RESULT_OK && !files.empty()) {
@@ -1294,26 +1307,26 @@ int main(int argc, char* argv[]) {
strcat(envopt, pos); strcat(envopt, pos);
} }
int idx = -1; int idx = -1;
opt.injectMessages = true; // for skipping unknown values s_opt.injectMessages = true; // for skipping unknown values
error_t err = argp_parse(&aargp, cnt, envargv, ARGP_PARSE_ARGV0|ARGP_SILENT|ARGP_IN_ORDER, error_t err = argp_parse(&aargp, cnt, envargv, ARGP_PARSE_ARGV0|ARGP_SILENT|ARGP_IN_ORDER,
&idx, &opt); &idx, &s_opt);
if (err != 0 && idx == -1) { // ignore args for non-arg boolean options if (err != 0 && idx == -1) { // ignore args for non-arg boolean options
logError(lf_main, "invalid/unknown argument in env: %s", envopt); logError(lf_main, "invalid/unknown argument in env: %s", envopt);
} }
opt.injectMessages = false; // restore (was not parsed from cmdline args yet) s_opt.injectMessages = false; // restore (was not parsed from cmdline args yet)
} }
int arg_index = -1; int arg_index = -1;
if (argp_parse(&aargp, argc, argv, ARGP_IN_ORDER, &arg_index, &opt) != 0) { if (argp_parse(&aargp, argc, argv, ARGP_IN_ORDER, &arg_index, &s_opt) != 0) {
logError(lf_main, "invalid arguments"); logError(lf_main, "invalid arguments");
return EINVAL; return EINVAL;
} }
string configPath = string(opt.configPath); string configPath = string(s_opt.configPath);
if (configPath.find("://") == string::npos) { if (configPath.find("://") == string::npos) {
s_configLocalPrefix = configPath[configPath.length()-1] == '/' ? configPath : configPath + "/"; s_configLocalPrefix = configPath[configPath.length()-1] == '/' ? configPath : configPath + "/";
} else { } else {
if (!opt.scanConfig) { if (!s_opt.scanConfig) {
logError(lf_main, "invalid configpath without scanconfig"); logError(lf_main, "invalid configpath without scanconfig");
return EINVAL; return EINVAL;
} }
@@ -1323,29 +1336,31 @@ int main(int argc, char* argv[]) {
logError(lf_main, "invalid configPath URL"); logError(lf_main, "invalid configPath URL");
return EINVAL; return EINVAL;
} }
if (!s_configHttpClient.connect(configHost, configPort, proto == "https", PACKAGE_NAME "/" PACKAGE_VERSION)) { if (!lazyHttpClient()
|| !s_configHttpClient->connect(configHost, configPort, proto == "https", PACKAGE_NAME "/" PACKAGE_VERSION)) {
logError(lf_main, "invalid configPath URL"); logError(lf_main, "invalid configPath URL");
cleanup();
return EINVAL; return EINVAL;
} }
s_configHttpClient.disconnect(); s_configHttpClient->disconnect();
} }
if (!opt.readOnly && opt.scanConfig && opt.initialScan == 0) { if (!s_opt.readOnly && s_opt.scanConfig && s_opt.initialScan == 0) {
opt.initialScan = BROADCAST; s_opt.initialScan = BROADCAST;
} }
if (opt.logAreas != -1 || opt.logLevel != ll_COUNT) { if (s_opt.logAreas != -1 || s_opt.logLevel != ll_COUNT) {
setFacilitiesLogLevel(LF_ALL, ll_none); setFacilitiesLogLevel(LF_ALL, ll_none);
setFacilitiesLogLevel(opt.logAreas, opt.logLevel); setFacilitiesLogLevel(s_opt.logAreas, s_opt.logLevel);
} }
s_messageMap = new MessageMap(opt.checkConfig); s_messageMap = new MessageMap(s_opt.checkConfig);
if (opt.checkConfig) { if (s_opt.checkConfig) {
logNotice(lf_main, PACKAGE_STRING "." REVISION " performing configuration check..."); logNotice(lf_main, PACKAGE_STRING "." REVISION " performing configuration check...");
result_t result = loadConfigFiles(s_messageMap, true, opt.scanConfig && arg_index < argc); result_t result = loadConfigFiles(s_messageMap, true, s_opt.scanConfig && arg_index < argc);
result_t overallResult = executeInstructions(s_messageMap, true); result_t overallResult = executeInstructions(s_messageMap, true);
MasterSymbolString master; MasterSymbolString master;
SlaveSymbolString slave; SlaveSymbolString slave;
while (result == RESULT_OK && opt.scanConfig && arg_index < argc) { while (result == RESULT_OK && s_opt.scanConfig && arg_index < argc) {
// check scan config for each passed ident message // check scan config for each passed ident message
if (!parseMessage(argv[arg_index++], true, &master, &slave)) { if (!parseMessage(argv[arg_index++], true, &master, &slave)) {
continue; continue;
@@ -1375,28 +1390,31 @@ int main(int argc, char* argv[]) {
if (result != RESULT_OK) { if (result != RESULT_OK) {
overallResult = result; overallResult = result;
} }
if (result == RESULT_OK && opt.dumpConfig) { if (result == RESULT_OK && s_opt.dumpConfig) {
logNotice(lf_main, "configuration dump:"); logNotice(lf_main, "configuration dump:");
s_messageMap->dump(true, opt.dumpConfig, &cout); s_messageMap->dump(true, s_opt.dumpConfig, &cout);
} }
shutdown(overallResult != RESULT_OK); cleanup();
return 0; return overallResult == RESULT_OK ? EXIT_SUCCESS : EXIT_FAILURE;
} }
// open the device // open the device
Device *device = Device::create(opt.device, opt.extraLatency, !opt.noDeviceCheck, opt.readOnly, opt.initialSend); Device *device = Device::create(s_opt.device, s_opt.extraLatency, !s_opt.noDeviceCheck, s_opt.readOnly,
s_opt.initialSend);
if (device == nullptr) { if (device == nullptr) {
logError(lf_main, "unable to create device %s", opt.device); logError(lf_main, "unable to create device %s", s_opt.device);
cleanup();
return EINVAL; return EINVAL;
} }
if (!opt.foreground) { if (!s_opt.foreground) {
if (!setLogFile(opt.logFile)) { if (!setLogFile(s_opt.logFile)) {
logError(lf_main, "unable to open log file %s", opt.logFile); logError(lf_main, "unable to open log file %s", s_opt.logFile);
cleanup();
return EINVAL; return EINVAL;
} }
daemonize(); // make me daemon daemonize(); // make daemon
} }
// trap signals that we expect to receive // trap signals that we expect to receive
@@ -1406,8 +1424,8 @@ int main(int argc, char* argv[]) {
logNotice(lf_main, PACKAGE_STRING "." REVISION " started%s%s on%s device %s", logNotice(lf_main, PACKAGE_STRING "." REVISION " started%s%s on%s device %s",
device->isReadOnly() ? " read only" : "", device->isReadOnly() ? " read only" : "",
opt.scanConfig ? opt.initialScan == ESC ? " with auto scan" s_opt.scanConfig ? s_opt.initialScan == ESC ? " with auto scan"
: opt.initialScan == BROADCAST ? " with broadcast scan" : opt.initialScan == SYN ? " with full scan" : s_opt.initialScan == BROADCAST ? " with broadcast scan" : s_opt.initialScan == SYN ? " with full scan"
: " with single scan" : "", : " with single scan" : "",
device->isEnhancedProto() ? " enhanced" : "", device->isEnhancedProto() ? " enhanced" : "",
device->getName()); device->getName());
@@ -1416,8 +1434,8 @@ int main(int argc, char* argv[]) {
loadConfigFiles(s_messageMap); loadConfigFiles(s_messageMap);
// create the MainLoop and start it // create the MainLoop and start it
s_mainLoop = new MainLoop(opt, device, s_messageMap); s_mainLoop = new MainLoop(s_opt, device, s_messageMap);
if (opt.injectMessages) { if (s_opt.injectMessages) {
BusHandler* busHandler = s_mainLoop->getBusHandler(); BusHandler* busHandler = s_mainLoop->getBusHandler();
while (arg_index < argc) { while (arg_index < argc) {
// add each passed message // add each passed message
@@ -1428,7 +1446,7 @@ int main(int argc, char* argv[]) {
} }
busHandler->injectMessage(master, slave); busHandler->injectMessage(master, slave);
} }
if (opt.stopAfterInject) { if (s_opt.stopAfterInject) {
shutdown(); shutdown();
return 0; return 0;
} }