chiark / gitweb /
Move systemctl dot to systemd-analyze dot
[elogind.git] / src / systemctl / systemctl.c
index de1a022ae36174e19f4372bcab2da35c10390876..12e343e8530a71f8676daac08bc138a7e327cb6a 100644 (file)
@@ -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,
@@ -275,19 +270,6 @@ static bool avoid_bus(void) {
         return false;
 }
 
-struct unit_info {
-        const char *id;
-        const char *description;
-        const char *load_state;
-        const char *active_state;
-        const char *sub_state;
-        const char *following;
-        const char *unit_path;
-        uint32_t job_id;
-        const char *job_type;
-        const char *job_path;
-};
-
 static int compare_unit_info(const void *a, const void *b) {
         const char *d1, *d2;
         const struct unit_info *u = a, *v = b;
@@ -448,7 +430,7 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
 static int list_units(DBusConnection *bus, char **args) {
         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
         _cleanup_free_ struct unit_info *unit_infos = NULL;
-        DBusMessageIter iter, sub, sub2;
+        DBusMessageIter iter, sub;
         unsigned c = 0, n_units = 0;
         int r;
 
@@ -478,8 +460,6 @@ static int list_units(DBusConnection *bus, char **args) {
         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
                 struct unit_info *u;
 
-                assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT);
-
                 if (c >= n_units) {
                         struct unit_info *w;
 
@@ -493,21 +473,7 @@ static int list_units(DBusConnection *bus, char **args) {
 
                 u = unit_infos + c;
 
-                dbus_message_iter_recurse(&sub, &sub2);
-
-                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->id, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->description, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->load_state, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->active_state, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->sub_state, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->following, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &u->unit_path, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &u->job_id, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->job_type, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &u->job_path, false) < 0) {
-                        log_error("Failed to parse reply.");
-                        return -EIO;
-                }
+                bus_parse_unit_info(&sub, u);
 
                 dbus_message_iter_next(&sub);
                 c++;
@@ -842,8 +808,9 @@ static int list_dependencies_get_dependencies(DBusConnection *bus, const char *n
         }
 finish:
         if (r < 0)
-                strv_freep(&ret);
-        *deps = ret;
+                strv_free(ret);
+        else
+                *deps = ret;
         return r;
 }
 
@@ -919,190 +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 char *name, const char *path) {
-        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
-        const char *interface = "org.freedesktop.systemd1.Unit";
-        int r;
-        DBusMessageIter iter, sub, sub2, sub3;
-
-        assert(bus);
-        assert(path);
-
-        r = bus_method_call_with_reply(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        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(name, 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, sub2;
-        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) {
-                const char *id, *description, *load_state, *active_state, *sub_state, *following, *unit_path;
-
-                if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
-                        log_error("Failed to parse reply.");
-                        return -EIO;
-                }
-
-                dbus_message_iter_recurse(&sub, &sub2);
-
-                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &description, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &load_state, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &active_state, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &sub_state, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &following, true) < 0 ||
-                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, true) < 0) {
-                        log_error("Failed to parse reply.");
-                        return -EIO;
-                }
-
-                r = dot_one(bus, id, unit_path);
-                if (r < 0)
-                        return r;
-
-                /* printf("\t\"%s\";\n", 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;
@@ -2176,6 +1959,7 @@ static int set_cgroup(DBusConnection *bus, char **args) {
         DBusMessageIter iter;
         int r;
         _cleanup_free_ char *n = NULL;
+        const char *runtime;
 
         assert(bus);
         assert(args);
@@ -2207,6 +1991,10 @@ static int set_cgroup(DBusConnection *bus, char **args) {
         if (r < 0)
                 return log_oom();
 
+        runtime = arg_runtime ? "runtime" : "persistent";
+        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &runtime))
+                return log_oom();
+
         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
         if (!reply) {
                 log_error("Failed to issue method call: %s", bus_error_message(&error));
@@ -2223,6 +2011,7 @@ static int set_cgroup_attr(DBusConnection *bus, char **args) {
         DBusMessageIter iter, sub, sub2;
         char **x, **y;
         _cleanup_free_ char *n = NULL;
+        const char *runtime;
 
         assert(bus);
         assert(args);
@@ -2259,8 +2048,54 @@ static int set_cgroup_attr(DBusConnection *bus, char **args) {
                         return log_oom();
         }
 
-        if (!dbus_message_iter_close_container(&iter, &sub))
-                return -ENOMEM;
+        runtime = arg_runtime ? "runtime" : "persistent";
+        if (!dbus_message_iter_close_container(&iter, &sub) ||
+            !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &runtime))
+                return log_oom();
+
+        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+        if (!reply) {
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
+                dbus_error_free(&error);
+                return -EIO;
+        }
+
+        return 0;
+}
+
+static int get_cgroup_attr(DBusConnection *bus, char **args) {
+        _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
+        DBusError error;
+        DBusMessageIter iter;
+        int r;
+        _cleanup_free_ char *n = NULL;
+        _cleanup_strv_free_ char **list = NULL;
+        char **a;
+
+        assert(bus);
+        assert(args);
+
+        dbus_error_init(&error);
+
+        n = unit_name_mangle(args[1]);
+        if (!n)
+                return log_oom();
+
+        m = dbus_message_new_method_call(
+                        "org.freedesktop.systemd1",
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "GetUnitControlGroupAttributes");
+        if (!m)
+                return log_oom();
+
+        dbus_message_iter_init_append(m, &iter);
+        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n))
+                return log_oom();
+
+        r = bus_append_strv_iter(&iter, args + 2);
+        if (r < 0)
+                return log_oom();
 
         reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
         if (!reply) {
@@ -2269,6 +2104,20 @@ static int set_cgroup_attr(DBusConnection *bus, char **args) {
                 return -EIO;
         }
 
+        dbus_message_iter_init(reply, &iter);
+        r = bus_parse_strv_iter(&iter, &list);
+        if (r < 0) {
+                log_error("Failed to parse value list.");
+                return r;
+        }
+
+        STRV_FOREACH(a, list) {
+                if (endswith(*a, "\n"))
+                        fputs(*a, stdout);
+                else
+                        puts(*a);
+        }
+
         return 0;
 }
 
@@ -2675,13 +2524,23 @@ static void print_status_info(UnitStatusInfo *i) {
 
         if (i->id && arg_transport != TRANSPORT_SSH) {
                 printf("\n");
-                show_journal_by_unit(stdout,
-                                     i->id,
-                                     arg_output,
-                                     0,
-                                     i->inactive_exit_timestamp_monotonic,
-                                     arg_lines,
-                                     flags);
+                if(arg_scope == UNIT_FILE_SYSTEM)
+                        show_journal_by_unit(stdout,
+                                             i->id,
+                                             arg_output,
+                                             0,
+                                             i->inactive_exit_timestamp_monotonic,
+                                             arg_lines,
+                                             flags);
+                else
+                        show_journal_by_user_unit(stdout,
+                                                  i->id,
+                                                  arg_output,
+                                                  0,
+                                                  i->inactive_exit_timestamp_monotonic,
+                                                  arg_lines,
+                                                  getuid(),
+                                                  flags);
         }
 
         if (i->need_daemon_reload)
@@ -3094,7 +2953,7 @@ static int print_property(const char *name, DBusMessageIter *iter) {
                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
                                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
 
-                                        printf("ControlGroupAttribute={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
+                                        printf("ControlGroupAttributes={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
                                                controller,
                                                attr,
                                                value);
@@ -4242,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"
@@ -4275,12 +4132,14 @@ static int systemctl_help(void) {
                "  help [NAME...|PID...]           Show manual for one or more units\n"
                "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
                "                                  units\n"
-               "  set-cgroup [NAME] [CGROUP...]   Add unit to a control group\n"
-               "  unset-cgroup [NAME] [CGROUP...] Remove unit from a control group\n"
+               "  get-cgroup-attr [NAME] [ATTR] ...\n"
+               "                                  Get control group attrubute\n"
                "  set-cgroup-attr [NAME] [ATTR] [VALUE] ...\n"
                "                                  Set control group attribute\n"
                "  unset-cgroup-attr [NAME] [ATTR...]\n"
                "                                  Unset control group attribute\n"
+               "  set-cgroup [NAME] [CGROUP...]   Add unit to a control group\n"
+               "  unset-cgroup [NAME] [CGROUP...] Remove unit from a control group\n"
                "  load [NAME...]                  Load one or more units\n"
                "  list-dependencies [NAME]        Recursively show units which are required\n"
                "                                  or wanted by this unit\n\n"
@@ -4301,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"
@@ -4424,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,
@@ -4455,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 },
@@ -4563,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;
@@ -5260,6 +5106,7 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
                 { "isolate",               EQUAL, 2, start_unit        },
                 { "set-cgroup",            MORE,  2, set_cgroup        },
                 { "unset-cgroup",          MORE,  2, set_cgroup        },
+                { "get-cgroup-attr",       MORE,  2, get_cgroup_attr   },
                 { "set-cgroup-attr",       MORE,  2, set_cgroup_attr   },
                 { "unset-cgroup-attr",     MORE,  2, set_cgroup        },
                 { "kill",                  MORE,  2, kill_unit         },
@@ -5270,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     },