return false;
}
-static int condition_test_kernel_version(Condition *c, char **env) {
+static int condition_test_version_cmp(const char *condition, const char *ver) {
CompareOperator operator;
- struct utsname u;
bool first = true;
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_KERNEL_VERSION);
-
- assert_se(uname(&u) >= 0);
+ assert(condition);
+ assert(ver);
- for (const char *p = c->parameter;;) {
+ for (const char *p = condition;;) {
_cleanup_free_ char *word = NULL;
const char *s;
int r;
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unexpected end of expression: %s", p);
}
- r = version_or_fnmatch_compare(operator, u.release, s);
+ r = version_or_fnmatch_compare(operator, ver, s);
if (r < 0)
return r;
if (!r)
return true;
}
+static int condition_test_version(Condition *c, char **env) {
+ int r;
+
+ assert(c);
+ assert(c->type == CONDITION_VERSION);
+
+ /* An empty condition is considered true. */
+ if (isempty(c->parameter))
+ return true;
+
+ const char *p = c->parameter;
+ _cleanup_free_ char *word = NULL;
+ r = extract_first_word(&p, &word, COMPARE_OPERATOR_WITH_FNMATCH_CHARS WHITESPACE,
+ EXTRACT_DONT_COALESCE_SEPARATORS|EXTRACT_RETAIN_SEPARATORS);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to parse compare predicate \"%s\": %m", p);
+ if (r == 0)
+ return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Missing right operand in condition: %s", c->parameter);
+
+ if (streq(word, "systemd"))
+ return condition_test_version_cmp(p, STRINGIFY(PROJECT_VERSION));
+
+ /* if no predicate has been set, default to "kernel" and use the whole parameter as condition */
+ if (!streq(word, "kernel"))
+ p = c->parameter;
+
+ struct utsname u;
+ assert_se(uname(&u) >= 0);
+ return condition_test_version_cmp(p, u.release);
+}
+
static int condition_test_osrelease(Condition *c, char **env) {
int r;
[CONDITION_FILE_NOT_EMPTY] = condition_test_file_not_empty,
[CONDITION_FILE_IS_EXECUTABLE] = condition_test_file_is_executable,
[CONDITION_KERNEL_COMMAND_LINE] = condition_test_kernel_command_line,
- [CONDITION_KERNEL_VERSION] = condition_test_kernel_version,
+ [CONDITION_VERSION] = condition_test_version,
[CONDITION_CREDENTIAL] = condition_test_credential,
[CONDITION_VIRTUALIZATION] = condition_test_virtualization,
[CONDITION_SECURITY] = condition_test_security,
condition_dump(c, f, prefix, to_string);
}
-static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
+static const char* const _condition_type_table[_CONDITION_TYPE_MAX] = {
[CONDITION_ARCHITECTURE] = "ConditionArchitecture",
[CONDITION_FIRMWARE] = "ConditionFirmware",
[CONDITION_VIRTUALIZATION] = "ConditionVirtualization",
[CONDITION_HOST] = "ConditionHost",
[CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine",
- [CONDITION_KERNEL_VERSION] = "ConditionKernelVersion",
+ [CONDITION_VERSION] = "ConditionVersion",
[CONDITION_CREDENTIAL] = "ConditionCredential",
[CONDITION_SECURITY] = "ConditionSecurity",
[CONDITION_CAPABILITY] = "ConditionCapability",
[CONDITION_KERNEL_MODULE_LOADED] = "ConditionKernelModuleLoaded",
};
-DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType);
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP(_condition_type, ConditionType);
+
+const char* condition_type_to_string(ConditionType t) {
+ return _condition_type_to_string(t);
+}
+
+ConditionType condition_type_from_string(const char *s) {
+ /* for backward compatibility */
+ if (streq_ptr(s, "ConditionKernelVersion"))
+ return CONDITION_VERSION;
-static const char* const assert_type_table[_CONDITION_TYPE_MAX] = {
+ return _condition_type_from_string(s);
+}
+
+static const char* const _assert_type_table[_CONDITION_TYPE_MAX] = {
[CONDITION_ARCHITECTURE] = "AssertArchitecture",
[CONDITION_FIRMWARE] = "AssertFirmware",
[CONDITION_VIRTUALIZATION] = "AssertVirtualization",
[CONDITION_HOST] = "AssertHost",
[CONDITION_KERNEL_COMMAND_LINE] = "AssertKernelCommandLine",
- [CONDITION_KERNEL_VERSION] = "AssertKernelVersion",
+ [CONDITION_VERSION] = "AssertVersion",
[CONDITION_CREDENTIAL] = "AssertCredential",
[CONDITION_SECURITY] = "AssertSecurity",
[CONDITION_CAPABILITY] = "AssertCapability",
[CONDITION_KERNEL_MODULE_LOADED] = "AssertKernelModuleLoaded",
};
-DEFINE_STRING_TABLE_LOOKUP(assert_type, ConditionType);
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP(_assert_type, ConditionType);
+
+const char* assert_type_to_string(ConditionType t) {
+ return _assert_type_to_string(t);
+}
+
+ConditionType assert_type_from_string(const char *s) {
+ /* for backward compatibility */
+ if (streq_ptr(s, "AssertKernelVersion"))
+ return CONDITION_VERSION;
+
+ return _assert_type_from_string(s);
+}
static const char* const condition_result_table[_CONDITION_RESULT_MAX] = {
[CONDITION_UNTESTED] = "untested",
struct utsname u;
const char *v;
- ASSERT_NOT_NULL((condition = condition_new(CONDITION_KERNEL_VERSION, "*thisreallyshouldntbeinthekernelversion*", false, false)));
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "*thisreallyshouldntbeinthekernelversion*", false, false)));
ASSERT_OK_ZERO(condition_test(condition, environ));
condition_free(condition);
- ASSERT_NOT_NULL((condition = condition_new(CONDITION_KERNEL_VERSION, "*", false, false)));
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "*", false, false)));
ASSERT_OK_POSITIVE(condition_test(condition, environ));
condition_free(condition);
/* An artificially empty condition. It evaluates to true, but normally
* such condition cannot be created, because the condition list is reset instead. */
- ASSERT_NOT_NULL((condition = condition_new(CONDITION_KERNEL_VERSION, "", false, false)));
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "", false, false)));
ASSERT_OK_POSITIVE(condition_test(condition, environ));
condition_free(condition);
ASSERT_OK_ERRNO(uname(&u));
- ASSERT_NOT_NULL((condition = condition_new(CONDITION_KERNEL_VERSION, u.release, false, false)));
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, u.release, false, false)));
ASSERT_OK_POSITIVE(condition_test(condition, environ));
condition_free(condition);
strshorten(u.release, 4);
strcpy(strchr(u.release, 0), "*");
- ASSERT_NOT_NULL((condition = condition_new(CONDITION_KERNEL_VERSION, u.release, false, false)));
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, u.release, false, false)));
ASSERT_OK_POSITIVE(condition_test(condition, environ));
condition_free(condition);
/* 0.1.2 would be a very very very old kernel */
- ASSERT_NOT_NULL((condition = condition_new(CONDITION_KERNEL_VERSION, "> 0.1.2", false, false)));
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "> 0.1.2", false, false)));
ASSERT_OK_POSITIVE(condition_test(condition, environ));
condition_free(condition);
- ASSERT_NOT_NULL((condition = condition_new(CONDITION_KERNEL_VERSION, ">0.1.2", false, false)));
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, ">0.1.2", false, false)));
ASSERT_OK_POSITIVE(condition_test(condition, environ));
condition_free(condition);
- ASSERT_NOT_NULL((condition = condition_new(CONDITION_KERNEL_VERSION, "'>0.1.2' '<9.0.0'", false, false)));
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "'>0.1.2' '<9.0.0'", false, false)));
ASSERT_OK_POSITIVE(condition_test(condition, environ));
condition_free(condition);
- ASSERT_NOT_NULL((condition = condition_new(CONDITION_KERNEL_VERSION, "> 0.1.2 < 9.0.0", false, false)));
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "> 0.1.2 < 9.0.0", false, false)));
ASSERT_ERROR(condition_test(condition, environ), EINVAL);
condition_free(condition);
- ASSERT_NOT_NULL((condition = condition_new(CONDITION_KERNEL_VERSION, ">", false, false)));
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, ">", false, false)));
ASSERT_ERROR(condition_test(condition, environ), EINVAL);
condition_free(condition);
- ASSERT_NOT_NULL((condition = condition_new(CONDITION_KERNEL_VERSION, ">= 0.1.2", false, false)));
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, ">= 0.1.2", false, false)));
ASSERT_OK_POSITIVE(condition_test(condition, environ));
condition_free(condition);
- ASSERT_NOT_NULL((condition = condition_new(CONDITION_KERNEL_VERSION, "< 0.1.2", false, false)));
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "< 0.1.2", false, false)));
ASSERT_OK_ZERO(condition_test(condition, environ));
condition_free(condition);
- ASSERT_NOT_NULL((condition = condition_new(CONDITION_KERNEL_VERSION, "<= 0.1.2", false, false)));
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "<= 0.1.2", false, false)));
ASSERT_OK_ZERO(condition_test(condition, environ));
condition_free(condition);
- ASSERT_NOT_NULL((condition = condition_new(CONDITION_KERNEL_VERSION, "= 0.1.2", false, false)));
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "= 0.1.2", false, false)));
ASSERT_OK_ZERO(condition_test(condition, environ));
condition_free(condition);
/* 4711.8.15 is a very very very future kernel */
- ASSERT_NOT_NULL((condition = condition_new(CONDITION_KERNEL_VERSION, "< 4711.8.15", false, false)));
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "< 4711.8.15", false, false)));
ASSERT_OK_POSITIVE(condition_test(condition, environ));
condition_free(condition);
- ASSERT_NOT_NULL((condition = condition_new(CONDITION_KERNEL_VERSION, "<= 4711.8.15", false, false)));
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "<= 4711.8.15", false, false)));
ASSERT_OK_POSITIVE(condition_test(condition, environ));
condition_free(condition);
- ASSERT_NOT_NULL((condition = condition_new(CONDITION_KERNEL_VERSION, "= 4711.8.15", false, false)));
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "= 4711.8.15", false, false)));
ASSERT_OK_ZERO(condition_test(condition, environ));
condition_free(condition);
- ASSERT_NOT_NULL((condition = condition_new(CONDITION_KERNEL_VERSION, "> 4711.8.15", false, false)));
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "> 4711.8.15", false, false)));
ASSERT_OK_ZERO(condition_test(condition, environ));
condition_free(condition);
- ASSERT_NOT_NULL((condition = condition_new(CONDITION_KERNEL_VERSION, " >= 4711.8.15", false, false)));
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, " >= 4711.8.15", false, false)));
ASSERT_OK_ZERO(condition_test(condition, environ));
condition_free(condition);
ASSERT_OK_ERRNO(uname(&u));
v = strjoina(">=", u.release);
- ASSERT_NOT_NULL((condition = condition_new(CONDITION_KERNEL_VERSION, v, false, false)));
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, v, false, false)));
ASSERT_OK_POSITIVE(condition_test(condition, environ));
condition_free(condition);
v = strjoina("= ", u.release);
- ASSERT_NOT_NULL((condition = condition_new(CONDITION_KERNEL_VERSION, v, false, false)));
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, v, false, false)));
ASSERT_OK_POSITIVE(condition_test(condition, environ));
condition_free(condition);
v = strjoina("<=", u.release);
- ASSERT_NOT_NULL((condition = condition_new(CONDITION_KERNEL_VERSION, v, false, false)));
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, v, false, false)));
ASSERT_OK_POSITIVE(condition_test(condition, environ));
condition_free(condition);
v = strjoina("> ", u.release);
- ASSERT_NOT_NULL((condition = condition_new(CONDITION_KERNEL_VERSION, v, false, false)));
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, v, false, false)));
ASSERT_OK_ZERO(condition_test(condition, environ));
condition_free(condition);
v = strjoina("< ", u.release);
- ASSERT_NOT_NULL((condition = condition_new(CONDITION_KERNEL_VERSION, v, false, false)));
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, v, false, false)));
+ ASSERT_OK_ZERO(condition_test(condition, environ));
+ condition_free(condition);
+}
+
+TEST(condition_test_version) {
+ Condition *condition;
+ const char *v;
+ char ver[8];
+
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "systemd *thisreallyshouldntbeinthesystemdversion*", false, false)));
+ ASSERT_OK_ZERO(condition_test(condition, environ));
+ condition_free(condition);
+
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "systemd *", false, false)));
+ ASSERT_OK_POSITIVE(condition_test(condition, environ));
+ condition_free(condition);
+
+ /* An artificially empty condition. It evaluates to true, but normally
+ * such condition cannot be created, because the condition list is reset instead. */
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "", false, false)));
+ ASSERT_OK_POSITIVE(condition_test(condition, environ));
+ condition_free(condition);
+
+ /* 42 would be a very very very old systemd release */
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "systemd > 42", false, false)));
+ ASSERT_OK_POSITIVE(condition_test(condition, environ));
+ condition_free(condition);
+
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "systemd>42", false, false)));
+ ASSERT_OK_POSITIVE(condition_test(condition, environ));
+ condition_free(condition);
+
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "systemd '>42' '<9000'", false, false)));
+ ASSERT_OK_POSITIVE(condition_test(condition, environ));
+ condition_free(condition);
+
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "systemd > 42 < 9000", false, false)));
+ ASSERT_ERROR(condition_test(condition, environ), EINVAL);
+ condition_free(condition);
+
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "systemd>", false, false)));
+ ASSERT_ERROR(condition_test(condition, environ), EINVAL);
+ condition_free(condition);
+
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "systemd >= 42", false, false)));
+ ASSERT_OK_POSITIVE(condition_test(condition, environ));
+ condition_free(condition);
+
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "systemd < 42", false, false)));
+ ASSERT_OK_ZERO(condition_test(condition, environ));
+ condition_free(condition);
+
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "systemd <= 42", false, false)));
+ ASSERT_OK_ZERO(condition_test(condition, environ));
+ condition_free(condition);
+
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "systemd = 42", false, false)));
+ ASSERT_OK_ZERO(condition_test(condition, environ));
+ condition_free(condition);
+
+ /* 9000 is a very very very future systemd release */
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "systemd < 9000", false, false)));
+ ASSERT_OK_POSITIVE(condition_test(condition, environ));
+ condition_free(condition);
+
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "systemd <= 9000", false, false)));
+ ASSERT_OK_POSITIVE(condition_test(condition, environ));
+ condition_free(condition);
+
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "systemd = 9000", false, false)));
+ ASSERT_OK_ZERO(condition_test(condition, environ));
+ condition_free(condition);
+
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "systemd > 9000", false, false)));
+ ASSERT_OK_ZERO(condition_test(condition, environ));
+ condition_free(condition);
+
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, "systemd >= 9000", false, false)));
+ ASSERT_OK_ZERO(condition_test(condition, environ));
+ condition_free(condition);
+
+ xsprintf(ver, "%d", PROJECT_VERSION);
+
+ v = strjoina("systemd>=", ver);
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, v, false, false)));
+ ASSERT_OK_POSITIVE(condition_test(condition, environ));
+ condition_free(condition);
+
+ v = strjoina("systemd = ", ver);
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, v, false, false)));
+ ASSERT_OK_POSITIVE(condition_test(condition, environ));
+ condition_free(condition);
+
+ v = strjoina("systemd<=", ver);
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, v, false, false)));
+ ASSERT_OK_POSITIVE(condition_test(condition, environ));
+ condition_free(condition);
+
+ v = strjoina("systemd > ", ver);
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, v, false, false)));
+ ASSERT_OK_ZERO(condition_test(condition, environ));
+ condition_free(condition);
+
+ v = strjoina("systemd < ", ver);
+ ASSERT_NOT_NULL((condition = condition_new(CONDITION_VERSION, v, false, false)));
ASSERT_OK_ZERO(condition_test(condition, environ));
condition_free(condition);
}