From 54a8423788ec3cc6240959ab9f5cdac40baf047a Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 23 Jun 2019 03:18:52 +0900 Subject: [PATCH] network,udev: fix multiple invert matching lines Previously, ``` [Match] Name=!aaa Name=!bbb ``` does not work. This fixes the issue. --- src/libsystemd-network/network-internal.c | 126 +++++++++++++++++----- src/libsystemd-network/network-internal.h | 3 +- src/network/networkd-network-gperf.gperf | 8 +- src/network/test-networkd-conf.c | 2 +- src/udev/net/link-config-gperf.gperf | 8 +- 5 files changed, 111 insertions(+), 36 deletions(-) diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index 9a1b2fba89b..60227cf2864 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -73,26 +73,32 @@ int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_ return 0; } -static bool net_condition_test_strv(char * const *raw_patterns, - const char *string) { - if (strv_isempty(raw_patterns)) +static bool net_condition_test_strv(char * const *patterns, const char *string) { + char * const *p; + bool match = false, has_positive_rule = false; + + if (strv_isempty(patterns)) return true; - /* If the patterns begin with "!", edit it out and negate the test. */ - if (raw_patterns[0][0] == '!') { - char **patterns; - size_t i, length; + STRV_FOREACH(p, patterns) { + const char *q = *p; + bool invert; + + invert = *q == '!'; + q += invert; - length = strv_length(raw_patterns) + 1; /* Include the NULL. */ - patterns = newa(char*, length); - patterns[0] = raw_patterns[0] + 1; /* Skip the "!". */ - for (i = 1; i < length; i++) - patterns[i] = raw_patterns[i]; + if (!invert) + has_positive_rule = true; - return !string || !strv_fnmatch(patterns, string, 0); + if (string && fnmatch(q, string, 0) == 0) { + if (invert) + return false; + else + match = true; + } } - return string && strv_fnmatch(raw_patterns, string, 0); + return has_positive_rule ? match : true; } bool net_match_config(Set *match_mac, @@ -164,7 +170,7 @@ int config_parse_net_condition(const char *unit, return 0; } -int config_parse_ifnames( +int config_parse_match_strv( const char *unit, const char *filename, unsigned line, @@ -176,7 +182,9 @@ int config_parse_ifnames( void *data, void *userdata) { + const char *p = rvalue; char ***sv = data; + bool invert; int r; assert(filename); @@ -184,30 +192,96 @@ int config_parse_ifnames( assert(rvalue); assert(data); + if (isempty(rvalue)) { + *sv = strv_free(*sv); + return 0; + } + + invert = *p == '!'; + p += invert; + for (;;) { - _cleanup_free_ char *word = NULL; + _cleanup_free_ char *word = NULL, *k = NULL; - r = extract_first_word(&rvalue, &word, NULL, 0); + r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE); + if (r == 0) + return 0; + if (r == -ENOMEM) + return log_oom(); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse interface name list: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue); return 0; } + + if (invert) { + k = strjoin("!", word); + if (!k) + return log_oom(); + } else + k = TAKE_PTR(word); + + r = strv_consume(sv, TAKE_PTR(k)); + if (r < 0) + return log_oom(); + } +} + +int config_parse_match_ifnames( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + const char *p = rvalue; + char ***sv = data; + bool invert; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + invert = *p == '!'; + p += invert; + + for (;;) { + _cleanup_free_ char *word = NULL, *k = NULL; + + r = extract_first_word(&p, &word, NULL, 0); if (r == 0) - break; + return 0; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, + "Failed to parse interface name list: %s", rvalue); + return 0; + } if (!ifname_valid(word)) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue); - return 0; + log_syntax(unit, LOG_ERR, filename, line, 0, + "Interface name is not valid or too long, ignoring assignment: %s", word); + continue; } - r = strv_push(sv, word); + if (invert) { + k = strjoin("!", word); + if (!k) + return log_oom(); + } else + k = TAKE_PTR(word); + + r = strv_consume(sv, TAKE_PTR(k)); if (r < 0) return log_oom(); - - word = NULL; } - - return 0; } int config_parse_ifalias(const char *unit, diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h index ebfb1c3c754..958938d3fe2 100644 --- a/src/libsystemd-network/network-internal.h +++ b/src/libsystemd-network/network-internal.h @@ -28,7 +28,8 @@ bool net_match_config(Set *match_mac, CONFIG_PARSER_PROTOTYPE(config_parse_net_condition); CONFIG_PARSER_PROTOTYPE(config_parse_hwaddr); CONFIG_PARSER_PROTOTYPE(config_parse_hwaddrs); -CONFIG_PARSER_PROTOTYPE(config_parse_ifnames); +CONFIG_PARSER_PROTOTYPE(config_parse_match_strv); +CONFIG_PARSER_PROTOTYPE(config_parse_match_ifnames); CONFIG_PARSER_PROTOTYPE(config_parse_ifalias); CONFIG_PARSER_PROTOTYPE(config_parse_bridge_port_priority); diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 2986ff1123d..1b3d4ff1bae 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -22,10 +22,10 @@ struct ConfigPerfItem; %includes %% Match.MACAddress, config_parse_hwaddrs, 0, offsetof(Network, match_mac) -Match.Path, config_parse_strv, 0, offsetof(Network, match_path) -Match.Driver, config_parse_strv, 0, offsetof(Network, match_driver) -Match.Type, config_parse_strv, 0, offsetof(Network, match_type) -Match.Name, config_parse_ifnames, 0, offsetof(Network, match_name) +Match.Path, config_parse_match_strv, 0, offsetof(Network, match_path) +Match.Driver, config_parse_match_strv, 0, offsetof(Network, match_driver) +Match.Type, config_parse_match_strv, 0, offsetof(Network, match_type) +Match.Name, config_parse_match_ifnames, 0, offsetof(Network, match_name) Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(Network, conditions) Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(Network, conditions) Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(Network, conditions) diff --git a/src/network/test-networkd-conf.c b/src/network/test-networkd-conf.c index dfb41f801b3..4b599c430bd 100644 --- a/src/network/test-networkd-conf.c +++ b/src/network/test-networkd-conf.c @@ -174,7 +174,7 @@ static void test_config_parse_address_one(const char *rvalue, int family, unsign assert_se(network = new0(Network, 1)); network->n_ref = 1; assert_se(network->filename = strdup("hogehoge.network")); - assert_se(config_parse_ifnames("network", "filename", 1, "section", 1, "Name", 0, "*", &network->match_name, network) == 0); + assert_se(config_parse_match_ifnames("network", "filename", 1, "section", 1, "Name", 0, "*", &network->match_name, network) == 0); assert_se(config_parse_address("network", "filename", 1, "section", 1, "Address", 0, rvalue, network, network) == 0); assert_se(network->n_static_addresses == 1); assert_se(network_verify(network) >= 0); diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf index 9698211d1da..2bdb3dcb5ec 100644 --- a/src/udev/net/link-config-gperf.gperf +++ b/src/udev/net/link-config-gperf.gperf @@ -20,10 +20,10 @@ struct ConfigPerfItem; %includes %% Match.MACAddress, config_parse_hwaddrs, 0, offsetof(link_config, match_mac) -Match.OriginalName, config_parse_ifnames, 0, offsetof(link_config, match_name) -Match.Path, config_parse_strv, 0, offsetof(link_config, match_path) -Match.Driver, config_parse_strv, 0, offsetof(link_config, match_driver) -Match.Type, config_parse_strv, 0, offsetof(link_config, match_type) +Match.OriginalName, config_parse_match_ifnames, 0, offsetof(link_config, match_name) +Match.Path, config_parse_match_strv, 0, offsetof(link_config, match_path) +Match.Driver, config_parse_match_strv, 0, offsetof(link_config, match_driver) +Match.Type, config_parse_match_strv, 0, offsetof(link_config, match_type) Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(link_config, conditions) Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(link_config, conditions) Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(link_config, conditions) -- 2.39.2