chiark / gitweb /
systemctl: move "dump" command from systemctl to systemd-analyze
authorLennart Poettering <lennart@poettering.net>
Fri, 26 Jul 2013 14:34:52 +0000 (16:34 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 26 Jul 2013 14:36:25 +0000 (16:36 +0200)
It's an analysis command and its format is explicitly not covered by any
stability guarantees, hence move away from systemctl and into
systemd-analyze, minimizing the already large interface of systemctl a
bit.

This patch also adds auto-paging to the various systemd-analyze commands
where that makes sense

TODO
man/systemctl.xml
man/systemd-analyze.xml
src/analyze/systemd-analyze.c
src/systemctl/systemctl.c

diff --git a/TODO b/TODO
index 279ea60..5294b74 100644 (file)
--- a/TODO
+++ b/TODO
@@ -90,8 +90,6 @@ Features:
 
 * move systemctl set-log-level to systemd-analyze?
 
-* move "systemctl dump" to systemd-analyze
-
 * add a fixed dbus path for "my own unit", "my own session", ... to PID1, logind, ...
 
 * service_coldplug() appears to reinstall the wrong stop timeout watch?
index ee13a70..06c8c18 100644 (file)
@@ -993,16 +993,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
           all pending jobs.</para>
         </listitem>
       </varlistentry>
-      <varlistentry>
-        <term><command>dump</command></term>
 
-        <listitem>
-          <para>Dump server status. This will output a (usually very
-          long) human readable manager status dump. Its format is
-          subject to change without notice and should not be parsed by
-          applications.</para>
-        </listitem>
-      </varlistentry>
       <varlistentry>
         <term><command>list-dependencies <replaceable>NAME</replaceable></command></term>
 
index f5a9424..905b44b 100644 (file)
                         <arg choice="plain">dot</arg>
                         <arg choice="opt" rep="repeat"><replaceable>PATTERN</replaceable></arg>
                 </cmdsynopsis>
+                <cmdsynopsis>
+                        <command>systemd-analyze</command>
+                        <arg choice="opt" rep="repeat">OPTIONS</arg>
+                        <arg choice="plain">dump</arg>
+                </cmdsynopsis>
         </refsynopsisdiv>
 
         <refsect1>
                 been started at what time, highlighting the time they
                 spent on initialization.</para>
 
-                <para><command>systemd-analyze dot</command> Generate
+                <para><command>systemd-analyze dot</command> generates
                 textual dependency graph description in dot format for
                 further processing with the GraphViz
                 <citerefentry><refentrytitle>dot</refentrytitle><manvolnum>1</manvolnum></citerefentry>
                 any of these patterns match either the origin or
                 destination node.</para>
 
+                <para><command>systemd-analyze dump</command> outputs
+                a (usually very long) human-readable serialization of
+                the complete server state. Its format is subject to
+                change without notice and should not be parsed by
+                applications.</para>
+
                 <para>If no command is passed, <command>systemd-analyze
                 time</command> is implied.</para>
 
                                 unless specified with a different unit,
                                 e.g. "50ms".</para></listitem>
                         </varlistentry>
+
+                        <varlistentry>
+                                <term><option>--no-pager</option></term>
+
+                                <listitem>
+                                        <para>Do not pipe output into a pager.</para>
+                                </listitem>
+                        </varlistentry>
                 </variablelist>
 
         </refsect1>
@@ -257,6 +276,24 @@ $ eog targets.svg</programlisting>
         </refsect1>
 
         <refsect1>
+                <title>Environment</title>
+
+                <variablelist class='environment-variables'>
+                        <varlistentry>
+                                <term><varname>$SYSTEMD_PAGER</varname></term>
+
+                                <listitem>
+                                        <para>Pager to use when <option>--no-pager</option> is not
+                                        given; overrides <varname>$PAGER</varname>.  Setting this to
+                                        an empty string or the value <literal>cat</literal> is
+                                        equivalent to passing
+                                        <option>--no-pager</option>.</para>
+                                </listitem>
+                        </varlistentry>
+                </variablelist>
+        </refsect1>
+
+        <refsect1>
                 <title>See Also</title>
                 <para>
                         <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
index ffdcd14..2748b3a 100644 (file)
@@ -38,6 +38,7 @@
 #include "unit-name.h"
 #include "special.h"
 #include "hashmap.h"
+#include "pager.h"
 
 #define SCALE_X (0.1 / 1000.0)   /* pixels per us */
 #define SCALE_Y 20.0
@@ -67,8 +68,8 @@ static enum dot {
 } arg_dot = DEP_ALL;
 static char** arg_dot_from_patterns = NULL;
 static char** arg_dot_to_patterns = NULL;
-
-usec_t arg_fuzz = 0;
+static usec_t arg_fuzz = 0;
+static bool arg_no_pager = false;
 
 struct boot_times {
         usec_t firmware_time;
@@ -83,6 +84,7 @@ struct boot_times {
         usec_t unitsload_start_time;
         usec_t unitsload_finish_time;
 };
+
 struct unit_times {
         char *name;
         usec_t ixt;
@@ -92,6 +94,14 @@ struct unit_times {
         usec_t time;
 };
 
+static void pager_open_if_enabled(void) {
+
+        if (arg_no_pager)
+                return;
+
+        pager_open(false);
+}
+
 static int bus_get_uint64_property(DBusConnection *bus, const char *path, const char *interface, const char *property, uint64_t *val) {
         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
         DBusMessageIter iter, sub;
@@ -590,7 +600,6 @@ static int analyze_plot(DBusConnection *bus) {
         svg_text("right", 400000, y, "Loading unit files");
         y++;
 
-
         svg("</g>\n\n");
 
         svg("</svg>");
@@ -600,7 +609,6 @@ static int analyze_plot(DBusConnection *bus) {
         return 0;
 }
 
-
 static int list_dependencies_print(const char *name, unsigned int level, unsigned int branches,
                                    bool last, struct unit_times *times, struct boot_times *boot) {
         unsigned int i;
@@ -914,6 +922,8 @@ static int analyze_critical_chain(DBusConnection *bus, char *names[]) {
         }
         unit_times_hashmap = h;
 
+        pager_open_if_enabled();
+
         puts("The time after the unit is active or started is printed after the \"@\" character.\n"
              "The time the unit takes to start is printed after the \"+\" character.\n");
 
@@ -921,9 +931,8 @@ static int analyze_critical_chain(DBusConnection *bus, char *names[]) {
                 char **name;
                 STRV_FOREACH(name, names)
                         list_dependencies(bus, *name);
-        } else {
+        } else
                 list_dependencies(bus, SPECIAL_DEFAULT_TARGET);
-        }
 
         hashmap_free(h);
         free_unit_times(times, (unsigned) n);
@@ -941,6 +950,8 @@ static int analyze_blame(DBusConnection *bus) {
 
         qsort(times, n, sizeof(struct unit_times), compare_unit_time);
 
+        pager_open_if_enabled();
+
         for (i = 0; i < (unsigned) n; i++) {
                 char ts[FORMAT_TIMESPAN_MAX];
 
@@ -1165,8 +1176,44 @@ static int dot(DBusConnection *bus, char* patterns[]) {
         return 0;
 }
 
-static void analyze_help(void)
-{
+static int dump(DBusConnection *bus, char **args) {
+        _cleanup_free_ DBusMessage *reply = NULL;
+        DBusError error;
+        int r;
+        const char *text;
+
+        dbus_error_init(&error);
+
+        pager_open_if_enabled();
+
+        r = bus_method_call_with_reply(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "Dump",
+                        &reply,
+                        NULL,
+                        DBUS_TYPE_INVALID);
+        if (r < 0)
+                return r;
+
+        if (!dbus_message_get_args(reply, &error,
+                                   DBUS_TYPE_STRING, &text,
+                                   DBUS_TYPE_INVALID)) {
+                log_error("Failed to parse reply: %s", bus_error_message(&error));
+                dbus_error_free(&error);
+                return  -EIO;
+        }
+
+        fputs(text, stdout);
+        return 0;
+}
+
+static void analyze_help(void) {
+
+        pager_open_if_enabled();
+
         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
                "Process systemd profiling information\n\n"
                "  -h --help           Show this help\n"
@@ -1181,13 +1228,15 @@ static void analyze_help(void)
                "     --fuzz=TIMESPAN  When printing the tree of the critical chain, print also\n"
                "                      services, which finished TIMESPAN earlier, than the\n"
                "                      latest in the branch. The unit of TIMESPAN is seconds\n"
-               "                      unless specified with a different unit, i.e. 50ms\n\n"
+               "                      unless specified with a different unit, i.e. 50ms\n"
+               "     --no-pager       Do not pipe output into a pager\n\n"
                "Commands:\n"
                "  time                Print time spent in the kernel before reaching userspace\n"
                "  blame               Print list of running units ordered by time to init\n"
                "  critical-chain      Print a tree of the time critical chain of units\n"
                "  plot                Output SVG graphic showing service initialization\n"
-               "  dot                 Dump dependency graph (in dot(1) format)\n\n",
+               "  dot                 Output dependency graph in dot(1) format\n"
+               "  dump                Output state serialization of service manager\n",
                program_invocation_short_name);
 
         /* When updating this list, including descriptions, apply
@@ -1195,8 +1244,7 @@ static void analyze_help(void)
          * shell-completion/systemd-zsh-completion.zsh too. */
 }
 
-static int parse_argv(int argc, char *argv[])
-{
+static int parse_argv(int argc, char *argv[]) {
         int r;
 
         enum {
@@ -1207,20 +1255,22 @@ static int parse_argv(int argc, char *argv[])
                 ARG_SYSTEM,
                 ARG_DOT_FROM_PATTERN,
                 ARG_DOT_TO_PATTERN,
-                ARG_FUZZ
+                ARG_FUZZ,
+                ARG_NO_PAGER
         };
 
         static const struct option options[] = {
-                { "help",      no_argument,       NULL, 'h'           },
-                { "version",   no_argument,       NULL, ARG_VERSION   },
-                { "order",     no_argument,       NULL, ARG_ORDER     },
-                { "require",   no_argument,       NULL, ARG_REQUIRE   },
-                { "user",      no_argument,       NULL, ARG_USER      },
-                { "system",    no_argument,       NULL, ARG_SYSTEM    },
-                { "from-pattern", required_argument, NULL, ARG_DOT_FROM_PATTERN},
-                { "to-pattern",   required_argument, NULL, ARG_DOT_TO_PATTERN  },
-                { "fuzz",      required_argument, NULL, ARG_FUZZ  },
-                { NULL,        0,                 NULL, 0             }
+                { "help",         no_argument,       NULL, 'h'                  },
+                { "version",      no_argument,       NULL, ARG_VERSION          },
+                { "order",        no_argument,       NULL, ARG_ORDER            },
+                { "require",      no_argument,       NULL, ARG_REQUIRE          },
+                { "user",         no_argument,       NULL, ARG_USER             },
+                { "system",       no_argument,       NULL, ARG_SYSTEM           },
+                { "from-pattern", required_argument, NULL, ARG_DOT_FROM_PATTERN },
+                { "to-pattern",   required_argument, NULL, ARG_DOT_TO_PATTERN   },
+                { "fuzz",         required_argument, NULL, ARG_FUZZ             },
+                { "no-pager",     no_argument,       NULL, ARG_NO_PAGER         },
+                { NULL,           0,                 NULL, 0                    }
         };
 
         assert(argc >= 0);
@@ -1271,6 +1321,10 @@ static int parse_argv(int argc, char *argv[])
                                 return r;
                         break;
 
+                case ARG_NO_PAGER:
+                        arg_no_pager = true;
+                        break;
+
                 case -1:
                         return 1;
 
@@ -1293,14 +1347,14 @@ int main(int argc, char *argv[]) {
         log_open();
 
         r = parse_argv(argc, argv);
-        if (r < 0)
-                return EXIT_FAILURE;
-        else if (r <= 0)
-                return EXIT_SUCCESS;
+        if (r <= 0)
+                goto finish;
 
         bus = dbus_bus_get(arg_scope == UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, NULL);
-        if (!bus)
-                return EXIT_FAILURE;
+        if (!bus) {
+                r = -EIO;
+                goto finish;
+        }
 
         if (!argv[optind] || streq(argv[optind], "time"))
                 r = analyze_time(bus);
@@ -1312,12 +1366,18 @@ int main(int argc, char *argv[]) {
                 r = analyze_plot(bus);
         else if (streq(argv[optind], "dot"))
                 r = dot(bus, argv+optind+1);
+        else if (streq(argv[optind], "dump"))
+                r = dump(bus, argv+optind+1);
         else
                 log_error("Unknown operation '%s'.", argv[optind]);
 
+        dbus_connection_unref(bus);
+
+finish:
+        pager_close();
+
         strv_free(arg_dot_from_patterns);
         strv_free(arg_dot_to_patterns);
-        dbus_connection_unref(bus);
 
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }
index 9f47b2c..4e33a41 100644 (file)
@@ -3797,40 +3797,6 @@ static int set_property(DBusConnection *bus, char **args) {
         return 0;
 }
 
-static int dump(DBusConnection *bus, char **args) {
-        _cleanup_free_ DBusMessage *reply = NULL;
-        DBusError error;
-        int r;
-        const char *text;
-
-        dbus_error_init(&error);
-
-        pager_open_if_enabled();
-
-        r = bus_method_call_with_reply(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "Dump",
-                        &reply,
-                        NULL,
-                        DBUS_TYPE_INVALID);
-        if (r < 0)
-                return r;
-
-        if (!dbus_message_get_args(reply, &error,
-                                   DBUS_TYPE_STRING, &text,
-                                   DBUS_TYPE_INVALID)) {
-                log_error("Failed to parse reply: %s", bus_error_message(&error));
-                dbus_error_free(&error);
-                return  -EIO;
-        }
-
-        fputs(text, stdout);
-        return 0;
-}
-
 static int snapshot(DBusConnection *bus, char **args) {
         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
         DBusError error;
@@ -4787,8 +4753,6 @@ static int systemctl_help(void) {
                "Job Commands:\n"
                "  list-jobs                       List jobs\n"
                "  cancel [JOB...]                 Cancel all, one, or more jobs\n\n"
-               "Status Commands:\n"
-               "  dump                            Dump server status\n\n"
                "Snapshot Commands:\n"
                "  snapshot [NAME]                 Create a snapshot\n"
                "  delete [NAME...]                Remove one or more snapshots\n\n"
@@ -4927,43 +4891,43 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
         };
 
         static const struct option options[] = {
-                { "help",      no_argument,       NULL, 'h'           },
-                { "version",   no_argument,       NULL, ARG_VERSION   },
-                { "type",      required_argument, NULL, 't'           },
-                { "property",  required_argument, NULL, 'p'           },
-                { "all",       no_argument,       NULL, 'a'           },
-                { "reverse",   no_argument,       NULL, ARG_REVERSE   },
-                { "after",     no_argument,       NULL, ARG_AFTER     },
-                { "before",    no_argument,       NULL, ARG_BEFORE    },
-                { "show-types", no_argument,      NULL, ARG_SHOW_TYPES },
-                { "failed",    no_argument,       NULL, ARG_FAILED    },
-                { "full",      no_argument,       NULL, 'l'           },
-                { "fail",      no_argument,       NULL, ARG_FAIL      },
-                { "irreversible", no_argument,    NULL, ARG_IRREVERSIBLE },
-                { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
-                { "ignore-inhibitors", no_argument, NULL, 'i'         },
-                { "user",      no_argument,       NULL, ARG_USER      },
-                { "system",    no_argument,       NULL, ARG_SYSTEM    },
-                { "global",    no_argument,       NULL, ARG_GLOBAL    },
-                { "no-block",  no_argument,       NULL, ARG_NO_BLOCK  },
-                { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
-                { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
-                { "no-wall",   no_argument,       NULL, ARG_NO_WALL   },
-                { "quiet",     no_argument,       NULL, 'q'           },
-                { "root",      required_argument, NULL, ARG_ROOT      },
-                { "force",     no_argument,       NULL, ARG_FORCE     },
-                { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
-                { "kill-who",  required_argument, NULL, ARG_KILL_WHO  },
-                { "signal",    required_argument, NULL, 's'           },
-                { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
-                { "host",      required_argument, NULL, 'H'           },
-                { "privileged",no_argument,       NULL, 'P'           },
-                { "runtime",   no_argument,       NULL, ARG_RUNTIME   },
-                { "lines",     required_argument, NULL, 'n'           },
-                { "output",    required_argument, NULL, 'o'           },
-                { "plain",     no_argument,       NULL, ARG_PLAIN     },
-                { "state",     required_argument, NULL, ARG_STATE     },
-                { NULL,        0,                 NULL, 0             }
+                { "help",                no_argument,       NULL, 'h'                     },
+                { "version",             no_argument,       NULL, ARG_VERSION             },
+                { "type",                required_argument, NULL, 't'                     },
+                { "property",            required_argument, NULL, 'p'                     },
+                { "all",                 no_argument,       NULL, 'a'                     },
+                { "reverse",             no_argument,       NULL, ARG_REVERSE             },
+                { "after",               no_argument,       NULL, ARG_AFTER               },
+                { "before",              no_argument,       NULL, ARG_BEFORE              },
+                { "show-types",          no_argument,       NULL, ARG_SHOW_TYPES          },
+                { "failed",              no_argument,       NULL, ARG_FAILED              }, /* compatibility only */
+                { "full",                no_argument,       NULL, 'l'                     },
+                { "fail",                no_argument,       NULL, ARG_FAIL                },
+                { "irreversible",        no_argument,       NULL, ARG_IRREVERSIBLE        },
+                { "ignore-dependencies", no_argument,       NULL, ARG_IGNORE_DEPENDENCIES },
+                { "ignore-inhibitors",   no_argument,       NULL, 'i'                     },
+                { "user",                no_argument,       NULL, ARG_USER                },
+                { "system",              no_argument,       NULL, ARG_SYSTEM              },
+                { "global",              no_argument,       NULL, ARG_GLOBAL              },
+                { "no-block",            no_argument,       NULL, ARG_NO_BLOCK            },
+                { "no-legend",           no_argument,       NULL, ARG_NO_LEGEND           },
+                { "no-pager",            no_argument,       NULL, ARG_NO_PAGER            },
+                { "no-wall",             no_argument,       NULL, ARG_NO_WALL             },
+                { "quiet",               no_argument,       NULL, 'q'                     },
+                { "root",                required_argument, NULL, ARG_ROOT                },
+                { "force",               no_argument,       NULL, ARG_FORCE               },
+                { "no-reload",           no_argument,       NULL, ARG_NO_RELOAD           },
+                { "kill-who",            required_argument, NULL, ARG_KILL_WHO            },
+                { "signal",              required_argument, NULL, 's'                     },
+                { "no-ask-password",     no_argument,       NULL, ARG_NO_ASK_PASSWORD     },
+                { "host",                required_argument, NULL, 'H'                     },
+                { "privileged",          no_argument,       NULL, 'P'                     },
+                { "runtime",             no_argument,       NULL, ARG_RUNTIME             },
+                { "lines",               required_argument, NULL, 'n'                     },
+                { "output",              required_argument, NULL, 'o'                     },
+                { "plain",               no_argument,       NULL, ARG_PLAIN               },
+                { "state",               required_argument, NULL, ARG_STATE               },
+                { NULL,                  0,                 NULL, 0                       }
         };
 
         int c;
@@ -5829,7 +5793,6 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
                 { "show",                  MORE,  1, show              },
                 { "status",                MORE,  1, show              },
                 { "help",                  MORE,  2, show              },
-                { "dump",                  EQUAL, 1, dump              },
                 { "snapshot",              LESS,  2, snapshot          },
                 { "delete",                MORE,  2, delete_snapshot   },
                 { "daemon-reload",         EQUAL, 1, daemon_reload     },