chiark / gitweb /
systemctl: ellipsize job list only when necessary, highlight running
[elogind.git] / src / systemctl / systemctl.c
index 72e9c5539b13d53b75719f954f17ee1c2d9cef14..af7ecd7af15d8e89f7e8e375c7b2ec58afa47a0c 100644 (file)
@@ -136,7 +136,7 @@ static void pager_open_if_enabled(void) {
         if (arg_no_pager)
                 return;
 
-        pager_open();
+        pager_open(false);
 }
 
 static void ask_password_agent_open_if_enabled(void) {
@@ -328,7 +328,7 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
 
         if (!arg_full) {
                 unsigned basic_len;
-                id_len = MIN(max_id_len, 25);
+                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;
@@ -337,7 +337,7 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
                         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, 25);
+                        incr = MIN(extra_len, 25u);
                         desc_len += incr;
                         extra_len -= incr;
                         /* split the remaining space between UNIT and DESC,
@@ -463,7 +463,7 @@ static int get_unit_list(DBusConnection *bus, DBusMessage **reply,
                 if (*c >= n_units) {
                         struct unit_info *w;
 
-                        n_units = MAX(2 * *c, 16);
+                        n_units = MAX(2 * *c, 16u);
                         w = realloc(*unit_infos, sizeof(struct unit_info) * n_units);
                         if (!w)
                                 return log_oom();
@@ -543,7 +543,7 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) {
 
         if (!arg_full) {
                 unsigned basic_cols;
-                id_cols = MIN(max_id_len, 25);
+                id_cols = MIN(max_id_len, 25u);
                 basic_cols = 1 + id_cols + state_cols;
                 if (basic_cols < (unsigned) columns())
                         id_cols += MIN(columns() - basic_cols, max_id_len - id_cols);
@@ -657,7 +657,7 @@ static int list_unit_files(DBusConnection *bus, char **args) {
                         if (c >= n_units) {
                                 UnitFileList *w;
 
-                                n_units = MAX(2*c, 16);
+                                n_units = MAX(2*c, 16u);
                                 w = realloc(units, sizeof(struct UnitFileList) * n_units);
                                 if (!w)
                                         return log_oom();
@@ -694,7 +694,7 @@ static int list_dependencies_print(const char *name, int level, unsigned int bra
         int i;
         _cleanup_free_ char *n = NULL;
         size_t len = 0;
-        size_t max_len = MAX(columns(),20);
+        size_t max_len = MAX(columns(),20u);
 
         for (i = level - 1; i >= 0; i--) {
                 len += 2;
@@ -895,13 +895,84 @@ static int list_dependencies(DBusConnection *bus, char **args) {
         return list_dependencies_one(bus, u, 0, NULL, 0);
 }
 
+struct job_info {
+        uint32_t id;
+        char *name, *type, *state;
+};
+
+static void list_jobs_print(struct job_info* jobs, size_t n) {
+        size_t i;
+        struct job_info *j;
+        const char *on, *off;
+        bool shorten = false;
+
+        assert(n == 0 || jobs);
+
+        if (n == 0) {
+                on = ansi_highlight_green(true);
+                off = ansi_highlight_green(false);
+
+                printf("%sNo jobs running.%s\n", on, off);
+                return;
+        }
+
+        pager_open_if_enabled();
+
+        {
+                /* JOB UNIT TYPE STATE */
+                unsigned l0 = 3, l1 = 4, l2 = 4, l3 = 5;
+
+                for (i = 0, j = jobs; i < n; i++, j++) {
+                        assert(j->name && j->type && j->state);
+                        l0 = MAX(l0, decimal_str_max(j->id));
+                        l1 = MAX(l1, strlen(j->name));
+                        l2 = MAX(l2, strlen(j->type));
+                        l3 = MAX(l3, strlen(j->state));
+                }
+
+                if (!arg_full && l0 + 1 + l1 + l2 + 1 + l3 > columns()) {
+                        l1 = MAX(33u, columns() - l0 - l2 - l3 - 3);
+                        shorten = true;
+                }
+
+                if (on_tty())
+                        printf("%*s %-*s %-*s %-*s\n",
+                               l0, "JOB",
+                               l1, "UNIT",
+                               l2, "TYPE",
+                               l3, "STATE");
+
+                for (i = 0, j = jobs; i < n; i++, j++) {
+                        char _cleanup_free_ *e = NULL;
+
+                        if (streq(j->state, "running")) {
+                                on = ansi_highlight(true);
+                                off = ansi_highlight(false);
+                        } else
+                                on = off = "";
+
+                        e = shorten ? ellipsize(j->name, l1, 33) : NULL;
+                        printf("%*u %s%-*s%s %-*s %s%-*s%s\n",
+                               l0, j->id,
+                               on, l1, e ? e : j->name, off,
+                               l2, j->type,
+                               on, l3, j->state, off);
+                }
+        }
+
+        on = ansi_highlight(true);
+        off = ansi_highlight(false);
+
+        if (on_tty())
+                printf("\n%s%zu jobs listed%s.\n", on, n, off);
+}
+
 static int list_jobs(DBusConnection *bus, char **args) {
         _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
         DBusMessageIter iter, sub, sub2;
-        unsigned k = 0;
         int r;
-
-        pager_open_if_enabled();
+        struct job_info *jobs = NULL;
+        size_t size = 0, used = 0;
 
         r = bus_method_call_with_reply(
                         bus,
@@ -924,13 +995,9 @@ static int list_jobs(DBusConnection *bus, char **args) {
 
         dbus_message_iter_recurse(&iter, &sub);
 
-        if (on_tty())
-                printf("%4s %-25s %-15s %-7s\n", "JOB", "UNIT", "TYPE", "STATE");
-
         while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
                 const char *name, *type, *state, *job_path, *unit_path;
                 uint32_t id;
-                char _cleanup_free_ *e = NULL;
 
                 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
                         log_error("Failed to parse reply.");
@@ -946,19 +1013,37 @@ static int list_jobs(DBusConnection *bus, char **args) {
                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 ||
                     bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) {
                         log_error("Failed to parse reply.");
-                        return -EIO;
+                        r = -EIO;
+                        goto finish;
                 }
 
-                e = arg_full ? NULL : ellipsize(name, 25, 33);
-                printf("%4u %-25s %-15s %-7s\n", id, e ? e : name, type, state);
+                if (!greedy_realloc((void**) &jobs, &size,
+                                    sizeof(struct job_info) * (used + 1))) {
+                        r = log_oom();
+                        goto finish;
+                }
 
-                k++;
+                jobs[used++] = (struct job_info) { id,
+                                                   strdup(name),
+                                                   strdup(type),
+                                                   strdup(state) };
+                if (!jobs[used-1].name || !jobs[used-1].type || !jobs[used-1].state) {
+                        r = log_oom();
+                        goto finish;
+                }
 
                 dbus_message_iter_next(&sub);
         }
 
-        if (on_tty())
-                printf("\n%u jobs listed.\n", k);
+        list_jobs_print(jobs, used);
+
+ finish:
+        while (used--) {
+                free(jobs[used].name);
+                free(jobs[used].type);
+                free(jobs[used].state);
+        }
+        free(jobs);
 
         return 0;
 }
@@ -1193,14 +1278,11 @@ static int enable_wait_for_jobs(DBusConnection *bus) {
 
 static int wait_for_jobs(DBusConnection *bus, Set *s) {
         int r = 0;
-        WaitData d;
+        WaitData d = { .set = s };
 
         assert(bus);
         assert(s);
 
-        zero(d);
-        d.set = s;
-
         if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL))
                 return log_oom();
 
@@ -2053,7 +2135,7 @@ static int set_cgroup_attr(DBusConnection *bus, char **args) {
 }
 
 static int get_cgroup_attr(DBusConnection *bus, char **args) {
-        _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
+        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
         _cleanup_free_ char *n = NULL;
         char **argument;
         int r;
@@ -2225,6 +2307,8 @@ typedef struct UnitStatusInfo {
         const char *source_path;
         const char *default_control_group;
 
+        char **dropin_paths;
+
         const char *load_error;
         const char *result;
 
@@ -2255,6 +2339,9 @@ typedef struct UnitStatusInfo {
         unsigned n_connections;
         bool accept;
 
+        /* Pairs of type, path */
+        char **listen;
+
         /* Device */
         const char *sysfs_path;
 
@@ -2280,9 +2367,20 @@ static void print_status_info(UnitStatusInfo *i) {
                 on_tty() * OUTPUT_COLOR |
                 !arg_quiet * OUTPUT_WARN_CUTOFF |
                 arg_full * OUTPUT_FULL_WIDTH;
+        int maxlen = 8; /* a value that'll suffice most of the time */
+        char **t, **t2;
 
         assert(i);
 
+        STRV_FOREACH_PAIR(t, t2, i->listen)
+                maxlen = MAX(maxlen, (int)(sizeof("Listen") - 1 + strlen(*t)));
+        if (i->accept)
+                maxlen = MAX(maxlen, (int)sizeof("Accept") - 1);
+        if (i->main_pid > 0)
+                maxlen = MAX(maxlen, (int)sizeof("Main PID") - 1);
+        else if (i->control_pid > 0)
+                maxlen = MAX(maxlen, (int)sizeof("Control") - 1);
+
         /* This shows pretty information about a unit. See
          * print_property() for a low-level property printer */
 
@@ -2294,7 +2392,7 @@ static void print_status_info(UnitStatusInfo *i) {
         printf("\n");
 
         if (i->following)
-                printf("\t  Follow: unit currently follows state of %s\n", i->following);
+                printf(" %*s: unit currently follows state of %s\n", maxlen, "Follow", i->following);
 
         if (streq_ptr(i->load_state, "error")) {
                 on = ansi_highlight_red(true);
@@ -2305,13 +2403,45 @@ static void print_status_info(UnitStatusInfo *i) {
         path = i->source_path ? i->source_path : i->fragment_path;
 
         if (i->load_error)
-                printf("\t  Loaded: %s%s%s (Reason: %s)\n", on, strna(i->load_state), off, i->load_error);
+                printf(" %*s: %s%s%s (Reason: %s)\n",
+                       maxlen, "Loaded", on, strna(i->load_state), off, i->load_error);
         else if (path && i->unit_file_state)
-                printf("\t  Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, path, i->unit_file_state);
+                printf(" %*s: %s%s%s (%s; %s)\n",
+                       maxlen, "Loaded", on, strna(i->load_state), off, path, i->unit_file_state);
         else if (path)
-                printf("\t  Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, path);
+                printf(" %*s: %s%s%s (%s)\n",
+                       maxlen, "Loaded", on, strna(i->load_state), off, path);
         else
-                printf("\t  Loaded: %s%s%s\n", on, strna(i->load_state), off);
+                printf(" %*s: %s%s%s\n",
+                       maxlen, "Loaded", on, strna(i->load_state), off);
+
+        if (!strv_isempty(i->dropin_paths)) {
+                char ** dropin;
+                char * dir = NULL;
+                bool last = false;
+
+                STRV_FOREACH(dropin, i->dropin_paths) {
+                        if (! dir || last) {
+                                printf("  %*s ", maxlen, dir ? "" : "Drop-In:");
+
+                                free(dir);
+
+                                if (path_get_parent(*dropin, &dir) < 0) {
+                                        log_oom();
+                                        return;
+                                }
+
+                                printf("%s\n %*s  %s", dir, maxlen, "",
+                                       draw_special_char(DRAW_TREE_RIGHT));
+                        }
+
+                        last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
+
+                        printf("%s%s", path_get_file_name(*dropin), last ? "\n" : ", ");
+                }
+
+                free(dir);
+        }
 
         ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
 
@@ -2325,16 +2455,11 @@ static void print_status_info(UnitStatusInfo *i) {
                 on = off = "";
 
         if (ss)
-                printf("\t  Active: %s%s (%s)%s",
-                       on,
-                       strna(i->active_state),
-                       ss,
-                       off);
+                printf(" %*s: %s%s (%s)%s",
+                       maxlen, "Active",  on, strna(i->active_state), ss, off);
         else
-                printf("\t  Active: %s%s%s",
-                       on,
-                       strna(i->active_state),
-                       off);
+                printf(" %*s: %s%s%s",
+                       maxlen, "Active", on, strna(i->active_state), off);
 
         if (!isempty(i->result) && !streq(i->result, "success"))
                 printf(" (Result: %s)", i->result);
@@ -2361,44 +2486,37 @@ static void print_status_info(UnitStatusInfo *i) {
                 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
 
                 if (s1)
-                        printf("\t          start condition failed at %s; %s\n", s2, s1);
+                        printf(" %*s start condition failed at %s; %s\n", maxlen, "", s2, s1);
                 else if (s2)
-                        printf("\t          start condition failed at %s\n", s2);
+                        printf(" %*s start condition failed at %s\n", maxlen, "", s2);
         }
 
         if (i->sysfs_path)
-                printf("\t  Device: %s\n", i->sysfs_path);
+                printf(" %*s: %s\n", maxlen, "Device", i->sysfs_path);
         if (i->where)
-                printf("\t   Where: %s\n", i->where);
+                printf(" %*s: %s\n", maxlen, "Where", i->where);
         if (i->what)
-                printf("\t    What: %s\n", i->what);
+                printf(" %*s: %s\n", maxlen, "What", i->what);
 
-        if (!strv_isempty(i->documentation)) {
-                char **t;
-                bool first = true;
+        STRV_FOREACH(t, i->documentation)
+                printf(" %*s %s\n", maxlen+1, t == i->documentation ? "Docs:" : "", *t);
 
-                STRV_FOREACH(t, i->documentation) {
-                        if (first) {
-                                printf("\t    Docs: %s\n", *t);
-                                first = false;
-                        } else
-                                printf("\t          %s\n", *t);
-                }
-        }
+        STRV_FOREACH_PAIR(t, t2, i->listen)
+                printf(" %*s %s (%s)\n", maxlen+1, t == i->listen ? "Listen:" : "", *t2, *t);
 
         if (i->accept)
-                printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
+                printf(" %*s: %u; Connected: %u\n", maxlen, "Accepted", i->n_accepted, i->n_connections);
 
         LIST_FOREACH(exec, p, i->exec) {
-                _cleanup_free_ char *t = NULL;
+                _cleanup_free_ char *argv = NULL;
                 bool good;
 
                 /* Only show exited processes here */
                 if (p->code == 0)
                         continue;
 
-                t = strv_join(p->argv, " ");
-                printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t));
+                argv = strv_join(p->argv, " ");
+                printf(" %*s: %u %s=%s ", maxlen, "Process", p->pid, p->name, strna(argv));
 
                 good = is_clean_exit_lsb(p->code, p->status, NULL);
                 if (!good) {
@@ -2434,16 +2552,14 @@ static void print_status_info(UnitStatusInfo *i) {
         }
 
         if (i->main_pid > 0 || i->control_pid > 0) {
-                printf("\t");
-
                 if (i->main_pid > 0) {
-                        printf("Main PID: %u", (unsigned) i->main_pid);
+                        printf(" %*s: %u", maxlen, "Main PID", (unsigned) i->main_pid);
 
                         if (i->running) {
-                                _cleanup_free_ char *t = NULL;
-                                get_process_comm(i->main_pid, &t);
-                                if (t)
-                                        printf(" (%s)", t);
+                                _cleanup_free_ char *comm = NULL;
+                                get_process_comm(i->main_pid, &comm);
+                                if (comm)
+                                        printf(" (%s)", comm);
                         } else if (i->exit_code > 0) {
                                 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
 
@@ -2460,40 +2576,43 @@ static void print_status_info(UnitStatusInfo *i) {
                                         printf("signal=%s", signal_to_string(i->exit_status));
                                 printf(")");
                         }
-                }
 
-                if (i->main_pid > 0 && i->control_pid > 0)
-                        printf(";");
+                        if (i->control_pid > 0)
+                                printf(";");
+                }
 
                 if (i->control_pid > 0) {
-                        _cleanup_free_ char *t = NULL;
+                        _cleanup_free_ char *c = NULL;
 
-                        printf(" Control: %u", (unsigned) i->control_pid);
+                        printf(" %*s: %u", i->main_pid ? 0 : maxlen, "Control", (unsigned) i->control_pid);
 
-                        get_process_comm(i->control_pid, &t);
-                        if (t)
-                                printf(" (%s)", t);
+                        get_process_comm(i->control_pid, &c);
+                        if (c)
+                                printf(" (%s)", c);
                 }
 
                 printf("\n");
         }
 
         if (i->status_text)
-                printf("\t  Status: \"%s\"\n", i->status_text);
+                printf(" %*s: \"%s\"\n", maxlen, "Status", i->status_text);
 
         if (i->default_control_group &&
             (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_by_spec(i->default_control_group, false) == 0)) {
                 unsigned c;
 
-                printf("\t  CGroup: %s\n", i->default_control_group);
+                printf(" %*s: %s\n", maxlen, "CGroup", i->default_control_group);
 
                 if (arg_transport != TRANSPORT_SSH) {
                         unsigned k = 0;
                         pid_t extra[2];
+                        char prefix[maxlen + 4];
+                        memset(prefix, ' ', sizeof(prefix) - 1);
+                        prefix[sizeof(prefix) - 1] = '\0';
 
                         c = columns();
-                        if (c > 18)
-                                c -= 18;
+                        if (c > sizeof(prefix) - 1)
+                                c -= sizeof(prefix) - 1;
                         else
                                 c = 0;
 
@@ -2503,29 +2622,22 @@ static void print_status_info(UnitStatusInfo *i) {
                         if (i->control_pid > 0)
                                 extra[k++] = i->control_pid;
 
-                        show_cgroup_and_extra_by_spec(i->default_control_group, "\t\t  ", c, false, extra, k, flags);
+                        show_cgroup_and_extra_by_spec(i->default_control_group, prefix,
+                                                      c, false, extra, k, flags);
                 }
         }
 
         if (i->id && arg_transport != TRANSPORT_SSH) {
                 printf("\n");
-                if(arg_scope == UNIT_FILE_SYSTEM)
-                        show_journal_by_unit(stdout,
-                                             i->id,
-                                             arg_output,
-                                             0,
-                                             i->inactive_exit_timestamp_monotonic,
-                                             arg_lines,
-                                             flags);
-                else
-                        show_journal_by_user_unit(stdout,
-                                                  i->id,
-                                                  arg_output,
-                                                  0,
-                                                  i->inactive_exit_timestamp_monotonic,
-                                                  arg_lines,
-                                                  getuid(),
-                                                  flags);
+                show_journal_by_unit(stdout,
+                                     i->id,
+                                     arg_output,
+                                     0,
+                                     i->inactive_exit_timestamp_monotonic,
+                                     arg_lines,
+                                     getuid(),
+                                     flags,
+                                     arg_scope == UNIT_FILE_SYSTEM);
         }
 
         if (i->need_daemon_reload)
@@ -2744,6 +2856,38 @@ 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, "Listen")) {
+                        DBusMessageIter sub, sub2;
+
+                        dbus_message_iter_recurse(iter, &sub);
+                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
+                                const char *type, *path;
+
+                                dbus_message_iter_recurse(&sub, &sub2);
+
+                                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
+                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0) {
+                                        int r;
+
+                                        r = strv_extend(&i->listen, type);
+                                        if (r < 0)
+                                                return r;
+                                        r = strv_extend(&i->listen, path);
+                                        if (r < 0)
+                                                return r;
+                                }
+
+                                dbus_message_iter_next(&sub);
+                        }
+
+                        return 0;
+
+                } 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;
+
                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
                            streq(name, "Documentation")) {
 
@@ -2752,16 +2896,13 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn
                         dbus_message_iter_recurse(iter, &sub);
                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
                                 const char *s;
-                                char **l;
+                                int r;
 
                                 dbus_message_iter_get_basic(&sub, &s);
 
-                                l = strv_append(i->documentation, s);
-                                if (!l)
-                                        return -ENOMEM;
-
-                                strv_free(i->documentation);
-                                i->documentation = l;
+                                r = strv_extend(&i->documentation, s);
+                                if (r < 0)
+                                        return r;
 
                                 dbus_message_iter_next(&sub);
                         }
@@ -2874,6 +3015,7 @@ static int print_property(const char *name, DBusMessageIter *iter) {
                         DBusMessageIter sub, sub2;
 
                         dbus_message_iter_recurse(iter, &sub);
+
                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
                                 const char *type, *path;
 
@@ -2888,6 +3030,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, "Listen")) {
+                        DBusMessageIter sub, sub2;
+
+                        dbus_message_iter_recurse(iter, &sub);
+                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
+                                const char *type, *path;
+
+                                dbus_message_iter_recurse(&sub, &sub2);
+
+                                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
+                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
+                                        printf("Listen%s=%s\n", type, path);
+
+                                dbus_message_iter_next(&sub);
+                        }
+
+                        return 0;
+
                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
                         DBusMessageIter sub, sub2;
 
@@ -2905,8 +3065,8 @@ static int print_property(const char *name, DBusMessageIter *iter) {
 
                                         printf("%s={ value=%s ; next_elapse=%s }\n",
                                                base,
-                                               format_timespan(timespan1, sizeof(timespan1), value),
-                                               format_timespan(timespan2, sizeof(timespan2), next_elapse));
+                                               format_timespan(timespan1, sizeof(timespan1), value, 0),
+                                               format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
                                 }
 
                                 dbus_message_iter_next(&sub);
@@ -2943,9 +3103,8 @@ static int print_property(const char *name, DBusMessageIter *iter) {
 
                         dbus_message_iter_recurse(iter, &sub);
                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
-                                ExecStatusInfo info;
+                                ExecStatusInfo info = {};
 
-                                zero(info);
                                 if (exec_status_info_deserialize(&sub, &info) >= 0) {
                                         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
                                         char _cleanup_free_ *t;
@@ -2988,18 +3147,16 @@ static int print_property(const char *name, DBusMessageIter *iter) {
 }
 
 static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
-        _cleanup_free_ DBusMessage *reply = NULL;
+        DBusMessage _cleanup_free_ *reply = NULL;
         const char *interface = "";
         int r;
         DBusMessageIter iter, sub, sub2, sub3;
-        UnitStatusInfo info;
+        UnitStatusInfo info = {};
         ExecStatusInfo *p;
 
         assert(path);
         assert(new_line);
 
-        zero(info);
-
         r = bus_method_call_with_reply(
                         bus,
                         "org.freedesktop.systemd1",
@@ -3063,6 +3220,8 @@ static int show_one(const char *verb, DBusConnection *bus, const char *path, boo
         }
 
         strv_free(info.documentation);
+        strv_free(info.dropin_paths);
+        strv_free(info.listen);
 
         if (!streq_ptr(info.active_state, "active") &&
             !streq_ptr(info.active_state, "reloading") &&
@@ -3574,7 +3733,7 @@ static int enable_sysv_units(char **args) {
 #if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG)
         const char *verb = args[0];
         unsigned f = 1, t = 1;
-        LookupPaths paths;
+        LookupPaths paths = {};
 
         if (arg_scope != UNIT_FILE_SYSTEM)
                 return 0;
@@ -3587,7 +3746,6 @@ static int enable_sysv_units(char **args) {
         /* Processes all SysV units, and reshuffles the array so that
          * afterwards only the native units remain */
 
-        zero(paths);
         r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, NULL, NULL, NULL);
         if (r < 0)
                 return r;
@@ -4251,16 +4409,21 @@ static int runlevel_help(void) {
 
 static int help_types(void) {
         int i;
+        const char *t;
 
         puts("Available unit types:");
-        for(i = UNIT_SERVICE; i < _UNIT_TYPE_MAX; i++)
-                if (unit_type_table[i])
-                        puts(unit_type_table[i]);
+        for(i = 0; i < _UNIT_TYPE_MAX; i++) {
+                t = unit_type_to_string(i);
+                if (t)
+                        puts(t);
+        }
 
         puts("\nAvailable unit load states: ");
-        for(i = UNIT_STUB; i < _UNIT_LOAD_STATE_MAX; i++)
-                if (unit_type_table[i])
-                        puts(unit_load_state_table[i]);
+        for(i = 0; i < _UNIT_LOAD_STATE_MAX; i++) {
+                t = unit_load_state_to_string(i);
+                if (t)
+                        puts(t);
+        }
 
         return 0;
 }
@@ -4631,23 +4794,22 @@ static int parse_time_spec(const char *t, usec_t *_u) {
         } else {
                 char *e = NULL;
                 long hour, minute;
-                struct tm tm;
+                struct tm tm = {};
                 time_t s;
                 usec_t n;
 
                 errno = 0;
                 hour = strtol(t, &e, 10);
-                if (errno != 0 || *e != ':' || hour < 0 || hour > 23)
+                if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
                         return -EINVAL;
 
                 minute = strtol(e+1, &e, 10);
-                if (errno != 0 || *e != 0 || minute < 0 || minute > 59)
+                if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
                         return -EINVAL;
 
                 n = now(CLOCK_REALTIME);
                 s = (time_t) (n / USEC_PER_SEC);
 
-                zero(tm);
                 assert_se(localtime_r(&s, &tm));
 
                 tm.tm_hour = (int) hour;
@@ -4926,7 +5088,7 @@ static int parse_argv(int argc, char *argv[]) {
                                  * request to it. For now we simply
                                  * guess that it is Upstart. */
 
-                                execv("/lib/upstart/telinit", argv);
+                                execv(TELINIT, argv);
 
                                 log_error("Couldn't find an alternative telinit implementation to spawn.");
                                 return -EIO;
@@ -5049,21 +5211,22 @@ finish:
 }
 
 static int talk_initctl(void) {
-        struct init_request request;
-        int r, fd;
+        struct init_request request = {};
+        int r;
+        int _cleanup_close_ fd = -1;
         char rl;
 
-        if (!(rl = action_to_runlevel()))
+        rl = action_to_runlevel();
+        if (!rl)
                 return 0;
 
-        zero(request);
         request.magic = INIT_MAGIC;
         request.sleeptime = 0;
         request.cmd = INIT_CMD_RUNLVL;
         request.runlevel = rl;
 
-        if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) {
-
+        fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY);
+        if (fd < 0) {
                 if (errno == ENOENT)
                         return 0;
 
@@ -5073,9 +5236,7 @@ static int talk_initctl(void) {
 
         errno = 0;
         r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
-        close_nointr_nofail(fd);
-
-        if (r < 0) {
+        if (r) {
                 log_error("Failed to write to "INIT_FIFO": %m");
                 return errno ? -errno : -EIO;
         }
@@ -5255,41 +5416,38 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
 
 static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
         int _cleanup_close_ fd;
-        struct msghdr msghdr;
-        struct iovec iovec[2];
-        union sockaddr_union sockaddr;
-        struct sd_shutdown_command c;
+        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,
+                 .iov_len = offsetof(struct sd_shutdown_command, wall_message),
+                }
+        };
+        struct msghdr msghdr = {
+                .msg_name = &sockaddr,
+                .msg_namelen = offsetof(struct sockaddr_un, sun_path)
+                               + sizeof("/run/systemd/shutdownd") - 1,
+                .msg_iov = iovec,
+                .msg_iovlen = 1,
+        };
 
         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
         if (fd < 0)
                 return -errno;
 
-        zero(c);
-        c.usec = t;
-        c.mode = mode;
-        c.dry_run = dry_run;
-        c.warn_wall = warn;
-
-        zero(sockaddr);
-        sockaddr.sa.sa_family = AF_UNIX;
-        strncpy(sockaddr.un.sun_path, "/run/systemd/shutdownd", sizeof(sockaddr.un.sun_path));
-
-        zero(msghdr);
-        msghdr.msg_name = &sockaddr;
-        msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/systemd/shutdownd") - 1;
-
-        zero(iovec);
-        iovec[0].iov_base = (char*) &c;
-        iovec[0].iov_len = offsetof(struct sd_shutdown_command, wall_message);
-
-        if (isempty(message))
-                msghdr.msg_iovlen = 1;
-        else {
+        if (!isempty(message)) {
                 iovec[1].iov_base = (char*) message;
                 iovec[1].iov_len = strlen(message);
-                msghdr.msg_iovlen = 2;
+                msghdr.msg_iovlen++;
         }
-        msghdr.msg_iov = iovec;
 
         if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0)
                 return -errno;