config: allow to enable/disable configuration snippets
Support a new configuration option [.config] enable=<ENABLED> for configuration snippets. This new [.config] section is only relevant within the snippet itself and it is not merged into the combined configuration. Currently only the "enable" key is supported. If the "enable" key is missing, it obviously defaults to being enabled. It allows snippets to be skipped from loading. The main configuration "NetworkManager.conf" cannot be skipped. <ENABLED> can be a boolean value (false), to skip a configuration snippet from loading. It can also be a string to match against the NetworkManager version, like "enable=nm-version-min:1.1,nm-version-min:1.0.6" There are several motivations for this: - the user can disable an entire configuration snippet by toggeling one entry. This generalizes the functionality of the global-dns.enable setting, but in a way that applies to configuration on a per-file basis. - for developing, we often switch between different versions of NetworkManager. Thus, we might want to use different configuration. E.g. before global-dns options, I want to use "dns=none" and manage resolv.conf myself. Now, I can use global-dns setting to do that. That can be achieved with something like the following (not exactly, it's an example only): [.config] enable=nm-version-min:1.1 [main] dns=default [global-dns-domain-*] nameserver=127.0.0.1 Arguably, this would be more awesome, if we would bump our micro devel version (1.1.0) more often while developing 1.2.0 (*hint*). - in principle, packages could drop configuration snippets and enable them based on the NetworkManager version. - with the "env:" spec, you can enable/disable snippets by configuring an environment variable. Again, useful for testing and developing.
This commit is contained in:
@@ -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
|
||||
|
Reference in New Issue
Block a user