]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network,udev: fix multiple invert matching lines
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 22 Jun 2019 18:18:52 +0000 (03:18 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 30 Jun 2019 16:24:42 +0000 (01:24 +0900)
Previously,
```
[Match]
Name=!aaa
Name=!bbb
```
does not work. This fixes the issue.

src/libsystemd-network/network-internal.c
src/libsystemd-network/network-internal.h
src/network/networkd-network-gperf.gperf
src/network/test-networkd-conf.c
src/udev/net/link-config-gperf.gperf

index 9a1b2fba89b80b87771aea47f9d52493619014e1..60227cf2864265a6d1fa6fc655bbd5d5d97752cd 100644 (file)
@@ -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,
index ebfb1c3c754909a086000febc25d075311fc5163..958938d3fe2bf6c289664686a38a9779df3ebf3e 100644 (file)
@@ -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);
 
index 2986ff1123d92c95cd3c9b356f8864410abba513..1b3d4ff1bae752d7e298e6a31bbd56ed8532cd47 100644 (file)
@@ -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)
index dfb41f801b359d1b65063cc57e06b9c6ef6967a6..4b599c430bd73ccb6193f729486026bfef060d16 100644 (file)
@@ -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);
index 9698211d1da826ddc00a4b1acc1f17c534b3ee25..2bdb3dcb5ec596833cce3001e09bb3736c813b61 100644 (file)
@@ -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)