1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2024-10-27 01:55:32 +03:00

systemctl: move "dump" command from systemctl to systemd-analyze

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
This commit is contained in:
Lennart Poettering 2013-07-26 16:34:52 +02:00
parent 6577c7cea7
commit 9ea9d4cf16
5 changed files with 165 additions and 116 deletions

2
TODO
View File

@ -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?

View 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>

View File

@ -82,6 +82,11 @@
<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>
@ -127,7 +132,7 @@
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>
@ -143,6 +148,12 @@
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>
@ -228,6 +239,14 @@
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>
@ -256,6 +275,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>

View 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;
}

View 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 },