chiark / gitweb /
systemctl: use isolate when called as telinit for a runlevel
[elogind.git] / src / systemctl.c
index baae019e0fcedebc0bd7bd81d6463d702962677b..1f93bc974aec3c7002cc7339adc1e5e8bd2a4d4d 100644 (file)
 #include "path-lookup.h"
 #include "conf-parser.h"
 #include "sd-daemon.h"
+#include "shutdownd.h"
+#include "exit-status.h"
+#include "bus-errors.h"
+#include "build.h"
 
 static const char *arg_type = NULL;
 static char **arg_property = NULL;
@@ -68,6 +72,7 @@ static bool arg_full = false;
 static bool arg_force = false;
 static bool arg_defaults = false;
 static char **arg_wall = NULL;
+static usec_t arg_when = 0;
 static enum action {
         ACTION_INVALID,
         ACTION_SYSTEMCTL,
@@ -84,6 +89,7 @@ static enum action {
         ACTION_RELOAD,
         ACTION_REEXEC,
         ACTION_RUNLEVEL,
+        ACTION_CANCEL_SHUTDOWN,
         _ACTION_MAX
 } arg_action = ACTION_SYSTEMCTL;
 static enum dot {
@@ -121,8 +127,7 @@ static const char *ansi_highlight_green(bool b) {
         return b ? ANSI_HIGHLIGHT_GREEN_ON : ANSI_HIGHLIGHT_OFF;
 }
 
-static bool error_is_no_service(DBusError *error) {
-
+static bool error_is_no_service(const DBusError *error) {
         assert(error);
 
         if (!dbus_error_is_set(error))
@@ -137,6 +142,34 @@ static bool error_is_no_service(DBusError *error) {
         return startswith(error->name, "org.freedesktop.DBus.Error.Spawn.");
 }
 
+static int translate_bus_error_to_exit_status(int r, const DBusError *error) {
+        assert(error);
+
+        if (!dbus_error_is_set(error))
+                return r;
+
+        if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED) ||
+            dbus_error_has_name(error, BUS_ERROR_ONLY_BY_DEPENDENCY) ||
+            dbus_error_has_name(error, BUS_ERROR_NO_ISOLATION) ||
+            dbus_error_has_name(error, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE))
+                return EXIT_NOPERMISSION;
+
+        if (dbus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT))
+                return EXIT_NOTINSTALLED;
+
+        if (dbus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE) ||
+            dbus_error_has_name(error, BUS_ERROR_NOT_SUPPORTED))
+                return EXIT_NOTIMPLEMENTED;
+
+        if (dbus_error_has_name(error, BUS_ERROR_LOAD_FAILED))
+                return EXIT_NOTCONFIGURED;
+
+        if (r != 0)
+                return r;
+
+        return EXIT_FAILURE;
+}
+
 static int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) {
 
         assert(iter);
@@ -211,11 +244,11 @@ static int compare_unit_info(const void *a, const void *b) {
         if (d1 && d2) {
                 int r;
 
-                if ((r = strcmp(d1, d2)) != 0)
+                if ((r = strcasecmp(d1, d2)) != 0)
                         return r;
         }
 
-        return strcmp(u->id, v->id);
+        return strcasecmp(u->id, v->id);
 }
 
 static int list_units(DBusConnection *bus, char **args, unsigned n) {
@@ -240,7 +273,7 @@ static int list_units(DBusConnection *bus, char **args, unsigned n) {
         }
 
         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                log_error("Failed to issue method call: %s", error.message);
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
                 r = -EIO;
                 goto finish;
         }
@@ -304,8 +337,12 @@ static int list_units(DBusConnection *bus, char **args, unsigned n) {
 
         qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
 
-        if (isatty(STDOUT_FILENO))
-                printf("%-45s %-6s %-12s %-12s %-15s %s\n", "UNIT", "LOAD", "ACTIVE", "SUB", "JOB", "DESCRIPTION");
+        if (isatty(STDOUT_FILENO)) {
+                if (columns() >= 80+12 || arg_full)
+                        printf("%-25s %-6s %-12s %-18s %-15s %s\n", "UNIT", "LOAD", "ACTIVE", "SUB", "JOB", "DESCRIPTION");
+                else
+                        printf("%-25s %-6s %-12s %-18s %-15s\n", "UNIT", "LOAD", "ACTIVE", "SUB", "JOB");
+        }
 
         for (k = 0; k < c; k++) {
                 const char *dot;
@@ -316,30 +353,47 @@ static int list_units(DBusConnection *bus, char **args, unsigned n) {
                     (arg_all || !(streq(u->active_state, "inactive") || u->following[0]) || u->job_id > 0)) {
                         char *e;
                         int a = 0, b = 0;
-                        const char *on, *off;
+                        const char *on_loaded, *off_loaded;
+                        const char *on_active, *off_active;
 
-                        if (streq(u->active_state, "maintenance")) {
-                                on = ansi_highlight(true);
-                                off = ansi_highlight(false);
+                        if (!streq(u->load_state, "loaded")) {
+                                on_loaded = ansi_highlight(true);
+                                off_loaded = ansi_highlight(false);
                         } else
-                                on = off = "";
+                                on_loaded = off_loaded = "";
+
+                        if (streq(u->active_state, "failed")) {
+                                on_active = ansi_highlight(true);
+                                off_active = ansi_highlight(false);
+                        } else
+                                on_active = off_active = "";
+
+                        e = arg_full ? NULL : ellipsize(u->id, 25, 33);
+
+                        printf("%-25s %s%-6s%s %s%-12s %-18s%s%n",
+                               e ? e : u->id,
+                               on_loaded, u->load_state, off_loaded,
+                               on_active, u->active_state, u->sub_state, off_active,
+                               &a);
 
-                        e = arg_full ? NULL : ellipsize(u->id, 45, 33);
-                        printf("%-45s %-6s %s%-12s %-12s%s%n", e ? e : u->id, u->load_state, on, u->active_state, u->sub_state, off, &a);
                         free(e);
 
-                        a -= strlen(on) + strlen(off);
+                        a -= strlen(on_loaded) + strlen(off_loaded);
+                        a -= strlen(on_active) + strlen(off_active);
 
                         if (u->job_id != 0)
-                                printf(" => %-12s%n", u->job_type, &b);
+                                printf(" %-15s%n", u->job_type, &b);
                         else
                                 b = 1 + 15;
 
-                        if (a + b + 2 < columns()) {
+                        if (a + b + 1 < columns()) {
                                 if (u->job_id == 0)
                                         printf("                ");
 
-                                printf(" %.*s", columns() - a - b - 2, u->description);
+                                if (arg_full)
+                                        printf(" %s", u->description);
+                                else
+                                        printf(" %.*s", columns() - a - b - 1, u->description);
                         }
 
                         fputs("\n", stdout);
@@ -348,10 +402,10 @@ static int list_units(DBusConnection *bus, char **args, unsigned n) {
 
         if (isatty(STDOUT_FILENO)) {
 
-                printf("\nLOAD   = Load State, reflects whether the unit configuration was properly loaded.\n"
-                       "ACTIVE = Active State, the high-level unit activation state, i.e. generalization of the substate.\n"
-                       "SUB    = Substate, the low-level unit activation state, possible values depend on unit type.\n"
-                       "JOB    = Job, shows pending jobs for the unit.\n");
+                printf("\nLOAD   = Reflects whether the unit definition was properly loaded.\n"
+                       "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
+                       "SUB    = The low-level unit activation state, values depend on unit type.\n"
+                       "JOB    = Pending job for the unit.\n");
 
                 if (arg_all)
                         printf("\n%u units listed.\n", c);
@@ -464,7 +518,7 @@ static int dot_one(DBusConnection *bus, const char *name, const char *path) {
         }
 
         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                log_error("Failed to issue method call: %s", error.message);
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
                 r = -EIO;
                 goto finish;
         }
@@ -547,7 +601,7 @@ static int dot(DBusConnection *bus, char **args, unsigned n) {
         }
 
         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                log_error("Failed to issue method call: %s", error.message);
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
                 r = -EIO;
                 goto finish;
         }
@@ -640,7 +694,7 @@ static int list_jobs(DBusConnection *bus, char **args, unsigned n) {
         }
 
         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                log_error("Failed to issue method call: %s", error.message);
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
                 r = -EIO;
                 goto finish;
         }
@@ -655,7 +709,8 @@ static int list_jobs(DBusConnection *bus, char **args, unsigned n) {
 
         dbus_message_iter_recurse(&iter, &sub);
 
-        printf("%4s %-45s %-17s %-7s\n", "JOB", "UNIT", "TYPE", "STATE");
+        if (isatty(STDOUT_FILENO))
+                printf("%4s %-25s %-15s %-7s\n", "JOB", "UNIT", "TYPE", "STATE");
 
         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
                 const char *name, *type, *state, *job_path, *unit_path;
@@ -681,8 +736,8 @@ static int list_jobs(DBusConnection *bus, char **args, unsigned n) {
                         goto finish;
                 }
 
-                e = arg_full ? NULL : ellipsize(name, 45, 33);
-                printf("%4u %-45s %-17s %-7s\n", id, e ? e : name, type, state);
+                e = arg_full ? NULL : ellipsize(name, 25, 33);
+                printf("%4u %-25s %-15s %-7s\n", id, e ? e : name, type, state);
                 free(e);
 
                 k++;
@@ -690,7 +745,9 @@ static int list_jobs(DBusConnection *bus, char **args, unsigned n) {
                 dbus_message_iter_next(&sub);
         }
 
-        printf("\n%u jobs listed.\n", k);
+        if (isatty(STDOUT_FILENO))
+                printf("\n%u jobs listed.\n", k);
+
         r = 0;
 
 finish:
@@ -737,7 +794,7 @@ static int load_unit(DBusConnection *bus, char **args, unsigned n) {
                 }
 
                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                        log_error("Failed to issue method call: %s", error.message);
+                        log_error("Failed to issue method call: %s", bus_error_message(&error));
                         r = -EIO;
                         goto finish;
                 }
@@ -805,7 +862,7 @@ static int cancel_job(DBusConnection *bus, char **args, unsigned n) {
                 }
 
                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                        log_error("Failed to issue method call: %s", error.message);
+                        log_error("Failed to issue method call: %s", bus_error_message(&error));
                         r = -EIO;
                         goto finish;
                 }
@@ -813,7 +870,7 @@ static int cancel_job(DBusConnection *bus, char **args, unsigned n) {
                 if (!dbus_message_get_args(reply, &error,
                                            DBUS_TYPE_OBJECT_PATH, &path,
                                            DBUS_TYPE_INVALID)) {
-                        log_error("Failed to parse reply: %s", error.message);
+                        log_error("Failed to parse reply: %s", bus_error_message(&error));
                         r = -EIO;
                         goto finish;
                 }
@@ -831,7 +888,7 @@ static int cancel_job(DBusConnection *bus, char **args, unsigned n) {
 
                 dbus_message_unref(reply);
                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                        log_error("Failed to issue method call: %s", error.message);
+                        log_error("Failed to issue method call: %s", bus_error_message(&error));
                         r = -EIO;
                         goto finish;
                 }
@@ -960,7 +1017,7 @@ static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *me
                                            DBUS_TYPE_OBJECT_PATH, &path,
                                            DBUS_TYPE_BOOLEAN, &success,
                                            DBUS_TYPE_INVALID))
-                        log_error("Failed to parse message: %s", error.message);
+                        log_error("Failed to parse message: %s", bus_error_message(&error));
                 else {
                         char *p;
 
@@ -994,7 +1051,7 @@ static int enable_wait_for_jobs(DBusConnection *bus) {
                            &error);
 
         if (dbus_error_is_set(&error)) {
-                log_error("Failed to add match: %s", error.message);
+                log_error("Failed to add match: %s", bus_error_message(&error));
                 dbus_error_free(&error);
                 return -EIO;
         }
@@ -1025,7 +1082,7 @@ static int wait_for_jobs(DBusConnection *bus, Set *s) {
                 ;
 
         if (!arg_quiet && d.failed)
-                log_error("Job failed, see logs for details.");
+                log_error("Job failed, see system logs for details.");
 
         r = d.failed ? -EIO : 0;
 
@@ -1040,10 +1097,10 @@ static int start_unit_one(
                 const char *method,
                 const char *name,
                 const char *mode,
+                DBusError *error,
                 Set *s) {
 
         DBusMessage *m = NULL, *reply = NULL;
-        DBusError error;
         const char *path;
         int r;
 
@@ -1051,10 +1108,9 @@ static int start_unit_one(
         assert(method);
         assert(name);
         assert(mode);
+        assert(error);
         assert(arg_no_block || s);
 
-        dbus_error_init(&error);
-
         if (!(m = dbus_message_new_method_call(
                               "org.freedesktop.systemd1",
                               "/org/freedesktop/systemd1",
@@ -1074,24 +1130,24 @@ static int start_unit_one(
                 goto finish;
         }
 
-        if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
+        if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error))) {
 
-                if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(&error)) {
+                if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(error)) {
                         /* There's always a fallback possible for
                          * legacy actions. */
-                        r = 0;
+                        r = -EADDRNOTAVAIL;
                         goto finish;
                 }
 
-                log_error("Failed to issue method call: %s", error.message);
+                log_error("Failed to issue method call: %s", bus_error_message(error));
                 r = -EIO;
                 goto finish;
         }
 
-        if (!dbus_message_get_args(reply, &error,
+        if (!dbus_message_get_args(reply, error,
                                    DBUS_TYPE_OBJECT_PATH, &path,
                                    DBUS_TYPE_INVALID)) {
-                log_error("Failed to parse reply: %s", error.message);
+                log_error("Failed to parse reply: %s", bus_error_message(error));
                 r = -EIO;
                 goto finish;
         }
@@ -1116,7 +1172,7 @@ static int start_unit_one(
                 }
         }
 
-        r = 1;
+        r = 0;
 
 finish:
         if (m)
@@ -1125,8 +1181,6 @@ finish:
         if (reply)
                 dbus_message_unref(reply);
 
-        dbus_error_free(&error);
-
         return r;
 }
 
@@ -1162,10 +1216,13 @@ static int start_unit(DBusConnection *bus, char **args, unsigned n) {
                 [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET
         };
 
-        int r;
+        int r, ret = 0;
         unsigned i;
         const char *method, *mode, *one_name;
         Set *s = NULL;
+        DBusError error;
+
+        dbus_error_init(&error);
 
         assert(bus);
 
@@ -1197,46 +1254,52 @@ static int start_unit(DBusConnection *bus, char **args, unsigned n) {
                 method = "StartUnit";
 
                 mode = (arg_action == ACTION_EMERGENCY ||
-                        arg_action == ACTION_RESCUE) ? "isolate" : "replace";
+                        arg_action == ACTION_RESCUE ||
+                        arg_action == ACTION_RUNLEVEL2 ||
+                        arg_action == ACTION_RUNLEVEL3 ||
+                        arg_action == ACTION_RUNLEVEL4 ||
+                        arg_action == ACTION_RUNLEVEL5) ? "isolate" : "replace";
 
                 one_name = table[arg_action];
         }
 
         if (!arg_no_block) {
-                if ((r = enable_wait_for_jobs(bus)) < 0) {
-                        log_error("Could not watch jobs: %s", strerror(-r));
+                if ((ret = enable_wait_for_jobs(bus)) < 0) {
+                        log_error("Could not watch jobs: %s", strerror(-ret));
                         goto finish;
                 }
 
                 if (!(s = set_new(string_hash_func, string_compare_func))) {
                         log_error("Failed to allocate set.");
-                        r = -ENOMEM;
+                        ret = -ENOMEM;
                         goto finish;
                 }
         }
 
-        r = 0;
-
         if (one_name) {
-                if ((r = start_unit_one(bus, method, one_name, mode, s)) <= 0)
+                if ((ret = start_unit_one(bus, method, one_name, mode, &error, s)) <= 0)
                         goto finish;
         } else {
                 for (i = 1; i < n; i++)
-                        if ((r = start_unit_one(bus, method, args[i], mode, s)) < 0)
-                                goto finish;
+                        if ((r = start_unit_one(bus, method, args[i], mode, &error, s)) != 0) {
+                                ret = translate_bus_error_to_exit_status(r, &error);
+                                dbus_error_free(&error);
+                        }
         }
 
         if (!arg_no_block)
-                if ((r = wait_for_jobs(bus, s)) < 0)
+                if ((r = wait_for_jobs(bus, s)) < 0) {
+                        ret = r;
                         goto finish;
-
-        r = 1;
+                }
 
 finish:
         if (s)
                 set_free_free(s);
 
-        return r;
+        dbus_error_free(&error);
+
+        return ret;
 }
 
 static int start_special(DBusConnection *bus, char **args, unsigned n) {
@@ -1258,7 +1321,7 @@ static int check_unit(DBusConnection *bus, char **args, unsigned n) {
         const char
                 *interface = "org.freedesktop.systemd1.Unit",
                 *property = "ActiveState";
-        int r = -EADDRNOTAVAIL;
+        int r = 3; /* According to LSB: "program is not running" */
         DBusError error;
         unsigned i;
 
@@ -1303,7 +1366,7 @@ static int check_unit(DBusConnection *bus, char **args, unsigned n) {
                 if (!dbus_message_get_args(reply, &error,
                                            DBUS_TYPE_OBJECT_PATH, &path,
                                            DBUS_TYPE_INVALID)) {
-                        log_error("Failed to parse reply: %s", error.message);
+                        log_error("Failed to parse reply: %s", bus_error_message(&error));
                         r = -EIO;
                         goto finish;
                 }
@@ -1330,7 +1393,7 @@ static int check_unit(DBusConnection *bus, char **args, unsigned n) {
 
                 dbus_message_unref(reply);
                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                        log_error("Failed to issue method call: %s", error.message);
+                        log_error("Failed to issue method call: %s", bus_error_message(&error));
                         r = -EIO;
                         goto finish;
                 }
@@ -1355,7 +1418,7 @@ static int check_unit(DBusConnection *bus, char **args, unsigned n) {
                 if (!arg_quiet)
                         puts(state);
 
-                if (streq(state, "active") || startswith(state, "reloading"))
+                if (streq(state, "active") || streq(state, "reloading"))
                         r = 0;
 
                 dbus_message_unref(m);
@@ -1480,13 +1543,19 @@ typedef struct UnitStatusInfo {
         const char *path;
         const char *default_control_group;
 
+        usec_t inactive_exit_timestamp;
+        usec_t active_enter_timestamp;
+        usec_t active_exit_timestamp;
+        usec_t inactive_enter_timestamp;
+
         bool need_daemon_reload;
 
         /* Service */
         pid_t main_pid;
         pid_t control_pid;
         const char *status_text;
-        bool running;
+        bool running:1;
+        bool is_sysv:1;
 
         usec_t start_timestamp;
         usec_t exit_timestamp;
@@ -1513,6 +1582,9 @@ typedef struct UnitStatusInfo {
 static void print_status_info(UnitStatusInfo *i) {
         ExecStatusInfo *p;
         const char *on, *off, *ss;
+        usec_t timestamp;
+        char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
+        char since2[FORMAT_TIMESTAMP_MAX], *s2;
 
         assert(i);
 
@@ -1539,7 +1611,7 @@ static void print_status_info(UnitStatusInfo *i) {
 
         ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
 
-        if (streq_ptr(i->active_state, "maintenance")) {
+        if (streq_ptr(i->active_state, "failed")) {
                 on = ansi_highlight(true);
                 off = ansi_highlight(false);
         } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
@@ -1549,17 +1621,34 @@ static void print_status_info(UnitStatusInfo *i) {
                 on = off = "";
 
         if (ss)
-                printf("\t  Active: %s%s (%s)%s\n",
+                printf("\t  Active: %s%s (%s)%s",
                        on,
                        strna(i->active_state),
                        ss,
                        off);
         else
-                printf("\t  Active: %s%s%s\n",
+                printf("\t  Active: %s%s%s",
                        on,
                        strna(i->active_state),
                        off);
 
+        timestamp = (streq_ptr(i->active_state, "active")      ||
+                     streq_ptr(i->active_state, "reloading"))   ? i->active_enter_timestamp :
+                    (streq_ptr(i->active_state, "inactive")    ||
+                     streq_ptr(i->active_state, "failed"))      ? i->inactive_enter_timestamp :
+                    streq_ptr(i->active_state, "activating")    ? i->inactive_exit_timestamp :
+                                                                  i->active_exit_timestamp;
+
+        s1 = format_timestamp_pretty(since1, sizeof(since1), timestamp);
+        s2 = format_timestamp(since2, sizeof(since2), timestamp);
+
+        if (s1)
+                printf(" since [%s; %s]\n", s2, s1);
+        else if (s2)
+                printf(" since [%s]\n", s2);
+        else
+                printf("\n");
+
         if (i->sysfs_path)
                 printf("\t  Device: %s\n", i->sysfs_path);
         else if (i->where)
@@ -1578,12 +1667,18 @@ static void print_status_info(UnitStatusInfo *i) {
                         continue;
 
                 t = strv_join(p->argv, " ");
-                printf("\t  Exited: %u (%s, code=%s, ", p->pid, strna(t), sigchld_code_to_string(p->code));
+                printf("\t Process: %u (%s, code=%s, ", p->pid, strna(t), sigchld_code_to_string(p->code));
                 free(t);
 
-                if (p->code == CLD_EXITED)
+                if (p->code == CLD_EXITED) {
+                        const char *c;
+
                         printf("status=%i", p->status);
-                else
+
+                        if ((c = exit_status_to_string(p->status, i->is_sysv ? EXIT_STATUS_LSB : EXIT_STATUS_SYSTEMD)))
+                                printf("/%s", c);
+
+                } else
                         printf("signal=%s", signal_to_string(p->status));
                 printf(")\n");
 
@@ -1601,7 +1696,7 @@ static void print_status_info(UnitStatusInfo *i) {
                 printf("\t");
 
                 if (i->main_pid > 0) {
-                        printf("    Main: %u", (unsigned) i->main_pid);
+                        printf("Main PID: %u", (unsigned) i->main_pid);
 
                         if (i->running) {
                                 char *t = NULL;
@@ -1613,9 +1708,15 @@ static void print_status_info(UnitStatusInfo *i) {
                         } else if (i->exit_code > 0) {
                                 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
 
-                                if (i->exit_code == CLD_EXITED)
+                                if (i->exit_code == CLD_EXITED) {
+                                        const char *c;
+
                                         printf("status=%i", i->exit_status);
-                                else
+
+                                        if ((c = exit_status_to_string(i->exit_status, i->is_sysv ? EXIT_STATUS_LSB : EXIT_STATUS_SYSTEMD)))
+                                                printf("/%s", c);
+
+                                } else
                                         printf("signal=%s", signal_to_string(i->exit_status));
                                 printf(")");
                         }
@@ -1684,9 +1785,10 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn
                                 i->description = s;
                         else if (streq(name, "FragmentPath"))
                                 i->path = s;
-                        else if (streq(name, "SysVPath"))
+                        else if (streq(name, "SysVPath")) {
+                                i->is_sysv = true;
                                 i->path = s;
-                        else if (streq(name, "DefaultControlGroup"))
+                        else if (streq(name, "DefaultControlGroup"))
                                 i->default_control_group = s;
                         else if (streq(name, "StatusText"))
                                 i->status_text = s;
@@ -1759,6 +1861,14 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn
                         i->start_timestamp = (usec_t) u;
                 else if (streq(name, "ExecMainExitTimestamp"))
                         i->exit_timestamp = (usec_t) u;
+                else if (streq(name, "ActiveEnterTimestamp"))
+                        i->active_enter_timestamp = (usec_t) u;
+                else if (streq(name, "InactiveEnterTimestamp"))
+                        i->inactive_enter_timestamp = (usec_t) u;
+                else if (streq(name, "InactiveExitTimestamp"))
+                        i->inactive_exit_timestamp = (usec_t) u;
+                else if (streq(name, "ActiveExitTimestamp"))
+                        i->active_exit_timestamp = (usec_t) u;
 
                 break;
         }
@@ -2073,7 +2183,7 @@ static int show_one(DBusConnection *bus, const char *path, bool show_properties,
         }
 
         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                log_error("Failed to issue method call: %s", error.message);
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
                 r = -EIO;
                 goto finish;
         }
@@ -2132,16 +2242,21 @@ static int show_one(DBusConnection *bus, const char *path, bool show_properties,
                 dbus_message_iter_next(&sub);
         }
 
+        r = 0;
+
         if (!show_properties)
                 print_status_info(&info);
 
+        if (!streq_ptr(info.active_state, "active") &&
+            !streq_ptr(info.active_state, "reloading"))
+                /* According to LSB: "program not running" */
+                r = 3;
+
         while ((p = info.exec)) {
                 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
                 exec_status_info_free(p);
         }
 
-        r = 0;
-
 finish:
         if (m)
                 dbus_message_unref(m);
@@ -2156,7 +2271,7 @@ finish:
 
 static int show(DBusConnection *bus, char **args, unsigned n) {
         DBusMessage *m = NULL, *reply = NULL;
-        int r;
+        int r, ret = 0;
         DBusError error;
         unsigned i;
         bool show_properties, new_line = false;
@@ -2172,7 +2287,7 @@ static int show(DBusConnection *bus, char **args, unsigned n) {
                 /* If not argument is specified inspect the manager
                  * itself */
 
-                r = show_one(bus, "/org/freedesktop/systemd1", show_properties, &new_line);
+                ret = show_one(bus, "/org/freedesktop/systemd1", show_properties, &new_line);
                 goto finish;
         }
 
@@ -2190,7 +2305,7 @@ static int show(DBusConnection *bus, char **args, unsigned n) {
                                               "org.freedesktop.systemd1.Manager",
                                               "LoadUnit"))) {
                                 log_error("Could not allocate message.");
-                                r = -ENOMEM;
+                                ret = -ENOMEM;
                                 goto finish;
                         }
 
@@ -2198,15 +2313,15 @@ static int show(DBusConnection *bus, char **args, unsigned n) {
                                                       DBUS_TYPE_STRING, &args[i],
                                                       DBUS_TYPE_INVALID)) {
                                 log_error("Could not append arguments to message.");
-                                r = -ENOMEM;
+                                ret = -ENOMEM;
                                 goto finish;
                         }
 
                         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
 
                                 if (!dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) {
-                                        log_error("Failed to issue method call: %s", error.message);
-                                        r = -EIO;
+                                        log_error("Failed to issue method call: %s", bus_error_message(&error));
+                                        ret = -EIO;
                                         goto finish;
                                 }
 
@@ -2219,7 +2334,7 @@ static int show(DBusConnection *bus, char **args, unsigned n) {
                                                       "org.freedesktop.systemd1.Manager",
                                                       "GetUnit"))) {
                                         log_error("Could not allocate message.");
-                                        r = -ENOMEM;
+                                        ret = -ENOMEM;
                                         goto finish;
                                 }
 
@@ -2227,13 +2342,17 @@ static int show(DBusConnection *bus, char **args, unsigned n) {
                                                               DBUS_TYPE_STRING, &args[i],
                                                               DBUS_TYPE_INVALID)) {
                                         log_error("Could not append arguments to message.");
-                                        r = -ENOMEM;
+                                        ret = -ENOMEM;
                                         goto finish;
                                 }
 
                                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                                        log_error("Failed to issue method call: %s", error.message);
-                                        r = -EIO;
+                                        log_error("Failed to issue method call: %s", bus_error_message(&error));
+
+                                        if (dbus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT))
+                                                ret = 4; /* According to LSB: "program or service status is unknown" */
+                                        else
+                                                ret = -EIO;
                                         goto finish;
                                 }
                         }
@@ -2248,7 +2367,7 @@ static int show(DBusConnection *bus, char **args, unsigned n) {
                                               "org.freedesktop.systemd1.Manager",
                                               "GetJob"))) {
                                 log_error("Could not allocate message.");
-                                r = -ENOMEM;
+                                ret = -ENOMEM;
                                 goto finish;
                         }
 
@@ -2256,13 +2375,13 @@ static int show(DBusConnection *bus, char **args, unsigned n) {
                                                       DBUS_TYPE_UINT32, &id,
                                                       DBUS_TYPE_INVALID)) {
                                 log_error("Could not append arguments to message.");
-                                r = -ENOMEM;
+                                ret = -ENOMEM;
                                 goto finish;
                         }
 
                         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                                log_error("Failed to issue method call: %s", error.message);
-                                r = -EIO;
+                                log_error("Failed to issue method call: %s", bus_error_message(&error));
+                                ret = -EIO;
                                 goto finish;
                         }
                 } else {
@@ -2275,7 +2394,7 @@ static int show(DBusConnection *bus, char **args, unsigned n) {
                                               "org.freedesktop.systemd1.Manager",
                                               "GetUnitByPID"))) {
                                 log_error("Could not allocate message.");
-                                r = -ENOMEM;
+                                ret = -ENOMEM;
                                 goto finish;
                         }
 
@@ -2283,13 +2402,13 @@ static int show(DBusConnection *bus, char **args, unsigned n) {
                                                       DBUS_TYPE_UINT32, &id,
                                                       DBUS_TYPE_INVALID)) {
                                 log_error("Could not append arguments to message.");
-                                r = -ENOMEM;
+                                ret = -ENOMEM;
                                 goto finish;
                         }
 
                         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                                log_error("Failed to issue method call: %s", error.message);
-                                r = -EIO;
+                                log_error("Failed to issue method call: %s", bus_error_message(&error));
+                                ret = -EIO;
                                 goto finish;
                         }
                 }
@@ -2297,21 +2416,19 @@ static int show(DBusConnection *bus, char **args, unsigned n) {
                 if (!dbus_message_get_args(reply, &error,
                                            DBUS_TYPE_OBJECT_PATH, &path,
                                            DBUS_TYPE_INVALID)) {
-                        log_error("Failed to parse reply: %s", error.message);
-                        r = -EIO;
+                        log_error("Failed to parse reply: %s", bus_error_message(&error));
+                        ret = -EIO;
                         goto finish;
                 }
 
-                if ((r = show_one(bus, path, show_properties, &new_line)) < 0)
-                        goto finish;
+                if ((r = show_one(bus, path, show_properties, &new_line)) != 0)
+                        ret = r;
 
                 dbus_message_unref(m);
                 dbus_message_unref(reply);
                 m = reply = NULL;
         }
 
-        r = 0;
-
 finish:
         if (m)
                 dbus_message_unref(m);
@@ -2321,7 +2438,7 @@ finish:
 
         dbus_error_free(&error);
 
-        return r;
+        return ret;
 }
 
 static DBusHandlerResult monitor_filter(DBusConnection *connection, DBusMessage *message, void *data) {
@@ -2350,7 +2467,7 @@ static DBusHandlerResult monitor_filter(DBusConnection *connection, DBusMessage
                                            DBUS_TYPE_STRING, &id,
                                            DBUS_TYPE_OBJECT_PATH, &path,
                                            DBUS_TYPE_INVALID))
-                        log_error("Failed to parse message: %s", error.message);
+                        log_error("Failed to parse message: %s", bus_error_message(&error));
                 else if (streq(dbus_message_get_member(message), "UnitNew"))
                         printf("Unit %s added.\n", id);
                 else
@@ -2365,21 +2482,30 @@ static DBusHandlerResult monitor_filter(DBusConnection *connection, DBusMessage
                                            DBUS_TYPE_UINT32, &id,
                                            DBUS_TYPE_OBJECT_PATH, &path,
                                            DBUS_TYPE_INVALID))
-                        log_error("Failed to parse message: %s", error.message);
+                        log_error("Failed to parse message: %s", bus_error_message(&error));
                 else if (streq(dbus_message_get_member(message), "JobNew"))
                         printf("Job %u added.\n", id);
                 else
                         printf("Job %u removed.\n", id);
 
 
-        } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Unit", "Changed") ||
-                   dbus_message_is_signal(message, "org.freedesktop.systemd1.Job", "Changed")) {
+        } else if (dbus_message_is_signal(message, "org.freedesktop.DBus.Properties", "PropertiesChanged")) {
 
                 const char *path, *interface, *property = "Id";
                 DBusMessageIter iter, sub;
 
                 path = dbus_message_get_path(message);
-                interface = dbus_message_get_interface(message);
+
+                if (!dbus_message_get_args(message, &error,
+                                          DBUS_TYPE_STRING, &interface,
+                                          DBUS_TYPE_INVALID)) {
+                        log_error("Failed to parse message: %s", bus_error_message(&error));
+                        goto finish;
+                }
+
+                if (!streq(interface, "org.freedesktop.systemd1.Job") &&
+                    !streq(interface, "org.freedesktop.systemd1.Unit"))
+                        goto finish;
 
                 if (!(m = dbus_message_new_method_call(
                               "org.freedesktop.systemd1",
@@ -2399,7 +2525,7 @@ static DBusHandlerResult monitor_filter(DBusConnection *connection, DBusMessage
                 }
 
                 if (!(reply = dbus_connection_send_with_reply_and_block(connection, m, -1, &error))) {
-                        log_error("Failed to issue method call: %s", error.message);
+                        log_error("Failed to issue method call: %s", bus_error_message(&error));
                         goto finish;
                 }
 
@@ -2471,7 +2597,7 @@ static int monitor(DBusConnection *bus, char **args, unsigned n) {
                                    &error);
 
                 if (dbus_error_is_set(&error)) {
-                        log_error("Failed to add match: %s", error.message);
+                        log_error("Failed to add match: %s", bus_error_message(&error));
                         r = -EIO;
                         goto finish;
                 }
@@ -2479,25 +2605,12 @@ static int monitor(DBusConnection *bus, char **args, unsigned n) {
                 dbus_bus_add_match(bus,
                                    "type='signal',"
                                    "sender='org.freedesktop.systemd1',"
-                                   "interface='org.freedesktop.systemd1.Unit',"
-                                   "member='Changed'",
+                                   "interface='org.freedesktop.DBus.Properties',"
+                                   "member='PropertiesChanged'",
                                    &error);
 
                 if (dbus_error_is_set(&error)) {
-                        log_error("Failed to add match: %s", error.message);
-                        r = -EIO;
-                        goto finish;
-                }
-
-                dbus_bus_add_match(bus,
-                                   "type='signal',"
-                                   "sender='org.freedesktop.systemd1',"
-                                   "interface='org.freedesktop.systemd1.Job',"
-                                   "member='Changed'",
-                                   &error);
-
-                if (dbus_error_is_set(&error)) {
-                        log_error("Failed to add match: %s", error.message);
+                        log_error("Failed to add match: %s", bus_error_message(&error));
                         r = -EIO;
                         goto finish;
                 }
@@ -2520,7 +2633,7 @@ static int monitor(DBusConnection *bus, char **args, unsigned n) {
         }
 
         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                log_error("Failed to issue method call: %s", error.message);
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
                 r = -EIO;
                 goto finish;
         }
@@ -2563,7 +2676,7 @@ static int dump(DBusConnection *bus, char **args, unsigned n) {
         }
 
         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                log_error("Failed to issue method call: %s", error.message);
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
                 r = -EIO;
                 goto finish;
         }
@@ -2571,7 +2684,7 @@ static int dump(DBusConnection *bus, char **args, unsigned n) {
         if (!dbus_message_get_args(reply, &error,
                                    DBUS_TYPE_STRING, &text,
                                    DBUS_TYPE_INVALID)) {
-                log_error("Failed to parse reply: %s", error.message);
+                log_error("Failed to parse reply: %s", bus_error_message(&error));
                 r = -EIO;
                 goto finish;
         }
@@ -2627,7 +2740,7 @@ static int snapshot(DBusConnection *bus, char **args, unsigned n) {
         }
 
         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                log_error("Failed to issue method call: %s", error.message);
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
                 r = -EIO;
                 goto finish;
         }
@@ -2635,7 +2748,7 @@ static int snapshot(DBusConnection *bus, char **args, unsigned n) {
         if (!dbus_message_get_args(reply, &error,
                                    DBUS_TYPE_OBJECT_PATH, &path,
                                    DBUS_TYPE_INVALID)) {
-                log_error("Failed to parse reply: %s", error.message);
+                log_error("Failed to parse reply: %s", bus_error_message(&error));
                 r = -EIO;
                 goto finish;
         }
@@ -2661,7 +2774,7 @@ static int snapshot(DBusConnection *bus, char **args, unsigned n) {
 
         dbus_message_unref(reply);
         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                log_error("Failed to issue method call: %s", error.message);
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
                 r = -EIO;
                 goto finish;
         }
@@ -2732,7 +2845,7 @@ static int delete_snapshot(DBusConnection *bus, char **args, unsigned n) {
                 }
 
                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                        log_error("Failed to issue method call: %s", error.message);
+                        log_error("Failed to issue method call: %s", bus_error_message(&error));
                         r = -EIO;
                         goto finish;
                 }
@@ -2740,7 +2853,7 @@ static int delete_snapshot(DBusConnection *bus, char **args, unsigned n) {
                 if (!dbus_message_get_args(reply, &error,
                                            DBUS_TYPE_OBJECT_PATH, &path,
                                            DBUS_TYPE_INVALID)) {
-                        log_error("Failed to parse reply: %s", error.message);
+                        log_error("Failed to parse reply: %s", bus_error_message(&error));
                         r = -EIO;
                         goto finish;
                 }
@@ -2758,7 +2871,7 @@ static int delete_snapshot(DBusConnection *bus, char **args, unsigned n) {
 
                 dbus_message_unref(reply);
                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                        log_error("Failed to issue method call: %s", error.message);
+                        log_error("Failed to issue method call: %s", bus_error_message(&error));
                         r = -EIO;
                         goto finish;
                 }
@@ -2801,7 +2914,7 @@ static int daemon_reload(DBusConnection *bus, char **args, unsigned n) {
                         streq(args[0], "clear-jobs")        ||
                         streq(args[0], "cancel")            ? "ClearJobs" :
                         streq(args[0], "daemon-reexec")     ? "Reexecute" :
-                        streq(args[0], "reset-maintenance") ? "ResetMaintenance" :
+                        streq(args[0], "reset-failed")      ? "ResetFailed" :
                         streq(args[0], "daemon-exit")       ? "Exit" :
                                                               "Reload";
         }
@@ -2820,16 +2933,16 @@ static int daemon_reload(DBusConnection *bus, char **args, unsigned n) {
                 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(&error)) {
                         /* There's always a fallback possible for
                          * legacy actions. */
-                        r = 0;
+                        r = -EADDRNOTAVAIL;
                         goto finish;
                 }
 
-                log_error("Failed to issue method call: %s", error.message);
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
                 r = -EIO;
                 goto finish;
         }
 
-        r = 1;
+        r = 0;
 
 finish:
         if (m)
@@ -2843,7 +2956,7 @@ finish:
         return r;
 }
 
-static int reset_maintenance(DBusConnection *bus, char **args, unsigned n) {
+static int reset_failed(DBusConnection *bus, char **args, unsigned n) {
         DBusMessage *m = NULL, *reply = NULL;
         unsigned i;
         int r;
@@ -2861,7 +2974,7 @@ static int reset_maintenance(DBusConnection *bus, char **args, unsigned n) {
                                       "org.freedesktop.systemd1",
                                       "/org/freedesktop/systemd1",
                                       "org.freedesktop.systemd1.Manager",
-                                      "ResetMaintenanceUnit"))) {
+                                      "ResetFailedUnit"))) {
                         log_error("Could not allocate message.");
                         r = -ENOMEM;
                         goto finish;
@@ -2876,7 +2989,7 @@ static int reset_maintenance(DBusConnection *bus, char **args, unsigned n) {
                 }
 
                 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                        log_error("Failed to issue method call: %s", error.message);
+                        log_error("Failed to issue method call: %s", bus_error_message(&error));
                         r = -EIO;
                         goto finish;
                 }
