chiark / gitweb /
systemctl: refactor show()
[elogind.git] / src / systemctl / systemctl.c
index 737cd67d6814b12f1706e009bbe58c0f3536b9ae..e10721362dce7bac53cbc6d1db38d6f2db8e3af6 100644 (file)
 #include "spawn-polkit-agent.h"
 #include "install.h"
 #include "logs-show.h"
-#include "path-util.h"
 #include "socket-util.h"
 #include "fileio.h"
 #include "bus-util.h"
 #include "bus-message.h"
 #include "bus-error.h"
+#include "bus-errors.h"
 
 static char **arg_types = NULL;
 static char **arg_states = NULL;
@@ -137,6 +137,8 @@ static bool arg_plain = false;
 static int daemon_reload(sd_bus *bus, char **args);
 static int halt_now(enum action a);
 
+static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet);
+
 static void pager_open_if_enabled(void) {
 
         if (arg_no_pager)
@@ -195,7 +197,7 @@ static int translate_bus_error_to_exit_status(int r, const sd_bus_error *error)
                 return EXIT_NOTINSTALLED;
 
         if (sd_bus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE) ||
-            sd_bus_error_has_name(error, BUS_ERROR_NOT_SUPPORTED))
+            sd_bus_error_has_name(error, SD_BUS_ERROR_NOT_SUPPORTED))
                 return EXIT_NOTIMPLEMENTED;
 
         if (sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED))
