diff options
-rw-r--r-- | man/systemd-analyze.xml | 62 | ||||
-rw-r--r-- | src/analyze/analyze-compare-versions.c | 47 | ||||
-rw-r--r-- | src/analyze/analyze-compare-versions.h | 3 | ||||
-rw-r--r-- | src/analyze/analyze.c | 4 | ||||
-rw-r--r-- | src/analyze/meson.build | 2 |
5 files changed, 116 insertions, 2 deletions
diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml index 97290d479b..8061743c56 100644 --- a/man/systemd-analyze.xml +++ b/man/systemd-analyze.xml @@ -121,6 +121,14 @@ <cmdsynopsis> <command>systemd-analyze</command> <arg choice="opt" rep="repeat">OPTIONS</arg> + <arg choice="plain">compare-versions</arg> + <arg choice="plain"><replaceable>VERSION1</replaceable></arg> + <arg choice="opt"><replaceable>OP</replaceable></arg> + <arg choice="plain"><replaceable>VERSION2</replaceable></arg> + </cmdsynopsis> + <cmdsynopsis> + <command>systemd-analyze</command> + <arg choice="opt" rep="repeat">OPTIONS</arg> <arg choice="plain">verify</arg> <arg choice="opt" rep="repeat"><replaceable>FILE</replaceable></arg> </cmdsynopsis> @@ -548,6 +556,52 @@ NAutoVTs=8 </refsect2> <refsect2> + <title><command>systemd-analyze compare-versions + <replaceable>VERSION1</replaceable> + <optional><replaceable>OP</replaceable></optional> + <replaceable>VERSION2</replaceable></command></title> + + <para>This command has two distinct modes of operation, depending on whether the operator + <replaceable>OP</replaceable> is specified.</para> + + <para>In the first mode — when <replaceable>OP</replaceable> is not specified — it will compare the two + version strings and print either <literal><replaceable>VERSION1</replaceable> < + <replaceable>VERSION2</replaceable></literal>, or <literal><replaceable>VERSION1</replaceable> == + <replaceable>VERSION2</replaceable></literal>, or <literal><replaceable>VERSION1</replaceable> > + <replaceable>VERSION2</replaceable></literal> as appropriate.</para> + + <para>The exit status is <constant>0</constant> if the versions are equal, <constant>11</constant> if + the version of the right is smaller, and <constant>12</constant> if the version of the left is + smaller. (This matches the convention used by <command>rpmdev-vercmp</command>.)</para> + + <para>In the second mode — when <replaceable>OP</replaceable> is specified — it will compare the two + version strings using the operation <replaceable>OP</replaceable> and return <constant>0</constant> + (success) if they condition is satisfied, and <constant>1</constant> (failure) + otherwise. <constant>OP</constant> may be <command>lt</command>, <command>le</command>, + <command>eq</command>, <command>ne</command>, <command>ge</command>, <command>gt</command>. In this + mode, no output is printed. + (This matches the convention used by + <citerefentry project='die-net'><refentrytitle>dpkg</refentrytitle><manvolnum>1</manvolnum></citerefentry> + <option>--compare-versions</option>.)</para> + + <example> + <title>Compare versions of a package</title> + + <programlisting> +$ systemd-analyze compare-versions systemd-250~rc1.fc36.aarch64 systemd-251.fc36.aarch64 +systemd-250~rc1.fc36.aarch64 < systemd-251.fc36.aarch64 +$ echo $? +12 + +$ systemd-analyze compare-versions 1 lt 2; echo $? +0 +$ systemd-analyze compare-versions 1 ge 2; echo $? +1 + </programlisting> + </example> + </refsect2> + + <refsect2> <title><command>systemd-analyze verify <replaceable>FILE</replaceable>...</command></title> <para>This command will load unit files and print warnings if any errors are detected. Files specified @@ -1197,8 +1251,12 @@ $ systemd-analyze verify /tmp/source:alias.service <refsect1> <title>Exit status</title> - <para>On success, 0 is returned, a non-zero failure code - otherwise.</para> + <para>For most commands, 0 is returned on success, and a non-zero failure code otherwise.</para> + + <para>With the verb <command>compare-versions</command>, in the two-argument form, + <constant>12</constant>, <constant>0</constant>, <constant>11</constant> is returned if the second + version string is respectively larger, equal, or smaller to the first. In the three-argument form, + <constant>0</constant> or <constant>1</constant> if the condition is respectively true or false.</para> </refsect1> <xi:include href="common-variables.xml" /> 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', |