From: Lennart Poettering Date: Fri, 26 Aug 2022 14:10:40 +0000 (+0200) Subject: condition: split out order operator enum X-Git-Tag: v252-rc1~273^2~16 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a8835c1190ca944ea0fa5f541ee1933d55188b9a;p=thirdparty%2Fsystemd.git condition: split out order operator enum 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. --- diff --git a/src/shared/compare-operator.c b/src/shared/compare-operator.c new file mode 100644 index 00000000000..f9796ab80c0 --- /dev/null +++ b/src/shared/compare-operator.c @@ -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 index 00000000000..2efd4cae688 --- /dev/null +++ b/src/shared/compare-operator.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include +#include + +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); diff --git a/src/shared/condition.c b/src/shared/condition.c index 00d732e6ef6..dc0d6d8eb5c 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -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); } diff --git a/src/shared/meson.build b/src/shared/meson.build index 426a87b70cf..abac8a7eb8b 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -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',