chiark / gitweb /
systemctl: make LOAD column width dynamic
[elogind.git] / src / systemctl / systemctl.c
index 04464deec825c3e2cec999e6938613862cdf8bce..b75f335ae9be30a7959a6f82a84220e4a4487099 100644 (file)
@@ -20,6 +20,8 @@
 ***/
 
 #include <sys/reboot.h>
+#include <linux/reboot.h>
+#include <sys/syscall.h>
 #include <stdio.h>
 #include <getopt.h>
 #include <locale.h>
 #include "fileio.h"
 
 static char **arg_types = NULL;
-static char **arg_load_states = NULL;
+static char **arg_states = NULL;
 static char **arg_properties = NULL;
 static bool arg_all = false;
+static bool original_stdout_is_tty;
 static enum dependency {
         DEPENDENCY_FORWARD,
         DEPENDENCY_REVERSE,
@@ -93,7 +96,6 @@ static bool arg_quiet = false;
 static bool arg_full = false;
 static int arg_force = 0;
 static bool arg_ask_password = true;
-static bool arg_failed = false;
 static bool arg_runtime = false;
 static char **arg_wall = NULL;
 static const char *arg_kill_who = NULL;
@@ -176,30 +178,6 @@ static void polkit_agent_open_if_enabled(void) {
 }
 #endif
 
-static const char *ansi_highlight(bool b) {
-
-        if (!on_tty())
-                return "";
-
-        return b ? ANSI_HIGHLIGHT_ON : ANSI_HIGHLIGHT_OFF;
-}
-
-static const char *ansi_highlight_red(bool b) {
-
-        if (!on_tty())
-                return "";
-
-        return b ? ANSI_HIGHLIGHT_RED_ON : ANSI_HIGHLIGHT_OFF;
-}
-
-static const char *ansi_highlight_green(bool b) {
-
-        if (!on_tty())
-                return "";
-
-        return b ? ANSI_HIGHLIGHT_GREEN_ON : ANSI_HIGHLIGHT_OFF;
-}
-
 static int translate_bus_error_to_exit_status(int r, const DBusError *error) {
         assert(error);
 
@@ -301,25 +279,26 @@ static int compare_unit_info(const void *a, const void *b) {
 static bool output_show_unit(const struct unit_info *u) {
         const char *dot;
 
-        if (arg_failed)
-                return streq(u->active_state, "failed");
+        if (!strv_isempty(arg_states))
+                return strv_contains(arg_states, u->load_state) || strv_contains(arg_states, u->sub_state) || strv_contains(arg_states, u->active_state);
 
         return (!arg_types || ((dot = strrchr(u->id, '.')) &&
                                strv_find(arg_types, dot+1))) &&
-                (!arg_load_states || strv_find(arg_load_states, u->load_state)) &&
                 (arg_all || !(streq(u->active_state, "inactive")
                               || u->following[0]) || u->job_id > 0);
 }
 
 static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
-        unsigned id_len, max_id_len, active_len, sub_len, job_len, desc_len, n_shown = 0;
+        unsigned id_len, max_id_len, load_len, active_len, sub_len, job_len, desc_len;
+        unsigned n_shown = 0;
         const struct unit_info *u;
         int job_count = 0;
 
-        max_id_len = sizeof("UNIT")-1;
-        active_len = sizeof("ACTIVE")-1;
-        sub_len = sizeof("SUB")-1;
-        job_len = sizeof("JOB")-1;
+        max_id_len = strlen("UNIT");
+        load_len = strlen("LOAD");
+        active_len = strlen("ACTIVE");
+        sub_len = strlen("SUB");
+        job_len = strlen("JOB");
         desc_len = 0;
 
         for (u = unit_infos; u < unit_infos + c; u++) {
@@ -327,6 +306,7 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
                         continue;
 
                 max_id_len = MAX(max_id_len, strlen(u->id));
+                load_len = MAX(load_len, strlen(u->load_state));
                 active_len = MAX(active_len, strlen(u->active_state));
                 sub_len = MAX(sub_len, strlen(u->sub_state));
                 if (u->job_id != 0) {
@@ -335,7 +315,7 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
                 }
         }
 
-        if (!arg_full) {
+        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;
@@ -369,7 +349,7 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
                         continue;
 
                 if (!n_shown && !arg_no_legend) {
-                        printf("%-*s %-6s %-*s %-*s ", id_len, "UNIT", "LOAD",
+                        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");
@@ -381,27 +361,28 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
 
                 n_shown++;
 
-                if (streq(u->load_state, "error")) {
-                        on_loaded = on = ansi_highlight_red(true);
-                        off_loaded = off = ansi_highlight_red(false);
+                if (streq(u->load_state, "error") ||
+                    streq(u->load_state, "not-found")) {
+                        on_loaded = on = ansi_highlight_red();
+                        off_loaded = off = ansi_highlight_off();
                 } else
                         on_loaded = off_loaded = "";
 
                 if (streq(u->active_state, "failed")) {
-                        on_active = on = ansi_highlight_red(true);
-                        off_active = off = ansi_highlight_red(false);
+                        on_active = on = ansi_highlight_red();
+                        off_active = off = ansi_highlight_off();
                 } else
                         on_active = off_active = "";
 
                 e = arg_full ? NULL : ellipsize(u->id, id_len, 33);
 
-                printf("%s%-*s%s %s%-6s%s %s%-*s %-*s%s %-*s",
+                printf("%s%-*s%s %s%-*s%s %s%-*s %-*s%s %-*s",
                        on, id_len, e ? e : u->id, off,
-                       on_loaded, u->load_state, off_loaded,
+                       on_loaded, load_len, u->load_state, off_loaded,
                        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 (!arg_full && arg_no_pager)
+                if (desc_len > 0)
                         printf("%.*s\n", desc_len, u->description);
                 else
                         printf("%s\n", u->description);
@@ -417,11 +398,11 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
                         if (job_count)
                                 printf("JOB    = Pending job for the unit.\n");
                         puts("");
-                        on = ansi_highlight(true);
-                        off = ansi_highlight(false);
+                        on = ansi_highlight();
+                        off = ansi_highlight_off();
                 } else {
-                        on = ansi_highlight_red(true);
-                        off = ansi_highlight_red(false);
+                        on = ansi_highlight_red();
+                        off = ansi_highlight_off();
                 }
 
                 if (arg_all)
@@ -495,7 +476,7 @@ static int list_units(DBusConnection *bus, char **args) {
         if (r < 0)
                 return r;
 
-        qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
+        qsort_safe(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
 
         output_units_list(unit_infos, c);
 
@@ -684,13 +665,13 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
                         printf("\n");
                 }
 
-                on = ansi_highlight(true);
-                off = ansi_highlight(false);
+                on = ansi_highlight();
+                off = ansi_highlight_off();
                 if (!arg_no_legend)
                         printf("\n");
         } else {
-                on = ansi_highlight_red(true);
-                off = ansi_highlight_red(false);
+                on = ansi_highlight_red();
+                off = ansi_highlight_off();
         }
 
         if (!arg_no_legend) {
@@ -757,8 +738,8 @@ static int list_sockets(DBusConnection *bus, char **args) {
                 listen = triggered = NULL; /* avoid cleanup */
         }
 
-        qsort(socket_infos, cs, sizeof(struct socket_info),
-              (__compar_fn_t) socket_info_compare);
+        qsort_safe(socket_infos, cs, sizeof(struct socket_info),
+                   (__compar_fn_t) socket_info_compare);
 
         output_sockets_list(socket_infos, cs);
 
@@ -772,7 +753,7 @@ static int list_sockets(DBusConnection *bus, char **args) {
         }
         free(socket_infos);
 
-        return 0;
+        return r;
 }
 
 static int compare_unit_file_list(const void *a, const void *b) {
@@ -839,11 +820,11 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) {
                     u->state == UNIT_FILE_MASKED_RUNTIME ||
                     u->state == UNIT_FILE_DISABLED ||
                     u->state == UNIT_FILE_INVALID) {
-                        on  = ansi_highlight_red(true);
-                        off = ansi_highlight_red(false);
+                        on  = ansi_highlight_red();
+                        off = ansi_highlight_off();
                 } else if (u->state == UNIT_FILE_ENABLED) {
-                        on  = ansi_highlight_green(true);
-                        off = ansi_highlight_green(false);
+                        on  = ansi_highlight_green();
+                        off = ansi_highlight_off();
                 } else
                         on = off = "";
 
@@ -1132,7 +1113,7 @@ static int list_dependencies_one(DBusConnection *bus, const char *name, int leve
         if (r < 0)
                 return r;
 
-        qsort(deps, strv_length(deps), sizeof (char*), list_dependencies_compare);
+        qsort_safe(deps, strv_length(deps), sizeof (char*), list_dependencies_compare);
 
         STRV_FOREACH(c, deps) {
                 if (strv_contains(u, *c)) {
@@ -1186,7 +1167,7 @@ static int list_dependencies(DBusConnection *bus, char **args) {
 
 static int get_default(DBusConnection *bus, char **args) {
         char *path = NULL;
-        _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
+        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
         int r;
         _cleanup_dbus_error_free_ DBusError error;
 
@@ -1251,8 +1232,8 @@ static void list_jobs_print(struct job_info* jobs, size_t n) {
         assert(n == 0 || jobs);
 
         if (n == 0) {
-                on = ansi_highlight_green(true);
-                off = ansi_highlight_green(false);
+                on = ansi_highlight_green();
+                off = ansi_highlight_off();
 
                 printf("%sNo jobs running.%s\n", on, off);
                 return;
@@ -1288,8 +1269,8 @@ static void list_jobs_print(struct job_info* jobs, size_t n) {
                         _cleanup_free_ char *e = NULL;
 
                         if (streq(j->state, "running")) {
-                                on = ansi_highlight(true);
-                                off = ansi_highlight(false);
+                                on = ansi_highlight();
+                                off = ansi_highlight_off();
                         } else
                                 on = off = "";
 
@@ -1302,8 +1283,8 @@ static void list_jobs_print(struct job_info* jobs, size_t n) {
                 }
         }
 
-        on = ansi_highlight(true);
-        off = ansi_highlight(false);
+        on = ansi_highlight();
+        off = ansi_highlight_off();
 
         if (on_tty())
                 printf("\n%s%zu jobs listed%s.\n", on, n, off);
@@ -1389,36 +1370,6 @@ static int list_jobs(DBusConnection *bus, char **args) {
         return 0;
 }
 
-static int load_unit(DBusConnection *bus, char **args) {
-        char **name;
-
-        assert(args);
-
-        STRV_FOREACH(name, args+1) {
-                _cleanup_free_ char *n = NULL;
-                int r;
-
-                n = unit_name_mangle(*name);
-                if (!n)
-                        return log_oom();
-
-                r = bus_method_call_with_reply(
-                                bus,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                "LoadUnit",
-                                NULL,
-                                NULL,
-                                DBUS_TYPE_STRING, &n,
-                                DBUS_TYPE_INVALID);
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
 static int cancel_job(DBusConnection *bus, char **args) {
         char **name;
 
@@ -1454,8 +1405,9 @@ static int cancel_job(DBusConnection *bus, char **args) {
         return 0;
 }
 
-static bool need_daemon_reload(DBusConnection *bus, const char *unit) {
+static int need_daemon_reload(DBusConnection *bus, const char *unit) {
         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
+        _cleanup_dbus_error_free_ DBusError error;
         dbus_bool_t b = FALSE;
         DBusMessageIter iter, sub;
         const char
@@ -1465,6 +1417,8 @@ static bool need_daemon_reload(DBusConnection *bus, const char *unit) {
         _cleanup_free_ char *n = NULL;
         int r;
 
+        dbus_error_init(&error);
+
         /* We ignore all errors here, since this is used to show a warning only */
 
         n = unit_name_mangle(unit);
@@ -1478,7 +1432,7 @@ static bool need_daemon_reload(DBusConnection *bus, const char *unit) {
                         "org.freedesktop.systemd1.Manager",
                         "GetUnit",
                         &reply,
-                        NULL,
+                        &error,
                         DBUS_TYPE_STRING, &n,
                         DBUS_TYPE_INVALID);
         if (r < 0)
@@ -1499,7 +1453,7 @@ static bool need_daemon_reload(DBusConnection *bus, const char *unit) {
                         "org.freedesktop.DBus.Properties",
                         "Get",
                         &reply,
-                        NULL,
+                        &error,
                         DBUS_TYPE_STRING, &interface,
                         DBUS_TYPE_STRING, &property,
                         DBUS_TYPE_INVALID);
@@ -1547,6 +1501,7 @@ static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *me
         } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
                 uint32_t id;
                 const char *path, *result, *unit;
+                char *r;
 
                 if (dbus_message_get_args(message, &error,
                                           DBUS_TYPE_UINT32, &id,
@@ -1555,7 +1510,11 @@ static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *me
                                           DBUS_TYPE_STRING, &result,
                                           DBUS_TYPE_INVALID)) {
 
-                        free(set_remove(d->set, (char*) path));
+                        r = set_remove(d->set, (char*) path);
+                        if (!r)
+                                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+                        free(r);
 
                         if (!isempty(result))
                                 d->result = strdup(result);
@@ -1575,7 +1534,11 @@ static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *me
                         /* Compatibility with older systemd versions <
                          * 183 during upgrades. This should be dropped
                          * one day. */
-                        free(set_remove(d->set, (char*) path));
+                        r = set_remove(d->set, (char*) path);
+                        if (!r)
+                                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+                        free(r);
 
                         if (*result)
                                 d->result = strdup(result);
@@ -1919,7 +1882,7 @@ static int start_unit_one(
                 return -EIO;
         }
 
-        if (need_daemon_reload(bus, n))
+        if (need_daemon_reload(bus, n) > 0)
                 log_warning("Warning: Unit file of %s changed on disk, 'systemctl %sdaemon-reload' recommended.",
                             n, arg_scope == UNIT_FILE_SYSTEM ? "" : "--user ");
 
@@ -2530,6 +2493,10 @@ typedef struct UnitStatusInfo {
 
         usec_t condition_timestamp;
         bool condition_result;
+        bool failed_condition_trigger;
+        bool failed_condition_negate;
+        const char *failed_condition;
+        const char *failed_condition_param;
 
         /* Socket */
         unsigned n_accepted;
@@ -2551,7 +2518,8 @@ typedef struct UnitStatusInfo {
         LIST_HEAD(ExecStatusInfo, exec);
 } UnitStatusInfo;
 
-static void print_status_info(UnitStatusInfo *i) {
+static void print_status_info(UnitStatusInfo *i,
+                              bool *ellipsized) {
         ExecStatusInfo *p;
         const char *on, *off, *ss;
         usec_t timestamp;
@@ -2582,8 +2550,8 @@ static void print_status_info(UnitStatusInfo *i) {
                 printf("   Follow: unit currently follows state of %s\n", i->following);
 
         if (streq_ptr(i->load_state, "error")) {
-                on = ansi_highlight_red(true);
-                off = ansi_highlight_red(false);
+                on = ansi_highlight_red();
+                off = ansi_highlight_off();
         } else
                 on = off = "";
 
@@ -2633,11 +2601,11 @@ 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, "failed")) {
-                on = ansi_highlight_red(true);
-                off = ansi_highlight_red(false);
+                on = ansi_highlight_red();
+                off = ansi_highlight_off();
         } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
-                on = ansi_highlight_green(true);
-                off = ansi_highlight_green(false);
+                on = ansi_highlight_green();
+                off = ansi_highlight_off();
         } else
                 on = off = "";
 
@@ -2672,10 +2640,15 @@ static void print_status_info(UnitStatusInfo *i) {
                 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
                 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
 
-                if (s1)
-                        printf("          start condition failed at %s; %s\n", s2, s1);
-                else if (s2)
-                        printf("          start condition failed at %s\n", s2);
+                printf("           start condition failed at %s%s%s\n",
+                       s2, s1 ? "; " : "", s1 ? s1 : "");
+                if (i->failed_condition_trigger)
+                        printf("           none of the trigger conditions were met\n");
+                else if (i->failed_condition)
+                        printf("           %s=%s%s was not met\n",
+                               i->failed_condition,
+                               i->failed_condition_negate ? "!" : "",
+                               i->failed_condition_param);
         }
 
         if (i->sysfs_path)
@@ -2707,8 +2680,8 @@ static void print_status_info(UnitStatusInfo *i) {
 
                 good = is_clean_exit_lsb(p->code, p->status, NULL);
                 if (!good) {
-                        on = ansi_highlight_red(true);
-                        off = ansi_highlight_red(false);
+                        on = ansi_highlight_red();
+                        off = ansi_highlight_off();
                 } else
                         on = off = "";
 
@@ -2785,7 +2758,7 @@ static void print_status_info(UnitStatusInfo *i) {
                 printf("   Status: \"%s\"\n", i->status_text);
 
         if (i->control_group &&
-            (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, i->control_group, false) == 0)) {
+            (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, i->control_group, false) == 0)) {
                 unsigned c;
 
                 printf("   CGroup: %s\n", i->control_group);
@@ -2822,13 +2795,14 @@ static void print_status_info(UnitStatusInfo *i) {
                                      arg_lines,
                                      getuid(),
                                      flags,
-                                     arg_scope == UNIT_FILE_SYSTEM);
+                                     arg_scope == UNIT_FILE_SYSTEM,
+                                     ellipsized);
         }
 
         if (i->need_daemon_reload)
                 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %sdaemon-reload' recommended.\n",
-                       ansi_highlight_red(true),
-                       ansi_highlight_red(false),
+                       ansi_highlight_red(),
+                       ansi_highlight_off(),
                        arg_scope == UNIT_FILE_SYSTEM ? "" : "--user ");
 }
 
@@ -3034,25 +3008,29 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn
                                 ExecStatusInfo *info;
                                 int r;
 
-                                if (!(info = new0(ExecStatusInfo, 1)))
+                                info = new0(ExecStatusInfo, 1);
+                                if (!info)
                                         return -ENOMEM;
 
-                                if (!(info->name = strdup(name))) {
+                                info->name = strdup(name);
+                                if (!info->name) {
                                         free(info);
                                         return -ENOMEM;
                                 }
 
-                                if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
+                                r = exec_status_info_deserialize(&sub, info);
+                                if (r < 0) {
                                         free(info);
                                         return r;
                                 }
 
-                                LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
+                                LIST_PREPEND(exec, i->exec, info);
 
                                 dbus_message_iter_next(&sub);
                         }
 
-                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Listen")) {
+                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
+                           streq(name, "Listen")) {
                         DBusMessageIter sub, sub2;
 
                         dbus_message_iter_recurse(iter, &sub);
@@ -3078,7 +3056,8 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn
 
                         return 0;
 
-                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING && streq(name, "DropInPaths")) {
+                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
+                           streq(name, "DropInPaths")) {
                         int r = bus_parse_strv_iter(iter, &i->dropin_paths);
                         if (r < 0)
                                 return r;
@@ -3101,6 +3080,36 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn
 
                                 dbus_message_iter_next(&sub);
                         }
+
+                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
+                           streq(name, "Conditions")) {
+                        DBusMessageIter sub, sub2;
+
+                        dbus_message_iter_recurse(iter, &sub);
+                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
+                                const char *cond, *param;
+                                dbus_bool_t trigger, negate;
+                                dbus_int32_t state;
+
+                                dbus_message_iter_recurse(&sub, &sub2);
+                                log_debug("here");
+
+                                if(bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &cond, true) >= 0 &&
+                                   bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &trigger, true) >= 0 &&
+                                   bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &negate, true) >= 0 &&
+                                   bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &param, true) >= 0 &&
+                                   bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &state, false) >= 0) {
+                                        log_debug("%s %d %d %s %d", cond, trigger, negate, param, state);
+                                        if (state < 0 && (!trigger || !i->failed_condition)) {
+                                                i->failed_condition = cond;
+                                                i->failed_condition_trigger = trigger;
+                                                i->failed_condition_negate = negate;
+                                                i->failed_condition_param = param;
+                                        }
+                                }
+
+                                dbus_message_iter_next(&sub);
+                        }
                 }
 
                 break;
@@ -3321,6 +3330,24 @@ static int print_property(const char *name, DBusMessageIter *iter) {
                         }
                         return 0;
 
+                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "BlockIODeviceWeight")) {
+                        DBusMessageIter sub, sub2;
+
+                        dbus_message_iter_recurse(iter, &sub);
+                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
+                                const char *path;
+                                uint64_t weight;
+
+                                dbus_message_iter_recurse(&sub, &sub2);
+
+                                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
+                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &weight, false) >= 0)
+                                        printf("%s=%s %" PRIu64 "\n", name, strna(path), weight);
+
+                                dbus_message_iter_next(&sub);
+                        }
+                        return 0;
+
                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth"))) {
                         DBusMessageIter sub, sub2;
 
@@ -3353,7 +3380,12 @@ static int print_property(const char *name, DBusMessageIter *iter) {
         return 0;
 }
 
-static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
+static int show_one(const char *verb,
+                    DBusConnection *bus,
+                    const char *path,
+                    bool show_properties,
+                    bool *new_line,
+                    bool *ellipsized) {
         _cleanup_free_ DBusMessage *reply = NULL;
         const char *interface = "";
         int r;
@@ -3423,7 +3455,7 @@ static int show_one(const char *verb, DBusConnection *bus, const char *path, boo
                 if (streq(verb, "help"))
                         show_unit_help(&info);
                 else
-                        print_status_info(&info);
+                        print_status_info(&info, ellipsized);
         }
 
         strv_free(info.documentation);
@@ -3447,14 +3479,18 @@ static int show_one(const char *verb, DBusConnection *bus, const char *path, boo
         }
 
         while ((p = info.exec)) {
-                LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
+                LIST_REMOVE(exec, info.exec, p);
                 exec_status_info_free(p);
         }
 
         return r;
 }
 
-static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, bool *new_line) {
+static int show_one_by_pid(const char *verb,
+                           DBusConnection *bus,
+                           uint32_t pid,
+                           bool *new_line,
+                           bool *ellipsized) {
         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
         const char *path = NULL;
         _cleanup_dbus_error_free_ DBusError error;
@@ -3482,11 +3518,15 @@ static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid,
                 return -EIO;
         }
 
-        r = show_one(verb, bus, path, false, new_line);
+        r = show_one(verb, bus, path, false, new_line, ellipsized);
         return r;
 }
 
-static int show_all(const char* verb, DBusConnection *bus, bool show_properties, bool *new_line) {
+static int show_all(const char* verb,
+                    DBusConnection *bus,
+                    bool show_properties,
+                    bool *new_line,
+                    bool *ellipsized) {
         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
         _cleanup_free_ struct unit_info *unit_infos = NULL;
         unsigned c = 0;
@@ -3497,7 +3537,7 @@ static int show_all(const char* verb, DBusConnection *bus, bool show_properties,
         if (r < 0)
                 return r;
 
-        qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
+        qsort_safe(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
 
         for (u = unit_infos; u < unit_infos + c; u++) {
                 _cleanup_free_ char *p = NULL;
@@ -3511,7 +3551,7 @@ static int show_all(const char* verb, DBusConnection *bus, bool show_properties,
 
                 printf("%s -> '%s'\n", u->id, p);
 
-                r = show_one(verb, bus, p, show_properties, new_line);
+                r = show_one(verb, bus, p, show_properties, new_line, ellipsized);
                 if (r != 0)
                         return r;
         }
@@ -3523,6 +3563,7 @@ static int show(DBusConnection *bus, char **args) {
         int r, ret = 0;
         bool show_properties, show_status, new_line = false;
         char **name;
+        bool ellipsized = false;
 
         assert(bus);
         assert(args);
@@ -3536,48 +3577,51 @@ static int show(DBusConnection *bus, char **args) {
         /* If no argument is specified inspect the manager itself */
 
         if (show_properties && strv_length(args) <= 1)
-                return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line);
+                return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized);
 
         if (show_status && strv_length(args) <= 1)
-                return show_all(args[0], bus, false, &new_line);
-
-        STRV_FOREACH(name, args+1) {
-                uint32_t id;
+                ret = show_all(args[0], bus, false, &new_line, &ellipsized);
+        else
+                STRV_FOREACH(name, args+1) {
+                        uint32_t id;
 
-                if (safe_atou32(*name, &id) < 0) {
-                        _cleanup_free_ char *p = NULL, *n = NULL;
-                        /* Interpret as unit name */
+                        if (safe_atou32(*name, &id) < 0) {
+                                _cleanup_free_ char *p = NULL, *n = NULL;
+                                /* Interpret as unit name */
 
-                        n = unit_name_mangle(*name);
-                        if (!n)
-                                return log_oom();
+                                n = unit_name_mangle(*name);
+                                if (!n)
+                                        return log_oom();
 
-                        p = unit_dbus_path_from_name(n);
-                        if (!p)
-                                return log_oom();
+                                p = unit_dbus_path_from_name(n);
+                                if (!p)
+                                        return log_oom();
 
-                        r = show_one(args[0], bus, p, show_properties, &new_line);
-                        if (r != 0)
-                                ret = r;
+                                r = show_one(args[0], bus, p, show_properties, &new_line, &ellipsized);
+                                if (r != 0)
+                                        ret = r;
 
-                } else if (show_properties) {
-                        _cleanup_free_ char *p = NULL;
+                        } else if (show_properties) {
+                                _cleanup_free_ char *p = NULL;
 
-                        /* Interpret as job id */
-                        if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0)
-                                return log_oom();
+                                /* Interpret as job id */
+                                if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0)
+                                        return log_oom();
 
-                        r = show_one(args[0], bus, p, show_properties, &new_line);
-                        if (r != 0)
-                                ret = r;
+                                r = show_one(args[0], bus, p, show_properties, &new_line, &ellipsized);
+                                if (r != 0)
+                                        ret = r;
 
-                } else {
-                        /* Interpret as PID */
-                        r = show_one_by_pid(args[0], bus, id, &new_line);
-                        if (r != 0)
-                                ret = r;
+                        } else {
+                                /* Interpret as PID */
+                                r = show_one_by_pid(args[0], bus, id, &new_line, &ellipsized);
+                                if (r != 0)
+                                        ret = r;
+                        }
                 }
-        }
+
+        if (ellipsized && !arg_quiet)
+                printf("Hint: Some lines were ellipsized, use -l to show in full.\n");
 
         return ret;
 }
@@ -3619,7 +3663,7 @@ static int append_assignment(DBusMessageIter *iter, const char *assignment) {
                     !dbus_message_iter_append_basic(&sub, DBUS_TYPE_BOOLEAN, &b))
                         return log_oom();
 
-        } else if (streq(field, "MemoryLimit") || streq(field, "MemorySoftLimit")) {
+        } else if (streq(field, "MemoryLimit")) {
                 off_t bytes;
                 uint64_t u;
 
@@ -3674,6 +3718,11 @@ static int append_assignment(DBusMessageIter *iter, const char *assignment) {
                                 rwm = "";
                         }
 
+                        if (!path_startswith(path, "/dev")) {
+                                log_error("%s is not a device file in /dev.", path);
+                                return -EINVAL;
+                        }
+
                         if (!dbus_message_iter_open_container(&sub2, DBUS_TYPE_STRUCT, NULL, &sub3) ||
                             !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &path) ||
                             !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &rwm) ||
@@ -3684,6 +3733,94 @@ static int append_assignment(DBusMessageIter *iter, const char *assignment) {
                 if (!dbus_message_iter_close_container(&sub, &sub2))
                         return log_oom();
 
+        } else if (streq(field, "BlockIOReadBandwidth") || streq(field, "BlockIOWriteBandwidth")) {
+                DBusMessageIter sub2;
+
+                if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a(st)", &sub) ||
+                    !dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "(st)", &sub2))
+                        return log_oom();
+
+                if (!isempty(eq)) {
+                        const char *path, *bandwidth;
+                        DBusMessageIter sub3;
+                        uint64_t u;
+                        off_t bytes;
+                        char *e;
+
+                        e = strchr(eq, ' ');
+                        if (e) {
+                                path = strndupa(eq, e - eq);
+                                bandwidth = e+1;
+                        } else {
+                                log_error("Failed to parse %s value %s.", field, eq);
+                                return -EINVAL;
+                        }
+
+                        if (!path_startswith(path, "/dev")) {
+                                log_error("%s is not a device file in /dev.", path);
+                                return -EINVAL;
+                        }
+
+                        r = parse_bytes(bandwidth, &bytes);
+                        if (r < 0) {
+                                log_error("Failed to parse byte value %s.", bandwidth);
+                                return -EINVAL;
+                        }
+
+                        u = (uint64_t) bytes;
+
+                        if (!dbus_message_iter_open_container(&sub2, DBUS_TYPE_STRUCT, NULL, &sub3) ||
+                            !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &path) ||
+                            !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_UINT64, &u) ||
+                            !dbus_message_iter_close_container(&sub2, &sub3))
+                                return log_oom();
+                }
+
+                if (!dbus_message_iter_close_container(&sub, &sub2))
+                        return log_oom();
+
+        } else if (streq(field, "BlockIODeviceWeight")) {
+                DBusMessageIter sub2;
+
+                if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a(st)", &sub) ||
+                    !dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "(st)", &sub2))
+                        return log_oom();
+
+                if (!isempty(eq)) {
+                        const char *path, *weight;
+                        DBusMessageIter sub3;
+                        uint64_t u;
+                        char *e;
+
+                        e = strchr(eq, ' ');
+                        if (e) {
+                                path = strndupa(eq, e - eq);
+                                weight = e+1;
+                        } else {
+                                log_error("Failed to parse %s value %s.", field, eq);
+                                return -EINVAL;
+                        }
+
+                        if (!path_startswith(path, "/dev")) {
+                                log_error("%s is not a device file in /dev.", path);
+                                return -EINVAL;
+                        }
+
+                        r = safe_atou64(weight, &u);
+                        if (r < 0) {
+                                log_error("Failed to parse %s value %s.", field, weight);
+                                return -EINVAL;
+                        }
+                        if (!dbus_message_iter_open_container(&sub2, DBUS_TYPE_STRUCT, NULL, &sub3) ||
+                            !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &path) ||
+                            !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_UINT64, &u) ||
+                            !dbus_message_iter_close_container(&sub2, &sub3))
+                                return log_oom();
+                }
+
+                if (!dbus_message_iter_close_container(&sub, &sub2))
+                        return log_oom();
+
         } else {
                 log_error("Unknown assignment %s.", assignment);
                 return -EINVAL;
@@ -3697,7 +3834,8 @@ static int append_assignment(DBusMessageIter *iter, const char *assignment) {
 
 static int set_property(DBusConnection *bus, char **args) {
 
-        _cleanup_free_ DBusMessage *m = NULL, *reply = NULL;
+        _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
+        _cleanup_free_ char *n = NULL;
         DBusMessageIter iter, sub;
         dbus_bool_t runtime;
         DBusError error;
@@ -3718,7 +3856,11 @@ static int set_property(DBusConnection *bus, char **args) {
 
         runtime = arg_runtime;
 
-        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &args[1]) ||
+        n = unit_name_mangle(args[1]);
+        if (!n)
+                return log_oom();
+
+        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n) ||
             !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &runtime) ||
             !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sv)", &sub))
                 return log_oom();