@@ -2930,7 +3043,7 @@ static int show_enviroment(DBusConnection *bus, char **args, unsigned n) {
         }
 
         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                log_error("Failed to issue method call: %s", error.message);
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
                 r = -EIO;
                 goto finish;
         }
@@ -3028,7 +3141,7 @@ static int set_environment(DBusConnection *bus, char **args, unsigned n) {
         }
 
         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                log_error("Failed to issue method call: %s", error.message);
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
                 r = -EIO;
                 goto finish;
         }
@@ -3737,6 +3850,7 @@ static int systemctl_help(void) {
         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
                "Send control commands to or query the systemd manager.\n\n"
                "  -h --help          Show this help\n"
+               "     --version       Show package version\n"
                "  -t --type=TYPE     List only units of a particular type\n"
                "  -p --property=NAME Show only properties by this name\n"
                "  -a --all           Show all units/properties, including dead/empty ones\n"
@@ -3771,8 +3885,8 @@ static int systemctl_help(void) {
                "  status [NAME...|PID...]         Show runtime status of one or more units\n"
                "  show [NAME...|JOB...]           Show properties of one or more\n"
                "                                  units/jobs or the manager\n"
-               "  reset-maintenance [NAME...]     Reset maintenance state for all, one,\n"
-               "                                  or more units\n"
+               "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
+               "                                  units\n"
                "  enable [NAME...]                Enable one or more unit files\n"
                "  disable [NAME...]               Disable one or more unit files\n"
                "  is-enabled [NAME...]            Check whether unit files are enabled\n"
@@ -3824,7 +3938,7 @@ static int halt_help(void) {
 
 static int shutdown_help(void) {
 
-        printf("%s [OPTIONS...] [now] [WALL...]\n\n"
+        printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
                "Shut down the system.\n\n"
                "     --help      Show this help\n"
                "  -H --halt      Halt the machine\n"
@@ -3832,7 +3946,8 @@ static int shutdown_help(void) {
                "  -r --reboot    Reboot the machine\n"
                "  -h             Equivalent to --poweroff, overriden by --halt\n"
                "  -k             Don't halt/power-off/reboot, just send warnings\n"
-               "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
+               "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
+               "  -c             Cancel a pending shutdown\n",
                program_invocation_short_name);
 
         return 0;
@@ -3870,6 +3985,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
 
         enum {
                 ARG_FAIL = 0x100,
+                ARG_VERSION,
                 ARG_SESSION,
                 ARG_SYSTEM,
                 ARG_GLOBAL,
@@ -3885,6 +4001,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
 
         static const struct option options[] = {
                 { "help",      no_argument,       NULL, 'h'           },
+                { "version",   no_argument,       NULL, ARG_VERSION   },
                 { "type",      required_argument, NULL, 't'           },
                 { "property",  required_argument, NULL, 'p'           },
                 { "all",       no_argument,       NULL, 'a'           },
@@ -3900,7 +4017,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 { "require",   no_argument,       NULL, ARG_REQUIRE   },
                 { "force",     no_argument,       NULL, ARG_FORCE     },
                 { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
-                { "defaults",   no_argument,      NULL, ARG_DEFAULTS  },
+                { "defaults",  no_argument,       NULL, ARG_DEFAULTS  },
                 { NULL,        0,                 NULL, 0             }
         };
 
@@ -3917,6 +4034,12 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         systemctl_help();
                         return 0;
 
+                case ARG_VERSION:
+                        puts(PACKAGE_STRING);
+                        puts(DISTRIBUTION);
+                        puts(SYSTEMD_FEATURES);
+                        return 0;
+
                 case 't':
                         arg_type = optarg;
                         break;
@@ -4099,6 +4222,56 @@ static int halt_parse_argv(int argc, char *argv[]) {
         return 1;
 }
 
+static int parse_time_spec(const char *t, usec_t *_u) {
+        assert(t);
+        assert(_u);
+
+        if (streq(t, "now"))
+                *_u = 0;
+        else if (t[0] == '+') {
+                uint64_t u;
+
+                if (safe_atou64(t + 1, &u) < 0)
+                        return -EINVAL;
+
+                *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
+        } else {
+                char *e = NULL;
+                long hour, minute;
+                struct tm tm;
+                time_t s;
+                usec_t n;
+
+                errno = 0;
+                hour = strtol(t, &e, 10);
+                if (errno != 0 || *e != ':' || hour < 0 || hour > 23)
+                        return -EINVAL;
+
+                minute = strtol(e+1, &e, 10);
+                if (errno != 0 || *e != 0 || minute < 0 || minute > 59)
+                        return -EINVAL;
+
+                n = now(CLOCK_REALTIME);
+                s = (time_t) (n / USEC_PER_SEC);
+
+                zero(tm);
+                assert_se(localtime_r(&s, &tm));
+
+                tm.tm_hour = (int) hour;
+                tm.tm_min = (int) minute;
+                tm.tm_sec = 0;
+
+                assert_se(s = mktime(&tm));
+
+                *_u = (usec_t) s * USEC_PER_SEC;
+
+                while (*_u <= n)
+                        *_u += USEC_PER_DAY;
+        }
+
+        return 0;
+}
+
 static int shutdown_parse_argv(int argc, char *argv[]) {
 
         enum {
@@ -4115,12 +4288,12 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
                 { NULL,        0,                 NULL, 0           }
         };
 
-        int c;
+        int c, r;
 
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "HPrhkt:a", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
                 switch (c) {
 
                 case ARG_HELP:
@@ -4157,6 +4330,10 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
                         /* Compatibility nops */
                         break;
 
+                case 'c':
+                        arg_action = ACTION_CANCEL_SHUTDOWN;
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -4166,10 +4343,15 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
                 }
         }
 
-        if (argc > optind && !streq(argv[optind], "now"))
-                log_warning("First argument '%s' isn't 'now'. Ignoring.", argv[optind]);
+        if (argc > optind) {
+                if ((r = parse_time_spec(argv[optind], &arg_when)) < 0) {
+                        log_error("Failed to parse time specification: %s", argv[optind]);
+                        return r;
+                }
+        } else
+                arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
 
-        /* We ignore the time argument */
+        /* We skip the time argument */
         if (argc > optind + 1)
                 arg_wall = argv + optind + 1;
 
@@ -4397,7 +4579,7 @@ static int talk_upstart(void) {
                         goto finish;
                 }
 
-                log_error("Failed to connect to Upstart bus: %s", error.message);
+                log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error));
                 r = -EIO;
                 goto finish;
         }
@@ -4437,16 +4619,16 @@ static int talk_upstart(void) {
         if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
 
                 if (error_is_no_service(&error)) {
-                        r = 0;
+                        r = -EADDRNOTAVAIL;
                         goto finish;
                 }
 
-                log_error("Failed to issue method call: %s", error.message);
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
                 r = -EIO;
                 goto finish;
         }
 
-        r = 1;
+        r = 0;
 
 finish:
         if (m)
@@ -4456,6 +4638,7 @@ finish:
                 dbus_message_unref(reply);
 
         if (bus) {
+                dbus_connection_flush(bus);
                 dbus_connection_close(bus);
                 dbus_connection_unref(bus);
         }
@@ -4548,7 +4731,7 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
                 { "default",               EQUAL, 1, start_special     },
                 { "rescue",                EQUAL, 1, start_special     },
                 { "emergency",             EQUAL, 1, start_special     },
-                { "reset-maintenance",     MORE,  1, reset_maintenance },
+                { "reset-failed",          MORE,  1, reset_failed      },
                 { "enable",                MORE,  2, enable_unit       },
                 { "disable",               MORE,  2, enable_unit       },
                 { "is-enabled",            MORE,  2, enable_unit       }
@@ -4624,6 +4807,49 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
         return verbs[i].dispatch(bus, argv + optind, left);
 }
 
+static int send_shutdownd(usec_t t, char mode, bool warn, const char *message) {
+        int fd = -1;
+        struct msghdr msghdr;
+        struct iovec iovec;
+        union sockaddr_union sockaddr;
+        struct shutdownd_command c;
+
+        zero(c);
+        c.elapse = t;
+        c.mode = mode;
+        c.warn_wall = warn;
+
+        if (message)
+                strncpy(c.wall_message, message, sizeof(c.wall_message));
+
+        if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0)
+                return -errno;
+
+        zero(sockaddr);
+        sockaddr.sa.sa_family = AF_UNIX;
+        sockaddr.un.sun_path[0] = 0;
+        strncpy(sockaddr.un.sun_path+1, "/org/freedesktop/systemd1/shutdownd", sizeof(sockaddr.un.sun_path)-1);
+
+        zero(iovec);
+        iovec.iov_base = (char*) &c;
+        iovec.iov_len = sizeof(c);
+
+        zero(msghdr);
+        msghdr.msg_name = &sockaddr;
+        msghdr.msg_namelen = sizeof(sa_family_t) + 1 + sizeof("/org/freedesktop/systemd1/shutdownd") - 1;
+
+        msghdr.msg_iov = &iovec;
+        msghdr.msg_iovlen = 1;
+
+        if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
+                close_nointr_nofail(fd);
+                return -errno;
+        }
+
+        close_nointr_nofail(fd);
+        return 0;
+}
+
 static int reload_with_fallback(DBusConnection *bus) {
 
         if (bus) {
@@ -4647,7 +4873,7 @@ static int start_with_fallback(DBusConnection *bus) {
 
         if (bus) {
                 /* First, try systemd via D-Bus. */
-                if (start_unit(bus, NULL, 0) > 0)
+                if (start_unit(bus, NULL, 0) >= 0)
                         goto done;
         }
 
@@ -4673,10 +4899,32 @@ static int halt_main(DBusConnection *bus) {
         int r;
 
         if (geteuid() != 0) {
-                log_error("Must to be root.");
+                log_error("Must be root.");
                 return -EPERM;
         }
 
+        if (arg_when > 0) {
+                char *m;
+                char date[FORMAT_TIMESTAMP_MAX];
+
+                m = strv_join(arg_wall, " ");
+                r = send_shutdownd(arg_when,
+                                   arg_action == ACTION_HALT     ? 'H' :
+                                   arg_action == ACTION_POWEROFF ? 'P' :
+                                                                   'r',
+                                   !arg_no_wall,
+                                   m);
+                free(m);
+
+                if (r < 0)
+                        log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
+                else {
+                        log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
+                                 format_timestamp(date, sizeof(date), arg_when));
+                        return 0;
+                }
+        }
+
         if (!arg_dry && !arg_immediate)
                 return start_with_fallback(bus);
 
@@ -4738,25 +4986,27 @@ static int runlevel_main(void) {
 }
 
 int main(int argc, char*argv[]) {
-        int r, retval = 1;
+        int r, retval = EXIT_FAILURE;
         DBusConnection *bus = NULL;
         DBusError error;
 
         dbus_error_init(&error);
 
         log_parse_environment();
+        log_open();
 
         if ((r = parse_argv(argc, argv)) < 0)
                 goto finish;
         else if (r == 0) {
-                retval = 0;
+                retval = EXIT_SUCCESS;
                 goto finish;
         }
 
         /* /sbin/runlevel doesn't need to communicate via D-Bus, so
          * let's shortcut this */
         if (arg_action == ACTION_RUNLEVEL) {
-                retval = runlevel_main() < 0;
+                r = runlevel_main();
+                retval = r < 0 ? EXIT_FAILURE : r;
                 goto finish;
         }
 
@@ -4764,15 +5014,14 @@ int main(int argc, char*argv[]) {
 
         switch (arg_action) {
 
-        case ACTION_SYSTEMCTL: {
-                retval = systemctl_main(bus, argc, argv, &error) < 0;
+        case ACTION_SYSTEMCTL:
+                r = systemctl_main(bus, argc, argv, &error);
                 break;
-        }
 
         case ACTION_HALT:
         case ACTION_POWEROFF:
         case ACTION_REBOOT:
-                retval = halt_main(bus) < 0;
+                r = halt_main(bus);
                 break;
 
         case ACTION_RUNLEVEL2:
@@ -4782,12 +5031,16 @@ int main(int argc, char*argv[]) {
         case ACTION_RESCUE:
         case ACTION_EMERGENCY:
         case ACTION_DEFAULT:
-                retval = start_with_fallback(bus) < 0;
+                r = start_with_fallback(bus);
                 break;
 
         case ACTION_RELOAD:
         case ACTION_REEXEC:
-                retval = reload_with_fallback(bus) < 0;
+                r = reload_with_fallback(bus);
+                break;
+
+        case ACTION_CANCEL_SHUTDOWN:
+                r = send_shutdownd(0, 0, false, NULL);
                 break;
 
         case ACTION_INVALID:
@@ -4796,9 +5049,12 @@ int main(int argc, char*argv[]) {
                 assert_not_reached("Unknown action");
         }
 
+        retval = r < 0 ? EXIT_FAILURE : r;
+
 finish:
 
         if (bus) {
+                dbus_connection_flush(bus);
                 dbus_connection_close(bus);
                 dbus_connection_unref(bus);
         }