typedef struct WaitData {
Set *set;
- bool failed;
+ char *result;
} WaitData;
static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
} else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
uint32_t id;
- const char *path;
+ const char *path, *result;
dbus_bool_t success = true;
- if (!dbus_message_get_args(message, &error,
- DBUS_TYPE_UINT32, &id,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_BOOLEAN, &success,
- DBUS_TYPE_INVALID))
- log_error("Failed to parse message: %s", bus_error_message(&error));
- else {
+ if (dbus_message_get_args(message, &error,
+ DBUS_TYPE_UINT32, &id,
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_STRING, &result,
+ DBUS_TYPE_INVALID)) {
char *p;
+ if ((p = set_remove(d->set, (char*) path)))
+ free(p);
+
+ if (*result)
+ d->result = strdup(result);
+
+ goto finish;
+ }
+#ifndef LEGACY
+ dbus_error_free(&error);
+
+ if (dbus_message_get_args(message, &error,
+ DBUS_TYPE_UINT32, &id,
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_BOOLEAN, &success,
+ DBUS_TYPE_INVALID)) {
+ char *p;
+
+ /* Compatibility with older systemd versions <
+ * 19 during upgrades. This should be dropped
+ * one day */
+
if ((p = set_remove(d->set, (char*) path)))
free(p);
if (!success)
- d->failed = true;
+ d->result = strdup("failed");
+
+ goto finish;
}
+#endif
+
+ log_error("Failed to parse message: %s", bus_error_message(&error));
}
+finish:
dbus_error_free(&error);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
zero(d);
d.set = s;
- d.failed = false;
if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL)) {
log_error("Failed to add filter.");
dbus_connection_read_write_dispatch(bus, -1))
;
- if (!arg_quiet && d.failed)
- log_error("Job failed. See system logs and 'systemctl status' for details.");
+ if (!arg_quiet && d.result) {
+ if (streq(d.result, "timeout"))
+ log_error("Job timed out.");
+ else if (streq(d.result, "canceled"))
+ log_error("Job canceled.");
+ else if (streq(d.result, "dependency"))
+ log_error("A dependency job failed. See system logs for details.");
+ else if (!streq(d.result, "done"))
+ log_error("Job failed. See system logs and 'systemctl status' for details.");
+ }
+
+ if (streq_ptr(d.result, "timeout"))
+ r = -ETIME;
+ else if (streq_ptr(d.result, "canceled"))
+ r = -ECANCELED;
+ else if (!streq_ptr(d.result, "done"))
+ r = -EIO;
+ else
+ r = 0;
- r = d.failed ? -EIO : 0;
+ free(d.result);
finish:
/* This is slightly dirty, since we don't undo the filter registration. */
} else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobNew") ||
dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
uint32_t id;
- const char *path;
+ const char *path, *result;
if (!dbus_message_get_args(message, &error,
DBUS_TYPE_UINT32, &id,
DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_STRING, &result,
DBUS_TYPE_INVALID))
log_error("Failed to parse message: %s", bus_error_message(&error));
else if (streq(dbus_message_get_member(message), "JobNew"))
return 0;
}
+static bool kexec_loaded(void) {
+ bool loaded = false;
+ char *s;
+
+ if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) {
+ if (s[0] == '1')
+ loaded = true;
+ free(s);
+ }
+ return loaded;
+}
+
static int shutdown_parse_argv(int argc, char *argv[]) {
enum {
break;
case 'r':
- arg_action = ACTION_REBOOT;
+ if (kexec_loaded())
+ arg_action = ACTION_KEXEC;
+ else
+ arg_action = ACTION_REBOOT;
break;
case 'h':
arg_action = ACTION_POWEROFF;
return halt_parse_argv(argc, argv);
} else if (strstr(program_invocation_short_name, "reboot")) {
- arg_action = ACTION_REBOOT;
+ if (kexec_loaded())
+ arg_action = ACTION_KEXEC;
+ else
+ arg_action = ACTION_REBOOT;
return halt_parse_argv(argc, argv);
} else if (strstr(program_invocation_short_name, "shutdown")) {
arg_action = ACTION_POWEROFF;
case ACTION_HALT:
case ACTION_POWEROFF:
case ACTION_REBOOT:
+ case ACTION_KEXEC:
r = halt_main(bus);
break;