chiark / gitweb /
systemctl: add bus_method_call_with_reply
[elogind.git] / src / systemctl / systemctl.c
index b8b9ed09546c793a097eca91e3f1c5d6d42fd62d..94b225cb31f09e57238f4bef99888aef6cd0939a 100644 (file)
@@ -65,6 +65,7 @@
 #include "path-util.h"
 
 static const char *arg_type = NULL;
+static const char *arg_load_state = NULL;
 static char **arg_property = NULL;
 static bool arg_all = false;
 static const char *arg_job_mode = "replace";
@@ -85,7 +86,6 @@ static bool arg_failed = false;
 static bool arg_runtime = false;
 static char **arg_wall = NULL;
 static const char *arg_kill_who = NULL;
-static const char *arg_kill_mode = NULL;
 static int arg_signal = SIGTERM;
 static const char *arg_root = NULL;
 static usec_t arg_when = 0;
@@ -245,14 +245,73 @@ static int translate_bus_error_to_exit_status(int r, const DBusError *error) {
         return EXIT_FAILURE;
 }
 
+static int bus_method_call_with_reply(DBusConnection *bus,
+                                       const char *destination,
+                                       const char *path,
+                                       const char *interface,
+                                       const char *method,
+                                       DBusMessage **return_reply,
+                                       DBusError *return_error,
+                                       int first_arg_type, ...) {
+        DBusError error;
+        DBusMessage *m, *reply;
+        va_list ap;
+        int r = 0;
+
+        dbus_error_init(&error);
+        assert(bus);
+
+        m = dbus_message_new_method_call(destination, path, interface, method);
+        if (!m) {
+                r = log_oom();
+                goto finish;
+        }
+
+        va_start(ap, first_arg_type);
+        if (!dbus_message_append_args_valist(m, first_arg_type, ap)) {
+                va_end(ap);
+                dbus_message_unref(m);
+                r = log_oom();
+                goto finish;
+        }
+        va_end(ap);
+
+        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+        dbus_message_unref(m);
+        if (!reply) {
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
+                if (error_is_no_service(&error))
+                        r = -ENOENT;
+                else if (dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED))
+                        r = -EACCES;
+                else if (dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY))
+                        r = -ETIMEDOUT;
+                else
+                        r = -EIO;
+                goto finish;
+        }
+        if (return_reply)
+                *return_reply = reply;
+        else
+                dbus_message_unref(reply);
+finish:
+        if(return_error)
+                *return_error=error;
+        else
+                dbus_error_free(&error);
+
+        return r;
+}
+
 static void warn_wall(enum action a) {
         static const char *table[_ACTION_MAX] = {
-                [ACTION_HALT]      = "The system is going down for system halt NOW!",
-                [ACTION_REBOOT]    = "The system is going down for reboot NOW!",
-                [ACTION_POWEROFF]  = "The system is going down for power-off NOW!",
-                [ACTION_KEXEC]     = "The system is going down for kexec reboot NOW!",
-                [ACTION_RESCUE]    = "The system is going down to rescue mode NOW!",
-                [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!"
+                [ACTION_HALT]            = "The system is going down for system halt NOW!",
+                [ACTION_REBOOT]          = "The system is going down for reboot NOW!",
+                [ACTION_POWEROFF]        = "The system is going down for power-off NOW!",
+                [ACTION_KEXEC]           = "The system is going down for kexec reboot NOW!",
+                [ACTION_RESCUE]          = "The system is going down to rescue mode NOW!",
+                [ACTION_EMERGENCY]       = "The system is going down to emergency mode NOW!",
+                [ACTION_CANCEL_SHUTDOWN] = "The system shutdown has been cancelled NOW!"
         };
 
         if (arg_no_wall)
@@ -337,7 +396,9 @@ static bool output_show_unit(const struct unit_info *u) {
 
         return (!arg_type || ((dot = strrchr(u->id, '.')) &&
                               streq(dot+1, arg_type))) &&
-                (arg_all || !(streq(u->active_state, "inactive") || u->following[0]) || u->job_id > 0);
+                (!arg_load_state || streq(u->load_state, arg_load_state)) &&
+                (arg_all || !(streq(u->active_state, "inactive")
+                              || u->following[0]) || u->job_id > 0);
 }
 
 static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
@@ -655,10 +716,8 @@ static int list_unit_files(DBusConnection *bus, char **args) {
                 Iterator i;
 
                 h = hashmap_new(string_hash_func, string_compare_func);
-                if (!h) {
-                        log_error("Out of memory");
-                        return -ENOMEM;
-                }
+                if (!h)
+                        return log_oom();
 
                 r = unit_file_get_list(arg_scope, arg_root, h);
                 if (r < 0) {
@@ -671,8 +730,7 @@ static int list_unit_files(DBusConnection *bus, char **args) {
                 units = new(UnitFileList, n_units);
                 if (!units) {
                         unit_file_list_free(h);
-                        log_error("Out of memory");
-                        return -ENOMEM;
+                        return log_oom();
                 }
 
                 HASHMAP_FOREACH(u, h, i) {
@@ -781,7 +839,7 @@ static int dot_one_property(const char *name, const char *prop, DBusMessageIter
                 "RequiresOverridable",   "[color=\"black\"]",
                 "Requisite",             "[color=\"darkblue\"]",
                 "RequisiteOverridable",  "[color=\"darkblue\"]",
-                "Wants",                 "[color=\"darkgrey\"]",
+                "Wants",                 "[color=\"grey66\"]",
                 "Conflicts",             "[color=\"red\"]",
                 "ConflictedBy",          "[color=\"red\"]",
                 "After",                 "[color=\"green\"]"
@@ -2137,9 +2195,6 @@ static int kill_unit(DBusConnection *bus, char **args) {
         if (!arg_kill_who)
                 arg_kill_who = "all";
 
-        if (!arg_kill_mode)
-                arg_kill_mode = streq(arg_kill_who, "all") ? "control-group" : "process";
-
         STRV_FOREACH(name, args+1) {
                 DBusMessage *reply;
                 char *n;
@@ -2160,7 +2215,6 @@ static int kill_unit(DBusConnection *bus, char **args) {
                 b = dbus_message_append_args(m,
                                              DBUS_TYPE_STRING, n ? &n : name,
                                              DBUS_TYPE_STRING, &arg_kill_who,
-                                             DBUS_TYPE_STRING, &arg_kill_mode,
                                              DBUS_TYPE_INT32, &arg_signal,
                                              DBUS_TYPE_INVALID);
                 free(n);
@@ -2589,8 +2643,16 @@ static void print_status_info(UnitStatusInfo *i) {
         }
 
         if (i->id && arg_transport != TRANSPORT_SSH) {
+                int flags =
+                        arg_lines * OUTPUT_SHOW_ALL |
+                        arg_follow * OUTPUT_FOLLOW |
+                        !arg_quiet * OUTPUT_WARN_CUTOFF |
+                        on_tty() * OUTPUT_COLOR;
+
                 printf("\n");
-                show_journal_by_unit(i->id, arg_output, 0, i->inactive_exit_timestamp_monotonic, arg_lines, arg_all, arg_follow, !arg_quiet);
+                show_journal_by_unit(i->id, arg_output, 0,
+                                     i->inactive_exit_timestamp_monotonic,
+                                     arg_lines, flags);
         }
 
         if (i->need_daemon_reload)
@@ -2627,14 +2689,14 @@ static void show_unit_help(UnitStatusInfo *i) {
                         if (e) {
                                 page = strndup((*p) + 4, e - *p - 4);
                                 if (!page) {
-                                        log_error("Out of memory.");
+                                        log_oom();
                                         return;
                                 }
 
                                 section = strndup(e + 1, *p + k - e - 2);
                                 if (!section) {
                                         free(page);
-                                        log_error("Out of memory");
+                                        log_oom();
                                         return;
                                 }
 
@@ -2663,7 +2725,7 @@ static void show_unit_help(UnitStatusInfo *i) {
 
                         wait_for_terminate(pid, NULL);
                 } else
-                        log_info("Can't show %s.", *p);
+                        log_info("Can't show: %s", *p);
         }
 }
 
@@ -3279,10 +3341,8 @@ static int show(DBusConnection *bus, char **args) {
                         n = unit_name_mangle(*name);
                         p = unit_dbus_path_from_name(n ? n : *name);
                         free(n);
-                        if (!p) {
-                                log_error("Out of memory");
-                                return -ENOMEM;
-                        }
+                        if (!p)
+                                return log_oom();
 
                         r = show_one(args[0], bus, p, show_properties, &new_line);
                         free(p);
@@ -3295,10 +3355,8 @@ static int show(DBusConnection *bus, char **args) {
                         /* Interpret as job id */
 
                         char *p;
-                        if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0) {
-                                log_error("Out of memory");
-                                return -ENOMEM;
-                        }
+                        if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0)
+                                return log_oom();
 
                         r = show_one(args[0], bus, p, show_properties, &new_line);
                         free(p);
@@ -3921,7 +3979,7 @@ finish:
 static int enable_sysv_units(char **args) {
         int r = 0;
 
-#if defined (HAVE_SYSV_COMPAT) && (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_SUSE) || defined(TARGET_MEEGO) || defined(TARGET_ALTLINUX) || defined(TARGET_MAGEIA))
+#if defined (HAVE_SYSV_COMPAT) && (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_SUSE) || defined(TARGET_ALTLINUX) || defined(TARGET_MAGEIA))
         const char *verb = args[0];
         unsigned f = 1, t = 1;
         LookupPaths paths;
@@ -3971,8 +4029,7 @@ static int enable_sysv_units(char **args) {
                                 asprintf(&p, "%s/%s", *k, name);
 
                         if (!p) {
-                                log_error("No memory");
-                                r = -ENOMEM;
+                                r = log_oom();
                                 goto finish;
                         }
 
@@ -3992,8 +4049,7 @@ static int enable_sysv_units(char **args) {
                 else
                         asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
                 if (!p) {
-                        log_error("No memory");
-                        r = -ENOMEM;
+                        r = log_oom();
                         goto finish;
                 }
 
@@ -4021,10 +4077,9 @@ static int enable_sysv_units(char **args) {
 
                 l = strv_join((char**)argv, " ");
                 if (!l) {
-                        log_error("No memory.");
                         free(q);
                         free(p);
-                        r = -ENOMEM;
+                        r = log_oom();
                         goto finish;
                 }
 
@@ -4181,8 +4236,7 @@ static int enable_unit(DBusConnection *bus, char **args) {
                                 "org.freedesktop.systemd1.Manager",
                                 method);
                 if (!m) {
-                        log_error("Out of memory");
-                        r = -ENOMEM;
+                        r = log_oom();
                         goto finish;
                 }
 
@@ -4336,8 +4390,7 @@ static int unit_is_enabled(DBusConnection *bus, char **args) {
                                         "org.freedesktop.systemd1.Manager",
                                         "GetUnitFileState");
                         if (!m) {
-                                log_error("Out of memory");
-                                r = -ENOMEM;
+                                r = log_oom();
                                 goto finish;
                         }
 
@@ -4585,7 +4638,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 ARG_ROOT,
                 ARG_FULL,
                 ARG_NO_RELOAD,
-                ARG_KILL_MODE,
                 ARG_KILL_WHO,
                 ARG_NO_ASK_PASSWORD,
                 ARG_FAILED,
@@ -4617,7 +4669,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 { "root",      required_argument, NULL, ARG_ROOT      },
                 { "force",     no_argument,       NULL, ARG_FORCE     },
                 { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
-                { "kill-mode", required_argument, NULL, ARG_KILL_MODE }, /* undocumented on purpose */
                 { "kill-who",  required_argument, NULL, ARG_KILL_WHO  },
                 { "signal",    required_argument, NULL, 's'           },
                 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
@@ -4650,9 +4701,17 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         return 0;
 
                 case 't':
-                        arg_type = optarg;
-                        break;
-
+                        if (unit_type_from_string(optarg) >= 0) {
+                                arg_type = optarg;
+                                break;
+                        }
+                        if (unit_load_state_from_string(optarg) >= 0) {
+                                arg_load_state = optarg;
+                                break;
+                        }
+                        log_error("Unkown unit type or load state '%s'.",
+                                  optarg);
+                        return -EINVAL;
                 case 'p': {
                         char **l;
 
@@ -4755,10 +4814,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         arg_kill_who = optarg;
                         break;
 
-                case ARG_KILL_MODE:
-                        arg_kill_mode = optarg;
-                        break;
-
                 case 's':
                         if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
                                 log_error("Failed to parse signal string %s.", optarg);
@@ -5037,7 +5092,7 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
                 }
         }
 
-        if (argc > optind) {
+        if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
                 r = parse_time_spec(argv[optind], &arg_when);
                 if (r < 0) {
                         log_error("Failed to parse time specification: %s", argv[optind]);
@@ -5046,8 +5101,11 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
         } else
                 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
 
-        /* We skip the time argument */
-        if (argc > optind + 1)
+        if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
+                /* No time argument for shutdown cancel */
+                arg_wall = argv + optind;
+        else if (argc > optind + 1)
+                /* We skip the time argument */
                 arg_wall = argv + optind + 1;
 
         optind = argc;
@@ -5636,7 +5694,7 @@ done:
         return 0;
 }
 
-static void halt_now(enum action a) {
+static _noreturn_ void halt_now(enum action a) {
 
        /* Make sure C-A-D is handled by the kernel from this
          * point on... */
@@ -5826,9 +5884,22 @@ int main(int argc, char*argv[]) {
                 r = reload_with_fallback(bus);
                 break;
 
-        case ACTION_CANCEL_SHUTDOWN:
-                r = send_shutdownd(0, 0, false, false, NULL);
+        case ACTION_CANCEL_SHUTDOWN: {
+                char *m = NULL;
+
+                if (arg_wall) {
+                        m = strv_join(arg_wall, " ");
+                        if (!m) {
+                                retval = EXIT_FAILURE;
+                                goto finish;
+                        }
+                }
+                r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m);
+                if (r < 0)
+                        log_warning("Failed to talk to shutdownd, shutdown hasn't been cancelled: %s", strerror(-r));
+                free(m);
                 break;
+        }
 
         case ACTION_INVALID:
         case ACTION_RUNLEVEL: