chiark / gitweb /
Remove duplicate includes
[elogind.git] / src / systemctl / systemctl.c
index 7c2d71f68523136776a8357e50e1d17ebe6f6de1..2e1863675f7f3ce3b58ebdb17bd5a0f02f3885bc 100644 (file)
@@ -65,7 +65,6 @@
 #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"
@@ -135,7 +134,7 @@ static OutputMode arg_output = OUTPUT_SHORT;
 static bool arg_plain = false;
 
 static int daemon_reload(sd_bus *bus, char **args);
-static void halt_now(enum action a);
+static int halt_now(enum action a);
 
 static void pager_open_if_enabled(void) {
 
@@ -155,6 +154,9 @@ static void ask_password_agent_open_if_enabled(void) {
         if (arg_scope != UNIT_FILE_SYSTEM)
                 return;
 
+        if (arg_transport != BUS_TRANSPORT_LOCAL)
+                return;
+
         ask_password_agent_open();
 }
 
@@ -319,18 +321,23 @@ static void output_units_list(const UnitInfo *unit_infos, unsigned c) {
 
         if (!arg_full && original_stdout_is_tty) {
                 unsigned basic_len;
+
                 id_len = MIN(max_id_len, 25u);
                 basic_len = 5 + id_len + 5 + active_len + sub_len;
+
                 if (job_count)
                         basic_len += job_len + 1;
+
                 if (basic_len < (unsigned) columns()) {
                         unsigned extra_len, incr;
                         extra_len = columns() - basic_len;
+
                         /* Either UNIT already got 25, or is fully satisfied.
                          * Grant up to 25 to DESC now. */
                         incr = MIN(extra_len, 25u);
                         desc_len += incr;
                         extra_len -= incr;
+
                         /* split the remaining space between UNIT and DESC,
                          * but do not give UNIT more than it needs. */
                         if (extra_len > 0) {
@@ -351,10 +358,15 @@ static void output_units_list(const UnitInfo *unit_infos, unsigned c) {
                         continue;
 
                 if (!n_shown && !arg_no_legend) {
-                        printf("%-*s %-*s %-*s %-*s ", id_len, "UNIT", load_len, "LOAD",
-                               active_len, "ACTIVE", sub_len, "SUB");
+                        printf("%-*s %-*s %-*s %-*s ",
+                               id_len, "UNIT",
+                               load_len, "LOAD",
+                               active_len, "ACTIVE",
+                               sub_len, "SUB");
+
                         if (job_count)
                                 printf("%-*s ", job_len, "JOB");
+
                         if (!arg_full && arg_no_pager)
                                 printf("%.*s\n", desc_len, "DESCRIPTION");
                         else
@@ -384,6 +396,7 @@ static void output_units_list(const UnitInfo *unit_infos, unsigned c) {
                        on_active, active_len, u->active_state,
                        sub_len, u->sub_state, off_active,
                        job_count ? job_len + 1 : 0, u->job_id ? u->job_type : "");
+
                 if (desc_len > 0)
                         printf("%.*s\n", desc_len, u->description);
                 else
@@ -518,13 +531,12 @@ static int get_triggered_units(
 static int get_listening(
                 sd_bus *bus,
                 const char* unit_path,
-                char*** listen,
-                unsigned *c) {
+                char*** listening) {
 
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
         const char *type, *path;
-        int r;
+        int r, n = 0;
 
         r = sd_bus_get_property(
                         bus,
@@ -546,15 +558,15 @@ static int get_listening(
 
         while ((r = sd_bus_message_read(reply, "(ss)", &type, &path)) > 0) {
 
-                r = strv_extend(listen, type);
+                r = strv_extend(listening, type);
                 if (r < 0)
                         return log_oom();
 
-                r = strv_extend(listen, path);
+                r = strv_extend(listening, path);
                 if (r < 0)
                         return log_oom();
 
-                (*c)++;
+                n++;
         }
         if (r < 0)
                 return bus_log_parse_error(r);
@@ -563,7 +575,7 @@ static int get_listening(
         if (r < 0)
                 return bus_log_parse_error(r);
 
-        return 0;
+        return n;
 }
 
 struct socket_info {
@@ -581,10 +593,16 @@ struct socket_info {
         bool own_triggered;
 };
 
-static int socket_info_compare(struct socket_info *a, struct socket_info *b) {
-        int o = strcmp(a->path, b->path);
+static int socket_info_compare(const struct socket_info *a, const struct socket_info *b) {
+        int o;
+
+        assert(a);
+        assert(b);
+
+        o = strcmp(a->path, b->path);
         if (o == 0)
                 o = strcmp(a->type, b->type);
+
         return o;
 }
 
@@ -597,8 +615,8 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
         const char *on, *off;
 
         for (s = socket_infos; s < socket_infos + cs; s++) {
-                char **a;
                 unsigned tmp = 0;
+                char **a;
 
                 socklen = MAX(socklen, strlen(s->id));
                 if (arg_show_types)
@@ -657,36 +675,35 @@ static int list_sockets(sd_bus *bus, char **args) {
         struct socket_info *socket_infos = NULL;
         const UnitInfo *u;
         struct socket_info *s;
-        unsigned cu = 0, cs = 0;
+        unsigned cs = 0;
         size_t size = 0;
-        int r;
+        int r = 0, n;
 
         pager_open_if_enabled();
 
-        r = get_unit_list(bus, &reply, &unit_infos);
-        if (r < 0)
-                return r;
-
-        cu = (unsigned) r;
+        n = get_unit_list(bus, &reply, &unit_infos);
+        if (n < 0)
+                return n;
 
-        for (u = unit_infos; u < unit_infos + cu; u++) {
-                const char *dot;
-                _cleanup_strv_free_ char **listen = NULL, **triggered = NULL;
-                unsigned c = 0, i;
+        for (u = unit_infos; u < unit_infos + n; u++) {
+                _cleanup_strv_free_ char **listening = NULL, **triggered = NULL;
+                int i, c;
 
                 if (!output_show_unit(u))
                         continue;
 
-                if ((dot = strrchr(u->id, '.')) && !streq(dot+1, "socket"))
+                if (!endswith(u->id, ".socket"))
                         continue;
 
                 r = get_triggered_units(bus, u->unit_path, &triggered);
                 if (r < 0)
                         goto cleanup;
 
-                r = get_listening(bus, u->unit_path, &listen, &c);
-                if (r < 0)
+                c = get_listening(bus, u->unit_path, &listening);
+                if (c < 0) {
+                        r = c;
                         goto cleanup;
+                }
 
                 if (!GREEDY_REALLOC(socket_infos, size, cs + c)) {
                         r = log_oom();
@@ -696,16 +713,16 @@ static int list_sockets(sd_bus *bus, char **args) {
                 for (i = 0; i < c; i++)
                         socket_infos[cs + i] = (struct socket_info) {
                                 .id = u->id,
-                                .type = listen[i*2],
-                                .path = listen[i*2 + 1],
+                                .type = listening[i*2],
+                                .path = listening[i*2 + 1],
                                 .triggered = triggered,
                                 .own_triggered = i==0,
                         };
 
                 /* from this point on we will cleanup those socket_infos */
                 cs += c;
-                free(listen);
-                listen = triggered = NULL; /* avoid cleanup */
+                free(listening);
+                listening = triggered = NULL; /* avoid cleanup */
         }
 
         qsort_safe(socket_infos, cs, sizeof(struct socket_info),
@@ -726,6 +743,224 @@ static int list_sockets(sd_bus *bus, char **args) {
         return r;
 }
 
+static int get_next_elapse(
+                sd_bus *bus,
+                const char *path,
+                dual_timestamp *next) {
+
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        dual_timestamp t;
+        int r;
+
+        assert(bus);
+        assert(path);
+        assert(next);
+
+        r = sd_bus_get_property_trivial(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        path,
+                        "org.freedesktop.systemd1.Timer",
+                        "NextElapseUSecMonotonic",
+                        &error,
+                        't',
+                        &t.monotonic);
+        if (r < 0) {
+                log_error("Failed to get next elapsation time: %s", bus_error_message(&error, r));
+                return r;
+        }
+
+        r = sd_bus_get_property_trivial(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        path,
+                        "org.freedesktop.systemd1.Timer",
+                        "NextElapseUSecRealtime",
+                        &error,
+                        't',
+                        &t.realtime);
+        if (r < 0) {
+                log_error("Failed to get next elapsation time: %s", bus_error_message(&error, r));
+                return r;
+        }
+
+        *next = t;
+        return 0;
+}
+
+struct timer_info {
+        const char* id;
+        usec_t next_elapse;
+        char** triggered;
+};
+
+static int timer_info_compare(const struct timer_info *a, const struct timer_info *b) {
+        assert(a);
+        assert(b);
+
+        if (a->next_elapse < b->next_elapse)
+                return -1;
+        if (a->next_elapse > b->next_elapse)
+                return 1;
+
+        return strcmp(a->id, b->id);
+}
+
+static int output_timers_list(struct timer_info *timer_infos, unsigned n) {
+        struct timer_info *t;
+        unsigned
+                nextlen = sizeof("NEXT") - 1,
+                leftlen = sizeof("LEFT") - 1,
+                unitlen = sizeof("UNIT") - 1,
+                activatelen = sizeof("ACTIVATES") - 1;
+
+        const char *on, *off;
+
+        assert(timer_infos || n == 0);
+
+        for (t = timer_infos; t < timer_infos + n; t++) {
+                unsigned ul = 0;
+                char **a;
+
+                if (t->next_elapse > 0) {
+                        char tstamp[FORMAT_TIMESTAMP_MAX] = "", trel[FORMAT_TIMESTAMP_RELATIVE_MAX] = "";
+
+                        format_timestamp(tstamp, sizeof(tstamp), t->next_elapse);
+                        nextlen = MAX(nextlen, strlen(tstamp) + 1);
+
+                        format_timestamp_relative(trel, sizeof(trel), t->next_elapse);
+                        leftlen = MAX(leftlen, strlen(trel));
+                }
+
+                unitlen = MAX(unitlen, strlen(t->id));
+
+                STRV_FOREACH(a, t->triggered)
+                        ul += strlen(*a) + 2*(a != t->triggered);
+                activatelen = MAX(activatelen, ul);
+        }
+
+        if (n > 0) {
+                if (!arg_no_legend)
+                        printf("%-*s %-*s %-*s %s\n",
+                               nextlen, "NEXT",
+                               leftlen, "LEFT",
+                               unitlen, "UNIT",
+                                        "ACTIVATES");
+
+                for (t = timer_infos; t < timer_infos + n; t++) {
+                        char tstamp[FORMAT_TIMESTAMP_MAX] = "n/a", trel[FORMAT_TIMESTAMP_RELATIVE_MAX] = "n/a";
+                        char **a;
+
+                        format_timestamp(tstamp, sizeof(tstamp), t->next_elapse);
+                        format_timestamp_relative(trel, sizeof(trel), t->next_elapse);
+
+                        printf("%-*s %-*s %-*s",
+                               nextlen, tstamp, leftlen, trel, unitlen, t->id);
+
+                        STRV_FOREACH(a, t->triggered)
+                                printf("%s %s",
+                                       a == t->triggered ? "" : ",", *a);
+                        printf("\n");
+                }
+
+                on = ansi_highlight();
+                off = ansi_highlight_off();
+                if (!arg_no_legend)
+                        printf("\n");
+        } else {
+                on = ansi_highlight_red();
+                off = ansi_highlight_off();
+        }
+
+        if (!arg_no_legend) {
+                printf("%s%u timers listed.%s\n", on, n, off);
+                if (!arg_all)
+                        printf("Pass --all to see loaded but inactive timers, too.\n");
+        }
+
+        return 0;
+}
+
+static int list_timers(sd_bus *bus, char **args) {
+
+        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+        _cleanup_free_ struct timer_info *timer_infos = NULL;
+        _cleanup_free_ UnitInfo *unit_infos = NULL;
+        struct timer_info *t;
+        const UnitInfo *u;
+        size_t size = 0;
+        int n, c = 0;
+        dual_timestamp nw;
+        int r = 0;
+
+        pager_open_if_enabled();
+
+        n = get_unit_list(bus, &reply, &unit_infos);
+        if (n < 0)
+                return n;
+
+        dual_timestamp_get(&nw);
+
+        for (u = unit_infos; u < unit_infos + n; u++) {
+                _cleanup_strv_free_ char **triggered = NULL;
+                dual_timestamp next;
+                usec_t m;
+
+                if (!output_show_unit(u))
+                        continue;
+
+                if (!endswith(u->id, ".timer"))
+                        continue;
+
+                r = get_triggered_units(bus, u->unit_path, &triggered);
+                if (r < 0)
+                        goto cleanup;
+
+                r = get_next_elapse(bus, u->unit_path, &next);
+                if (r < 0)
+                        goto cleanup;
+
+                if (next.monotonic != (usec_t) -1 && next.monotonic > 0) {
+                        usec_t converted;
+
+                        if (next.monotonic > nw.monotonic)
+                                converted = nw.realtime + (next.monotonic - nw.monotonic);
+                        else
+                                converted = nw.realtime - (nw.monotonic - next.monotonic);
+
+                        if (next.realtime != (usec_t) -1 && next.realtime > 0)
+                                m = MIN(converted, next.realtime);
+                        else
+                                m = converted;
+                } else
+                        m = next.realtime;
+
+                if (!GREEDY_REALLOC(timer_infos, size, c+1)) {
+                        r = log_oom();
+                        goto cleanup;
+                }
+
+                timer_infos[c++] = (struct timer_info) {
+                        .id = u->id,
+                        .next_elapse = m,
+                        .triggered = triggered,
+                };
+
+                triggered = NULL; /* avoid cleanup */
+        }
+
+        qsort_safe(timer_infos, c, sizeof(struct timer_info),
+                   (__compar_fn_t) timer_info_compare);
+
+        output_timers_list(timer_infos, c);
+
+ cleanup:
+        for (t = timer_infos; t < timer_infos + c; t++)
+                strv_free(t->triggered);
+
+        return r;
+}
+
 static int compare_unit_file_list(const void *a, const void *b) {
         const char *d1, *d2;
         const UnitFileList *u = a, *v = b;
@@ -756,6 +991,7 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) {
 
         max_id_len = sizeof("UNIT FILE")-1;
         state_cols = sizeof("STATE")-1;
+
         for (u = units; u < units + c; u++) {
                 if (!output_show_unit_file(u))
                         continue;
@@ -766,6 +1002,7 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) {
 
         if (!arg_full) {
                 unsigned basic_cols;
+
                 id_cols = MIN(max_id_len, 25u);
                 basic_cols = 1 + id_cols + state_cols;
                 if (basic_cols < (unsigned) columns())
@@ -774,7 +1011,9 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) {
                 id_cols = max_id_len;
 
         if (!arg_no_legend)
-                printf("%-*s %-*s\n", id_cols, "UNIT FILE", state_cols, "STATE");
+                printf("%-*s %-*s\n",
+                       id_cols, "UNIT FILE",
+                       state_cols, "STATE");
 
         for (u = units; u < units + c; u++) {
                 _cleanup_free_ char *e = NULL;
@@ -901,12 +1140,13 @@ static int list_unit_files(sd_bus *bus, char **args) {
 }
 
 static int list_dependencies_print(const char *name, int level, unsigned int branches, bool last) {
-        int i;
         _cleanup_free_ char *n = NULL;
-        size_t len = 0;
         size_t max_len = MAX(columns(),20u);
+        size_t len = 0;
+        int i;
 
         if (!arg_plain) {
+
                 for (i = level - 1; i >= 0; i--) {
                         len += 2;
                         if(len > max_len - 3 && !arg_full) {
@@ -916,14 +1156,16 @@ static int list_dependencies_print(const char *name, int level, unsigned int bra
                         printf("%s", draw_special_char(branches & (1 << i) ? DRAW_TREE_VERT : DRAW_TREE_SPACE));
                 }
                 len += 2;
+
                 if(len > max_len - 3 && !arg_full) {
                         printf("%s...\n",max_len % 2 ? "" : " ");
                         return 0;
                 }
+
                 printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH));
         }
 
-        if(arg_full){
+        if (arg_full){
                 printf("%s\n", name);
                 return 0;
         }
@@ -1031,10 +1273,12 @@ static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, cha
 
 static int list_dependencies_compare(const void *_a, const void *_b) {
         const char **a = (const char**) _a, **b = (const char**) _b;
+
         if (unit_name_to_type(*a) == UNIT_TARGET && unit_name_to_type(*b) != UNIT_TARGET)
                 return 1;
         if (unit_name_to_type(*a) != UNIT_TARGET && unit_name_to_type(*b) == UNIT_TARGET)
                 return -1;
+
         return strcasecmp(*a, *b);
 }
 
@@ -1049,6 +1293,10 @@ static int list_dependencies_one(
         char **c;
         int r = 0;
 
+        assert(bus);
+        assert(name);
+        assert(units);
+
         u = strv_append(*units, name);
         if (!u)
                 return log_oom();
@@ -1175,6 +1423,11 @@ static void output_jobs_list(const struct job_info* jobs, unsigned n) {
 
         pager_open_if_enabled();
 
+        id_len = sizeof("JOB")-1;
+        unit_len = sizeof("UNIT")-1;
+        type_len = sizeof("TYPE")-1;
+        state_len = sizeof("STATE")-1;
+
         for (j = jobs; j < jobs + n; j++) {
                 uint32_t id = j->id;
                 assert(j->name && j->type && j->state);
@@ -1190,11 +1443,12 @@ static void output_jobs_list(const struct job_info* jobs, unsigned n) {
                 shorten = true;
         }
 
-        printf("%*s %-*s %-*s %-*s\n",
-               id_len, "JOB",
-               unit_len, "UNIT",
-               type_len, "TYPE",
-               state_len, "STATE");
+        if (!arg_no_legend)
+                printf("%*s %-*s %-*s %-*s\n",
+                       id_len, "JOB",
+                       unit_len, "UNIT",
+                       type_len, "TYPE",
+                       state_len, "STATE");
 
         for (j = jobs; j < jobs + n; j++) {
                 _cleanup_free_ char *e = NULL;
@@ -1213,10 +1467,12 @@ static void output_jobs_list(const struct job_info* jobs, unsigned n) {
                        on, state_len, j->state, off);
         }
 
-        on = ansi_highlight();
-        off = ansi_highlight_off();
+        if (!arg_no_legend) {
+                on = ansi_highlight();
+                off = ansi_highlight_off();
 
-        printf("\n%s%u jobs listed%s.\n", on, n, off);
+                printf("\n%s%u jobs listed%s.\n", on, n, off);
+        }
 }
 
 static int list_jobs(sd_bus *bus, char **args) {
@@ -1676,10 +1932,8 @@ static int start_unit_one(
                         return log_oom();
 
                 r = set_consume(s, p);
-                if (r < 0) {
-                        log_error("Failed to add path to set.");
-                        return r;
-                }
+                if (r < 0)
+                        return log_oom();
         }
 
         return 0;
@@ -1742,8 +1996,7 @@ static int start_unit(sd_bus *bus, char **args) {
                         streq(args[0], "reload-or-restart")     ? "ReloadOrRestartUnit" :
 
                         streq(args[0], "reload-or-try-restart") ||
-                        streq(args[0], "condreload") ||
-
+                        streq(args[0], "condreload")            ||
                         streq(args[0], "force-reload")          ? "ReloadOrTryRestartUnit" :
                                                                   "StartUnit";
                 action = verb_to_action(args[0]);
@@ -1752,7 +2005,6 @@ static int start_unit(sd_bus *bus, char **args) {
                        action_table[action].mode ?: arg_job_mode;
 
                 one_name = action_table[action].target;
-
         } else {
                 assert(arg_action < ELEMENTSOF(action_table));
                 assert(action_table[arg_action].target);
@@ -1873,7 +2125,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;
@@ -1910,11 +2161,11 @@ static int check_inhibitors(sd_bus *bus, enum action a) {
                 /* If logind is not around, then there are no inhibitors... */
                 return 0;
 
-        r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "ssssuu");
+        r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
         if (r < 0)
                 return bus_log_parse_error(r);
 
-        while ((r = sd_bus_message_read(reply, "ssssuu", &what, &who, &why, &mode, &uid, &pid)) > 0) {
+        while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
                 _cleanup_free_ char *comm = NULL, *user = NULL;
                 _cleanup_strv_free_ char **sv = NULL;
 
@@ -2003,7 +2254,7 @@ static int start_special(sd_bus *bus, char **args) {
             (a == ACTION_HALT ||
              a == ACTION_POWEROFF ||
              a == ACTION_REBOOT))
-                halt_now(a);
+                return halt_now(a);
 
         if (arg_force >= 1 &&
             (a == ACTION_HALT ||
@@ -2500,7 +2751,7 @@ static void print_status_info(
 
                 printf("   CGroup: %s\n", i->control_group);
 
-                if (arg_transport == BUS_TRANSPORT_LOCAL) {
+                if (arg_transport == BUS_TRANSPORT_LOCAL || arg_transport == BUS_TRANSPORT_CONTAINER) {
                         unsigned k = 0;
                         pid_t extra[2];
                         char prefix[] = "           ";
@@ -2556,11 +2807,11 @@ static void show_unit_help(UnitStatusInfo *i) {
         STRV_FOREACH(p, i->documentation) {
 
                 if (startswith(*p, "man:")) {
-                        size_t k;
-                        char *e = NULL;
-                        _cleanup_free_ char *page = NULL, *section = NULL;
                         const char *args[4] = { "man", NULL, NULL, NULL };
+                        _cleanup_free_ char *page = NULL, *section = NULL;
+                        char *e = NULL;
                         pid_t pid;
+                        size_t k;
 
                         k = strlen(*p);
 
@@ -2887,8 +3138,11 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
         /* This is a low-level property printer, see
          * print_status_info() for the nicer output */
 
-        if (arg_properties && !strv_find(arg_properties, name))
-                return 0;
+        if (arg_properties && !strv_find(arg_properties, name)) {
+                /* skip what we didn't read */
+                r = sd_bus_message_skip(m, contents);
+                return r;
+        }
 
         switch (contents[0]) {
 
@@ -3285,7 +3539,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;
@@ -3591,7 +3844,7 @@ static int set_property(sd_bus *bus, char **args) {
         if (r < 0)
                 return bus_log_create_error(r);
 
-        r = sd_bus_send_with_reply_and_block(bus, m, -1, &error, NULL);
+        r = sd_bus_call(bus, m, 0, &error, NULL);
         if (r < 0) {
                 log_error("Failed to set unit properties on %s: %s", n, bus_error_message(&error, r));
                 return r;
@@ -3729,7 +3982,7 @@ static int daemon_reload(sd_bus *bus, char **args) {
         else if (r < 0)
                 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
 
-        return r;
+        return r < 0 ? r : 0;
 }
 
 static int reset_failed(sd_bus *bus, char **args) {
@@ -3878,7 +4131,7 @@ static int set_environment(sd_bus *bus, char **args) {
         if (r < 0)
                 return bus_log_create_error(r);
 
-        r = sd_bus_send_with_reply_and_block(bus, m, -1, &error, NULL);
+        r = sd_bus_call(bus, m, 0, &error, NULL);
         if (r < 0) {
                 log_error("Failed to set environment: %s", bus_error_message(&error, r));
                 return r;
@@ -4189,7 +4442,7 @@ static int enable_unit(sd_bus *bus, char **args) {
                                 return bus_log_create_error(r);
                 }
 
-                r = sd_bus_send_with_reply_and_block(bus, m, -0, &error, &reply);
+                r = sd_bus_call(bus, m, 0, &error, &reply);
                 if (r < 0) {
                         log_error("Failed to execute operation: %s", bus_error_message(&error, r));
                         return r;
@@ -4268,9 +4521,10 @@ static int unit_is_enabled(sd_bus *bus, char **args) {
                         UnitFileState state;
 
                         state = unit_file_get_state(arg_scope, arg_root, *name);
-
-                        if (state < 0)
+                        if (state < 0) {
+                                log_error("Failed to get unit file state for %s: %s", *name, strerror(-state));
                                 return state;
+                        }
 
                         if (state == UNIT_FILE_ENABLED ||
                             state == UNIT_FILE_ENABLED_RUNTIME ||
@@ -4370,6 +4624,7 @@ static int systemctl_help(void) {
                "Unit Commands:\n"
                "  list-units                      List loaded units\n"
                "  list-sockets                    List loaded sockets ordered by address\n"
+               "  list-timers                     List loaded timers ordered by next elapse\n"
                "  start [NAME...]                 Start (activate) one or more units\n"
                "  stop [NAME...]                  Stop (deactivate) one or more units\n"
                "  reload [NAME...]                Reload one or more units\n"
@@ -4651,7 +4906,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         /* Make sure that if the empty property list
                            was specified, we won't show any properties. */
                         if (isempty(optarg) && !arg_properties) {
-                                arg_properties = strv_new(NULL, NULL);
+                                arg_properties = new0(char*, 1);
                                 if (!arg_properties)
                                         return log_oom();
                         } else {
@@ -5291,18 +5546,21 @@ _pure_ static int action_to_runlevel(void) {
 }
 
 static int talk_initctl(void) {
-        struct init_request request = {};
-        int r;
+
+        struct init_request request = {
+                .magic = INIT_MAGIC,
+                .sleeptime  = 0,
+                .cmd = INIT_CMD_RUNLVL
+        };
+
         _cleanup_close_ int fd = -1;
         char rl;
+        int r;
 
         rl = action_to_runlevel();
         if (!rl)
                 return 0;
 
-        request.magic = INIT_MAGIC;
-        request.sleeptime = 0;
-        request.cmd = INIT_CMD_RUNLVL;
         request.runlevel = rl;
 
         fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY);
@@ -5324,7 +5582,7 @@ static int talk_initctl(void) {
         return 1;
 }
 
-static int systemctl_main(sd_bus *bus, int argc, char *argv[], const int r) {
+static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
 
         static const struct {
                 const char* verb;
@@ -5339,6 +5597,7 @@ static int systemctl_main(sd_bus *bus, int argc, char *argv[], const int r) {
                 { "list-units",            LESS,  1, list_units        },
                 { "list-unit-files",       EQUAL, 1, list_unit_files   },
                 { "list-sockets",          LESS,  1, list_sockets      },
+                { "list-timers",           LESS,  1, list_timers       },
                 { "list-jobs",             EQUAL, 1, list_jobs         },
                 { "clear-jobs",            EQUAL, 1, daemon_reload     },
                 { "cancel",                MORE,  2, cancel_job        },
@@ -5475,14 +5734,14 @@ static int systemctl_main(sd_bus *bus, int argc, char *argv[], const int r) {
                 if (((!streq(verbs[i].verb, "reboot") &&
                       !streq(verbs[i].verb, "halt") &&
                       !streq(verbs[i].verb, "poweroff")) || arg_force <= 0) && !bus) {
-                        log_error("Failed to get D-Bus connection: %s", strerror (-r));
+                        log_error("Failed to get D-Bus connection: %s", strerror (-bus_error));
                         return -EIO;
                 }
 
         } else {
 
                 if (!bus && !avoid_bus()) {
-                        log_error("Failed to get D-Bus connection: %s", strerror (-r));
+                        log_error("Failed to get D-Bus connection: %s", strerror (-bus_error));
                         return -EIO;
                 }
         }
@@ -5491,22 +5750,24 @@ static int systemctl_main(sd_bus *bus, int argc, char *argv[], const int r) {
 }
 
 static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
-        _cleanup_close_ int fd;
+
         struct sd_shutdown_command c = {
                 .usec = t,
                 .mode = mode,
                 .dry_run = dry_run,
                 .warn_wall = warn,
         };
+
         union sockaddr_union sockaddr = {
                 .un.sun_family = AF_UNIX,
                 .un.sun_path = "/run/systemd/shutdownd",
         };
-        struct iovec iovec[2] = {
-                {.iov_base = (char*) &c,
+
+        struct iovec iovec[2] = {{
+                 .iov_base = (char*) &c,
                  .iov_len = offsetof(struct sd_shutdown_command, wall_message),
-                }
-        };
+        }};
+
         struct msghdr msghdr = {
                 .msg_name = &sockaddr,
                 .msg_namelen = offsetof(struct sockaddr_un, sun_path)
@@ -5515,6 +5776,8 @@ static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const ch
                 .msg_iovlen = 1,
         };
 
+        _cleanup_close_ int fd;
+
         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
         if (fd < 0)
                 return -errno;
@@ -5571,11 +5834,9 @@ done:
         return 0;
 }
 
-static _noreturn_ void halt_now(enum action a) {
-
-        _cleanup_free_ char *param = NULL;
+static int halt_now(enum action a) {
 
-       /* Make sure C-A-D is handled by the kernel from this
+/* Make sure C-A-D is handled by the kernel from this
          * point on... */
         reboot(RB_ENABLE_CAD);
 
@@ -5584,29 +5845,30 @@ static _noreturn_ void halt_now(enum action a) {
         case ACTION_HALT:
                 log_info("Halting.");
                 reboot(RB_HALT_SYSTEM);
-                break;
+                return -errno;
 
         case ACTION_POWEROFF:
                 log_info("Powering off.");
                 reboot(RB_POWER_OFF);
-                break;
+                return -errno;
 
-        case ACTION_REBOOT:
-                if (read_one_line_file(REBOOT_PARAM_FILE, &param) == 0) {
-                        log_info("Rebooting with arg '%s'.", param);
+        case ACTION_REBOOT: {
+                _cleanup_free_ char *param = NULL;
+
+                if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
+                        log_info("Rebooting with argument '%s'.", param);
                         syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
                                 LINUX_REBOOT_CMD_RESTART2, param);
-                } else {
-                        log_info("Rebooting.");
-                        reboot(RB_AUTOBOOT);
                 }
-                break;
 
-        default:
-                assert_not_reached("Unknown halt action.");
+                log_info("Rebooting.");
+                reboot(RB_AUTOBOOT);
+                return -errno;
         }
 
-        assert_not_reached("Uh? This shouldn't happen.");
+        default:
+                assert_not_reached("Unknown action.");
+        }
 }
 
 static int halt_main(sd_bus *bus) {
@@ -5639,6 +5901,9 @@ static int halt_main(sd_bus *bus) {
                 _cleanup_free_ char *m;
 
                 m = strv_join(arg_wall, " ");
+                if (!m)
+                        return log_oom();
+
                 r = send_shutdownd(arg_when,
                                    arg_action == ACTION_HALT     ? 'H' :
                                    arg_action == ACTION_POWEROFF ? 'P' :
@@ -5675,9 +5940,10 @@ static int halt_main(sd_bus *bus) {
         if (arg_dry)
                 return 0;
 
-        halt_now(arg_action);
-        /* We should never reach this. */
-        return -ENOSYS;
+        r = halt_now(arg_action);
+        log_error("Failed to reboot: %s", strerror(-r));
+
+        return r;
 }
 
 static int runlevel_main(void) {
@@ -5726,13 +5992,11 @@ int main(int argc, char*argv[]) {
                 goto finish;
         }
 
-        if (!avoid_bus()) {
-                r = bus_open_transport(arg_transport, arg_host, arg_scope != UNIT_FILE_SYSTEM, &bus);
-                if (r < 0) {
-                        log_error("Failed to create bus connection: %s", strerror(-r));
-                        goto finish;
-                }
-        }
+        if (!avoid_bus())
+                r = bus_open_transport_systemd(arg_transport, arg_host, arg_scope != UNIT_FILE_SYSTEM, &bus);
+
+        /* systemctl_main() will print an error message for the bus
+         * connection, but only if it needs to */
 
         switch (arg_action) {