summaryrefslogtreecommitdiff
path: root/src/nm-core-utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-core-utils.c')
-rw-r--r--src/nm-core-utils.c187
1 files changed, 114 insertions, 73 deletions
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c
index 8019775a96..f5699b7e95 100644
--- a/src/nm-core-utils.c
+++ b/src/nm-core-utils.c
@@ -1698,30 +1698,109 @@ nm_match_spec_join (GSList *specs)
return g_string_free (str, FALSE);
}
+static void
+_pattern_parse (const char *input,
+ const char **out_pattern,
+ gboolean *out_is_inverted,
+ gboolean *out_is_mandatory)
+{
+ gboolean is_inverted = FALSE;
+ gboolean is_mandatory = FALSE;
+
+ if (input[0] == '&') {
+ input++;
+ is_mandatory = TRUE;
+ if (input[0] == '!') {
+ input++;
+ is_inverted = TRUE;
+ }
+ goto out;
+ }
+
+ if (input[0] == '|') {
+ input++;
+ if (input[0] == '!') {
+ input++;
+ is_inverted = TRUE;
+ }
+ goto out;
+ }
+
+ if (input[0] == '!') {
+ input++;
+ is_inverted = TRUE;
+ is_mandatory = TRUE;
+ goto out;
+ }
+
+out:
+ if (input[0] == '\\')
+ input++;
+
+ *out_pattern = input;
+ *out_is_inverted = is_inverted;
+ *out_is_mandatory = is_mandatory;
+}
+
gboolean
nm_wildcard_match_check (const char *str,
const char *const *patterns,
guint num_patterns)
{
- gsize i, neg = 0;
+ gboolean has_optional = FALSE;
+ gboolean has_any_optional = FALSE;
+ guint i;
for (i = 0; i < num_patterns; i++) {
- if (patterns[i][0] == '!') {
- neg++;
- if (!str)
- continue;
- if (!fnmatch (patterns[i] + 1, str, 0))
+ gboolean is_inverted;
+ gboolean is_mandatory;
+ gboolean match;
+ const char *p;
+
+ _pattern_parse (patterns[i], &p, &is_inverted, &is_mandatory);
+
+ match = (fnmatch (p, str, 0) == 0);
+ if (is_inverted)
+ match = !match;
+
+ if (is_mandatory) {
+ if (!match)
return FALSE;
+ } else {
+ has_any_optional = TRUE;
+ if (match)
+ has_optional = TRUE;
}
}
- if (neg == num_patterns)
- return TRUE;
+ return has_optional
+ || !has_any_optional;
+}
- if (str) {
- for (i = 0; i < num_patterns; i++) {
- if ( patterns[i][0] != '!'
- && !fnmatch (patterns[i], str, 0))
+/*****************************************************************************/
+
+static gboolean
+_kernel_cmdline_match (const char *const*proc_cmdline,
+ const char *pattern)
+{
+
+ if (proc_cmdline) {
+ gboolean has_equal = (!!strchr (pattern, '='));
+ gsize pattern_len = strlen (pattern);
+
+ for (; proc_cmdline[0]; proc_cmdline++) {
+ const char *c = proc_cmdline[0];
+
+ if (has_equal) {
+ /* if pattern contains '=' compare full key=value */
+ if (nm_streq (c, pattern))
+ return TRUE;
+ continue;
+ }
+
+ /* otherwise consider pattern as key only */
+ if ( strncmp (c, pattern, pattern_len) == 0
+ && NM_IN_SET (c[pattern_len], '\0', '='))
return TRUE;
}
}
@@ -1729,86 +1808,48 @@ nm_wildcard_match_check (const char *str,
return FALSE;
}
-/*****************************************************************************/
-
gboolean
nm_utils_kernel_cmdline_match_check (const char *const*proc_cmdline,
const char *const*patterns,
guint num_patterns,
GError **error)
{
- gboolean pos_patterns = FALSE;
+ gboolean has_optional = FALSE;
+ gboolean has_any_optional = FALSE;
guint i;
for (i = 0; i < num_patterns; i++) {
- const char *patterns_i = patterns[i];
- const char *const*proc_cmdline_i;
- gboolean negative = FALSE;
- gboolean found = FALSE;
- const char *equal;
-
- if (patterns_i[0] == '!') {
- ++patterns_i;
- negative = TRUE;
- } else
- pos_patterns = TRUE;
+ const char *element = patterns[i];
+ gboolean is_inverted = FALSE;
+ gboolean is_mandatory = FALSE;
+ gboolean match;
+ const char *p;
- equal = strchr (patterns_i, '=');
+ _pattern_parse (element, &p, &is_inverted, &is_mandatory);
- proc_cmdline_i = proc_cmdline;
- while (*proc_cmdline_i) {
- if (equal) {
- /* if pattern contains = compare full key=value */
- found = nm_streq (*proc_cmdline_i, patterns_i);
- } else {
- gsize l = strlen (patterns_i);
+ match = _kernel_cmdline_match (proc_cmdline, p);
+ if (is_inverted)
+ match = !match;
- /* otherwise consider pattern as key only */
- if ( strncmp (*proc_cmdline_i, patterns_i, l) == 0
- && NM_IN_SET ((*proc_cmdline_i)[l], '\0', '='))
- found = TRUE;
- }
- if ( found
- && negative) {
- /* first negative match */
+ if (is_mandatory) {
+ if (!match) {
nm_utils_error_set (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
"device does not satisfy match.kernel-command-line property %s",
patterns[i]);
return FALSE;
}
- proc_cmdline_i++;
+ } else {
+ has_any_optional = TRUE;
+ if (match)
+ has_optional = TRUE;
}
+ }
- /* FIXME(release-blocker): match.interface-name and match.driver have the meaning,
- * that any of the matches may yield success. For match.kernel-command-line, we
- * do here that all must match. This inconsistency is undesired.
- *
- * 1) improve gtk-doc documentation explaining how these options match.
- *
- * 2) possibly unify the behavior so that kernel-command-line behaves like other
- * matches (and ANY may match). Note that this would be contrary to systemd's
- * Conditions, which by default requires that ALL conditions match (AND). We
- * should be consistent within our match options, and not with systemd here.
- *
- * 2b) Note that systemd supports special token like "=|", to indicate that
- * ANY behavior. If we want, we could also introduce two special prefixes
- * "&..." and "|...", to support either. It's slightly complicated how
- * these work in combinations with "!".
- * Unless we fully decide what we do about this, NMSettingMatch.verify() should
- * reject matches that start with '&' or '|', because these will be reserved for
- * future use.
- *
- * 3) while fixing this, this code should move to a separate function so we
- * can unit test the match of kernel command lines.
- */
- if ( pos_patterns
- && !found) {
- /* positive patterns configured but no match */
- nm_utils_error_set (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
- "device does not satisfy any match.kernel-command-line property %s...",
- patterns[0]);
- return FALSE;
- }
+ if ( !has_optional
+ && has_any_optional) {
+ nm_utils_error_set (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
+ "device does not satisfy any match.kernel-command-line property");
+ return FALSE;
}
return TRUE;