summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/nm-macros-internal.h15
-rw-r--r--man/NetworkManager.conf.xml.in89
-rw-r--r--src/NetworkManagerUtils.c118
-rw-r--r--src/NetworkManagerUtils.h1
-rw-r--r--src/nm-config.c66
-rw-r--r--src/nm-config.h6
-rw-r--r--src/tests/config/Makefile.am1
-rw-r--r--src/tests/config/conf.d/20-config-enable-1.conf5
-rw-r--r--src/tests/config/test-config.c36
-rw-r--r--src/tests/test-general.c143
10 files changed, 474 insertions, 6 deletions
diff --git a/include/nm-macros-internal.h b/include/nm-macros-internal.h
index b1d75e68ed..0bf25821ad 100644
--- a/include/nm-macros-internal.h
+++ b/include/nm-macros-internal.h
@@ -286,4 +286,19 @@ nm_strstrip (char *str)
/*****************************************************************************/
+static inline guint
+nm_encode_version (guint major, guint minor, guint micro) {
+ /* analog to the preprocessor macro NM_ENCODE_VERSION(). */
+ return (major << 16) | (minor << 8) | micro;
+}
+
+static inline void
+nm_decode_version (guint version, guint *major, guint *minor, guint *micro) {
+ *major = (version & 0xFFFF0000u) >> 16;
+ *minor = (version & 0x0000FF00u) >> 8;
+ *micro = (version & 0x000000FFu);
+}
+
+/*****************************************************************************/
+
#endif /* __NM_MACROS_INTERNAL_H__ */
diff --git a/man/NetworkManager.conf.xml.in b/man/NetworkManager.conf.xml.in
index a8b7f3a38d..0fccc84dc6 100644
--- a/man/NetworkManager.conf.xml.in
+++ b/man/NetworkManager.conf.xml.in
@@ -703,6 +703,95 @@ ipv6.ip6-privacy=1
</refsect1>
<refsect1>
+ <title><literal>.config</literal> sections</title>
+ <para>This is a special section that contains options which apply
+ to the configuration file that contains the option.
+ </para>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term><varname>enable</varname></term>
+ <listitem>
+ <para>
+ Defaults to "<literal>true</literal>". If "<literal>false</literal>",
+ the configuration file will be skipped during loading.
+ Note that the main configation file <literal>NetworkManger.conf</literal>
+ cannot be disabled.
+<programlisting>
+# always skip loading the config file
+[.config]
+enable=false
+</programlisting>
+ </para>
+ <para>
+ You can also match against the version of NetworkManager. For example
+ the following are valid configurations:
+<programlisting>
+# only load on version 1.0.6
+[.config]
+enable=nm-version:1.0.6
+
+# load on all versions 1.0.x, but not 1.2.x
+[.config]
+enable=nm-version:1.0
+
+# only load on versions &gt;= 1.1.6. This does not match
+# with version 1.2.0 or 1.4.4. Only the last digit is considered.
+[.config]
+enable=nm-version-min:1.1.6
+
+# only load on versions &gt;= 1.2. Contrary to the previous
+# example, this also matches with 1.2.0, 1.2.10, 1.4.4, etc.
+[.config]
+enable=nm-version-min:1.2
+
+# Match against the maximum allowed version. The example matches
+# versions 1.2.0, 1.2.2, 1.2.4. Again, only the last version digit
+# is allowed to be smaller. So this would not match match on 1.1.10.
+[.config]
+enable=nm-version-max:1.2.6
+</programlisting>
+ </para>
+ <para>
+ You can also match against the value of the environment variable
+ <literal>NM_CONFIG_ENABLE_TAG</literal>, like:
+<programlisting>
+# always skip loading the file when running NetworkManager with
+# environment variable "NM_CONFIG_ENABLE_TAG=TAG1"
+[.config]
+enable=env:TAG1
+</programlisting>
+ </para>
+ <para>
+ More then one match can be specified. The configuration will be
+ enabled if one of the predicates matches ("or"). The special prefix "except:" can
+ be used to negate the match. Note that if one except-predicate
+ matches, the entire configuration will be disabled.
+ In other words, a except predicate always wins over other predicates.
+<programlisting>
+# enable the configuration either when the environment variable
+# is present or the version is at least 1.2.0.
+[.config]
+enable=env:TAG2,nm-version-min:1.2
+
+# enable the configuration for version &gt;= 1.2.0, but disable
+# it when the environment variable is set to "TAG3"
+[.config]
+enable=except:env:TAG3,nm-version-min:1.2
+
+# enable the configuration on &gt;= 1.3, &gt;= 1.2.6, and &gt;= 1.0.16.
+# Useful if a certain feature is only present since those releases.
+[.config]
+enable=nm-version-min:1.3,nm-version-min:1.2.6,nm-version-min:1.0.16
+</programlisting>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </refsect1>
+
+ <refsect1>
<title>Plugins</title>
<variablelist>
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
index 5d9df4ec8c..726ceb9b4a 100644
--- a/src/NetworkManagerUtils.c
+++ b/src/NetworkManagerUtils.c
@@ -1193,6 +1193,22 @@ nm_utils_find_helper(const char *progname, const char *try_first, GError **error
#define DEVICE_TYPE_TAG "type:"
#define SUBCHAN_TAG "s390-subchannels:"
#define EXCEPT_TAG "except:"
+#define MATCH_TAG_CONFIG_NM_VERSION "nm-version:"
+#define MATCH_TAG_CONFIG_NM_VERSION_MIN "nm-version-min:"
+#define MATCH_TAG_CONFIG_NM_VERSION_MAX "nm-version-max:"
+#define MATCH_TAG_CONFIG_ENV "env:"
+
+#define _spec_has_prefix(pspec, tag) \
+ ({ \
+ const char **_spec = (pspec); \
+ gboolean _has = FALSE; \
+ \
+ if (!g_ascii_strncasecmp (*_spec, (""tag), STRLEN (tag))) { \
+ *_spec += STRLEN (tag); \
+ _has = TRUE; \
+ } \
+ _has; \
+ })
static const char *
_match_except (const char *spec_str, gboolean *out_except)
@@ -1422,6 +1438,108 @@ nm_match_spec_s390_subchannels (const GSList *specs, const char *subchannels)
return match;
}
+static gboolean
+_match_config_nm_version (const char *str, const char *tag, guint cur_nm_version)
+{
+ gs_free char *s_ver = NULL;
+ gs_strfreev char **s_ver_tokens = NULL;
+ gint v_maj = -1, v_min = -1, v_mic = -1;
+ guint c_maj = -1, c_min = -1, c_mic = -1;
+ guint n_tokens;
+
+ s_ver = g_strdup (str);
+ g_strstrip (s_ver);
+
+ /* Let's be strict with the accepted format here. No funny stuff!! */
+
+ if (s_ver[strspn (s_ver, ".0123456789")] != '\0')
+ return FALSE;
+
+ s_ver_tokens = g_strsplit (s_ver, ".", -1);
+ n_tokens = g_strv_length (s_ver_tokens);
+ if (n_tokens == 0 || n_tokens > 3)
+ return FALSE;
+
+ v_maj = _nm_utils_ascii_str_to_int64 (s_ver_tokens[0], 10, 0, 0xFFFF, -1);
+ if (v_maj < 0)
+ return FALSE;
+ if (n_tokens >= 2) {
+ v_min = _nm_utils_ascii_str_to_int64 (s_ver_tokens[1], 10, 0, 0xFF, -1);
+ if (v_min < 0)
+ return FALSE;
+ }
+ if (n_tokens >= 3) {
+ v_mic = _nm_utils_ascii_str_to_int64 (s_ver_tokens[2], 10, 0, 0xFF, -1);
+ if (v_mic < 0)
+ return FALSE;
+ }
+
+ nm_decode_version (cur_nm_version, &c_maj, &c_min, &c_mic);
+
+#define CHECK_AND_RETURN_FALSE(cur, val, tag, is_last_digit) \
+ G_STMT_START { \
+ if (!strcmp (tag, MATCH_TAG_CONFIG_NM_VERSION_MIN)) { \
+ if (cur < val) \
+ return FALSE; \
+ } else if (!strcmp (tag, MATCH_TAG_CONFIG_NM_VERSION_MAX)) { \
+ if (cur > val) \
+ return FALSE; \
+ } else { \
+ if (cur != val) \
+ return FALSE; \
+ } \
+ if (!(is_last_digit)) { \
+ if (cur != val) \
+ return FALSE; \
+ } \
+ } G_STMT_END
+ if (v_mic >= 0)
+ CHECK_AND_RETURN_FALSE (c_mic, v_mic, tag, TRUE);
+ if (v_min >= 0)
+ CHECK_AND_RETURN_FALSE (c_min, v_min, tag, v_mic < 0);
+ CHECK_AND_RETURN_FALSE (c_maj, v_maj, tag, v_min < 0);
+ return TRUE;
+}
+
+NMMatchSpecMatchType
+nm_match_spec_match_config (const GSList *specs, guint cur_nm_version, const char *env)
+{
+ const GSList *iter;
+ NMMatchSpecMatchType match = NM_MATCH_SPEC_NO_MATCH;
+
+ if (!specs)
+ return NM_MATCH_SPEC_NO_MATCH;
+
+ for (iter = specs; iter; iter = g_slist_next (iter)) {
+ const char *spec_str = iter->data;
+ gboolean except;
+ gboolean v_match;
+
+ if (!spec_str || !*spec_str)
+ continue;
+
+ spec_str = _match_except (spec_str, &except);
+
+ if (_spec_has_prefix (&spec_str, MATCH_TAG_CONFIG_NM_VERSION))
+ v_match = _match_config_nm_version (spec_str, MATCH_TAG_CONFIG_NM_VERSION, cur_nm_version);
+ else if (_spec_has_prefix (&spec_str, MATCH_TAG_CONFIG_NM_VERSION_MIN))
+ v_match = _match_config_nm_version (spec_str, MATCH_TAG_CONFIG_NM_VERSION_MIN, cur_nm_version);
+ else if (_spec_has_prefix (&spec_str, MATCH_TAG_CONFIG_NM_VERSION_MAX))
+ v_match = _match_config_nm_version (spec_str, MATCH_TAG_CONFIG_NM_VERSION_MAX, cur_nm_version);
+ else if (_spec_has_prefix (&spec_str, MATCH_TAG_CONFIG_ENV))
+ v_match = env && env[0] && !strcmp (spec_str, env);
+ else
+ continue;
+
+ if (v_match) {
+ if (except)
+ return NM_MATCH_SPEC_NEG_MATCH;
+ match = NM_MATCH_SPEC_MATCH;
+ }
+ }
+ return match;
+}
+
/**
* nm_match_spec_split:
* @value: the string of device specs
diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h
index ceaa2c0c77..bf90e741cd 100644
--- a/src/NetworkManagerUtils.h
+++ b/src/NetworkManagerUtils.h
@@ -187,6 +187,7 @@ NMMatchSpecMatchType nm_match_spec_device_type (const GSList *specs, const char
NMMatchSpecMatchType nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr);
NMMatchSpecMatchType nm_match_spec_s390_subchannels (const GSList *specs, const char *subchannels);
NMMatchSpecMatchType nm_match_spec_interface_name (const GSList *specs, const char *interface_name);
+NMMatchSpecMatchType nm_match_spec_match_config (const GSList *specs, guint nm_version, const char *env);
GSList *nm_match_spec_split (const char *value);
char *nm_match_spec_join (GSList *specs);
diff --git a/src/nm-config.c b/src/nm-config.c
index fb9f0be988..f8c4ee817d 100644
--- a/src/nm-config.c
+++ b/src/nm-config.c
@@ -495,6 +495,47 @@ nm_config_create_keyfile ()
return keyfile;
}
+/* this is an external variable, to make loading testable. Other then that,
+ * no code is supposed to change this. */
+guint _nm_config_match_nm_version = NM_VERSION_CUR_STABLE;
+char *_nm_config_match_env = NULL;
+
+static gboolean
+ignore_config_snippet (GKeyFile *keyfile, gboolean is_base_config)
+{
+ GSList *specs;
+ gboolean as_bool;
+ NMMatchSpecMatchType match_type;
+
+ if (is_base_config)
+ return FALSE;
+
+ if (!g_key_file_has_key (keyfile, NM_CONFIG_KEYFILE_GROUP_CONFIG, NM_CONFIG_KEYFILE_KEY_CONFIG_ENABLE, NULL))
+ return FALSE;
+
+ /* first, let's try to parse the value as plain boolean. If that is possible, we don't treat
+ * the value as match-spec. */
+ as_bool = nm_config_keyfile_get_boolean (keyfile, NM_CONFIG_KEYFILE_GROUP_CONFIG, NM_CONFIG_KEYFILE_KEY_CONFIG_ENABLE, -1);
+ if (as_bool != -1)
+ return !as_bool;
+
+ if (G_UNLIKELY (!_nm_config_match_env)) {
+ const char *e;
+
+ e = g_getenv ("NM_CONFIG_ENABLE_TAG");
+ _nm_config_match_env = g_strdup (e ? e : "");
+ }
+
+ /* second, interpret the value as match-spec. */
+ specs = nm_config_get_match_spec (keyfile, NM_CONFIG_KEYFILE_GROUP_CONFIG, NM_CONFIG_KEYFILE_KEY_CONFIG_ENABLE, NULL);
+ match_type = nm_match_spec_match_config (specs,
+ _nm_config_match_nm_version,
+ _nm_config_match_env);
+ g_slist_free_full (specs, g_free);
+
+ return match_type != NM_MATCH_SPEC_MATCH;
+}
+
static int
_sort_groups_cmp (const char **pa, const char **pb, gpointer dummy)
{
@@ -568,7 +609,7 @@ _setting_is_string_list (const char *group, const char *key)
}
static gboolean
-read_config (GKeyFile *keyfile, const char *dirname, const char *path, GError **error)
+read_config (GKeyFile *keyfile, gboolean is_base_config, const char *dirname, const char *path, GError **error)
{
GKeyFile *kf;
char **groups, **keys;
@@ -598,6 +639,16 @@ read_config (GKeyFile *keyfile, const char *dirname, const char *path, GError **
return FALSE;
}
+ if (ignore_config_snippet (kf, is_base_config)) {
+ g_key_file_free (kf);
+ return TRUE;
+ }
+
+ /* the config-group is internal to every configuration snippets. It doesn't make sense
+ * to merge the into the global configuration, and it doesn't make sense to preserve the
+ * group beyond this point. */
+ g_key_file_remove_group (keyfile, NM_CONFIG_KEYFILE_GROUP_CONFIG, NULL);
+
/* Override the current settings with the new ones */
groups = g_key_file_get_groups (kf, &ngroups);
if (!groups)
@@ -744,7 +795,7 @@ read_base_config (GKeyFile *keyfile,
/* Try a user-specified config file first */
if (cli_config_main_file) {
/* Bad user-specific config file path is a hard error */
- if (read_config (keyfile, NULL, cli_config_main_file, error)) {
+ if (read_config (keyfile, TRUE, NULL, cli_config_main_file, error)) {
*out_config_main_file = g_strdup (cli_config_main_file);
return TRUE;
} else
@@ -759,7 +810,7 @@ read_base_config (GKeyFile *keyfile,
*/
/* Try deprecated nm-system-settings.conf first */
- if (read_config (keyfile, NULL, DEFAULT_CONFIG_MAIN_FILE_OLD, &my_error)) {
+ if (read_config (keyfile, TRUE, NULL, DEFAULT_CONFIG_MAIN_FILE_OLD, &my_error)) {
*out_config_main_file = g_strdup (DEFAULT_CONFIG_MAIN_FILE_OLD);
return TRUE;
}
@@ -772,7 +823,7 @@ read_base_config (GKeyFile *keyfile,
g_clear_error (&my_error);
/* Try the standard config file location next */
- if (read_config (keyfile, NULL, DEFAULT_CONFIG_MAIN_FILE, &my_error)) {
+ if (read_config (keyfile, TRUE, NULL, DEFAULT_CONFIG_MAIN_FILE, &my_error)) {
*out_config_main_file = g_strdup (DEFAULT_CONFIG_MAIN_FILE);
return TRUE;
}
@@ -878,7 +929,7 @@ read_entire_config (const NMConfigCmdLineOptions *cli,
continue;
}
- if (!read_config (keyfile, system_config_dir, filename, error)) {
+ if (!read_config (keyfile, FALSE, system_config_dir, filename, error)) {
g_key_file_free (keyfile);
return NULL;
}
@@ -894,7 +945,7 @@ read_entire_config (const NMConfigCmdLineOptions *cli,
g_assert (o_config_main_file);
for (i = 0; i < confs->len; i++) {
- if (!read_config (keyfile, config_dir, confs->pdata[i], error)) {
+ if (!read_config (keyfile, FALSE, config_dir, confs->pdata[i], error)) {
g_key_file_free (keyfile);
return NULL;
}
@@ -1067,6 +1118,9 @@ intern_config_read (const char *filename,
const char *group = groups[g];
gboolean is_intern, is_atomic;
+ if (!strcmp (group, NM_CONFIG_KEYFILE_GROUP_CONFIG))
+ continue;
+
keys = g_key_file_get_keys (keyfile, group, NULL, NULL);
if (!keys)
continue;
diff --git a/src/nm-config.h b/src/nm-config.h
index 46b2ac85ff..59a3e854b2 100644
--- a/src/nm-config.h
+++ b/src/nm-config.h
@@ -56,6 +56,7 @@ G_BEGIN_DECLS
#define NM_CONFIG_KEYFILE_GROUP_LOGGING "logging"
#define NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY "connectivity"
#define NM_CONFIG_KEYFILE_GROUP_GLOBAL_DNS "global-dns"
+#define NM_CONFIG_KEYFILE_GROUP_CONFIG ".config"
#define NM_CONFIG_KEYFILE_GROUP_KEYFILE "keyfile"
#define NM_CONFIG_KEYFILE_GROUP_IFUPDOWN "ifupdown"
@@ -63,6 +64,7 @@ G_BEGIN_DECLS
#define NM_CONFIG_KEYFILE_KEY_LOGGING_BACKEND "backend"
#define NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_ENABLE "enable"
+#define NM_CONFIG_KEYFILE_KEY_CONFIG_ENABLE "enable"
#define NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS ".was"
#define NM_CONFIG_KEYFILE_KEY_IFNET_AUTO_REFRESH "auto_refresh"
#define NM_CONFIG_KEYFILE_KEY_IFNET_MANAGED "managed"
@@ -149,6 +151,10 @@ void _nm_config_sort_groups (char **groups, gsize ngroups);
gboolean nm_config_set_global_dns (NMConfig *self, NMGlobalDnsConfig *global_dns, GError **error);
+/* internal defines ... */
+extern guint _nm_config_match_nm_version;
+extern char *_nm_config_match_env;
+
G_END_DECLS
#endif /* __NETWORKMANAGER_CONFIG_H__ */
diff --git a/src/tests/config/Makefile.am b/src/tests/config/Makefile.am
index 6ad9876f1f..4f3d7805d8 100644
--- a/src/tests/config/Makefile.am
+++ b/src/tests/config/Makefile.am
@@ -34,4 +34,5 @@ EXTRA_DIST = \
global-dns-invalid.conf \
conf.d/00-overrides.conf \
conf.d/10-more.conf \
+ conf.d/20-config-enable-1.conf \
conf.d/90-last.conf
diff --git a/src/tests/config/conf.d/20-config-enable-1.conf b/src/tests/config/conf.d/20-config-enable-1.conf
new file mode 100644
index 0000000000..e6800f5236
--- /dev/null
+++ b/src/tests/config/conf.d/20-config-enable-1.conf
@@ -0,0 +1,5 @@
+[.config]
+enable=nm-version:1.5.32,env:test-match-env-1
+
+[test-group-config-enable-1]
+key1=enabled
diff --git a/src/tests/config/test-config.c b/src/tests/config/test-config.c
index d3b2db6920..5eee306a9e 100644
--- a/src/tests/config/test-config.c
+++ b/src/tests/config/test-config.c
@@ -905,6 +905,40 @@ test_config_signal (void)
/*****************************************************************************/
+static void
+test_config_enable (void)
+{
+ gs_unref_object NMConfig *config = NULL;
+ guint match_nm_version = _nm_config_match_nm_version;
+ char *match_env = g_strdup (_nm_config_match_env);
+
+ g_clear_pointer (&_nm_config_match_env, g_free);
+ _nm_config_match_env = g_strdup ("something-else");
+
+ _nm_config_match_nm_version = nm_encode_version (1, 3, 4);
+ config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", NULL, SRCDIR "/conf.d", "", NULL);
+ assert_config_value (nm_config_get_data_orig (config), "test-group-config-enable-1", "key1", NULL);
+ g_clear_object (&config);
+
+ _nm_config_match_nm_version = nm_encode_version (1, 5, 32);
+ config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", NULL, SRCDIR "/conf.d", "", NULL);
+ assert_config_value (nm_config_get_data_orig (config), "test-group-config-enable-1", "key1", "enabled");
+ g_clear_object (&config);
+
+ _nm_config_match_nm_version = nm_encode_version (1, 5, 3);
+ g_clear_pointer (&_nm_config_match_env, g_free);
+ _nm_config_match_env = g_strdup ("test-match-env-1");
+ config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", NULL, SRCDIR "/conf.d", "", NULL);
+ assert_config_value (nm_config_get_data_orig (config), "test-group-config-enable-1", "key1", "enabled");
+ g_clear_object (&config);
+
+ _nm_config_match_nm_version = match_nm_version;
+ g_clear_pointer (&_nm_config_match_env, g_free);
+ _nm_config_match_env = match_env;
+}
+
+/*****************************************************************************/
+
NMTST_DEFINE ();
int
@@ -933,6 +967,8 @@ main (int argc, char **argv)
g_test_add_func ("/config/signal", test_config_signal);
+ g_test_add_func ("/config/enable", test_config_enable);
+
/* This one has to come last, because it leaves its values in
* nm-config.c's global variables, and there's no way to reset
* those to NULL.
diff --git a/src/tests/test-general.c b/src/tests/test-general.c
index ba3d958fb3..3c2a33a97d 100644
--- a/src/tests/test-general.c
+++ b/src/tests/test-general.c
@@ -773,6 +773,148 @@ test_nm_match_spec_interface_name (void)
/*******************************************/
+static void
+_do_test_match_spec_match_config (const char *file, gint line, const char *spec_str, guint version, guint v_maj, guint v_min, guint v_mic, NMMatchSpecMatchType expected)
+{
+ GSList *specs;
+ NMMatchSpecMatchType match_result;
+ guint c_maj, c_min, c_mic;
+
+ g_assert_cmpint (version, ==, nm_encode_version (v_maj, v_min, v_mic));
+
+ nm_decode_version (version, &c_maj, &c_min, &c_mic);
+ g_assert_cmpint (c_maj, ==, c_maj);
+ g_assert_cmpint (c_min, ==, c_min);
+ g_assert_cmpint (c_mic, ==, c_mic);
+
+ specs = nm_match_spec_split (spec_str);
+
+ match_result = nm_match_spec_match_config (specs, version, NULL);
+
+ if (expected != match_result)
+ g_error ("%s:%d: faild comparing \"%s\" with %u.%u.%u. Expected %d, but got %d", file, line, spec_str, v_maj, v_min, v_mic, (int) expected, (int) match_result);
+
+ if (g_slist_length (specs) == 1 && match_result != NM_MATCH_SPEC_NEG_MATCH) {
+ /* there is only one spec in the list... test that we match except: */
+ char *sss = g_strdup_printf ("except:%s", (char *) specs->data);
+ GSList *specs2 = g_slist_append (NULL, sss);
+ NMMatchSpecMatchType match_result2;
+
+
+ match_result2 = nm_match_spec_match_config (specs2, version, NULL);
+ if (match_result == NM_MATCH_SPEC_NO_MATCH)
+ g_assert_cmpint (match_result2, ==, NM_MATCH_SPEC_NO_MATCH);
+ else
+ g_assert_cmpint (match_result2, ==, NM_MATCH_SPEC_NEG_MATCH);
+
+ g_slist_free_full (specs2, g_free);
+ }
+
+ g_slist_free_full (specs, g_free);
+}
+#define do_test_match_spec_match_config(spec, v_maj, v_min, v_mic, expected) \
+ _do_test_match_spec_match_config (__FILE__, __LINE__, (""spec), NM_ENCODE_VERSION ((v_maj), (v_min), (v_mic)), (v_maj), (v_min), (v_mic), (expected))
+
+static void
+test_nm_match_spec_match_config (void)
+{
+ do_test_match_spec_match_config ("", 1, 2, 3, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version:1.2.3", 1, 2, 2, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version:1.2.3", 1, 2, 3, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version:1.2.3", 1, 2, 4, NM_MATCH_SPEC_NO_MATCH);
+
+ do_test_match_spec_match_config ("nm-version:1.2", 1, 1, 2, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version:1.2", 1, 2, 0, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version:1.2", 1, 2, 2, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version:1.2", 1, 2, 3, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version:1.2", 1, 2, 4, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version:1.2", 1, 3, 0, NM_MATCH_SPEC_NO_MATCH);
+
+ do_test_match_spec_match_config ("nm-version-min:1.2.3", 0, 2, 30, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.2.3", 1, 1, 1, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.2.3", 1, 2, 2, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.2.3", 1, 2, 3, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.2.3", 1, 2, 5, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.2.3", 1, 3, 0, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.2.3", 1, 3, 30, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.2.3", 1, 4, 30, NM_MATCH_SPEC_NO_MATCH);
+
+ do_test_match_spec_match_config ("nm-version-min:1.2", 0, 2, 30, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.2", 1, 1, 1, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.2", 1, 2, 0, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.2", 1, 2, 3, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.2", 1, 2, 5, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.2", 1, 3, 0, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.2", 1, 3, 30, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.2", 1, 4, 30, NM_MATCH_SPEC_MATCH);
+
+ do_test_match_spec_match_config ("nm-version-min:1", 0, 2, 30, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1", 1, 1, 1, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1", 1, 2, 0, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1", 1, 2, 3, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1", 1, 2, 5, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1", 1, 3, 0, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1", 1, 3, 30, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1", 1, 4, 30, NM_MATCH_SPEC_MATCH);
+
+
+ do_test_match_spec_match_config ("nm-version-max:1.2.3", 0, 2, 30, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version-max:1.2.3", 1, 1, 1, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version-max:1.2.3", 1, 2, 0, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-max:1.2.3", 1, 2, 1, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-max:1.2.3", 1, 2, 2, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-max:1.2.3", 1, 2, 3, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-max:1.2.3", 1, 2, 5, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version-max:1.2.3", 1, 3, 0, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version-max:1.2.3", 1, 3, 30, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version-max:1.2.3", 1, 4, 30, NM_MATCH_SPEC_NO_MATCH);
+
+ do_test_match_spec_match_config ("nm-version-max:1.2", 0, 2, 30, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version-max:1.2", 1, 1, 1, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-max:1.2", 1, 2, 0, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-max:1.2", 1, 2, 3, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-max:1.2", 1, 2, 5, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-max:1.2", 1, 3, 0, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version-max:1.2", 1, 3, 30, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version-max:1.2", 1, 4, 30, NM_MATCH_SPEC_NO_MATCH);
+
+ do_test_match_spec_match_config ("nm-version-max:1", 0, 2, 30, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-max:1", 1, 1, 1, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-max:1", 1, 2, 0, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-max:1", 1, 2, 3, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-max:1", 1, 2, 5, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-max:1", 1, 3, 0, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-max:1", 1, 3, 30, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-max:1", 1, 4, 30, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-max:1", 2, 4, 30, NM_MATCH_SPEC_NO_MATCH);
+
+ do_test_match_spec_match_config ("except:nm-version:1.4.8", 1, 6, 0, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.6,except:nm-version:1.4.8", 1, 6, 0, NM_MATCH_SPEC_MATCH);
+
+ do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 2, 0, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 2, 0, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 2, 15, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 2, 16, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 2, 17, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 2, 20, NM_MATCH_SPEC_MATCH);
+
+ do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 3, 0, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 4, 0, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 4, 5, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 4, 6, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 4, 7, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 4, 8, NM_MATCH_SPEC_NEG_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 4, 9, NM_MATCH_SPEC_MATCH);
+
+ do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 5, 0, NM_MATCH_SPEC_NO_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 6, 0, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 6, 5, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 7, 7, NM_MATCH_SPEC_MATCH);
+ do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 8, 8, NM_MATCH_SPEC_MATCH);
+}
+
+/*******************************************/
+
NMTST_DEFINE ();
int
@@ -796,6 +938,7 @@ main (int argc, char **argv)
g_test_add_func ("/general/connection-sort/autoconnect-priority", test_connection_sort_autoconnect_priority);
g_test_add_func ("/general/nm_match_spec_interface_name", test_nm_match_spec_interface_name);
+ g_test_add_func ("/general/nm_match_spec_match_config", test_nm_match_spec_match_config);
return g_test_run ();
}