Legacy 'interfaces' config option improvements

Legacy form is now incompatible with modern form.

Test case to check legacy parsing.
This commit is contained in:
Andrew Bettison 2012-12-04 18:22:26 +10:30
parent 93c38a764d
commit c53789d764
5 changed files with 71 additions and 50 deletions

1
conf.h
View File

@ -544,6 +544,7 @@ int cf_opt_sid(sid_t *sidp, const char *text);
int cf_opt_rhizome_bk(rhizome_bk_t *bkp, const char *text);
int cf_opt_interface_type(short *typep, const char *text);
int cf_opt_pattern_list(struct pattern_list *listp, const char *text);
int cf_opt_network_interface(struct config_network_interface *nifp, const struct cf_om_node *node);
int cf_opt_interface_list(struct config_interface_list *listp, const struct cf_om_node *node);
extern int cf_limbo;

View File

@ -394,7 +394,7 @@ int cf_opt_pattern_list(struct pattern_list *listp, const char *text)
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
int cf_opt_network_interface(struct config_network_interface *nifp, const char *text)
static int cf_opt_network_interface_legacy(struct config_network_interface *nifp, const char *text)
{
//DEBUGF("%s text=%s", __FUNCTION__, alloca_str_toprint(text));
struct config_network_interface nif;
@ -472,63 +472,67 @@ int cf_opt_network_interface(struct config_network_interface *nifp, const char *
return CFOK;
}
int cf_opt_network_interface(struct config_network_interface *nifp, const struct cf_om_node *node)
{
if (!node->text)
return cf_opt_config_network_interface(nifp, node);
cf_warn_spurious_children(node);
return cf_opt_network_interface_legacy(nifp, node->text);
}
/* Config parse function. Implements the original form of the 'interfaces' config option. Parses a
* comma-separated list of interface rules (see cf_opt_network_interface() for the format of each
* rule), then parses the regular config array-of-struct style interface option settings so that
* both forms are supported.
* comma-separated list of interface rules (see cf_opt_network_interface_legacy() for the format of
* each rule), then parses the regular config array-of-struct style interface option settings so
* that both forms are supported.
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
int cf_opt_interface_list(struct config_interface_list *listp, const struct cf_om_node *node)
{
int result = cf_opt_config_interface_list(listp, node);
if (result == CFERROR)
return CFERROR;
if (node->text) {
const char *p;
const char *arg = NULL;
unsigned n = listp->ac;
for (p = node->text; n < NELS(listp->av); ++p) {
if (*p == '\0' || *p == ',' || isspace(*p)) {
if (arg) {
int len = p - arg;
if (len > 80) {
result |= CFSTRINGOVERFLOW;
goto bye;
}
char buf[len + 1];
strncpy(buf, arg, len)[len] = '\0';
int ret = cf_opt_network_interface(&listp->av[n].value, buf);
switch (ret) {
case CFERROR: return CFERROR;
case CFOK:
len = snprintf(listp->av[n].key, sizeof listp->av[n].key - 1, "%u", n);
listp->av[n].key[len] = '\0';
++n;
break;
default:
cf_warn_node(node, NULL, "invalid interface rule %s", alloca_str_toprint(buf)); \
result |= CFSUB(ret);
break;
}
arg = NULL;
if (!node->text)
return cf_opt_config_interface_list(listp, node);
const char *p;
const char *arg = NULL;
unsigned n = listp->ac;
int result = CFOK;
for (p = node->text; n < NELS(listp->av); ++p) {
if (*p == '\0' || *p == ',' || isspace(*p)) {
if (arg) {
int len = p - arg;
if (len > 80) {
result |= CFSTRINGOVERFLOW;
goto bye;
}
if (!*p)
char buf[len + 1];
strncpy(buf, arg, len)[len] = '\0';
int ret = cf_opt_network_interface_legacy(&listp->av[n].value, buf);
switch (ret) {
case CFERROR: return CFERROR;
case CFOK:
len = snprintf(listp->av[n].key, sizeof listp->av[n].key - 1, "%u", n);
listp->av[n].key[len] = '\0';
++n;
break;
} else if (!arg)
arg = p;
}
if (*p) {
result |= CFARRAYOVERFLOW;
goto bye;
}
assert(n <= NELS(listp->av));
listp->ac = n;
default:
cf_warn_node(node, NULL, "invalid interface rule %s", alloca_str_toprint(buf)); \
result |= CFSUB(ret);
break;
}
arg = NULL;
}
if (!*p)
break;
} else if (!arg)
arg = p;
}
if (*p) {
result |= CFARRAYOVERFLOW;
goto bye;
}
assert(n <= NELS(listp->av));
listp->ac = n;
bye:
if (listp->ac == 0)
result |= CFEMPTY;
else
result &= ~CFEMPTY;
return result;
}

View File

@ -297,7 +297,7 @@ END_STRUCT
ARRAY(interface_list,)
KEY_STRING(15, cf_opt_str)
VALUE_SUB_STRUCT(network_interface)
VALUE_NODE_STRUCT(network_interface, cf_opt_network_interface)
END_ARRAY(10)
// The top level.

View File

@ -25,6 +25,12 @@ setup() {
setup_servald
}
execute_servald_config_error() {
execute --stderr --exit-status=2 --core-backtrace --executable=$servald "$@"
assertStderrGrep --matches=1 --message="stderr of ($executed) contains exactly one error message" '^ERROR:'
assertStderrGrep --matches=1 --message="stderr of ($executed) contains one config error message" '^ERROR:.*config file'
}
doc_GetCreateInstanceDir="Get creates instance directory"
setup_GetCreateInstanceDir() {
setup
@ -148,4 +154,14 @@ test_DebugFlagAll() {
assertStderrGrep --matches=3 '\<echo:argv\['
}
doc_InterfacesLegacy="Legacy interfaces config option is supported"
test_InterfacesLegacy() {
executeOk_servald config set interfaces '+eth,-wifi,+'
executeOk_servald config set interfaces '+'
executeOk_servald config set interfaces '-'
executeOk_servald config set interfaces '+eth=ethernet:4111:9M, +wifi=wifi:4112:900K, -'
execute_servald_config_error config set interfaces '+eth=foo:4111:9M'
assertExitStatus --stderr '!=' 0
}
runTests "$@"

View File

@ -61,14 +61,14 @@ test_StartLogfile() {
tfw_cat log
}
doc_StartNoInterfaces="Starting server with no configured interfaces gives error"
doc_StartNoInterfaces="Starting server with no configured interfaces gives warning"
setup_StartNoInterfaces() {
setup
}
test_StartNoInterfaces() {
start_servald_server
sleep 0.1
assertGrep --message="log contains 'no interfaces' error message" "$instance_servald_log" '^ERROR:.*interfaces'
assertGrep --message="log contains 'no interfaces' warning" "$instance_servald_log" '^WARN:.*interfaces'
tfw_cat "$instance_servald_log"
}