summaryrefslogtreecommitdiff
path: root/src/analyze
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2022-05-17 16:28:45 +0200
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2022-05-19 09:07:34 +0200
commitbc012a3e913075d14ac39d33a090c5dcddce2e09 (patch)
treeaaca9e491b34bd4ca37edf12295b7bb04352827e /src/analyze
parentfddad5f4a66a68682892e3fa7f22ec2689786d33 (diff)
downloadsystemd-bc012a3e913075d14ac39d33a090c5dcddce2e09.tar.gz
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.
Diffstat (limited to 'src/analyze')
-rw-r--r--src/analyze/analyze-compare-versions.c47
-rw-r--r--src/analyze/analyze-compare-versions.h3
-rw-r--r--src/analyze/analyze.c4
-rw-r--r--src/analyze/meson.build2
4 files changed, 56 insertions, 0 deletions
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 <stdio.h>
+
+#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',