It is now possible to combine --oneshot and --exitafter= with --useconfig=

pull/473/head
Fredrik Öhrström 2022-02-05 16:00:52 +01:00
rodzic 0582fcce9f
commit 3252901466
9 zmienionych plików z 318 dodań i 126 usunięć

Wyświetl plik

@ -24,61 +24,43 @@
using namespace std;
shared_ptr<Configuration> parseCommandLine(int argc, char **argv) {
static bool isDaemon(int argc, char **argv);
static bool checkIfUseConfig(int argc, char **argv);
static shared_ptr<Configuration> parseNormalCommandLine(Configuration *c, int argc, char **argv);
static shared_ptr<Configuration> parseCommandLineWithUseConfig(Configuration *c, int argc, char **argv, bool pid_file_expected);
shared_ptr<Configuration> parseCommandLine(int argc, char **argv)
{
Configuration * c = new Configuration;
int i=1;
const char *filename = strrchr(argv[0], '/');
if (filename)
{
filename++;
}
else
{
filename = argv[0];
}
c->bin_dir = dirname(currentProcessExe());
if (!strcmp(filename, "wmbusmetersd"))
if (isDaemon(argc, argv))
{
c->daemon = true;
if (argc < 2) {
error("Usage error: wmbusmetersd must have at least a single argument to the pid file.\n"
"But you can also supply --device= and --listento= to override the config files.\n");
error("Usage error: wmbusmetersd must have at least a single argument to the pid file.\n");
}
int i = 1;
bool pid_file_found = false;
for (;;)
{
if (argv[i] == NULL) break;
if (!strncmp(argv[i], "--device=", 9))
{
c->device_override = string(argv[i]+9);
debug("(daemon) device override \"%s\"\n", c->device_override.c_str());
i++;
continue;
}
if (!strncmp(argv[i], "--listento=", 11))
{
c->listento_override = string(argv[i]+11);
debug("(daemon) listento override \"%s\"\n", c->listento_override.c_str());
i++;
continue;
}
c->pid_file = argv[i];
pid_file_found = true;
break;
}
if (!pid_file_found)
{
error("Usage error: you must supply the pid file as the argument to wmbusmetersd.\n");
}
return shared_ptr<Configuration>(c);
return parseCommandLineWithUseConfig(c, argc, argv, true);
}
if (argc < 2) {
if (argc < 2)
{
c->need_help = true;
return shared_ptr<Configuration>(c);
}
if (checkIfUseConfig(argc, argv))
{
return parseCommandLineWithUseConfig(c, argc, argv, false);
}
return parseNormalCommandLine(c, argc, argv);
}
static shared_ptr<Configuration> parseNormalCommandLine(Configuration *c, int argc, char **argv)
{
int i = 1;
while (argv[i] && argv[i][0] == '-')
{
if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-help") || !strcmp(argv[i], "--help")) {
@ -205,52 +187,6 @@ shared_ptr<Configuration> parseCommandLine(int argc, char **argv) {
i++;
continue;
}
if (!strncmp(argv[i], "--useconfig", 11)) {
if (strlen(argv[i]) == 11)
{
c->useconfig = true;
c->config_root = "";
return shared_ptr<Configuration>(c);
}
else if (strlen(argv[i]) > 12 && argv[i][11] == '=')
{
size_t len = strlen(argv[i]) - 12;
c->useconfig = true;
c->config_root = string(argv[i]+12, len);
if (c->config_root == "/") {
c->config_root = "";
}
}
else
{
error("You must supply a directory to --useconfig=dir\n");
}
i++;
for (;;)
{
if (argv[i] == NULL) break;
if (!strncmp(argv[i], "--device=", 9))
{
c->device_override = string(argv[i]+9);
debug("(useconfig) device override \"%s\"\n", c->device_override.c_str());
i++;
continue;
}
if (!strncmp(argv[i], "--listento=", 11))
{
c->listento_override = string(argv[i]+11);
debug("(useconfig) listento override \"%s\"\n", c->listento_override.c_str());
i++;
continue;
}
break;
}
if (i+1 < argc) {
error("Usage error: --useconfig can only be followed by --device= and --listento=\n");
}
return shared_ptr<Configuration>(c);
continue;
}
if (!strncmp(argv[i], "--format=", 9))
{
if (!strcmp(argv[i]+9, "json"))
@ -406,7 +342,7 @@ shared_ptr<Configuration> parseCommandLine(int argc, char **argv) {
if (len > 0) {
c->logfile = string(argv[i]+10, len);
} else {
error("Not a valid log file name.");
error("Not a valid log file name.\n");
}
}
i++;
@ -661,3 +597,155 @@ shared_ptr<Configuration> parseCommandLine(int argc, char **argv) {
return shared_ptr<Configuration>(c);
}
shared_ptr<Configuration> parseCommandLineWithUseConfig(Configuration *c, int argc, char **argv, bool pid_file_expected)
{
int i = 1;
while (argv[i] && argv[i][0] == '-')
{
if (!strncmp(argv[i], "--useconfig", 11))
{
if (strlen(argv[i]) == 11)
{
c->useconfig = true;
c->config_root = "";
}
else if (strlen(argv[i]) > 12 && argv[i][11] == '=')
{
size_t len = strlen(argv[i]) - 12;
c->useconfig = true;
c->config_root = string(argv[i]+12, len);
if (c->config_root == "/") {
c->config_root = "";
}
}
else
{
error("You must supply a directory to --useconfig=dir\n");
}
i++;
continue;
}
if (!strncmp(argv[i], "--verbose", 9))
{
c->overrides.loglevel_override = "verbose";
debug("(useconfig) loglevel override \"%s\"\n", c->overrides.loglevel_override.c_str());
i++;
continue;
}
if (!strncmp(argv[i], "--normal", 8))
{
c->overrides.loglevel_override = "normal";
debug("(useconfig) loglevel override \"%s\"\n", c->overrides.loglevel_override.c_str());
i++;
continue;
}
if (!strncmp(argv[i], "--silent", 8))
{
c->overrides.loglevel_override = "silent";
debug("(useconfig) loglevel override \"%s\"\n", c->overrides.loglevel_override.c_str());
i++;
continue;
}
if (!strncmp(argv[i], "--debug", 7))
{
c->overrides.loglevel_override = "debug";
debug("(useconfig) loglevel override \"%s\"\n", c->overrides.loglevel_override.c_str());
i++;
continue;
}
if (!strncmp(argv[i], "--trace", 7))
{
c->overrides.loglevel_override = "trace";
debug("(useconfig) loglevel override \"%s\"\n", c->overrides.loglevel_override.c_str());
i++;
continue;
}
if (!strncmp(argv[i], "--device=", 9))
{
c->overrides.device_override = string(argv[i]+9);
debug("(useconfig) device override \"%s\"\n", c->overrides.device_override.c_str());
i++;
continue;
}
if (!strncmp(argv[i], "--listento=", 11))
{
c->overrides.listento_override = string(argv[i]+11);
debug("(useconfig) listento override \"%s\"\n", c->overrides.listento_override.c_str());
i++;
continue;
}
if (!strncmp(argv[i], "--exitafter=", 12) && strlen(argv[i]) > 12) {
int s = parseTime(argv[i]+12);
if (s <= 0) {
error("Not a valid time to exit after. \"%s\"\n", argv[i]+12);
}
c->overrides.exitafter_override = argv[i]+12;
i++;
continue;
}
if (!strcmp(argv[i], "--oneshot")) {
c->overrides.oneshot_override = "true";
i++;
continue;
}
if (!strncmp(argv[i], "--logfile=", 10)) {
size_t len = strlen(argv[i])-10;
if (len > 0) {
c->overrides.logfile_override = string(argv[i]+10, len);
} else {
error("Not a valid log file name.\n");
}
i++;
continue;
}
error("Usage error: --useconfig=... can only be used in combination with:\n"
"--device= --listento= --exitafter= --oneshot= --logfile= --silent --normal --verbose --debug --trace\n");
break;
}
if (pid_file_expected)
{
if (!argv[i])
{
error("Usage error: you must supply the pid file as the last argument to wmbusmetersd.\n");
}
c->pid_file = argv[i];
i++;
}
if (i+1 < argc)
{
error("Usage error: you must supply the pid file as the last argument to wmbusmetersd.\n");
}
return shared_ptr<Configuration>(c);
}
static bool isDaemon(int argc, char **argv)
{
const char *filename = strrchr(argv[0], '/');
if (filename)
{
filename++;
}
else
{
filename = argv[0];
}
return !strcmp(filename, "wmbusmetersd");
}
static bool checkIfUseConfig(int argc, char **argv)
{
while (*argv != NULL)
{
if (!strncmp(*argv, "--useconfig", 11)) return true;
argv++;
}
return false;
}

Wyświetl plik

@ -177,22 +177,48 @@ void parseMeterConfig(Configuration *c, vector<char> &buf, string file)
void handleLoglevel(Configuration *c, string loglevel)
{
if (loglevel == "verbose") { c->verbose = true; }
if (loglevel == "verbose")
{
c->silent = false;
c->verbose = true;
c->debug = false;
c->trace = false;
verboseEnabled(c->verbose);
}
else if (loglevel == "debug")
{
c->silent = false;
c->verbose = false;
c->debug = true;
c->trace = false;
// Kick in debug immediately.
debugEnabled(c->debug);
}
else if (loglevel == "trace")
{
c->silent = false;
c->verbose = false;
c->debug = false;
c->trace = true;
// Kick in trace immediately.
traceEnabled(c->trace);
}
else if (loglevel == "silent") { c->silent = true; }
else if (loglevel == "normal") { }
else {
else if (loglevel == "silent")
{
c->silent = true;
c->verbose = false;
c->debug = false;
c->trace = false;
}
else if (loglevel == "normal")
{
c->silent = false;
c->verbose = false;
c->debug = false;
c->trace = false;
}
else
{
warning("No such log level: \"%s\"\n", loglevel.c_str());
}
}
@ -358,6 +384,26 @@ void handleListenTo(Configuration *c, string mode)
c->default_device_linkmodes = lms;
}
void handleExitAfter(Configuration *c, string after)
{
if (c->exitafter > 0)
{
error("You have already specified an exit after time!\n");
}
c->exitafter = parseTime(after);
if (c->exitafter == 0)
{
error("Exit after time must be non-zero \"%s\"!\n", after.c_str());
}
}
void handleOneshot(Configuration *c)
{
c->oneshot = true;
}
void handleLogtelegrams(Configuration *c, string logtelegrams)
{
if (logtelegrams == "true") { c->logtelegrams = true; }
@ -579,7 +625,7 @@ void handleExtraConstantField(Configuration *c, string field)
c->extra_constant_fields.push_back(field);
}
shared_ptr<Configuration> loadConfiguration(string root, string device_override, string listento_override)
shared_ptr<Configuration> loadConfiguration(string root, ConfigOverrides overrides)
{
Configuration *c = new Configuration;
@ -587,7 +633,23 @@ shared_ptr<Configuration> loadConfiguration(string root, string device_override,
c->json = true;
vector<char> global_conf;
// --useconfig=/ will work to find /etc/wmbusmeters.conf and /etc/wmbusmeters.d
// --useconfig=/etc will also work to find /etc/wmbusmeters.conf and /etc/wmbusmeters.d
// The second one is preferable but for backward compatibility the first one is tested first.
// If there is no /+etc/wmbusmeters.conf then it will look for /+wmbusmeters.conf
string conf_dir = root;
string conf_file = root+"/etc/wmbusmeters.conf";
string conf_meter_dir = root+"/etc/wmbusmeters.d";
if (!checkFileExists(conf_file.c_str()))
{
conf_dir = root+"/etc";
conf_file = root+"/wmbusmeters.conf";
conf_meter_dir = root+"/wmbusmeters.d";
}
debug("(config) loading %s\n", conf_file.c_str());
bool ok = loadFile(conf_file, &global_conf);
global_conf.push_back('\n');
@ -609,6 +671,8 @@ shared_ptr<Configuration> loadConfiguration(string root, string device_override,
else if (p.first == "device") handleDeviceOrHex(c, p.second);
else if (p.first == "donotprobe") handleDoNotProbe(c, p.second);
else if (p.first == "listento") handleListenTo(c, p.second);
else if (p.first == "exitafter") handleExitAfter(c, p.second);
else if (p.first == "oneshot") handleOneshot(c);
else if (p.first == "logtelegrams") handleLogtelegrams(c, p.second);
else if (p.first == "meterfiles") handleMeterfiles(c, p.second);
else if (p.first == "meterfilesaction") handleMeterfilesAction(c, p.second);
@ -641,36 +705,60 @@ shared_ptr<Configuration> loadConfiguration(string root, string device_override,
}
vector<string> meters;
listFiles(root+"/etc/wmbusmeters.d", &meters);
listFiles(conf_meter_dir, &meters);
for (auto& f : meters)
{
vector<char> meter_conf;
string file = root+"/etc/wmbusmeters.d/"+f;
string file = conf_meter_dir+"/"+f;
loadFile(file.c_str(), &meter_conf);
meter_conf.push_back('\n');
parseMeterConfig(c, meter_conf, file);
}
if (device_override != "")
if (overrides.device_override != "")
{
// There is an override, therefore we
// drop any already loaded devices from the config file.
c->use_auto_device_detect = false;
c->supplied_bus_devices.clear();
if (startsWith(device_override, "/dev/rtlsdr"))
if (startsWith(overrides.device_override, "/dev/rtlsdr"))
{
debug("(config) use rtlwmbus instead of raw device %s\n", device_override.c_str());
device_override = "rtlwmbus";
debug("(config) use rtlwmbus instead of raw device %s\n", overrides.device_override.c_str());
overrides.device_override = "rtlwmbus";
}
debug("(config) overriding device with \"%s\"\n", device_override.c_str());
handleDeviceOrHex(c, device_override);
debug("(config) overriding device with \"%s\"\n", overrides.device_override.c_str());
handleDeviceOrHex(c, overrides.device_override);
}
if (listento_override != "")
if (overrides.listento_override != "")
{
debug("(config) overriding listento with \"%s\"\n", listento_override.c_str());
handleListenTo(c, listento_override);
debug("(config) overriding listento with \"%s\"\n", overrides.listento_override.c_str());
handleListenTo(c, overrides.listento_override);
}
if (overrides.exitafter_override != "")
{
debug("(config) overriding exitafter with \"%s\"\n", overrides.exitafter_override.c_str());
handleExitAfter(c, overrides.exitafter_override);
}
if (overrides.oneshot_override != "")
{
debug("(config) overriding oneshot with true\n");
handleOneshot(c);
}
if (overrides.loglevel_override != "")
{
debug("(config) overriding loglevel with %s\n", overrides.loglevel_override.c_str());
handleLoglevel(c, overrides.loglevel_override);
}
if (overrides.logfile_override != "")
{
debug("(config) overriding logfile with %s\n", overrides.logfile_override.c_str());
handleLogfile(c, overrides.logfile_override);
}
return shared_ptr<Configuration>(c);

Wyświetl plik

@ -42,6 +42,17 @@ enum class MeterFileTimestamp
Never, Day, Hour, Minute, Micros
};
// These values can be overridden from the command line.
struct ConfigOverrides
{
std::string loglevel_override;
std::string device_override;
std::string listento_override;
std::string exitafter_override;
std::string oneshot_override;
std::string logfile_override;
};
struct Configuration
{
string bin_dir {}; // The wmbusmeters binary executed is located here.
@ -49,8 +60,7 @@ struct Configuration
// inside the same directory.
bool daemon {};
std::string pid_file;
std::string device_override;
std::string listento_override;
ConfigOverrides overrides;
bool useconfig {};
std::string config_root;
bool need_help {};
@ -121,7 +131,7 @@ struct Configuration
~Configuration() = default;
};
shared_ptr<Configuration> loadConfiguration(string root, string device_override, string listento_override);
shared_ptr<Configuration> loadConfiguration(string root, ConfigOverrides overrides);
void parseMeterConfig(Configuration *c, vector<char> &buf, string file);
void handleConversions(Configuration *c, string s);

Wyświetl plik

@ -55,8 +55,10 @@ void log_start_information(Configuration *config);
void oneshot_check(Configuration *config, Telegram *t, Meter *meter);
void regular_checkup(Configuration *config);
bool start(Configuration *config);
void start_using_config_files(string root, bool is_daemon, string device_override, string listento_override);
void start_daemon(string pid_file, string device_override, string listento_override); // Will use config files.
void start_using_config_files(string root, bool is_daemon, ConfigOverrides overrides);
void start_daemon(string pid_file, ConfigOverrides overrides);
void setup_log_file(Configuration *config);
void setup_meters(Configuration *config, MeterManager *manager);
void write_pid(string pid_file, int pid);
@ -150,13 +152,13 @@ provided you with this binary. Read the full license for all details.
if (config->daemon)
{
start_daemon(config->pid_file, config->device_override, config->listento_override);
start_daemon(config->pid_file, config->overrides);
exit(0);
}
if (config->useconfig)
{
start_using_config_files(config->config_root, false, config->device_override, config->listento_override);
start_using_config_files(config->config_root, false, config->overrides);
exit(0);
}
else
@ -412,9 +414,9 @@ void setup_log_file(Configuration *config)
bool ok = enableLogfile(config->logfile, config->daemon);
if (!ok) {
if (config->daemon) {
warning("Could not open log file, will use syslog instead.\n");
warning("Could not open log file %s will use syslog instead.\n", config->logfile.c_str());
} else {
error("Could not open log file.\n");
error("Could not open log file %s\n", config->logfile.c_str());
}
}
}
@ -462,8 +464,9 @@ bool start(Configuration *config)
// Configure settings.
silentLogging(config->silent);
verboseEnabled(config->verbose);
logTelegramsEnabled(config->logtelegrams);
debugEnabled(config->debug);
traceEnabled(config->trace);
logTelegramsEnabled(config->logtelegrams);
if (config->addtimestamps == AddLogTimestamps::NotSet)
{
@ -472,7 +475,7 @@ bool start(Configuration *config)
}
setLogTimestamps(config->addtimestamps);
internalTestingEnabled(config->internaltesting);
traceEnabled(config->trace);
stderrEnabled(config->use_stderr_for_log);
setAlarmShells(config->alarm_shells);
setIgnoreDuplicateTelegrams(config->ignore_duplicate_telegrams);
@ -605,7 +608,7 @@ bool start(Configuration *config)
return gotHupped();
}
void start_daemon(string pid_file, string device_override, string listento_override)
void start_daemon(string pid_file, ConfigOverrides overrides)
{
setlogmask(LOG_UPTO (LOG_INFO));
openlog("wmbusmetersd", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
@ -655,15 +658,15 @@ void start_daemon(string pid_file, string device_override, string listento_overr
if (open("/dev/null", O_RDWR) == -1) {
error("Failed to reopen stderr while daemonising (errno=%d)",errno);
}
start_using_config_files("", true, device_override, listento_override);
start_using_config_files("", true, overrides);
}
void start_using_config_files(string root, bool is_daemon, string device_override, string listento_override)
void start_using_config_files(string root, bool is_daemon, ConfigOverrides overrides)
{
bool restart = false;
do
{
shared_ptr<Configuration> config = loadConfiguration(root, device_override, listento_override);
shared_ptr<Configuration> config = loadConfiguration(root, overrides);
config->daemon = is_daemon;
restart = start(config.get());
if (restart)

Wyświetl plik

@ -158,6 +158,9 @@ echo Slower tests...
tests/test_pipe.sh $PROG
if [ "$?" != "0" ]; then RC="1"; fi
tests/test_config_overrides.sh $PROG
if [ "$?" != "0" ]; then RC="1"; fi
if [ "$(uname)" = "Linux" ]
then
tests/test_alarm.sh $PROG

Wyświetl plik

@ -10,8 +10,8 @@ mkdir -p $TEST
TESTNAME="Test aes encrypted telegrams"
TESTRESULT="ERROR"
cat simulations/simulation_aes.msg | grep '^{' | tr -d '#' > $TEST/test_expected.txt
cat simulations/simulation_aes.msg | grep '^[CT]' | tr -d '#' > $TEST/test_input.txt
cat simulations/serial_aes.msg | grep '^{' | tr -d '#' > $TEST/test_expected.txt
cat simulations/serial_aes.msg | grep '^[CT]' | tr -d '#' > $TEST/test_input.txt
cat $TEST/test_input.txt | $PROG --format=json "stdin:rtlwmbus" \
ApWater apator162 88888888 00000000000000000000000000000000 \
Vatten multical21 76348799 28F64A24988064A079AA2C807D6102AE \

Wyświetl plik

@ -9,7 +9,7 @@ mkdir -p $TEST
TESTNAME="Test log timestamps"
cat simulations/simulation_aes.msg | grep '^[CT]' | grep 76348799 | tr -d '#' > $TEST/test_input.txt
cat simulations/serial_aes.msg | grep '^[CT]' | grep 76348799 | tr -d '#' > $TEST/test_input.txt
cat $TEST/test_input.txt | $PROG --format=json --logtimestamps=always --verbose "stdin:rtlwmbus" \
Vatten multical21 76348799 28F64A24988064A079AA2C807D6102AE > $TEST/test_output.txt 2> $TEST/test_stderr.txt

Wyświetl plik

@ -10,8 +10,8 @@ mkdir -p $TEST
TESTNAME="Test wrong keys"
TESTRESULT="ERROR"
cat simulations/simulation_aes.msg | grep '^{' | tr -d '#' > $TEST/test_expected.txt
cat simulations/simulation_aes.msg | grep '^[CT]' | tr -d '#' > $TEST/test_input.txt
cat simulations/serial_aes.msg | grep '^{' | tr -d '#' > $TEST/test_expected.txt
cat simulations/serial_aes.msg | grep '^[CT]' | tr -d '#' > $TEST/test_input.txt
cat $TEST/test_input.txt | $PROG --format=json "stdin:rtlwmbus" \
ApWater apator162 88888888 00000000000000000000000000000001 \
Vatten multical21 76348799 28F64A24988064A079AA2C807D6102AF \