summary refs log tree commit diff
path: root/src/systemd/src/libsystemd-network/network-internal.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/systemd/src/libsystemd-network/network-internal.c')
-rw-r--r--src/systemd/src/libsystemd-network/network-internal.c253
1 files changed, 218 insertions, 35 deletions
diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c
index de219a6d..209ce884 100644
--- a/src/systemd/src/libsystemd-network/network-internal.c
+++ b/src/systemd/src/libsystemd-network/network-internal.c
@@ -14,6 +14,7 @@
 #include "conf-parser.h"
 #include "device-util.h"
 #include "dhcp-lease-internal.h"
+#include "env-util.h"
 #include "ether-addr-util.h"
 #include "hexdecoct.h"
 #include "log.h"
@@ -27,7 +28,7 @@
 #include "util.h"
 
 #if 0 /* NM_IGNORED */
-const char *net_get_name(sd_device *device) {
+const char *net_get_name_persistent(sd_device *device) {
         const char *name, *field;
 
         assert(device);
@@ -42,7 +43,7 @@ const char *net_get_name(sd_device *device) {
 
 #define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a)
 
-int net_get_unique_predictable_data(sd_device *device, uint64_t *result) {
+int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *result) {
         size_t l, sz = 0;
         const char *name;
         int r;
@@ -50,10 +51,10 @@ int net_get_unique_predictable_data(sd_device *device, uint64_t *result) {
 
         assert(device);
 
-        /* net_get_name() will return one of the device names based on stable information about the
-         * device. If this is not available, we fall back to using the device name. */
-        name = net_get_name(device);
-        if (!name)
+        /* net_get_name_persistent() will return one of the device names based on stable information about
+         * the device. If this is not available, we fall back to using the actual device name. */
+        name = net_get_name_persistent(device);
+        if (!name && use_sysname)
                 (void) sd_device_get_sysname(device, &name);
         if (!name)
                 return log_device_debug_errno(device, SYNTHETIC_ERRNO(ENODATA),
@@ -76,26 +77,66 @@ int net_get_unique_predictable_data(sd_device *device, uint64_t *result) {
         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;
+
+                if (!invert)
+                        has_positive_rule = true;
+
+                if (string && fnmatch(q, string, 0) == 0) {
+                        if (invert)
+                                return false;
+                        else
+                                match = true;
+                }
+        }
+
+        return has_positive_rule ? match : true;
+}
+
+static int net_condition_test_property(char * const *match_property, sd_device *device) {
+        char * const *p;
+
+        if (strv_isempty(match_property))
+                return true;
+
+        STRV_FOREACH(p, match_property) {
+                _cleanup_free_ char *key = NULL;
+                const char *val, *dev_val;
+                bool invert, v;
+
+                invert = **p == '!';
+
+                val = strchr(*p + invert, '=');
+                if (!val)
+                        return -EINVAL;
 
-                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];
+                key = strndup(*p + invert, val - *p - invert);
+                if (!key)
+                        return -ENOMEM;
+
+                val++;
 
-                return !string || !strv_fnmatch(patterns, string, 0);
+                v = device &&
+                        sd_device_get_property_value(device, key, &dev_val) >= 0 &&
+                        fnmatch(val, dev_val, 0) == 0;
+
+                if (invert ? v : !v)
+                        return false;
         }
 
-        return string && strv_fnmatch(raw_patterns, string, 0);
+        return true;
 }
 
 bool net_match_config(Set *match_mac,
@@ -103,12 +144,25 @@ bool net_match_config(Set *match_mac,
                       char * const *match_drivers,
                       char * const *match_types,
                       char * const *match_names,
+                      char * const *match_property,
+                      sd_device *device,
                       const struct ether_addr *dev_mac,
-                      const char *dev_path,
-                      const char *dev_driver,
-                      const char *dev_type,
                       const char *dev_name) {
 
+        const char *dev_path = NULL, *dev_driver = NULL, *dev_type = NULL, *mac_str;
+
+        if (device) {
+                (void) sd_device_get_property_value(device, "ID_PATH", &dev_path);
+                (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &dev_driver);
+                (void) sd_device_get_devtype(device, &dev_type);
+
+                if (!dev_name)
+                        (void) sd_device_get_sysname(device, &dev_name);
+                if (!dev_mac &&
+                    sd_device_get_sysattr_value(device, "address", &mac_str) >= 0)
+                        dev_mac = ether_aton(mac_str);
+        }
+
         if (match_mac && (!dev_mac || !set_contains(match_mac, dev_mac)))
                 return false;
 
@@ -124,6 +178,9 @@ bool net_match_config(Set *match_mac,
         if (!net_condition_test_strv(match_names, dev_name))
                 return false;
 
+        if (!net_condition_test_property(match_property, device))
+                return false;
+
         return true;
 }
 
@@ -167,7 +224,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,
@@ -179,7 +236,9 @@ int config_parse_ifnames(
                 void *data,
                 void *userdata) {
 
+        const char *p = rvalue;
         char ***sv = data;
+        bool invert;
         int r;
 
         assert(filename);
@@ -187,30 +246,154 @@ 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);
+                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_match_property(
+                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, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
+                if (r == 0)
+                        return 0;
+                if (r == -ENOMEM)
+                        return log_oom();
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, 0,
+                                   "Invalid syntax, ignoring: %s", rvalue);
+                        return 0;
+                }
+
+                if (!env_assignment_is_valid(word)) {
+                        log_syntax(unit, LOG_ERR, filename, line, 0,
+                                   "Invalid property or value, ignoring assignment: %s", word);
+                        continue;
+                }
+
+                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_ifalias(const char *unit,
@@ -616,7 +799,7 @@ int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t siz
         assert(data);
 
         hex_buf = hexmem(data, size);
-        if (hex_buf == NULL)
+        if (!hex_buf)
                 return -ENOMEM;
 
         fprintf(f, "%s=%s\n", key, hex_buf);