From bc012a3e913075d14ac39d33a090c5dcddce2e09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 17 May 2022 16:28:45 +0200 Subject: analyze: add compare-versions The interface, output, and exit status convention are all taken directly from rpmdev-vercmp and dpkg --compare-versions. The implementation is different though. See test-string-util for a list of known cases where we compare strings incompatibly. The idea is that this string comparison function will be declared as "the" method to use for boot entry ordering in the specification and similar uses. Thus it's nice to allow users to compare strings. --- src/analyze/analyze-compare-versions.c | 47 ++++++++++++++++++++++++++++++++++ src/analyze/analyze-compare-versions.h | 3 +++ src/analyze/analyze.c | 4 +++ src/analyze/meson.build | 2 ++ 4 files changed, 56 insertions(+) create mode 100644 src/analyze/analyze-compare-versions.c create mode 100644 src/analyze/analyze-compare-versions.h (limited to 'src/analyze') diff --git a/src/analyze/analyze-compare-versions.c b/src/analyze/analyze-compare-versions.c new file mode 100644 index 0000000000..9545326fa9 --- /dev/null +++ b/src/analyze/analyze-compare-versions.c @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include + +#include "analyze-compare-versions.h" +#include "macro.h" +#include "string-util.h" +#include "strv.h" + +int verb_compare_versions(int argc, char *argv[], void *userdata) { + int r; + + assert(argc == 3 || argc == 4); + assert(argv); + + if (argc == 3) { + r = strverscmp_improved(ASSERT_PTR(argv[1]), ASSERT_PTR(argv[2])); + printf("%s %s %s\n", + argv[1], + r < 0 ? "<" : r > 0 ? ">" : "==", + argv[2]); + + /* This matches the exit convention used by rpmdev-vercmp. + * We don't use named values because 11 and 12 don't have names. */ + return r < 0 ? 12 : r > 0 ? 11 : 0; + + } else { + const char *op = ASSERT_PTR(argv[2]); + + r = strverscmp_improved(ASSERT_PTR(argv[1]), ASSERT_PTR(argv[3])); + + if (STR_IN_SET(op, "lt", "<")) + return r < 0 ? EXIT_SUCCESS : EXIT_FAILURE; + if (STR_IN_SET(op, "le", "<=")) + return r <= 0 ? EXIT_SUCCESS : EXIT_FAILURE; + if (STR_IN_SET(op, "eq", "==")) + return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE; + if (STR_IN_SET(op, "ne", "!=")) + return r != 0 ? EXIT_SUCCESS : EXIT_FAILURE; + if (STR_IN_SET(op, "ge", ">=")) + return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE; + if (STR_IN_SET(op, "gt", ">")) + return r > 0 ? EXIT_SUCCESS : EXIT_FAILURE; + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Unknown operator \"%s\".", op); + } +} diff --git a/src/analyze/analyze-compare-versions.h b/src/analyze/analyze-compare-versions.h new file mode 100644 index 0000000000..ac90ede2f0 --- /dev/null +++ b/src/analyze/analyze-compare-versions.h @@ -0,0 +1,3 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +int verb_compare_versions(int argc, char *argv[], void *userdata); diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index 2935ecea7a..4968946963 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -35,6 +35,7 @@ #include "analyze-timestamp.h" #include "analyze-unit-files.h" #include "analyze-unit-paths.h" +#include "analyze-compare-versions.h" #include "analyze-verify.h" #include "bus-error.h" #include "bus-locator.h" @@ -199,6 +200,8 @@ static int help(int argc, char *argv[], void *userdata) { " syscall-filter [NAME...] List syscalls in seccomp filters\n" " filesystems [NAME...] List known filesystems\n" " condition CONDITION... Evaluate conditions and asserts\n" + " compare-versions VERSION1 [OP] VERSION2\n" + " Compare two version strings\n" " verify FILE... Check unit files for correctness\n" " calendar SPEC... Validate repetitive calendar time\n" " events\n" @@ -564,6 +567,7 @@ static int run(int argc, char *argv[]) { { "capability", VERB_ANY, VERB_ANY, 0, verb_capabilities }, { "filesystems", VERB_ANY, VERB_ANY, 0, verb_filesystems }, { "condition", VERB_ANY, VERB_ANY, 0, verb_condition }, + { "compare-versions", 3, 4, 0, verb_compare_versions }, { "verify", 2, VERB_ANY, 0, verb_verify }, { "calendar", 2, VERB_ANY, 0, verb_calendar }, { "timestamp", 2, VERB_ANY, 0, verb_timestamp }, diff --git a/src/analyze/meson.build b/src/analyze/meson.build index f0cfbb195e..24ef94149c 100644 --- a/src/analyze/meson.build +++ b/src/analyze/meson.build @@ -9,6 +9,8 @@ systemd_analyze_sources = files( 'analyze-capability.h', 'analyze-cat-config.c', 'analyze-cat-config.h', + 'analyze-compare-versions.c', + 'analyze-compare-versions.h', 'analyze-condition.c', 'analyze-condition.h', 'analyze-critical-chain.c', -- cgit v1.2.1