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:
parent
6577c7cea7
commit
9ea9d4cf16
2
TODO
2
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?
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 },
|
||||
|
Loading…
Reference in New Issue
Block a user