diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/analyze/systemd-analyze.c | 188 | ||||
-rw-r--r-- | src/systemctl/systemctl.c | 191 |
2 files changed, 184 insertions, 195 deletions
diff --git a/src/analyze/systemd-analyze.c b/src/analyze/systemd-analyze.c index 1ea56c6896..88fb40676e 100644 --- a/src/analyze/systemd-analyze.c +++ b/src/analyze/systemd-analyze.c @@ -46,6 +46,11 @@ } while(false) static UnitFileScope arg_scope = UNIT_FILE_SYSTEM; +static enum dot { + DEP_ALL, + DEP_ORDER, + DEP_REQUIRE +} arg_dot = DEP_ALL; double scale_x = 0.1; // pixels per ms double scale_y = 20.0; @@ -532,6 +537,166 @@ static int analyze_time(DBusConnection *bus) return 0; } +static int graph_one_property(const char *name, const char *prop, DBusMessageIter *iter) { + + static const char * const colors[] = { + "Requires", "[color=\"black\"]", + "RequiresOverridable", "[color=\"black\"]", + "Requisite", "[color=\"darkblue\"]", + "RequisiteOverridable", "[color=\"darkblue\"]", + "Wants", "[color=\"grey66\"]", + "Conflicts", "[color=\"red\"]", + "ConflictedBy", "[color=\"red\"]", + "After", "[color=\"green\"]" + }; + + const char *c = NULL; + unsigned i; + + assert(name); + assert(prop); + assert(iter); + + for (i = 0; i < ELEMENTSOF(colors); i += 2) + if (streq(colors[i], prop)) { + c = colors[i+1]; + break; + } + + if (!c) + return 0; + + if (arg_dot != DEP_ALL) + if ((arg_dot == DEP_ORDER) != streq(prop, "After")) + return 0; + + if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_ARRAY && + dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) { + DBusMessageIter sub; + + dbus_message_iter_recurse(iter, &sub); + + for (dbus_message_iter_recurse(iter, &sub); + dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID; + dbus_message_iter_next(&sub)) { + const char *s; + + assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING); + dbus_message_iter_get_basic(&sub, &s); + printf("\t\"%s\"->\"%s\" %s;\n", name, s, c); + } + } + + return 0; +} + +static int graph_one(DBusConnection *bus, const struct unit_info *u) { + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; + const char *interface = "org.freedesktop.systemd1.Unit"; + int r; + DBusMessageIter iter, sub, sub2, sub3; + + assert(bus); + assert(u); + + r = bus_method_call_with_reply( + bus, + "org.freedesktop.systemd1", + u->unit_path, + "org.freedesktop.DBus.Properties", + "GetAll", + &reply, + NULL, + DBUS_TYPE_STRING, &interface, + DBUS_TYPE_INVALID); + if (r < 0) + return r; + + if (!dbus_message_iter_init(reply, &iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) { + log_error("Failed to parse reply."); + return -EIO; + } + + for (dbus_message_iter_recurse(&iter, &sub); + dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID; + dbus_message_iter_next(&sub)) { + const char *prop; + + assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY); + dbus_message_iter_recurse(&sub, &sub2); + + if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0 || + dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) { + log_error("Failed to parse reply."); + return -EIO; + } + + dbus_message_iter_recurse(&sub2, &sub3); + r = graph_one_property(u->id, prop, &sub3); + if (r < 0) + return r; + } + + return 0; +} + +static int dot(DBusConnection *bus) { + _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; + DBusMessageIter iter, sub; + int r; + + r = bus_method_call_with_reply( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "ListUnits", + &reply, + NULL, + DBUS_TYPE_INVALID); + if (r < 0) + return r; + + if (!dbus_message_iter_init(reply, &iter) || + dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || + dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) { + log_error("Failed to parse reply."); + return -EIO; + } + + printf("digraph systemd {\n"); + + for (dbus_message_iter_recurse(&iter, &sub); + dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID; + dbus_message_iter_next(&sub)) { + struct unit_info u; + + r = bus_parse_unit_info(&sub, &u); + if (r < 0) + return -EIO; + + r = graph_one(bus, &u); + if (r < 0) + return 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()) + 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 void analyze_help(void) { printf("%s [OPTIONS...] {COMMAND} ...\n\n" @@ -539,11 +704,14 @@ static void analyze_help(void) " -h --help Show this help\n" " --version Show package version\n" " --system Connect to system manager\n" - " --user Connect to user service manager\n\n" + " --user Connect to user service manager\n" + " --order When generating a dependency graph, show only order\n" + " --require When generating a dependency graph, show only requirement\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" - " plot output SVG graphic showing service initialization\n\n", + " time Print time spent in the kernel before reaching userspace\n" + " blame Print list of running units ordered by time to init\n" + " plot Output SVG graphic showing service initialization\n" + " dot Dump dependency graph (in dot(1) format)\n\n", program_invocation_short_name); } @@ -551,6 +719,8 @@ static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, + ARG_ORDER, + ARG_REQUIRE, ARG_USER, ARG_SYSTEM }; @@ -558,6 +728,8 @@ static int parse_argv(int argc, char *argv[]) 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 }, { NULL, 0, NULL, 0 } @@ -580,6 +752,12 @@ static int parse_argv(int argc, char *argv[]) case ARG_SYSTEM: arg_scope = UNIT_FILE_SYSTEM; break; + case ARG_ORDER: + arg_dot = DEP_ORDER; + break; + case ARG_REQUIRE: + arg_dot = DEP_REQUIRE; + break; case -1: return 1; case '?': @@ -614,6 +792,8 @@ int main(int argc, char *argv[]) { r = analyze_blame(bus); else if (streq(argv[optind], "plot")) r = analyze_plot(bus); + else if (streq(argv[optind], "dot")) + r = dot(bus); else log_error("Unknown operation '%s'.", argv[optind]); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 54c8ebc363..12e343e853 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -116,11 +116,6 @@ static enum action { ACTION_CANCEL_SHUTDOWN, _ACTION_MAX } arg_action = ACTION_SYSTEMCTL; -static enum dot { - DOT_ALL, - DOT_ORDER, - DOT_REQUIRE -} arg_dot = DOT_ALL; static enum transport { TRANSPORT_NORMAL, TRANSPORT_SSH, @@ -891,176 +886,6 @@ static int list_dependencies(DBusConnection *bus, char **args) { return list_dependencies_one(bus, u, 0, NULL, 0); } -static int dot_one_property(const char *name, const char *prop, DBusMessageIter *iter) { - - static const char * const colors[] = { - "Requires", "[color=\"black\"]", - "RequiresOverridable", "[color=\"black\"]", - "Requisite", "[color=\"darkblue\"]", - "RequisiteOverridable", "[color=\"darkblue\"]", - "Wants", "[color=\"grey66\"]", - "Conflicts", "[color=\"red\"]", - "ConflictedBy", "[color=\"red\"]", - "After", "[color=\"green\"]" - }; - - const char *c = NULL; - unsigned i; - - assert(name); - assert(prop); - assert(iter); - - for (i = 0; i < ELEMENTSOF(colors); i += 2) - if (streq(colors[i], prop)) { - c = colors[i+1]; - break; - } - - if (!c) - return 0; - - if (arg_dot != DOT_ALL) - if ((arg_dot == DOT_ORDER) != streq(prop, "After")) - return 0; - - switch (dbus_message_iter_get_arg_type(iter)) { - - case DBUS_TYPE_ARRAY: - - if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) { - DBusMessageIter sub; - - dbus_message_iter_recurse(iter, &sub); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - const char *s; - - assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING); - dbus_message_iter_get_basic(&sub, &s); - printf("\t\"%s\"->\"%s\" %s;\n", name, s, c); - - dbus_message_iter_next(&sub); - } - - return 0; - } - } - - return 0; -} - -static int dot_one(DBusConnection *bus, const struct unit_info *u) { - _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; - const char *interface = "org.freedesktop.systemd1.Unit"; - int r; - DBusMessageIter iter, sub, sub2, sub3; - - assert(bus); - assert(u); - - r = bus_method_call_with_reply( - bus, - "org.freedesktop.systemd1", - u->unit_path, - "org.freedesktop.DBus.Properties", - "GetAll", - &reply, - NULL, - DBUS_TYPE_STRING, &interface, - DBUS_TYPE_INVALID); - if (r < 0) - return r; - - if (!dbus_message_iter_init(reply, &iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) { - log_error("Failed to parse reply."); - return -EIO; - } - - dbus_message_iter_recurse(&iter, &sub); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - const char *prop; - - assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY); - dbus_message_iter_recurse(&sub, &sub2); - - if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0 || - dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) { - log_error("Failed to parse reply."); - return -EIO; - } - - dbus_message_iter_recurse(&sub2, &sub3); - r = dot_one_property(u->id, prop, &sub3); - if (r < 0) - return r; - - dbus_message_iter_next(&sub); - } - - return 0; -} - -static int dot(DBusConnection *bus, char **args) { - _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; - DBusMessageIter iter, sub; - int r; - - r = bus_method_call_with_reply( - bus, - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "ListUnits", - &reply, - NULL, - DBUS_TYPE_INVALID); - if (r < 0) - return r; - - if (!dbus_message_iter_init(reply, &iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) { - log_error("Failed to parse reply."); - return -EIO; - } - - printf("digraph systemd {\n"); - - dbus_message_iter_recurse(&iter, &sub); - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - struct unit_info u; - - r = bus_parse_unit_info(&sub, &u); - if (r < 0) - return -EIO; - - r = dot_one(bus, &u); - if (r < 0) - return r; - - /* printf("\t\"%s\";\n", u.id); */ - dbus_message_iter_next(&sub); - } - - 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()) - log_notice("-- You probably want to process this output with graphviz' dot tool.\n" - "-- Try a shell pipeline like 'systemctl dot | dot -Tsvg > systemd.svg'!\n"); - - return 0; -} - static int list_jobs(DBusConnection *bus, char **args) { _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; DBusMessageIter iter, sub, sub2; @@ -4276,8 +4101,6 @@ static int systemctl_help(void) { " --no-pager Do not pipe output into a pager\n" " --no-ask-password\n" " Do not ask for system passwords\n" - " --order When generating graph for dot, show only order\n" - " --require When generating graph for dot, show only requirement\n" " --system Connect to system manager\n" " --user Connect to user service manager\n" " --global Enable/disable unit files globally\n" @@ -4337,7 +4160,6 @@ static int systemctl_help(void) { " cancel [JOB...] Cancel all, one, or more jobs\n\n" "Status Commands:\n" " dump Dump server status\n" - " dot Dump dependency graph for dot(1)\n\n" "Snapshot Commands:\n" " snapshot [NAME] Create a snapshot\n" " delete [NAME...] Remove one or more snapshots\n\n" @@ -4460,8 +4282,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) { ARG_NO_LEGEND, ARG_NO_PAGER, ARG_NO_WALL, - ARG_ORDER, - ARG_REQUIRE, ARG_ROOT, ARG_FULL, ARG_NO_RELOAD, @@ -4491,8 +4311,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) { { "no-pager", no_argument, NULL, ARG_NO_PAGER }, { "no-wall", no_argument, NULL, ARG_NO_WALL }, { "quiet", no_argument, NULL, 'q' }, - { "order", no_argument, NULL, ARG_ORDER }, - { "require", no_argument, NULL, ARG_REQUIRE }, { "root", required_argument, NULL, ARG_ROOT }, { "force", no_argument, NULL, ARG_FORCE }, { "no-reload", no_argument, NULL, ARG_NO_RELOAD }, @@ -4599,14 +4417,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) { arg_no_wall = true; break; - case ARG_ORDER: - arg_dot = DOT_ORDER; - break; - - case ARG_REQUIRE: - arg_dot = DOT_REQUIRE; - break; - case ARG_ROOT: arg_root = optarg; break; @@ -5307,7 +5117,6 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError { "status", MORE, 2, show }, { "help", MORE, 2, show }, { "dump", EQUAL, 1, dump }, - { "dot", EQUAL, 1, dot }, { "snapshot", LESS, 2, snapshot }, { "delete", MORE, 2, delete_snapshot }, { "daemon-reload", EQUAL, 1, daemon_reload }, |