only update settings from args after verified as valid

This commit is contained in:
John
2022-09-24 15:44:56 +02:00
parent 406e7be6ef
commit 1f742a6235
3 changed files with 93 additions and 66 deletions
+5 -2
View File
@@ -84,6 +84,7 @@ static vector<string>* g_integrationVars = nullptr; //!< the integration settin
*/ */
static error_t knx_parse_opt(int key, char *arg, struct argp_state *state) { static error_t knx_parse_opt(int key, char *arg, struct argp_state *state) {
result_t result; result_t result;
unsigned int value;
switch (key) { switch (key) {
case O_URL: // --knxurl=[multicast][@interface] case O_URL: // --knxurl=[multicast][@interface]
if (arg == nullptr) { // empty is allowed if (arg == nullptr) { // empty is allowed
@@ -98,11 +99,12 @@ static error_t knx_parse_opt(int key, char *arg, struct argp_state *state) {
argp_error(state, "invalid knxrage value"); argp_error(state, "invalid knxrage value");
return EINVAL; return EINVAL;
} }
g_maxReadAge = parseInt(arg, 10, 0, 99999999, &result); value = parseInt(arg, 10, 0, 99999999, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argp_error(state, "invalid knxrage"); argp_error(state, "invalid knxrage");
return EINVAL; return EINVAL;
} }
g_maxReadAge = value;
break; break;
case O_AGW: // --knxwage=5 case O_AGW: // --knxwage=5
@@ -110,11 +112,12 @@ static error_t knx_parse_opt(int key, char *arg, struct argp_state *state) {
argp_error(state, "invalid knxwage value"); argp_error(state, "invalid knxwage value");
return EINVAL; return EINVAL;
} }
g_maxWriteAge = parseInt(arg, 10, 0, 99999999, &result); value = parseInt(arg, 10, 0, 99999999, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argp_error(state, "invalid knxwage"); argp_error(state, "invalid knxwage");
return EINVAL; return EINVAL;
} }
g_maxWriteAge = value;
break; break;
case O_INT: // --knxint=/etc/ebusd/knx.cfg case O_INT: // --knxint=/etc/ebusd/knx.cfg
+70 -48
View File
@@ -340,23 +340,25 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
s_configPath = arg; s_configPath = arg;
break; break;
case 's': // --scanconfig[=ADDR] (ADDR=<empty>|full|<hexaddr>) case 's': // --scanconfig[=ADDR] (ADDR=<empty>|full|<hexaddr>)
opt->scanConfig = true;
if (opt->pollInterval == 0) { if (opt->pollInterval == 0) {
argp_error(state, "scanconfig without polling may lead to invalid files included for certain products!"); argp_error(state, "scanconfig without polling may lead to invalid files included for certain products!");
return EINVAL; return EINVAL;
} }
opt->scanConfig = true;
if (!arg || arg[0] == 0 || strcmp("none", arg) == 0) { if (!arg || arg[0] == 0 || strcmp("none", arg) == 0) {
opt->initialScan = ESC; opt->initialScan = ESC;
} else if (strcmp("full", arg) == 0) { } else if (strcmp("full", arg) == 0) {
opt->initialScan = SYN; opt->initialScan = SYN;
} else { } else {
opt->initialScan = (symbol_t)parseInt(arg, 16, 0x00, 0xff, &result); symbol_t address = (symbol_t)parseInt(arg, 16, 0x00, 0xff, &result);
if (result != RESULT_OK || !isValidAddress(opt->initialScan)) { if (result != RESULT_OK || !isValidAddress(address)) {
argp_error(state, "invalid initial scan address"); argp_error(state, "invalid initial scan address");
return EINVAL; return EINVAL;
} }
if (isMaster(opt->initialScan)) { if (isMaster(address)) {
opt->initialScan = getSlaveAddress(opt->initialScan); opt->initialScan = getSlaveAddress(address);
} else {
opt->initialScan = address;
} }
} }
if (opt->readOnly && opt->initialScan != ESC) { if (opt->readOnly && opt->initialScan != ESC) {
@@ -379,11 +381,11 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
argp_error(state, "invalid checkconfig"); argp_error(state, "invalid checkconfig");
return EINVAL; return EINVAL;
} }
opt->dumpConfig = OF_DEFINITION;
if (!arg || arg[0] == 0 || strcmp("csv", arg) == 0) { if (!arg || arg[0] == 0 || strcmp("csv", arg) == 0) {
// no further flags // no further flags
opt->dumpConfig = OF_DEFINITION;
} else if (strcmp("json", arg) == 0) { } else if (strcmp("json", arg) == 0) {
opt->dumpConfig |= OF_NAMES | OF_UNITS | OF_COMMENTS | OF_VALUENAME | OF_ALL_ATTRS | OF_JSON; opt->dumpConfig = OF_DEFINITION | OF_NAMES | OF_UNITS | OF_COMMENTS | OF_VALUENAME | OF_ALL_ATTRS | OF_JSON;
} else { } else {
argp_error(state, "invalid dumpconfig"); argp_error(state, "invalid dumpconfig");
return EINVAL; return EINVAL;
@@ -398,15 +400,16 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
opt->dumpConfigTo = arg; opt->dumpConfigTo = arg;
break; break;
case O_POLINT: // --pollinterval=5 case O_POLINT: // --pollinterval=5
opt->pollInterval = parseInt(arg, 10, 0, 3600, &result); value = parseInt(arg, 10, 0, 3600, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argp_error(state, "invalid pollinterval"); argp_error(state, "invalid pollinterval");
return EINVAL; return EINVAL;
} }
if (opt->pollInterval == 0 && opt->scanConfig) { if (value == 0 && opt->scanConfig) {
argp_error(state, "scanconfig without polling may lead to invalid files included for certain products!"); argp_error(state, "scanconfig without polling may lead to invalid files included for certain products!");
return EINVAL; return EINVAL;
} }
opt->pollInterval = value;
break; break;
case 'i': // --inject[=stop] case 'i': // --inject[=stop]
if (opt->injectMessages || opt->checkConfig) { if (opt->injectMessages || opt->checkConfig) {
@@ -425,12 +428,15 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
// eBUS options: // eBUS options:
case 'a': // --address=31 case 'a': // --address=31
opt->address = (symbol_t)parseInt(arg, 16, 0, 0xff, &result); {
if (result != RESULT_OK || !isMaster(opt->address)) { symbol_t address = (symbol_t)parseInt(arg, 16, 0, 0xff, &result);
if (result != RESULT_OK || !isMaster(address)) {
argp_error(state, "invalid address"); argp_error(state, "invalid address");
return EINVAL; return EINVAL;
} }
opt->address = address;
break; break;
}
case O_ANSWER: // --answer case O_ANSWER: // --answer
if (opt->readOnly) { if (opt->readOnly) {
argp_error(state, "cannot combine readonly with answer/generatesyn/initsend/scanconfig=*"); argp_error(state, "cannot combine readonly with answer/generatesyn/initsend/scanconfig=*");
@@ -447,18 +453,20 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
opt->acquireTimeout = value > 1000 ? value/1000 : value; // backwards compatible (micros) opt->acquireTimeout = value > 1000 ? value/1000 : value; // backwards compatible (micros)
break; break;
case O_ACQRET: // --acquireretries=3 case O_ACQRET: // --acquireretries=3
opt->acquireRetries = parseInt(arg, 10, 0, 10, &result); value = parseInt(arg, 10, 0, 10, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argp_error(state, "invalid acquireretries"); argp_error(state, "invalid acquireretries");
return EINVAL; return EINVAL;
} }
opt->acquireRetries = value;
break; break;
case O_SNDRET: // --sendretries=2 case O_SNDRET: // --sendretries=2
opt->sendRetries = parseInt(arg, 10, 0, 10, &result); value = parseInt(arg, 10, 0, 10, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argp_error(state, "invalid sendretries"); argp_error(state, "invalid sendretries");
return EINVAL; return EINVAL;
} }
opt->sendRetries = value;
break; break;
case O_RCVTIM: // --receivetimeout=25 case O_RCVTIM: // --receivetimeout=25
value = parseInt(arg, 10, 1, 100000, &result); // backwards compatible (micros) value = parseInt(arg, 10, 1, 100000, &result); // backwards compatible (micros)
@@ -469,11 +477,12 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
opt->receiveTimeout = value > 1000 ? value/1000 : value; // backwards compatible (micros) opt->receiveTimeout = value > 1000 ? value/1000 : value; // backwards compatible (micros)
break; break;
case O_MASCNT: // --numbermasters=0 case O_MASCNT: // --numbermasters=0
opt->masterCount = parseInt(arg, 10, 0, 25, &result); value = parseInt(arg, 10, 0, 25, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argp_error(state, "invalid numbermasters"); argp_error(state, "invalid numbermasters");
return EINVAL; return EINVAL;
} }
opt->masterCount = value;
break; break;
case O_GENSYN: // --generatesyn case O_GENSYN: // --generatesyn
if (opt->readOnly) { if (opt->readOnly) {
@@ -515,21 +524,23 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
opt->pidFile = arg; opt->pidFile = arg;
break; break;
case 'p': // --port=8888 case 'p': // --port=8888
opt->port = (uint16_t)parseInt(arg, 10, 1, 65535, &result); value = parseInt(arg, 10, 1, 65535, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argp_error(state, "invalid port"); argp_error(state, "invalid port");
return EINVAL; return EINVAL;
} }
opt->port = (uint16_t)value;
break; break;
case O_LOCAL: // --localhost case O_LOCAL: // --localhost
opt->localOnly = true; opt->localOnly = true;
break; break;
case O_HTTPPT: // --httpport=0 case O_HTTPPT: // --httpport=0
opt->httpPort = (uint16_t)parseInt(arg, 10, 1, 65535, &result); value = parseInt(arg, 10, 1, 65535, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argp_error(state, "invalid httpport"); argp_error(state, "invalid httpport");
return EINVAL; return EINVAL;
} }
opt->httpPort = (uint16_t)value;
break; break;
case O_HTMLPA: // --htmlpath=/var/ebusd/html case O_HTMLPA: // --htmlpath=/var/ebusd/html
if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) { if (arg == nullptr || arg[0] == 0 || strcmp("/", arg) == 0) {
@@ -562,37 +573,38 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
opt->logFile = arg; opt->logFile = arg;
break; break;
case O_LOG: // --log=area(s):level case O_LOG: // --log=area(s):level
{ {
char* pos = strchr(arg, ':'); char* pos = strchr(arg, ':');
if (pos == nullptr) {
pos = strchr(arg, ' ');
if (pos == nullptr) { if (pos == nullptr) {
pos = strchr(arg, ' '); argp_error(state, "invalid log");
if (pos == nullptr) {
argp_error(state, "invalid log");
return EINVAL;
}
}
*pos = 0;
int facilities = parseLogFacilities(arg);
if (facilities == -1) {
argp_error(state, "invalid log: areas");
return EINVAL; return EINVAL;
} }
LogLevel level = parseLogLevel(pos + 1);
if (level == ll_COUNT) {
argp_error(state, "invalid log: level");
return EINVAL;
}
if (opt->logAreas != -1 || opt->logLevel != ll_COUNT) {
argp_error(state, "invalid log (combined with logareas or loglevel)");
return EINVAL;
}
setFacilitiesLogLevel(facilities, level);
opt->multiLog = true;
} }
*pos = 0;
int facilities = parseLogFacilities(arg);
if (facilities == -1) {
argp_error(state, "invalid log: areas");
return EINVAL;
}
LogLevel level = parseLogLevel(pos + 1);
if (level == ll_COUNT) {
argp_error(state, "invalid log: level");
return EINVAL;
}
if (opt->logAreas != -1 || opt->logLevel != ll_COUNT) {
argp_error(state, "invalid log (combined with logareas or loglevel)");
return EINVAL;
}
setFacilitiesLogLevel(facilities, level);
opt->multiLog = true;
break; break;
}
case O_LOGARE: // --logareas=all case O_LOGARE: // --logareas=all
opt->logAreas = parseLogFacilities(arg); {
if (opt->logAreas == -1) { int facilities = parseLogFacilities(arg);
if (facilities == -1) {
argp_error(state, "invalid logareas"); argp_error(state, "invalid logareas");
return EINVAL; return EINVAL;
} }
@@ -600,9 +612,12 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
argp_error(state, "invalid logareas (combined with log)"); argp_error(state, "invalid logareas (combined with log)");
return EINVAL; return EINVAL;
} }
opt->logAreas = facilities;
break; break;
}
case O_LOGLEV: // --loglevel=notice case O_LOGLEV: // --loglevel=notice
opt->logLevel = parseLogLevel(arg); {
LogLevel logLevel = parseLogLevel(arg);
if (opt->logLevel == ll_COUNT) { if (opt->logLevel == ll_COUNT) {
argp_error(state, "invalid loglevel"); argp_error(state, "invalid loglevel");
return EINVAL; return EINVAL;
@@ -611,7 +626,9 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
argp_error(state, "invalid loglevel (combined with log)"); argp_error(state, "invalid loglevel (combined with log)");
return EINVAL; return EINVAL;
} }
opt->logLevel = logLevel;
break; break;
}
// Raw logging options: // Raw logging options:
case O_RAW: // --lograwdata case O_RAW: // --lograwdata
@@ -625,11 +642,12 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
opt->logRawFile = arg; opt->logRawFile = arg;
break; break;
case O_RAWSIZ: // --lograwdatasize=100 case O_RAWSIZ: // --lograwdatasize=100
opt->logRawSize = parseInt(arg, 10, 1, 1000000, &result); value = parseInt(arg, 10, 1, 1000000, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argp_error(state, "invalid lograwdatasize"); argp_error(state, "invalid lograwdatasize");
return EINVAL; return EINVAL;
} }
opt->logRawSize = value;
break; break;
@@ -645,11 +663,12 @@ error_t parse_opt(int key, char *arg, struct argp_state *state) {
opt->dumpFile = arg; opt->dumpFile = arg;
break; break;
case O_DMPSIZ: // --dumpsize=100 case O_DMPSIZ: // --dumpsize=100
opt->dumpSize = parseInt(arg, 10, 1, 1000000, &result); value = parseInt(arg, 10, 1, 1000000, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argp_error(state, "invalid dumpsize"); argp_error(state, "invalid dumpsize");
return EINVAL; return EINVAL;
} }
opt->dumpSize = value;
break; break;
case O_DMPFLU: // --dumpflush case O_DMPFLU: // --dumpflush
opt->dumpFlush = true; opt->dumpFlush = true;
@@ -1345,11 +1364,14 @@ int main(int argc, char* argv[]) {
strcat(envopt, pos); strcat(envopt, pos);
} }
int idx = -1; int idx = -1;
s_opt.injectMessages = true; // for skipping unknown values s_opt.injectMessages = true; // for skipping unknown values via ARGP_ERR_UNKNOWN
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, &s_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); if (err == ESRCH) { // special value to abort immediately
logError(lf_main, "invalid argument in env: %s", envopt);
return EINVAL;
}
logError(lf_main, "invalid/unknown argument in env (ignored): %s", envopt);
} }
s_opt.injectMessages = false; // restore (was not parsed from cmdline args yet) s_opt.injectMessages = false; // restore (was not parsed from cmdline args yet)
} }
+18 -16
View File
@@ -150,7 +150,7 @@ void splitFields(const string& str, vector<string>* row);
*/ */
static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) { static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
result_t result = RESULT_OK; result_t result = RESULT_OK;
unsigned int value;
switch (key) { switch (key) {
case O_HOST: // --mqtthost=localhost case O_HOST: // --mqtthost=localhost
if (arg == nullptr || arg[0] == 0) { if (arg == nullptr || arg[0] == 0) {
@@ -161,11 +161,12 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
break; break;
case O_PORT: // --mqttport=1883 case O_PORT: // --mqttport=1883
g_port = (uint16_t)parseInt(arg, 10, 1, 65535, &result); value = parseInt(arg, 10, 1, 65535, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argp_error(state, "invalid mqttport"); argp_error(state, "invalid mqttport");
return EINVAL; return EINVAL;
} }
g_port = (uint16_t)value;
break; break;
case O_CLID: // --mqttclientid=clientid case O_CLID: // --mqttclientid=clientid
@@ -193,28 +194,28 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
break; break;
case O_TOPI: // --mqtttopic=ebusd case O_TOPI: // --mqtttopic=ebusd
{
if (arg == nullptr || arg[0] == 0 || strchr(arg, '+') || arg[strlen(arg)-1] == '/') { if (arg == nullptr || arg[0] == 0 || strchr(arg, '+') || arg[strlen(arg)-1] == '/') {
argp_error(state, "invalid mqtttopic"); argp_error(state, "invalid mqtttopic");
return EINVAL; return EINVAL;
} else { }
char *pos = strchr(arg, '#'); char *pos = strchr(arg, '#');
if (pos && (pos == arg || pos[1])) { // allow # only at very last position (to indicate not using any default) if (pos && (pos == arg || pos[1])) { // allow # only at very last position (to indicate not using any default)
argp_error(state, "invalid mqtttopic"); argp_error(state, "invalid mqtttopic");
return EINVAL; return EINVAL;
}
} }
if (g_topic) { if (g_topic) {
argp_error(state, "duplicate mqtttopic"); argp_error(state, "duplicate mqtttopic");
return EINVAL; return EINVAL;
} else {
StringReplacer replacer;
if (!replacer.parse(arg, true)) {
argp_error(state, "malformed mqtttopic");
return EINVAL;
}
g_topic = arg;
} }
StringReplacer replacer;
if (!replacer.parse(arg, true)) {
argp_error(state, "malformed mqtttopic");
return ESRCH; // abort in any case due to the above potentially being destructive
}
g_topic = arg;
break; break;
}
case O_GTOP: // --mqttglobal=global/ case O_GTOP: // --mqttglobal=global/
if (arg == nullptr || strchr(arg, '+') || strchr(arg, '#')) { if (arg == nullptr || strchr(arg, '+') || strchr(arg, '#')) {
@@ -229,11 +230,12 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) {
break; break;
case O_PQOS: // --mqttqos=0 case O_PQOS: // --mqttqos=0
g_qos = parseSignedInt(arg, 10, 0, 2, &result); value = parseInt(arg, 10, 0, 2, &result);
if (result != RESULT_OK) { if (result != RESULT_OK) {
argp_error(state, "invalid mqttqos value"); argp_error(state, "invalid mqttqos value");
return EINVAL; return EINVAL;
} }
g_qos = static_cast<signed>(value);
break; break;
case O_INTF: // --mqttint=/etc/ebusd/mqttint.cfg case O_INTF: // --mqttint=/etc/ebusd/mqttint.cfg