summaryrefslogtreecommitdiff
path: root/src/analyze
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2022-02-21 10:47:48 +0100
committerLennart Poettering <lennart@poettering.net>2022-02-21 17:22:23 +0100
commitcccd2af6f579fa63deafdde51014474f78d99958 (patch)
tree89d5c9e60fe1d6b0b46e506ddff2adee9a0cd50c /src/analyze
parent25eb70af8bdafb40ebe5850b9e1414e297677c1c (diff)
downloadsystemd-cccd2af6f579fa63deafdde51014474f78d99958.tar.gz
analyze: split out "dot" verb
Diffstat (limited to 'src/analyze')
-rw-r--r--src/analyze/analyze-dot.c184
-rw-r--r--src/analyze/analyze-dot.h4
-rw-r--r--src/analyze/analyze.c187
-rw-r--r--src/analyze/analyze.h10
-rw-r--r--src/analyze/meson.build2
5 files changed, 204 insertions, 183 deletions
diff --git a/src/analyze/analyze-dot.c b/src/analyze/analyze-dot.c
new file mode 100644
index 0000000000..08f9910368
--- /dev/null
+++ b/src/analyze/analyze-dot.c
@@ -0,0 +1,184 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "analyze.h"
+#include "analyze-dot.h"
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "bus-unit-util.h"
+#include "glob-util.h"
+#include "terminal-util.h"
+
+static int graph_one_property(
+ sd_bus *bus,
+ const UnitInfo *u,
+ const char *prop,
+ const char *color,
+ char *patterns[],
+ char *from_patterns[],
+ char *to_patterns[]) {
+
+ _cleanup_strv_free_ char **units = NULL;
+ char **unit;
+ int r;
+ bool match_patterns;
+
+ assert(u);
+ assert(prop);
+ assert(color);
+
+ match_patterns = strv_fnmatch(patterns, u->id);
+
+ if (!strv_isempty(from_patterns) && !match_patterns && !strv_fnmatch(from_patterns, u->id))
+ return 0;
+
+ r = bus_get_unit_property_strv(bus, u->unit_path, prop, &units);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(unit, units) {
+ bool match_patterns2;
+
+ match_patterns2 = strv_fnmatch(patterns, *unit);
+
+ if (!strv_isempty(to_patterns) && !match_patterns2 && !strv_fnmatch(to_patterns, *unit))
+ continue;
+
+ if (!strv_isempty(patterns) && !match_patterns && !match_patterns2)
+ continue;
+
+ printf("\t\"%s\"->\"%s\" [color=\"%s\"];\n", u->id, *unit, color);
+ }
+
+ return 0;
+}
+
+static int graph_one(sd_bus *bus, const UnitInfo *u, char *patterns[], char *from_patterns[], char *to_patterns[]) {
+ int r;
+
+ assert(bus);
+ assert(u);
+
+ if (IN_SET(arg_dot, DEP_ORDER, DEP_ALL)) {
+ r = graph_one_property(bus, u, "After", "green", patterns, from_patterns, to_patterns);
+ if (r < 0)
+ return r;
+ }
+
+ if (IN_SET(arg_dot, DEP_REQUIRE, DEP_ALL)) {
+ r = graph_one_property(bus, u, "Requires", "black", patterns, from_patterns, to_patterns);
+ if (r < 0)
+ return r;
+ r = graph_one_property(bus, u, "Requisite", "darkblue", patterns, from_patterns, to_patterns);
+ if (r < 0)
+ return r;
+ r = graph_one_property(bus, u, "Wants", "grey66", patterns, from_patterns, to_patterns);
+ if (r < 0)
+ return r;
+ r = graph_one_property(bus, u, "Conflicts", "red", patterns, from_patterns, to_patterns);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+static int expand_patterns(sd_bus *bus, char **patterns, char ***ret) {
+ _cleanup_strv_free_ char **expanded_patterns = NULL;
+ char **pattern;
+ int r;
+
+ STRV_FOREACH(pattern, patterns) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_free_ char *unit = NULL, *unit_id = NULL;
+
+ if (strv_extend(&expanded_patterns, *pattern) < 0)
+ return log_oom();
+
+ if (string_is_glob(*pattern))
+ continue;
+
+ unit = unit_dbus_path_from_name(*pattern);
+ if (!unit)
+ return log_oom();
+
+ r = sd_bus_get_property_string(
+ bus,
+ "org.freedesktop.systemd1",
+ unit,
+ "org.freedesktop.systemd1.Unit",
+ "Id",
+ &error,
+ &unit_id);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get ID: %s", bus_error_message(&error, r));
+
+ if (!streq(*pattern, unit_id)) {
+ if (strv_extend(&expanded_patterns, unit_id) < 0)
+ return log_oom();
+ }
+ }
+
+ *ret = TAKE_PTR(expanded_patterns); /* do not free */
+
+ return 0;
+}
+
+int dot(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ _cleanup_strv_free_ char **expanded_patterns = NULL;
+ _cleanup_strv_free_ char **expanded_from_patterns = NULL;
+ _cleanup_strv_free_ char **expanded_to_patterns = NULL;
+ int r;
+ UnitInfo u;
+
+ r = acquire_bus(&bus, NULL);
+ if (r < 0)
+ return bus_log_connect_error(r, arg_transport);
+
+ r = expand_patterns(bus, strv_skip(argv, 1), &expanded_patterns);
+ if (r < 0)
+ return r;
+
+ r = expand_patterns(bus, arg_dot_from_patterns, &expanded_from_patterns);
+ if (r < 0)
+ return r;
+
+ r = expand_patterns(bus, arg_dot_to_patterns, &expanded_to_patterns);
+ if (r < 0)
+ return r;
+
+ r = bus_call_method(bus, bus_systemd_mgr, "ListUnits", &error, &reply, NULL);
+ if (r < 0)
+ log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r));
+
+ r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ printf("digraph systemd {\n");
+
+ while ((r = bus_parse_unit_info(reply, &u)) > 0) {
+
+ r = graph_one(bus, &u, expanded_patterns, expanded_from_patterns, expanded_to_patterns);
+ if (r < 0)
+ return r;
+ }
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ printf("}\n");
+
+ log_info(" Color legend: black = Requires\n"
+ " dark blue = Requisite\n"
+ " dark grey = Wants\n"
+ " red = Conflicts\n"
+ " green = After\n");
+
+ if (on_tty() && !arg_quiet)
+ log_notice("-- You probably want to process this output with graphviz' dot tool.\n"
+ "-- Try a shell pipeline like 'systemd-analyze dot | dot -Tsvg > systemd.svg'!\n");
+
+ return 0;
+}
diff --git a/src/analyze/analyze-dot.h b/src/analyze/analyze-dot.h
new file mode 100644
index 0000000000..9017c1878a
--- /dev/null
+++ b/src/analyze/analyze-dot.h
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+int dot(int argc, char *argv[], void *userdata);
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index f9790d99ee..8326cfa49e 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -15,6 +15,7 @@
#include "analyze.h"
#include "analyze-calendar.h"
#include "analyze-condition.h"
+#include "analyze-dot.h"
#include "analyze-dump.h"
#include "analyze-elf.h"
#include "analyze-filesystems.h"
@@ -88,13 +89,8 @@
svg("</text>\n"); \
} while (false)
-static enum dot {
- DEP_ALL,
- DEP_ORDER,
- DEP_REQUIRE
-} arg_dot = DEP_ALL;
-static char **arg_dot_from_patterns = NULL;
-static char **arg_dot_to_patterns = NULL;
+DotMode arg_dot = DEP_ALL;
+char **arg_dot_from_patterns = NULL, **arg_dot_to_patterns = NULL;
static usec_t arg_fuzz = 0;
PagerFlags arg_pager_flags = 0;
BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
@@ -217,7 +213,7 @@ static int bus_get_uint64_property(sd_bus *bus, const char *path, const char *in
return 0;
}
-static int bus_get_unit_property_strv(sd_bus *bus, const char *path, const char *property, char ***strv) {
+int bus_get_unit_property_strv(sd_bus *bus, const char *path, const char *property, char ***strv) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
@@ -1204,181 +1200,6 @@ static int analyze_time(int argc, char *argv[], void *userdata) {
return 0;
}
-static int graph_one_property(
- sd_bus *bus,
- const UnitInfo *u,
- const char *prop,
- const char *color,
- char *patterns[],
- char *from_patterns[],
- char *to_patterns[]) {
-
- _cleanup_strv_free_ char **units = NULL;
- char **unit;
- int r;
- bool match_patterns;
-
- assert(u);
- assert(prop);
- assert(color);
-
- match_patterns = strv_fnmatch(patterns, u->id);
-
- if (!strv_isempty(from_patterns) && !match_patterns && !strv_fnmatch(from_patterns, u->id))
- return 0;
-
- r = bus_get_unit_property_strv(bus, u->unit_path, prop, &units);
- if (r < 0)
- return r;
-
- STRV_FOREACH(unit, units) {
- bool match_patterns2;
-
- match_patterns2 = strv_fnmatch(patterns, *unit);
-
- if (!strv_isempty(to_patterns) && !match_patterns2 && !strv_fnmatch(to_patterns, *unit))
- continue;
-
- if (!strv_isempty(patterns) && !match_patterns && !match_patterns2)
- continue;
-
- printf("\t\"%s\"->\"%s\" [color=\"%s\"];\n", u->id, *unit, color);
- }
-
- return 0;
-}
-
-static int graph_one(sd_bus *bus, const UnitInfo *u, char *patterns[], char *from_patterns[], char *to_patterns[]) {
- int r;
-
- assert(bus);
- assert(u);
-
- if (IN_SET(arg_dot, DEP_ORDER, DEP_ALL)) {
- r = graph_one_property(bus, u, "After", "green", patterns, from_patterns, to_patterns);
- if (r < 0)
- return r;
- }
-
- if (IN_SET(arg_dot, DEP_REQUIRE, DEP_ALL)) {
- r = graph_one_property(bus, u, "Requires", "black", patterns, from_patterns, to_patterns);
- if (r < 0)
- return r;
- r = graph_one_property(bus, u, "Requisite", "darkblue", patterns, from_patterns, to_patterns);
- if (r < 0)
- return r;
- r = graph_one_property(bus, u, "Wants", "grey66", patterns, from_patterns, to_patterns);
- if (r < 0)
- return r;
- r = graph_one_property(bus, u, "Conflicts", "red", patterns, from_patterns, to_patterns);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-static int expand_patterns(sd_bus *bus, char **patterns, char ***ret) {
- _cleanup_strv_free_ char **expanded_patterns = NULL;
- char **pattern;
- int r;
-
- STRV_FOREACH(pattern, patterns) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_free_ char *unit = NULL, *unit_id = NULL;
-
- if (strv_extend(&expanded_patterns, *pattern) < 0)
- return log_oom();
-
- if (string_is_glob(*pattern))
- continue;
-
- unit = unit_dbus_path_from_name(*pattern);
- if (!unit)
- return log_oom();
-
- r = sd_bus_get_property_string(
- bus,
- "org.freedesktop.systemd1",
- unit,
- "org.freedesktop.systemd1.Unit",
- "Id",
- &error,
- &unit_id);
- if (r < 0)
- return log_error_errno(r, "Failed to get ID: %s", bus_error_message(&error, r));
-
- if (!streq(*pattern, unit_id)) {
- if (strv_extend(&expanded_patterns, unit_id) < 0)
- return log_oom();
- }
- }
-
- *ret = TAKE_PTR(expanded_patterns); /* do not free */
-
- return 0;
-}
-
-static int dot(int argc, char *argv[], void *userdata) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
- _cleanup_strv_free_ char **expanded_patterns = NULL;
- _cleanup_strv_free_ char **expanded_from_patterns = NULL;
- _cleanup_strv_free_ char **expanded_to_patterns = NULL;
- int r;
- UnitInfo u;
-
- r = acquire_bus(&bus, NULL);
- if (r < 0)
- return bus_log_connect_error(r, arg_transport);
-
- r = expand_patterns(bus, strv_skip(argv, 1), &expanded_patterns);
- if (r < 0)
- return r;
-
- r = expand_patterns(bus, arg_dot_from_patterns, &expanded_from_patterns);
- if (r < 0)
- return r;
-
- r = expand_patterns(bus, arg_dot_to_patterns, &expanded_to_patterns);
- if (r < 0)
- return r;
-
- r = bus_call_method(bus, bus_systemd_mgr, "ListUnits", &error, &reply, NULL);
- if (r < 0)
- log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r));
-
- r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
- if (r < 0)
- return bus_log_parse_error(r);
-
- printf("digraph systemd {\n");
-
- while ((r = bus_parse_unit_info(reply, &u)) > 0) {
-
- r = graph_one(bus, &u, expanded_patterns, expanded_from_patterns, expanded_to_patterns);
- if (r < 0)
- return r;
- }
- if (r < 0)
- return bus_log_parse_error(r);
-
- printf("}\n");
-
- log_info(" Color legend: black = Requires\n"
- " dark blue = Requisite\n"
- " dark grey = Wants\n"
- " red = Conflicts\n"
- " green = After\n");
-
- if (on_tty() && !arg_quiet)
- log_notice("-- You probably want to process this output with graphviz' dot tool.\n"
- "-- Try a shell pipeline like 'systemd-analyze dot | dot -Tsvg > systemd.svg'!\n");
-
- return 0;
-}
-
static int cat_config(int argc, char *argv[], void *userdata) {
char **arg, **list;
int r;
diff --git a/src/analyze/analyze.h b/src/analyze/analyze.h
index 243e354458..1819b5d731 100644
--- a/src/analyze/analyze.h
+++ b/src/analyze/analyze.h
@@ -7,6 +7,14 @@
#include "pager.h"
#include "time-util.h"
+typedef enum DotMode {
+ DEP_ALL,
+ DEP_ORDER,
+ DEP_REQUIRE,
+} DotMode;
+
+extern DotMode arg_dot;
+extern char **arg_dot_from_patterns, **arg_dot_to_patterns;
extern PagerFlags arg_pager_flags;
extern BusTransport arg_transport;
extern unsigned arg_iterations;
@@ -15,4 +23,6 @@ extern bool arg_quiet;
int acquire_bus(sd_bus **bus, bool *use_full_bus);
+int bus_get_unit_property_strv(sd_bus *bus, const char *path, const char *property, char ***strv);
+
void time_parsing_hint(const char *p, bool calendar, bool timestamp, bool timespan);
diff --git a/src/analyze/meson.build b/src/analyze/meson.build
index 2d62412641..922a343e69 100644
--- a/src/analyze/meson.build
+++ b/src/analyze/meson.build
@@ -5,6 +5,8 @@ systemd_analyze_sources = files('''
analyze-calendar.h
analyze-condition.c
analyze-condition.h
+ analyze-dot.c
+ analyze-dot.h
analyze-dump.c
analyze-dump.h
analyze-elf.c