@@ -3751,40 +3893,6 @@ static int set_property(DBusConnection *bus, char **args) {
         return 0;
 }
 
-static int dump(DBusConnection *bus, char **args) {
-        _cleanup_free_ DBusMessage *reply = NULL;
-        DBusError error;
-        int r;
-        const char *text;
-
-        dbus_error_init(&error);
-
-        pager_open_if_enabled();
-
-        r = bus_method_call_with_reply(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "Dump",
-                        &reply,
-                        NULL,
-                        DBUS_TYPE_INVALID);
-        if (r < 0)
-                return r;
-
-        if (!dbus_message_get_args(reply, &error,
-                                   DBUS_TYPE_STRING, &text,
-                                   DBUS_TYPE_INVALID)) {
-                log_error("Failed to parse reply: %s", bus_error_message(&error));
-                dbus_error_free(&error);
-                return  -EIO;
-        }
-
-        fputs(text, stdout);
-        return 0;
-}
-
 static int snapshot(DBusConnection *bus, char **args) {
         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
         DBusError error;
@@ -3935,9 +4043,9 @@ static int daemon_reload(DBusConnection *bus, char **args) {
                 /* There's always a fallback possible for
                  * legacy actions. */
                 r = -EADDRNOTAVAIL;
-        else if (r == -ETIMEDOUT && streq(method, "Reexecute"))
-                /* On reexecution, we expect a disconnect, not
-                 * reply */
+        else if ((r == -ETIMEDOUT || r == -ECONNRESET) && streq(method, "Reexecute"))
+                /* On reexecution, we expect a disconnect, not a
+                 * reply */
                 r = 0;
         else if (r < 0)
                 log_error("Failed to issue method call: %s", bus_error_message(&error));
@@ -4115,13 +4223,12 @@ static int set_environment(DBusConnection *bus, char **args) {
         return 0;
 }
 
-static int enable_sysv_units(char **args) {
+static int enable_sysv_units(const char *verb, char **args) {
         int r = 0;
 
 #if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG)
-        const char *verb = args[0];
         unsigned f = 1, t = 1;
-        LookupPaths paths = {};
+        _cleanup_lookup_paths_free_ LookupPaths paths = {};
 
         if (arg_scope != UNIT_FILE_SYSTEM)
                 return 0;
@@ -4139,7 +4246,7 @@ static int enable_sysv_units(char **args) {
                 return r;
 
         r = 0;
-        for (f = 1; args[f]; f++) {
+        for (f = 0; args[f]; f++) {
                 const char *name;
                 _cleanup_free_ char *p = NULL, *q = NULL;
                 bool found_native = false, found_sysv;
@@ -4259,10 +4366,8 @@ static int enable_sysv_units(char **args) {
         }
 
 finish:
-        lookup_paths_free(&paths);
-
         /* Drop all SysV units */
-        for (f = 1, t = 1; args[f]; f++) {
+        for (f = 0, t = 0; args[f]; f++) {
 
                 if (isempty(args[f]))
                         continue;
@@ -4320,16 +4425,16 @@ static int enable_unit(DBusConnection *bus, char **args) {
 
         dbus_error_init(&error);
 
-        r = enable_sysv_units(args);
-        if (r < 0)
-                return r;
-
         if (!args[1])
                 return 0;
 
         r = mangle_names(args+1, &mangled_names);
         if (r < 0)
-                goto finish;
+                return r;
+
+        r = enable_sysv_units(verb, mangled_names);
+        if (r < 0)
+                return r;
 
         if (!bus || avoid_bus()) {
                 if (streq(verb, "enable")) {
@@ -4515,62 +4620,21 @@ finish:
         return r;
 }
 
-static int set_log_level(DBusConnection *bus, char **args) {
-        _cleanup_dbus_error_free_ DBusError error;
-        _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
-        DBusMessageIter iter, sub;
-        const char* property = "LogLevel";
-        const char* interface = "org.freedesktop.systemd1.Manager";
-        const char* value;
-
-        assert(bus);
-        assert(args);
-
-        value = args[1];
-        dbus_error_init(&error);
-
-        m = dbus_message_new_method_call("org.freedesktop.systemd1",
-                                         "/org/freedesktop/systemd1",
-                                         "org.freedesktop.DBus.Properties",
-                                         "Set");
-        if (!m)
-                return log_oom();
-
-        dbus_message_iter_init_append(m, &iter);
-
-        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
-            !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &property) ||
-            !dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, "s", &sub))
-                return log_oom();
-
-        if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &value)) {
-                dbus_message_iter_abandon_container(&iter, &sub);
-                return log_oom();
-        }
-
-        if (!dbus_message_iter_close_container(&iter, &sub))
-                return log_oom();
-
-        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
-        if (!reply) {
-                log_error("Failed to issue method call: %s", bus_error_message(&error));
-                return -EIO;
-        }
-
-        return 0;
-}
-
 static int unit_is_enabled(DBusConnection *bus, char **args) {
         _cleanup_dbus_error_free_ DBusError error;
         int r;
         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
         bool enabled;
         char **name;
-        char *n;
+        _cleanup_strv_free_ char **mangled_names = NULL;
 
         dbus_error_init(&error);
 
-        r = enable_sysv_units(args);
+        r = mangle_names(args+1, &mangled_names);
+        if (r < 0)
+                return r;
+
+        r = enable_sysv_units(args[0], mangled_names);
         if (r < 0)
                 return r;
 
@@ -4578,16 +4642,10 @@ static int unit_is_enabled(DBusConnection *bus, char **args) {
 
         if (!bus || avoid_bus()) {
 
-                STRV_FOREACH(name, args+1) {
+                STRV_FOREACH(name, mangled_names) {
                         UnitFileState state;
 
-                        n = unit_name_mangle(*name);
-                        if (!n)
-                                return log_oom();
-
-                        state = unit_file_get_state(arg_scope, arg_root, n);
-
-                        free(n);
+                        state = unit_file_get_state(arg_scope, arg_root, *name);
 
                         if (state < 0)
                                 return state;
@@ -4602,13 +4660,9 @@ static int unit_is_enabled(DBusConnection *bus, char **args) {
                 }
 
         } else {
-                STRV_FOREACH(name, args+1) {
+                STRV_FOREACH(name, mangled_names) {
                         const char *s;
 
-                        n = unit_name_mangle(*name);
-                        if (!n)
-                                return log_oom();
-
                         r = bus_method_call_with_reply (
                                         bus,
                                         "org.freedesktop.systemd1",
@@ -4617,11 +4671,9 @@ static int unit_is_enabled(DBusConnection *bus, char **args) {
                                         "GetUnitFileState",
                                         &reply,
                                         NULL,
-                                        DBUS_TYPE_STRING, &n,
+                                        DBUS_TYPE_STRING, name,
                                         DBUS_TYPE_INVALID);
 
-                        free(n);
-
                         if (r)
                                 return r;
 
@@ -4657,19 +4709,20 @@ static int systemctl_help(void) {
                "  -h --help           Show this help\n"
                "     --version        Show package version\n"
                "  -t --type=TYPE      List only units of a particular type\n"
+               "     --state=STATE    List only units with particular LOAD or SUB or ACTIVE state\n"
                "  -p --property=NAME  Show only properties by this name\n"
                "  -a --all            Show all loaded units/properties, including dead/empty\n"
                "                      ones. To list all units installed on the system, use\n"
                "                      the 'list-unit-files' command instead.\n"
                "     --reverse        Show reverse dependencies with 'list-dependencies'\n"
-               "     --failed         Show only failed units\n"
                "  -l --full           Don't ellipsize unit names on output\n"
                "     --fail           When queueing a new job, fail if conflicting jobs are\n"
                "                      pending\n"
-               "     --irreversible   Create jobs which cannot be implicitly cancelled\n"
-               "     --show-types     When showing sockets, explicitly show their type\n"
+               "     --irreversible   When queueing a new job, make sure it cannot be implicitly\n"
+               "                      cancelled\n"
                "     --ignore-dependencies\n"
                "                      When queueing a new job, ignore all its dependencies\n"
+               "     --show-types     When showing sockets, explicitly show their type\n"
                "  -i --ignore-inhibitors\n"
                "                      When shutting down or sleeping, ignore inhibitors\n"
                "     --kill-who=WHO   Who to send signal to\n"
@@ -4689,11 +4742,11 @@ static int systemctl_help(void) {
                "     --system         Connect to system manager\n"
                "     --user           Connect to user service manager\n"
                "     --global         Enable/disable unit files globally\n"
+               "     --runtime        Enable unit files only temporarily until next reboot\n"
                "  -f --force          When enabling unit files, override existing symlinks\n"
                "                      When shutting down, execute action immediately\n"
                "     --root=PATH      Enable unit files in the specified root directory\n"
-               "     --runtime        Enable unit files only temporarily until next reboot\n"
-               "  -n --lines=INTEGER  Journal entries to show\n"
+               "  -n --lines=INTEGER  Number of journal entries to show\n"
                "  -o --output=STRING  Change journal output mode (short, short-monotonic,\n"
                "                      verbose, export, json, json-pretty, json-sse, cat)\n\n"
                "Unit Commands:\n"
@@ -4720,7 +4773,6 @@ static int systemctl_help(void) {
                "  help [NAME...|PID...]           Show manual for one or more units\n"
                "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
                "                                  units\n"
-               "  load [NAME...]                  Load one or more units\n"
                "  list-dependencies [NAME]        Recursively show units which are required\n"
                "                                  or wanted by this unit or by which this\n"
                "                                  unit is required or wanted\n\n"
@@ -4731,26 +4783,23 @@ static int systemctl_help(void) {
                "  reenable [NAME...]              Reenable one or more unit files\n"
                "  preset [NAME...]                Enable/disable one or more unit files\n"
                "                                  based on preset configuration\n"
+               "  is-enabled [NAME...]            Check whether unit files are enabled\n\n"
                "  mask [NAME...]                  Mask one or more units\n"
                "  unmask [NAME...]                Unmask one or more units\n"
                "  link [PATH...]                  Link one or more units files into\n"
                "                                  the search path\n"
                "  get-default                     Get the name of the default target\n"
-               "  set-default NAME                Set the default target\n"
-               "  is-enabled [NAME...]            Check whether unit files are enabled\n\n"
+               "  set-default NAME                Set the default target\n\n"
                "Job Commands:\n"
                "  list-jobs                       List jobs\n"
                "  cancel [JOB...]                 Cancel all, one, or more jobs\n\n"
-               "Status Commands:\n"
-               "  dump                            Dump server status\n"
                "Snapshot Commands:\n"
                "  snapshot [NAME]                 Create a snapshot\n"
                "  delete [NAME...]                Remove one or more snapshots\n\n"
                "Environment Commands:\n"
                "  show-environment                Dump environment\n"
                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
-               "  unset-environment [NAME...]     Unset one or more environment variables\n"
-               "  set-log-level LEVEL             Set logging threshold for systemd\n\n"
+               "  unset-environment [NAME...]     Unset one or more environment variables\n\n"
                "Manager Lifecycle Commands:\n"
                "  daemon-reload                   Reload systemd manager configuration\n"
                "  daemon-reexec                   Reexecute systemd manager\n\n"
@@ -4760,7 +4809,7 @@ static int systemctl_help(void) {
                "  emergency                       Enter system emergency mode\n"
                "  halt                            Shut down and halt the system\n"
                "  poweroff                        Shut down and power-off the system\n"
-               "  reboot                          Shut down and reboot the system\n"
+               "  reboot [ARG]                    Shut down and reboot the system\n"
                "  kexec                           Shut down and reboot the system with kexec\n"
                "  exit                            Request user instance exit\n"
                "  switch-root [ROOT] [INIT]       Change to a different root file system\n"
@@ -4774,7 +4823,7 @@ static int systemctl_help(void) {
 
 static int halt_help(void) {
 
-        printf("%s [OPTIONS...]\n\n"
+        printf("%s [OPTIONS...]%s\n\n"
                "%s the system.\n\n"
                "     --help      Show this help\n"
                "     --halt      Halt the machine\n"
@@ -4785,6 +4834,7 @@ static int halt_help(void) {
                "  -d --no-wtmp   Don't write wtmp record\n"
                "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
                program_invocation_short_name,
+               arg_action == ACTION_REBOOT   ? " [ARG]" : "",
                arg_action == ACTION_REBOOT   ? "Reboot" :
                arg_action == ACTION_POWEROFF ? "Power off" :
                                                "Halt");
@@ -4848,13 +4898,6 @@ static int help_types(void) {
                         puts(t);
         }
 
-        puts("\nAvailable unit load states: ");
-        for(i = 0; i < _UNIT_LOAD_STATE_MAX; i++) {
-                t = unit_load_state_to_string(i);
-                if (t)
-                        puts(t);
-        }
-
         return 0;
 }
 
@@ -4883,46 +4926,48 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 ARG_FAILED,
                 ARG_RUNTIME,
                 ARG_FORCE,
-                ARG_PLAIN
+                ARG_PLAIN,
+                ARG_STATE
         };
 
         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'           },
-                { "reverse",   no_argument,       NULL, ARG_REVERSE   },
-                { "after",     no_argument,       NULL, ARG_AFTER     },
-                { "before",    no_argument,       NULL, ARG_BEFORE    },
-                { "show-types", no_argument,      NULL, ARG_SHOW_TYPES },
-                { "failed",    no_argument,       NULL, ARG_FAILED    },
-                { "full",      no_argument,       NULL, 'l'           },
-                { "fail",      no_argument,       NULL, ARG_FAIL      },
-                { "irreversible", no_argument,    NULL, ARG_IRREVERSIBLE },
-                { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
-                { "ignore-inhibitors", no_argument, NULL, 'i'         },
-                { "user",      no_argument,       NULL, ARG_USER      },
-                { "system",    no_argument,       NULL, ARG_SYSTEM    },
-                { "global",    no_argument,       NULL, ARG_GLOBAL    },
-                { "no-block",  no_argument,       NULL, ARG_NO_BLOCK  },
-                { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
-                { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
-                { "no-wall",   no_argument,       NULL, ARG_NO_WALL   },
-                { "quiet",     no_argument,       NULL, 'q'           },
-                { "root",      required_argument, NULL, ARG_ROOT      },
-                { "force",     no_argument,       NULL, ARG_FORCE     },
-                { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
-                { "kill-who",  required_argument, NULL, ARG_KILL_WHO  },
-                { "signal",    required_argument, NULL, 's'           },
-                { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
-                { "host",      required_argument, NULL, 'H'           },
-                { "privileged",no_argument,       NULL, 'P'           },
-                { "runtime",   no_argument,       NULL, ARG_RUNTIME   },
-                { "lines",     required_argument, NULL, 'n'           },
-                { "output",    required_argument, NULL, 'o'           },
-                { "plain",     no_argument,       NULL, ARG_PLAIN     },
-                { NULL,        0,                 NULL, 0             }
+                { "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'                     },
+                { "reverse",             no_argument,       NULL, ARG_REVERSE             },
+                { "after",               no_argument,       NULL, ARG_AFTER               },
+                { "before",              no_argument,       NULL, ARG_BEFORE              },
+                { "show-types",          no_argument,       NULL, ARG_SHOW_TYPES          },
+                { "failed",              no_argument,       NULL, ARG_FAILED              }, /* compatibility only */
+                { "full",                no_argument,       NULL, 'l'                     },
+                { "fail",                no_argument,       NULL, ARG_FAIL                },
+                { "irreversible",        no_argument,       NULL, ARG_IRREVERSIBLE        },
+                { "ignore-dependencies", no_argument,       NULL, ARG_IGNORE_DEPENDENCIES },
+                { "ignore-inhibitors",   no_argument,       NULL, 'i'                     },
+                { "user",                no_argument,       NULL, ARG_USER                },
+                { "system",              no_argument,       NULL, ARG_SYSTEM              },
+                { "global",              no_argument,       NULL, ARG_GLOBAL              },
+                { "no-block",            no_argument,       NULL, ARG_NO_BLOCK            },
+                { "no-legend",           no_argument,       NULL, ARG_NO_LEGEND           },
+                { "no-pager",            no_argument,       NULL, ARG_NO_PAGER            },
+                { "no-wall",             no_argument,       NULL, ARG_NO_WALL             },
+                { "quiet",               no_argument,       NULL, 'q'                     },
+                { "root",                required_argument, NULL, ARG_ROOT                },
+                { "force",               no_argument,       NULL, ARG_FORCE               },
+                { "no-reload",           no_argument,       NULL, ARG_NO_RELOAD           },
+                { "kill-who",            required_argument, NULL, ARG_KILL_WHO            },
+                { "signal",              required_argument, NULL, 's'                     },
+                { "no-ask-password",     no_argument,       NULL, ARG_NO_ASK_PASSWORD     },
+                { "host",                required_argument, NULL, 'H'                     },
+                { "privileged",          no_argument,       NULL, 'P'                     },
+                { "runtime",             no_argument,       NULL, ARG_RUNTIME             },
+                { "lines",               required_argument, NULL, 'n'                     },
+                { "output",              required_argument, NULL, 'o'                     },
+                { "plain",               no_argument,       NULL, ARG_PLAIN               },
+                { "state",               required_argument, NULL, ARG_STATE               },
+                {}
         };
 
         int c;
@@ -4935,8 +4980,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 switch (c) {
 
                 case 'h':
-                        systemctl_help();
-                        return 0;
+                        return systemctl_help();
 
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
@@ -4966,8 +5010,12 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                                         continue;
                                 }
 
+                                /* It's much nicer to use --state= for
+                                 * load states, but let's support this
+                                 * in --types= too for compatibility
+                                 * with old versions */
                                 if (unit_load_state_from_string(optarg) >= 0) {
-                                        if (strv_push(&arg_load_states, type))
+                                        if (strv_push(&arg_states, type) < 0)
                                                 return log_oom();
                                         type = NULL;
                                         continue;
@@ -4999,7 +5047,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                                         if (!prop)
                                                 return log_oom();
 
-                                        if (strv_push(&arg_properties, prop)) {
+                                        if (strv_push(&arg_properties, prop) < 0) {
                                                 free(prop);
                                                 return log_oom();
                                         }
@@ -5083,7 +5131,9 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_FAILED:
-                        arg_failed = true;
+                        if (strv_extend(&arg_states, "failed") < 0)
+                                return log_oom();
+
                         break;
 
                 case 'q':
@@ -5153,12 +5203,30 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         arg_plain = true;
                         break;
 
+                case ARG_STATE: {
+                        char *word, *state;
+                        size_t size;
+
+                        FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
+                                char *s;
+
+                                s = strndup(word, size);
+                                if (!s)
+                                        return log_oom();
+
+                                if (strv_push(&arg_states, s) < 0) {
+                                        free(s);
+                                        return log_oom();
+                                }
+                        }
+                        break;
+                }
+
                 case '?':
                         return -EINVAL;
 
                 default:
-                        log_error("Unknown option code '%c'.", c);
-                        return -EINVAL;
+                        assert_not_reached("Unhandled option");
                 }
         }
 
@@ -5188,10 +5256,10 @@ static int halt_parse_argv(int argc, char *argv[]) {
                 { "wtmp-only", no_argument,       NULL, 'w'         },
                 { "no-wtmp",   no_argument,       NULL, 'd'         },
                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
-                { NULL,        0,                 NULL, 0           }
+                {}
         };
 
-        int c, runlevel;
+        int c, r, runlevel;
 
         assert(argc >= 0);
         assert(argv);
@@ -5204,8 +5272,7 @@ static int halt_parse_argv(int argc, char *argv[]) {
                 switch (c) {
 
                 case ARG_HELP:
-                        halt_help();
-                        return 0;
+                        return halt_help();
 
                 case ARG_HALT:
                         arg_action = ACTION_HALT;
@@ -5246,12 +5313,18 @@ static int halt_parse_argv(int argc, char *argv[]) {
                         return -EINVAL;
 
                 default:
-                        log_error("Unknown option code '%c'.", c);
-                        return -EINVAL;
+                        assert_not_reached("Unhandled option");
                 }
         }
 
-        if (optind < argc) {
+        if (arg_action == ACTION_REBOOT && argc == optind + 1) {
+                r = write_string_file(REBOOT_PARAM_FILE, argv[optind]);
+                if (r < 0) {
+                        log_error("Failed to write reboot param to "
+                                  REBOOT_PARAM_FILE": %s", strerror(-r));
+                        return r;
+                }
+        } else if (optind < argc) {
                 log_error("Too many arguments.");
                 return -EINVAL;
         }
@@ -5322,7 +5395,7 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
                 { "reboot",    no_argument,       NULL, 'r'         },
                 { "kexec",     no_argument,       NULL, 'K'         }, /* not documented extension */
                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
-                { NULL,        0,                 NULL, 0           }
+                {}
         };
 
         int c, r;
@@ -5334,8 +5407,7 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
                 switch (c) {
 
                 case ARG_HELP:
-                        shutdown_help();
-                        return 0;
+                        return shutdown_help();
 
                 case 'H':
                         arg_action = ACTION_HALT;
@@ -5382,8 +5454,7 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
                         return -EINVAL;
 
                 default:
-                        log_error("Unknown option code '%c'.", c);
-                        return -EINVAL;
+                        assert_not_reached("Unhandled option");
                 }
         }
 
@@ -5418,7 +5489,7 @@ static int telinit_parse_argv(int argc, char *argv[]) {
         static const struct option options[] = {
                 { "help",      no_argument,       NULL, ARG_HELP    },
                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
-                { NULL,        0,                 NULL, 0           }
+                {}
         };
 
         static const struct {
@@ -5450,8 +5521,7 @@ static int telinit_parse_argv(int argc, char *argv[]) {
                 switch (c) {
 
                 case ARG_HELP:
-                        telinit_help();
-                        return 0;
+                        return telinit_help();
 
                 case ARG_NO_WALL:
                         arg_no_wall = true;
@@ -5461,8 +5531,7 @@ static int telinit_parse_argv(int argc, char *argv[]) {
                         return -EINVAL;
 
                 default:
-                        log_error("Unknown option code '%c'.", c);
-                        return -EINVAL;
+                        assert_not_reached("Unhandled option");
                 }
         }
 
@@ -5505,7 +5574,7 @@ static int runlevel_parse_argv(int argc, char *argv[]) {
 
         static const struct option options[] = {
                 { "help",      no_argument,       NULL, ARG_HELP    },
-                { NULL,        0,                 NULL, 0           }
+                {}
         };
 
         int c;
@@ -5517,15 +5586,14 @@ static int runlevel_parse_argv(int argc, char *argv[]) {
                 switch (c) {
 
                 case ARG_HELP:
-                        runlevel_help();
+                        return runlevel_help();
                         return 0;
 
                 case '?':
                         return -EINVAL;
 
                 default:
-                        log_error("Unknown option code '%c'.", c);
-                        return -EINVAL;
+                        assert_not_reached("Unhandled option");
                 }
         }
 
@@ -5603,94 +5671,6 @@ _pure_ static int action_to_runlevel(void) {
         return table[arg_action];
 }
 
-static int talk_upstart(void) {
-        _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
-        _cleanup_dbus_error_free_ DBusError error;
-        int previous, rl, r;
-        char
-                env1_buf[] = "RUNLEVEL=X",
-                env2_buf[] = "PREVLEVEL=X";
-        char *env1 = env1_buf, *env2 = env2_buf;
-        const char *emit = "runlevel";
-        dbus_bool_t b_false = FALSE;
-        DBusMessageIter iter, sub;
-        DBusConnection *bus;
-
-        dbus_error_init(&error);
-
-        if (!(rl = action_to_runlevel()))
-                return 0;
-
-        if (utmp_get_runlevel(&previous, NULL) < 0)
-                previous = 'N';
-
-        if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
-                if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
-                        r = 0;
-                        goto finish;
-                }
-
-                log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error));
-                r = -EIO;
-                goto finish;
-        }
-
-        if ((r = bus_check_peercred(bus)) < 0) {
-                log_error("Failed to verify owner of bus.");
-                goto finish;
-        }
-
-        if (!(m = dbus_message_new_method_call(
-                              "com.ubuntu.Upstart",
-                              "/com/ubuntu/Upstart",
-                              "com.ubuntu.Upstart0_6",
-                              "EmitEvent"))) {
-
-                log_error("Could not allocate message.");
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        dbus_message_iter_init_append(m, &iter);
-
-        env1_buf[sizeof(env1_buf)-2] = rl;
-        env2_buf[sizeof(env2_buf)-2] = previous;
-
-        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
-            !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
-            !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
-            !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
-            !dbus_message_iter_close_container(&iter, &sub) ||
-            !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
-                log_error("Could not append arguments to message.");
-                r = -ENOMEM;
-                goto finish;
-        }
-
-        if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-
-                if (bus_error_is_no_service(&error)) {
-                        r = -EADDRNOTAVAIL;
-                        goto finish;
-                }
-
-                log_error("Failed to issue method call: %s", bus_error_message(&error));
-                r = -EIO;
-                goto finish;
-        }
-
-        r = 1;
-
-finish:
-        if (bus) {
-                dbus_connection_flush(bus);
-                dbus_connection_close(bus);
-                dbus_connection_unref(bus);
-        }
-
-        return r;
-}
-
 static int talk_initctl(void) {
         struct init_request request = {};
         int r;
@@ -5742,7 +5722,6 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
                 { "list-sockets",          LESS,  1, list_sockets      },
                 { "list-jobs",             EQUAL, 1, list_jobs         },
                 { "clear-jobs",            EQUAL, 1, daemon_reload     },
-                { "load",                  MORE,  2, load_unit         },
                 { "cancel",                MORE,  2, cancel_job        },
                 { "start",                 MORE,  2, start_unit        },
                 { "stop",                  MORE,  2, start_unit        },
@@ -5763,7 +5742,6 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
                 { "show",                  MORE,  1, show              },
                 { "status",                MORE,  1, show              },
                 { "help",                  MORE,  2, show              },
-                { "dump",                  EQUAL, 1, dump              },
                 { "snapshot",              LESS,  2, snapshot          },
                 { "delete",                MORE,  2, delete_snapshot   },
                 { "daemon-reload",         EQUAL, 1, daemon_reload     },
@@ -5795,7 +5773,6 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
                 { "list-dependencies",     LESS,  2, list_dependencies },
                 { "set-default",           EQUAL, 2, enable_unit       },
                 { "get-default",           LESS,  1, get_default       },
-                { "set-log-level",         EQUAL, 2, set_log_level     },
                 { "set-property",          MORE,  3, set_property      },
         };
 
@@ -5965,11 +5942,6 @@ static int start_with_fallback(DBusConnection *bus) {
                         goto done;
         }
 
-        /* Hmm, talking to systemd via D-Bus didn't work. Then
-         * let's try to talk to Upstart via D-Bus. */
-        if (talk_upstart() > 0)
-                goto done;
-
         /* Nothing else worked, so let's try
          * /dev/initctl */
         if (talk_initctl() > 0)
@@ -5985,6 +5957,8 @@ done:
 
 static _noreturn_ void halt_now(enum action a) {
 
+        _cleanup_free_ char *param = NULL;
+
        /* Make sure C-A-D is handled by the kernel from this
          * point on... */
         reboot(RB_ENABLE_CAD);
@@ -6002,8 +5976,14 @@ static _noreturn_ void halt_now(enum action a) {
                 break;
 
         case ACTION_REBOOT:
-                log_info("Rebooting.");
-                reboot(RB_AUTOBOOT);
+                if (read_one_line_file(REBOOT_PARAM_FILE, &param) == 0) {
+                        log_info("Rebooting with arg '%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:
@@ -6111,6 +6091,11 @@ int main(int argc, char*argv[]) {
         log_parse_environment();
         log_open();
 
+        /* Explicitly not on_tty() to avoid setting cached value.
+         * This becomes relevant for piping output which might be
+         * ellipsized. */
+        original_stdout_is_tty = isatty(STDOUT_FILENO);
+
         r = parse_argv(argc, argv);
         if (r < 0)
                 goto finish;
@@ -6209,7 +6194,7 @@ finish:
         dbus_shutdown();
 
         strv_free(arg_types);
-        strv_free(arg_load_states);
+        strv_free(arg_states);
         strv_free(arg_properties);
 
         pager_close();