diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index c5ba817579f..9dd02c30604 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -1334,11 +1334,11 @@ ConditionKernelVersion= may be used to check whether the kernel version (as reported by uname -r) matches a certain expression (or if prefixed with the exclamation mark does not match it). The argument must be a list of (potentially quoted) - expressions. For each of the expressions, if it starts with one of <, - <=, = (or ==), != - (or <>), >=, > a relative - version comparison is done, otherwise the specified string is matched with shell-style - globs. + expressions. Each expression starts with one of <, <=, + = (or ==), != (or + <>), >=, > for a relative + version comparison, or =$, !=$ for a shell-style glob + match. If no operator is specified =$ is implied. Note that using the kernel version string is an unreliable way to determine which features are supported by a kernel, because of the widespread practice of backporting drivers, features, and diff --git a/src/shared/condition.c b/src/shared/condition.c index 2d9979b9c45..f893937156f 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -206,30 +206,30 @@ static int condition_test_kernel_version(Condition *c, char **env) { break; s = strstrip(word); - operator = parse_compare_operator(&s, 0); - if (operator >= 0) { - s += strspn(s, WHITESPACE); - if (isempty(s)) { - if (first) { - /* For backwards compatibility, allow whitespace between the operator and - * value, without quoting, but only in the first expression. */ - word = mfree(word); - r = extract_first_word(&p, &word, NULL, 0); - if (r < 0) - return log_debug_errno(r, "Failed to parse condition string \"%s\": %m", p); - if (r == 0) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unexpected end of expression: %s", p); - s = word; - } else + operator = parse_compare_operator(&s, COMPARE_ALLOW_FNMATCH); + if (operator < 0) /* No prefix? Then treat as glob string */ + operator = COMPARE_FNMATCH_EQUAL; + + s += strspn(s, WHITESPACE); + if (isempty(s)) { + if (first) { + /* For backwards compatibility, allow whitespace between the operator and + * value, without quoting, but only in the first expression. */ + word = mfree(word); + r = extract_first_word(&p, &word, NULL, 0); + if (r < 0) + return log_debug_errno(r, "Failed to parse condition string \"%s\": %m", p); + if (r == 0) return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unexpected end of expression: %s", p); - } + s = word; + } else + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unexpected end of expression: %s", p); + } - r = test_order(strverscmp_improved(u.release, s), operator); - } else - /* No prefix? Then treat as glob string */ - r = fnmatch(s, u.release, 0) == 0; - - if (r == 0) + r = version_or_fnmatch_compare(operator, u.release, s); + if (r < 0) + return r; + if (!r) return false; first = false;