summaryrefslogtreecommitdiff
path: root/src/analyze
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2013-07-26 16:34:52 +0200
committerLennart Poettering <lennart@poettering.net>2013-07-26 16:36:25 +0200
commit9ea9d4cf1656075559fcd6aeceb9530714c87d5b (patch)
treefc4121e07abacf62dabfbbe5e518c9ac00c65381 /src/analyze
parent6577c7cea72f19185ad999c223bcf663c010dc6f (diff)
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
Diffstat (limited to 'src/analyze')
-rw-r--r--src/analyze/systemd-analyze.c120
1 files changed, 90 insertions, 30 deletions
diff --git a/src/analyze/systemd-analyze.c b/src/analyze/systemd-analyze.c
index ffdcd14700..2748b3afc9 100644
--- a/src/analyze/systemd-analyze.c
+++ b/src/analyze/systemd-analyze.c
@@ -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;
}