From ba22ff13a07a9478921c5342ef07dd5dcdd0e7d1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 18 Mar 2019 16:43:33 +0100 Subject: [PATCH] condition: split out kernel version comparison steps Let's split out the operator parsing and the final verdict determination. That way we can reuse this logic for other purposes later on. --- src/shared/condition.c | 97 +++++++++++++++++++++++++----------------- 1 file changed, 58 insertions(+), 39 deletions(-) diff --git a/src/shared/condition.c b/src/shared/condition.c index fb77966264e..12c685acd5d 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -128,70 +128,89 @@ static int condition_test_kernel_command_line(Condition *c) { return false; } -static int condition_test_kernel_version(Condition *c) { - enum { - /* Listed in order of checking. Note that some comparators are prefixes of others, hence the longest - * should be listed first. */ - LOWER_OR_EQUAL, - GREATER_OR_EQUAL, - LOWER, - GREATER, - EQUAL, - _ORDER_MAX, - }; +typedef enum { + /* Listed in order of checking. Note that some comparators are prefixes of others, hence the longest + * should be listed first. */ + ORDER_LOWER_OR_EQUAL, + ORDER_GREATER_OR_EQUAL, + ORDER_LOWER, + ORDER_GREATER, + ORDER_EQUAL, + _ORDER_MAX, + _ORDER_INVALID = -1 +} OrderOperator; + +static OrderOperator parse_order(const char **s) { static const char *const prefix[_ORDER_MAX] = { - [LOWER_OR_EQUAL] = "<=", - [GREATER_OR_EQUAL] = ">=", - [LOWER] = "<", - [GREATER] = ">", - [EQUAL] = "=", + [ORDER_LOWER_OR_EQUAL] = "<=", + [ORDER_GREATER_OR_EQUAL] = ">=", + [ORDER_LOWER] = "<", + [ORDER_GREATER] = ">", + [ORDER_EQUAL] = "=", }; - const char *p = NULL; - struct utsname u; - size_t i; - int k; - - assert(c); - assert(c->parameter); - assert(c->type == CONDITION_KERNEL_VERSION); - assert_se(uname(&u) >= 0); + OrderOperator i; for (i = 0; i < _ORDER_MAX; i++) { - p = startswith(c->parameter, prefix[i]); - if (p) - break; + const char *e; + + e = startswith(*s, prefix[i]); + if (e) { + *s = e; + return i; + } } - /* No prefix? Then treat as glob string */ - if (!p) - return fnmatch(skip_leading_chars(c->parameter, NULL), u.release, 0) == 0; + return _ORDER_INVALID; +} - k = str_verscmp(u.release, skip_leading_chars(p, NULL)); +static bool test_order(int k, OrderOperator p) { - switch (i) { + switch (p) { - case LOWER: + case ORDER_LOWER: return k < 0; - case LOWER_OR_EQUAL: + case ORDER_LOWER_OR_EQUAL: return k <= 0; - case EQUAL: + case ORDER_EQUAL: return k == 0; - case GREATER_OR_EQUAL: + case ORDER_GREATER_OR_EQUAL: return k >= 0; - case GREATER: + case ORDER_GREATER: return k > 0; default: - assert_not_reached("Can't compare"); + assert_not_reached("unknown order"); + } } +static int condition_test_kernel_version(Condition *c) { + OrderOperator order; + struct utsname u; + const char *p; + + assert(c); + assert(c->parameter); + assert(c->type == CONDITION_KERNEL_VERSION); + + assert_se(uname(&u) >= 0); + + p = c->parameter; + order = parse_order(&p); + + /* No prefix? Then treat as glob string */ + if (order < 0) + return fnmatch(skip_leading_chars(c->parameter, NULL), u.release, 0) == 0; + + return test_order(str_verscmp(u.release, skip_leading_chars(p, NULL)), order); +} + static int condition_test_user(Condition *c) { uid_t id; int r; -- 2.39.5