analyze: add exit-codes verb
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Mon, 29 Jul 2019 13:44:39 +0000 (15:44 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Mon, 29 Jul 2019 13:54:53 +0000 (15:54 +0200)
man/systemd-analyze.xml
man/systemd.service.xml
src/analyze/analyze.c

index 7112362..8e9f24c 100644 (file)
     <cmdsynopsis>
       <command>systemd-analyze</command>
       <arg choice="opt" rep="repeat">OPTIONS</arg>
+      <arg choice="plain">exit-codes</arg>
+      <arg choice="opt" rep="repeat"><replaceable>CODE</replaceable></arg>
+    </cmdsynopsis>
+    <cmdsynopsis>
+      <command>systemd-analyze</command>
+      <arg choice="opt" rep="repeat">OPTIONS</arg>
       <arg choice="plain">condition</arg>
       <arg choice="plain"><replaceable>CONDITION</replaceable>…</arg>
     </cmdsynopsis>
@@ -366,6 +372,30 @@ $ eog targets.svg</programlisting>
     </refsect2>
 
     <refsect2>
+      <title><command>systemd-analyze exit-codes <optional><replaceable>CODE</replaceable>...</optional></command></title>
+
+      <para>This command prints a list of exit codes along with their "class", i.e. the source of the
+      definition (one of <literal>glibc</literal>, <literal>systemd</literal>, <literal>LSB</literal>, or
+      <literal>BSD</literal>), see the Process Exit Codes section in
+      <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+      If no additional arguments are specified, all known codes are are shown. Otherwise, only the
+      definitions for the specified codes are shown.</para>
+
+      <example>
+        <title><command>Show some example exit code names</command></title>
+
+        <programlisting>$ systemd-analyze exit-codes 0 1 {63..65}
+NAME    CODE CLASS
+SUCCESS 0    glibc
+FAILURE 1    glibc
+-       63   -
+USAGE   64   BSD
+DATAERR 65   BSD
+</programlisting>
+      </example>
+    </refsect2>
+
+    <refsect2>
       <title><command>systemd-analyze condition <replaceable>CONDITION</replaceable>...</command></title>
 
       <para>This command will evaluate <varname noindex='true'>Condition*=...</varname> and
index 06116df..40ac052 100644 (file)
 
           <para>Exit codes 75 (<constant>TEMPFAIL</constant>), 250, and the termination signal
           <constant>SIGKILL</constant> are considered clean service terminations.</para>
-        </example></listitem>
+        </example>
+
+        <para>Note: <command>systemd-analyze exit-codes</command> may be used to list exit
+        codes and translate between numerical code values and names.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 9272797..c8767e8 100644 (file)
@@ -24,6 +24,7 @@
 #include "conf-files.h"
 #include "copy.h"
 #include "def.h"
+#include "exit-status.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "format-table.h"
@@ -1637,6 +1638,48 @@ static void dump_syscall_filter(const SyscallFilterSet *set) {
                 printf("    %s%s%s\n", syscall[0] == '@' ? ansi_underline() : "", syscall, ansi_normal());
 }
 
+static int dump_exit_codes(int argc, char *argv[], void *userdata) {
+        _cleanup_(table_unrefp) Table *table = NULL;
+        int r;
+
+        table = table_new("name", "code", "class");
+        if (!table)
+                return log_oom();
+
+        if (strv_isempty(strv_skip(argv, 1)))
+                for (size_t i = 0; i < ELEMENTSOF(exit_status_mappings); i++) {
+                        if (!exit_status_mappings[i].name)
+                                continue;
+
+                        r = table_add_many(table,
+                                           TABLE_STRING, exit_status_mappings[i].name,
+                                           TABLE_UINT, i,
+                                           TABLE_STRING, exit_status_class(i));
+                        if (r < 0)
+                                return r;
+                }
+        else
+                for (int i = 1; i < argc; i++) {
+                        int code;
+
+                        code = exit_status_from_string(argv[i]);
+                        if (code < 0)
+                                return log_error_errno(r, "Invalid exit code \"%s\": %m", argv[i]);
+
+                        assert(code >= 0 && (size_t) code < ELEMENTSOF(exit_status_mappings));
+                        r = table_add_many(table,
+                                           TABLE_STRING, exit_status_mappings[code].name ?: "-",
+                                           TABLE_UINT, code,
+                                           TABLE_STRING, exit_status_class(code) ?: "-");
+                        if (r < 0)
+                                return r;
+                }
+
+        (void) pager_open(arg_pager_flags);
+
+        return table_print(table, NULL);
+}
+
 static int dump_syscall_filters(int argc, char *argv[], void *userdata) {
         bool first = true;
 
@@ -2165,6 +2208,7 @@ static int help(int argc, char *argv[], void *userdata) {
                "  dump                     Output state serialization of service manager\n"
                "  cat-config               Show configuration file and drop-ins\n"
                "  unit-paths               List load directories for units\n"
+               "  exit-codes               List exit code definitions\n"
                "  syscall-filter [NAME...] Print list of syscalls in seccomp filter\n"
                "  condition CONDITION...   Evaluate conditions and asserts\n"
                "  verify FILE...           Check unit files for correctness\n"
@@ -2368,6 +2412,7 @@ static int run(int argc, char *argv[]) {
                 { "dump",              VERB_ANY, 1,        0,            dump                   },
                 { "cat-config",        2,        VERB_ANY, 0,            cat_config             },
                 { "unit-paths",        1,        1,        0,            dump_unit_paths        },
+                { "exit-codes",        VERB_ANY, VERB_ANY, 0,            dump_exit_codes        },
                 { "syscall-filter",    VERB_ANY, VERB_ANY, 0,            dump_syscall_filters   },
                 { "condition",         2,        VERB_ANY, 0,            do_condition           },
                 { "verify",            2,        VERB_ANY, 0,            do_verify              },