@@ -750,7 +752,6 @@ static int get_next_elapse(
                 dual_timestamp *next) {
 
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
         dual_timestamp t;
         int r;
 
@@ -1310,6 +1311,8 @@ static int list_dependencies_one(
         qsort_safe(deps, strv_length(deps), sizeof (char*), list_dependencies_compare);
 
         STRV_FOREACH(c, deps) {
+                int state;
+
                 if (strv_contains(u, *c)) {
                         if (!arg_plain) {
                                 r = list_dependencies_print("...", level + 1, (branches << 1) | (c[1] == NULL ? 0 : 1), 1);
@@ -1319,6 +1322,12 @@ static int list_dependencies_one(
                         continue;
                 }
 
+                state = check_one_unit(bus, *c, "activating\0active\0reloading\0", true);
+                if (state > 0)
+                        printf("%s%s%s", ansi_highlight_green(), draw_special_char(DRAW_BLACK_CIRCLE), ansi_highlight_off());
+                else
+                        printf("%s%s%s", ansi_highlight_red(), draw_special_char(DRAW_BLACK_CIRCLE), ansi_highlight_off());
+
                 r = list_dependencies_print(*c, level, branches, c[1] == NULL);
                 if (r < 0)
                         return r;
@@ -1402,6 +1411,100 @@ static int get_default(sd_bus *bus, char **args) {
         return 0;
 }
 
+static void dump_unit_file_changes(const UnitFileChange *changes, unsigned n_changes) {
+        unsigned i;
+
+        assert(changes || n_changes == 0);
+
+        for (i = 0; i < n_changes; i++) {
+                if (changes[i].type == UNIT_FILE_SYMLINK)
+                        log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
+                else
+                        log_info("rm '%s'", changes[i].path);
+        }
+}
+
+static int deserialize_and_dump_unit_file_changes(sd_bus_message *m) {
+        const char *type, *path, *source;
+        int r;
+
+        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
+                if (!arg_quiet) {
+                        if (streq(type, "symlink"))
+                                log_info("ln -s '%s' '%s'", source, path);
+                        else
+                                log_info("rm '%s'", path);
+                }
+        }
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        r = sd_bus_message_exit_container(m);
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        return 0;
+}
+
+static int set_default(sd_bus *bus, char **args) {
+        _cleanup_free_ char *unit = NULL;
+        UnitFileChange *changes = NULL;
+        unsigned n_changes = 0;
+        int r;
+
+        unit = unit_name_mangle_with_suffix(args[1], ".target");
+        if (!unit)
+                return log_oom();
+
+        if (!bus || avoid_bus()) {
+                r = unit_file_set_default(arg_scope, arg_root, unit, arg_force, &changes, &n_changes);
+                if (r < 0) {
+                        log_error("Failed to set default target: %s", strerror(-r));
+                        return r;
+                }
+
+                if (!arg_quiet)
+                        dump_unit_file_changes(changes, n_changes);
+
+                r = 0;
+        } else {
+                _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+
+                r = sd_bus_call_method(
+                                bus,
+                                "org.freedesktop.systemd1",
+                                "/org/freedesktop/systemd1",
+                                "org.freedesktop.systemd1.Manager",
+                                "SetDefaultTarget",
+                                &error,
+                                &reply,
+                                "sb", unit, arg_force);
+                if (r < 0) {
+                        log_error("Failed to set default target: %s", bus_error_message(&error, -r));
+                        return r;
+                }
+
+                r = deserialize_and_dump_unit_file_changes(reply);
+                if (r < 0)
+                        return r;
+
+                /* Try to reload if enabeld */
+                if (!arg_no_reload)
+                        r = daemon_reload(bus, args);
+                else
+                        r = 0;
+        }
+
+        unit_file_changes_free(changes, n_changes);
+
+        return r;
+}
+
 struct job_info {
         uint32_t id;
         const char *name, *type, *state;
@@ -1618,7 +1721,7 @@ typedef struct WaitData {
         char *result;
 } WaitData;
 
-static int wait_filter(sd_bus *bus, sd_bus_message *m, void *data) {
+static int wait_filter(sd_bus *bus, sd_bus_message *m, void *data, sd_bus_error *error) {
         WaitData *d = data;
 
         assert(bus);
@@ -1671,7 +1774,7 @@ static int wait_filter(sd_bus *bus, sd_bus_message *m, void *data) {
                 }
 #endif
 
-                log_error("Failed to parse message.");
+                bus_log_parse_error(r);
         }
 
         return 0;
@@ -2127,7 +2230,6 @@ static int reboot_with_logind(sd_bus *bus, enum action a) {
 
 static int check_inhibitors(sd_bus *bus, enum action a) {
 #ifdef HAVE_LOGIND
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
         _cleanup_strv_free_ char **sessions = NULL;
         const char *what, *who, *why, *mode;
@@ -3502,16 +3604,13 @@ static int show_one(
         return r;
 }
 
-static int show_one_by_pid(
-                const char *verb,
+static int get_unit_dbus_path_by_pid(
                 sd_bus *bus,
                 uint32_t pid,
-                bool *new_line,
-                bool *ellipsized) {
+                char **unit) {
 
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
-        const char *path = NULL;
         int r;
 
         r = sd_bus_call_method(
@@ -3528,11 +3627,11 @@ static int show_one_by_pid(
                 return r;
         }
 
-        r = sd_bus_message_read(reply, "o", &path);
+        r = sd_bus_message_read(reply, "o", unit);
         if (r < 0)
                 return bus_log_parse_error(r);
 
-        return show_one(verb, bus, path, false, new_line, ellipsized);
+        return 0;
 }
 
 static int show_all(
@@ -3542,7 +3641,6 @@ static int show_all(
                 bool *new_line,
                 bool *ellipsized) {
 
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
         _cleanup_free_ UnitInfo *unit_infos = NULL;
         const UnitInfo *u;
@@ -3553,6 +3651,8 @@ static int show_all(
         if (r < 0)
                 return r;
 
+        pager_open_if_enabled();
+
         c = (unsigned) r;
 
         qsort_safe(unit_infos, c, sizeof(UnitInfo), compare_unit_info);
@@ -3567,8 +3667,6 @@ static int show_all(
                 if (!p)
                         return log_oom();
 
-                printf("%s -> '%s'\n", u->id, p);
-
                 r = show_one(verb, bus, p, show_properties, new_line, ellipsized);
                 if (r != 0)
                         return r;
@@ -3601,41 +3699,34 @@ static int show(sd_bus *bus, char **args) {
                 ret = show_all(args[0], bus, false, &new_line, &ellipsized);
         else
                 STRV_FOREACH(name, args+1) {
+                        _cleanup_free_ char *unit = NULL;
                         uint32_t id;
 
                         if (safe_atou32(*name, &id) < 0) {
-                                _cleanup_free_ char *p = NULL, *n = NULL;
+                                _cleanup_free_ char *n = NULL;
                                 /* Interpret as unit name */
 
                                 n = unit_name_mangle(*name);
                                 if (!n)
                                         return log_oom();
 
-                                p = unit_dbus_path_from_name(n);
-                                if (!p)
+                                unit = unit_dbus_path_from_name(n);
+                                if (!unit)
                                         return log_oom();
 
-                                r = show_one(args[0], bus, p, show_properties, &new_line, &ellipsized);
-                                if (r != 0)
-                                        ret = r;
-
                         } else if (show_properties) {
-                                _cleanup_free_ char *p = NULL;
-
                                 /* Interpret as job id */
-                                if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0)
+                                if (asprintf(&unit, "/org/freedesktop/systemd1/job/%u", id) < 0)
                                         return log_oom();
 
-                                r = show_one(args[0], bus, p, show_properties, &new_line, &ellipsized);
-                                if (r != 0)
-                                        ret = r;
-
                         } else {
                                 /* Interpret as PID */
-                                r = show_one_by_pid(args[0], bus, id, &new_line, &ellipsized);
-                                if (r != 0)
+                                r = get_unit_dbus_path_by_pid(bus, id, &unit);
+                                if (r < 0)
                                         ret = r;
                         }
+
+                        show_one(args[0], bus, unit, show_properties, &new_line, &ellipsized);
                 }
 
         if (ellipsized && !arg_quiet)
@@ -4335,12 +4426,10 @@ static int mangle_names(char **original_names, char ***mangled_names) {
 }
 
 static int enable_unit(sd_bus *bus, char **args) {
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_strv_free_ char **mangled_names = NULL;
         const char *verb = args[0];
         UnitFileChange *changes = NULL;
-        unsigned n_changes = 0, i;
+        unsigned n_changes = 0;
         int carries_install_info = -1;
         int r;
 
@@ -4373,8 +4462,6 @@ static int enable_unit(sd_bus *bus, char **args) {
                         r = unit_file_mask(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
                 else if (streq(verb, "unmask"))
                         r = unit_file_unmask(arg_scope, arg_runtime, arg_root, mangled_names, &changes, &n_changes);
-                else if (streq(verb, "set-default"))
-                        r = unit_file_set_default(arg_scope, arg_root, args[1], &changes, &n_changes);
                 else
                         assert_not_reached("Unknown verb");
 
@@ -4383,20 +4470,16 @@ static int enable_unit(sd_bus *bus, char **args) {
                         goto finish;
                 }
 
-                if (!arg_quiet) {
-                        for (i = 0; i < n_changes; i++) {
-                                if (changes[i].type == UNIT_FILE_SYMLINK)
-                                        log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
-                                else
-                                        log_info("rm '%s'", changes[i].path);
-                        }
-                }
+                if (!arg_quiet)
+                        dump_unit_file_changes(changes, n_changes);
 
                 r = 0;
         } else {
-                const char *method, *type, *path, *source;
+                _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
+                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
                 int expect_carries_install_info = false;
                 bool send_force = true;
+                const char *method;
 
                 if (streq(verb, "enable")) {
                         method = "EnableUnitFiles";
@@ -4417,8 +4500,6 @@ static int enable_unit(sd_bus *bus, char **args) {
                 else if (streq(verb, "unmask")) {
                         method = "UnmaskUnitFiles";
                         send_force = false;
-                } else if (streq(verb, "set-default")) {
-                        method = "SetDefaultTarget";
                 } else
                         assert_not_reached("Unknown verb");
 
@@ -4458,24 +4539,9 @@ static int enable_unit(sd_bus *bus, char **args) {
                                 return bus_log_parse_error(r);
                 }
 
-                r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(sss)");
-                if (r < 0)
-                        return bus_log_parse_error(r);
-
-                while ((r = sd_bus_message_read(reply, "(sss)", &type, &path, &source)) > 0) {
-                        if (!arg_quiet) {
-                                if (streq(type, "symlink"))
-                                        log_info("ln -s '%s' '%s'", source, path);
-                                else
-                                        log_info("rm '%s'", path);
-                        }
-                }
-                if (r < 0)
-                        return bus_log_parse_error(r);
-
-                r = sd_bus_message_exit_container(reply);
+                r = deserialize_and_dump_unit_file_changes(reply);
                 if (r < 0)
-                        return bus_log_parse_error(r);
+                        return r;
 
                 /* Try to reload if enabeld */
                 if (!arg_no_reload)
@@ -4595,14 +4661,10 @@ static int systemctl_help(void) {
                "  -a --all            Show all loaded units/properties, including dead/empty\n"
                "                      ones. To list all units installed on the system, use\n"
                "                      the 'list-unit-files' command instead.\n"
-               "     --reverse        Show reverse dependencies with 'list-dependencies'\n"
                "  -l --full           Don't ellipsize unit names on output\n"
-               "     --fail           When queueing a new job, fail if conflicting jobs are\n"
-               "                      pending\n"
-               "     --irreversible   When queueing a new job, make sure it cannot be implicitly\n"
-               "                      cancelled\n"
-               "     --ignore-dependencies\n"
-               "                      When queueing a new job, ignore all its dependencies\n"
+               "     --reverse        Show reverse dependencies with 'list-dependencies'\n"
+               "     --job-mode=MODE  Specify how to deal with already queued jobs, when\n"
+               "                      queueing a new job\n"
                "     --show-types     When showing sockets, explicitly show their type\n"
                "  -i --ignore-inhibitors\n"
                "                      When shutting down or sleeping, ignore inhibitors\n"
@@ -4804,7 +4866,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 ARG_RUNTIME,
                 ARG_FORCE,
                 ARG_PLAIN,
-                ARG_STATE
+                ARG_STATE,
+                ARG_JOB_MODE
         };
 
         static const struct option options[] = {
@@ -4819,9 +4882,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 { "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 },
+                { "job-mode",            required_argument, NULL, ARG_JOB_MODE            },
+                { "fail",                no_argument,       NULL, ARG_FAIL                }, /* compatibility only */
+                { "irreversible",        no_argument,       NULL, ARG_IRREVERSIBLE        }, /* compatibility only */
+                { "ignore-dependencies", no_argument,       NULL, ARG_IGNORE_DEPENDENCIES }, /* compatibility only */
                 { "ignore-inhibitors",   no_argument,       NULL, 'i'                     },
                 { "user",                no_argument,       NULL, ARG_USER                },
                 { "system",              no_argument,       NULL, ARG_SYSTEM              },
@@ -4959,6 +5023,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         arg_show_types = true;
                         break;
 
+                case ARG_JOB_MODE:
+                        arg_job_mode = optarg;
+                        break;
+
                 case ARG_FAIL:
                         arg_job_mode = "fail";
                         break;
@@ -5653,8 +5721,8 @@ static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
                 { "link",                  MORE,  2, enable_unit       },
                 { "switch-root",           MORE,  2, switch_root       },
                 { "list-dependencies",     LESS,  2, list_dependencies },
-                { "set-default",           EQUAL, 2, enable_unit       },
-                { "get-default",           LESS,  1, get_default       },
+                { "set-default",           EQUAL, 2, set_default       },
+                { "get-default",           EQUAL, 1, get_default       },
                 { "set-property",          MORE,  3, set_property      },
         };