]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
condition: split out order operator enum
authorLennart Poettering <lennart@poettering.net>
Fri, 26 Aug 2022 14:10:40 +0000 (16:10 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 1 Sep 2022 21:12:34 +0000 (23:12 +0200)
Let's move the operator enum into its own .c/.h file, so that we can
reuse it elsewhere, in particular systemd-analyze's compare-versions
logic.

Let's rename the concept CompareOperator, since it is nowadays
genericlaly about both order *and* fnmatch comparisons, hence just
naming it "order" is misleading.

src/shared/compare-operator.c [new file with mode: 0644]
src/shared/compare-operator.h [new file with mode: 0644]
src/shared/condition.c
src/shared/meson.build

diff --git a/src/shared/compare-operator.c b/src/shared/compare-operator.c
new file mode 100644 (file)
index 0000000..f9796ab
--- /dev/null
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "compare-operator.h"
+#include "string-util.h"
+
+CompareOperator parse_compare_operator(const char **s, bool allow_fnmatch) {
+        static const char *const prefix[_COMPARE_OPERATOR_MAX] = {
+                [COMPARE_FNMATCH_EQUAL] = "=$",
+                [COMPARE_FNMATCH_UNEQUAL] = "!=$",
+
+                [COMPARE_LOWER_OR_EQUAL] = "<=",
+                [COMPARE_GREATER_OR_EQUAL] = ">=",
+                [COMPARE_LOWER] = "<",
+                [COMPARE_GREATER] = ">",
+                [COMPARE_EQUAL] = "=",
+                [COMPARE_UNEQUAL] = "!=",
+        };
+
+        assert(s);
+
+        if (!*s) /* Hmm, we already reached the end, for example because extract_first_word() and
+                  * parse_compare_operator() are use on the same string? */
+                return _COMPARE_OPERATOR_INVALID;
+
+        for (CompareOperator i = 0; i < _COMPARE_OPERATOR_MAX; i++) {
+                const char *e;
+
+                e = startswith(*s, prefix[i]);
+                if (e) {
+                        if (!allow_fnmatch && COMPARE_OPERATOR_IS_FNMATCH(i))
+                                break;
+                        *s = e;
+                        return i;
+                }
+        }
+
+        return _COMPARE_OPERATOR_INVALID;
+}
diff --git a/src/shared/compare-operator.h b/src/shared/compare-operator.h
new file mode 100644 (file)
index 0000000..2efd4ca
--- /dev/null
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <errno.h>
+#include <stdbool.h>
+
+typedef enum CompareOperator {
+        /* Listed in order of checking. Note that some comparators are prefixes of others, hence the longest
+         * should be listed first. */
+
+        /* fnmatch() compare operators */
+        _COMPARE_OPERATOR_FNMATCH_FIRST,
+        COMPARE_FNMATCH_EQUAL = _COMPARE_OPERATOR_FNMATCH_FIRST,
+        COMPARE_FNMATCH_UNEQUAL,
+        _COMPARE_OPERATOR_FNMATCH_LAST = COMPARE_FNMATCH_UNEQUAL,
+
+        /* Order compare operators */
+        _COMPARE_OPERATOR_ORDER_FIRST,
+        COMPARE_LOWER_OR_EQUAL = _COMPARE_OPERATOR_ORDER_FIRST,
+        COMPARE_GREATER_OR_EQUAL,
+        COMPARE_LOWER,
+        COMPARE_GREATER,
+        COMPARE_EQUAL,
+        COMPARE_UNEQUAL,
+        _COMPARE_OPERATOR_ORDER_LAST = COMPARE_UNEQUAL,
+
+        _COMPARE_OPERATOR_MAX,
+        _COMPARE_OPERATOR_INVALID = -EINVAL,
+} CompareOperator;
+
+static inline bool COMPARE_OPERATOR_IS_FNMATCH(CompareOperator c) {
+        return c >= _COMPARE_OPERATOR_FNMATCH_FIRST && c <= _COMPARE_OPERATOR_FNMATCH_LAST;
+}
+
+static inline bool COMPARE_OPERATOR_IS_ORDER(CompareOperator c) {
+        return c >= _COMPARE_OPERATOR_ORDER_FIRST && c <= _COMPARE_OPERATOR_ORDER_LAST;
+}
+
+CompareOperator parse_compare_operator(const char **s, bool allow_fnmatch);
index 00d732e6ef63ba3c1609d9929fab5de7c360db57..dc0d6d8eb5c9fe2c70542d2588d320aba58acd39 100644 (file)
@@ -21,6 +21,7 @@
 #include "blockdev-util.h"
 #include "cap-list.h"
 #include "cgroup-util.h"
+#include "compare-operator.h"
 #include "condition.h"
 #include "cpu-set-util.h"
 #include "creds-util.h"
@@ -182,70 +183,25 @@ static int condition_test_credential(Condition *c, char **env) {
         return false;
 }
 
-typedef enum {
-        /* Listed in order of checking. Note that some comparators are prefixes of others, hence the longest
-         * should be listed first. */
-        _ORDER_FNMATCH_FIRST,
-        ORDER_FNMATCH_EQUAL = _ORDER_FNMATCH_FIRST,
-        ORDER_FNMATCH_UNEQUAL,
-        _ORDER_FNMATCH_LAST = ORDER_FNMATCH_UNEQUAL,
-        ORDER_LOWER_OR_EQUAL,
-        ORDER_GREATER_OR_EQUAL,
-        ORDER_LOWER,
-        ORDER_GREATER,
-        ORDER_EQUAL,
-        ORDER_UNEQUAL,
-        _ORDER_MAX,
-        _ORDER_INVALID = -EINVAL,
-} OrderOperator;
-
-static OrderOperator parse_order(const char **s, bool allow_fnmatch) {
-        static const char *const prefix[_ORDER_MAX] = {
-                [ORDER_FNMATCH_EQUAL] = "=$",
-                [ORDER_FNMATCH_UNEQUAL] = "!=$",
-                [ORDER_LOWER_OR_EQUAL] = "<=",
-                [ORDER_GREATER_OR_EQUAL] = ">=",
-                [ORDER_LOWER] = "<",
-                [ORDER_GREATER] = ">",
-                [ORDER_EQUAL] = "=",
-                [ORDER_UNEQUAL] = "!=",
-        };
-
-        for (OrderOperator i = 0; i < _ORDER_MAX; i++) {
-                const char *e;
-
-                e = startswith(*s, prefix[i]);
-                if (e) {
-                        if (!allow_fnmatch && (i >= _ORDER_FNMATCH_FIRST && i <= _ORDER_FNMATCH_LAST))
-                                break;
-                        *s = e;
-                        return i;
-                }
-        }
-
-        return _ORDER_INVALID;
-}
-
-static bool test_order(int k, OrderOperator p) {
-
+static bool test_order(int k, CompareOperator p) {
         switch (p) {
 
-        case ORDER_LOWER:
+        case COMPARE_LOWER:
                 return k < 0;
 
-        case ORDER_LOWER_OR_EQUAL:
+        case COMPARE_LOWER_OR_EQUAL:
                 return k <= 0;
 
-        case ORDER_EQUAL:
+        case COMPARE_EQUAL:
                 return k == 0;
 
-        case ORDER_UNEQUAL:
+        case COMPARE_UNEQUAL:
                 return k != 0;
 
-        case ORDER_GREATER_OR_EQUAL:
+        case COMPARE_GREATER_OR_EQUAL:
                 return k >= 0;
 
-        case ORDER_GREATER:
+        case COMPARE_GREATER:
                 return k > 0;
 
         default:
@@ -255,7 +211,7 @@ static bool test_order(int k, OrderOperator p) {
 }
 
 static int condition_test_kernel_version(Condition *c, char **env) {
-        OrderOperator order;
+        CompareOperator operator;
         struct utsname u;
         bool first = true;
 
@@ -277,8 +233,8 @@ static int condition_test_kernel_version(Condition *c, char **env) {
                         break;
 
                 s = strstrip(word);
-                order = parse_order(&s, /* allow_fnmatch= */ false);
-                if (order >= 0) {
+                operator = parse_compare_operator(&s, /* allow_fnmatch= */ false);
+                if (operator >= 0) {
                         s += strspn(s, WHITESPACE);
                         if (isempty(s)) {
                                 if (first) {
@@ -295,7 +251,7 @@ static int condition_test_kernel_version(Condition *c, char **env) {
                                         return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unexpected end of expression: %s", p);
                         }
 
-                        r = test_order(strverscmp_improved(u.release, s), order);
+                        r = test_order(strverscmp_improved(u.release, s), operator);
                 } else
                         /* No prefix? Then treat as glob string */
                         r = fnmatch(s, u.release, 0) == 0;
@@ -317,7 +273,7 @@ static int condition_test_osrelease(Condition *c, char **env) {
 
         for (const char *parameter = ASSERT_PTR(c->parameter);;) {
                 _cleanup_free_ char *key = NULL, *condition = NULL, *actual_value = NULL;
-                OrderOperator order;
+                CompareOperator operator;
                 const char *word;
                 bool matches;
 
@@ -327,7 +283,7 @@ static int condition_test_osrelease(Condition *c, char **env) {
                 if (r == 0)
                         break;
 
-                /* parse_order() needs the string to start with the comparators */
+                /* parse_compare_operator() needs the string to start with the comparators */
                 word = condition;
                 r = extract_first_word(&word, &key, "!<=>", EXTRACT_RETAIN_SEPARATORS);
                 if (r < 0)
@@ -338,8 +294,8 @@ static int condition_test_osrelease(Condition *c, char **env) {
                                         "Failed to parse parameter, key/value format expected: %m");
 
                 /* Do not allow whitespace after the separator, as that's not a valid os-release format */
-                order = parse_order(&word, /* allow_fnmatch= */ false);
-                if (order < 0 || isempty(word) || strchr(WHITESPACE, *word) != NULL)
+                operator = parse_compare_operator(&word, /* allow_fnmatch= */ false);
+                if (operator < 0 || isempty(word) || strchr(WHITESPACE, *word) != NULL)
                         return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
                                         "Failed to parse parameter, key/value format expected: %m");
 
@@ -348,12 +304,12 @@ static int condition_test_osrelease(Condition *c, char **env) {
                         return log_debug_errno(r, "Failed to parse os-release: %m");
 
                 /* Might not be comparing versions, so do exact string matching */
-                if (order == ORDER_EQUAL)
+                if (operator == COMPARE_EQUAL)
                         matches = streq_ptr(actual_value, word);
-                else if (order == ORDER_UNEQUAL)
+                else if (operator == COMPARE_UNEQUAL)
                         matches = !streq_ptr(actual_value, word);
                 else
-                        matches = test_order(strverscmp_improved(actual_value, word), order);
+                        matches = test_order(strverscmp_improved(actual_value, word), operator);
 
                 if (!matches)
                         return false;
@@ -363,7 +319,7 @@ static int condition_test_osrelease(Condition *c, char **env) {
 }
 
 static int condition_test_memory(Condition *c, char **env) {
-        OrderOperator order;
+        CompareOperator operator;
         uint64_t m, k;
         const char *p;
         int r;
@@ -375,19 +331,19 @@ static int condition_test_memory(Condition *c, char **env) {
         m = physical_memory();
 
         p = c->parameter;
-        order = parse_order(&p, /* allow_fnmatch= */ false);
-        if (order < 0)
-                order = ORDER_GREATER_OR_EQUAL; /* default to >= check, if nothing is specified. */
+        operator = parse_compare_operator(&p, /* allow_fnmatch= */ false);
+        if (operator < 0)
+                operator = COMPARE_GREATER_OR_EQUAL; /* default to >= check, if nothing is specified. */
 
         r = parse_size(p, 1024, &k);
         if (r < 0)
                 return log_debug_errno(r, "Failed to parse size '%s': %m", p);
 
-        return test_order(CMP(m, k), order);
+        return test_order(CMP(m, k), operator);
 }
 
 static int condition_test_cpus(Condition *c, char **env) {
-        OrderOperator order;
+        CompareOperator operator;
         const char *p;
         unsigned k;
         int r, n;
@@ -401,15 +357,15 @@ static int condition_test_cpus(Condition *c, char **env) {
                 return log_debug_errno(n, "Failed to determine CPUs in affinity mask: %m");
 
         p = c->parameter;
-        order = parse_order(&p, /* allow_fnmatch= */ false);
-        if (order < 0)
-                order = ORDER_GREATER_OR_EQUAL; /* default to >= check, if nothing is specified. */
+        operator = parse_compare_operator(&p, /* allow_fnmatch= */ false);
+        if (operator < 0)
+                operator = COMPARE_GREATER_OR_EQUAL; /* default to >= check, if nothing is specified. */
 
         r = safe_atou(p, &k);
         if (r < 0)
                 return log_debug_errno(r, "Failed to parse number of CPUs: %m");
 
-        return test_order(CMP((unsigned) n, k), order);
+        return test_order(CMP((unsigned) n, k), operator);
 }
 
 static int condition_test_user(Condition *c, char **env) {
@@ -589,7 +545,7 @@ static int condition_test_firmware_devicetree_compatible(const char *dtcarg) {
 
 static int condition_test_firmware_smbios_field(const char *expression) {
         _cleanup_free_ char *field = NULL, *expected_value = NULL, *actual_value = NULL;
-        OrderOperator operator;
+        CompareOperator operator;
         int r;
 
         assert(expression);
@@ -605,7 +561,7 @@ static int condition_test_firmware_smbios_field(const char *expression) {
         delete_trailing_chars(field, WHITESPACE);
 
         /* Parse operator */
-        operator = parse_order(&expression, /* allow_fnmatch= */ true);
+        operator = parse_compare_operator(&expression, /* allow_fnmatch= */ true);
         if (operator < 0)
                 return operator;
 
@@ -633,9 +589,9 @@ static int condition_test_firmware_smbios_field(const char *expression) {
         delete_trailing_chars(actual_value, WHITESPACE);
 
         /* Finally compare actual and expected value */
-        if (operator == ORDER_FNMATCH_EQUAL)
+        if (operator == COMPARE_FNMATCH_EQUAL)
                 return fnmatch(expected_value, actual_value, FNM_EXTMATCH) != FNM_NOMATCH;
-        if (operator == ORDER_FNMATCH_UNEQUAL)
+        if (operator == COMPARE_FNMATCH_UNEQUAL)
                 return fnmatch(expected_value, actual_value, FNM_EXTMATCH) == FNM_NOMATCH;
         return test_order(strverscmp_improved(actual_value, expected_value), operator);
 }
index 426a87b70cffe9844164612cdef9c4a900e53f18..abac8a7eb8b3bce389c4ba2331e0742a28f36d51 100644 (file)
@@ -71,6 +71,8 @@ shared_sources = files(
         'clean-ipc.h',
         'clock-util.c',
         'clock-util.h',
+        'compare-operator.c',
+        'compare-operator.h',
         'condition.c',
         'condition.h',
         'conf-parser.c',