]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/systemctl/systemctl.c
polkit-agent: don't use an inline function
[thirdparty/systemd.git] / src / systemctl / systemctl.c
index f50edbcee7289f9ee4c6dca06f65b9bd9658db8b..4be695d5b648ab7000b15049e3b37d01382420b8 100644 (file)
@@ -3,15 +3,12 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <getopt.h>
-#include <locale.h>
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdio.h>
-#include <string.h>
 #include <sys/mount.h>
 #include <sys/prctl.h>
 #include <sys/reboot.h>
-#include <sys/socket.h>
 #include <unistd.h>
 
 #include "sd-bus.h"
@@ -749,6 +746,64 @@ static int get_unit_list_recursive(
         return c;
 }
 
+static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***ret, bool *ret_expanded) {
+        _cleanup_strv_free_ char **mangled = NULL, **globs = NULL;
+        char **name;
+        int r, i;
+
+        assert(bus);
+        assert(ret);
+
+        STRV_FOREACH(name, names) {
+                char *t;
+                UnitNameMangle options = UNIT_NAME_MANGLE_GLOB | (arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN);
+
+                r = unit_name_mangle_with_suffix(*name, NULL, options, suffix ?: ".service", &t);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to mangle name: %m");
+
+                if (string_is_glob(t))
+                        r = strv_consume(&globs, t);
+                else
+                        r = strv_consume(&mangled, t);
+                if (r < 0)
+                        return log_oom();
+        }
+
+        /* Query the manager only if any of the names are a glob, since
+         * this is fairly expensive */
+        bool expanded = !strv_isempty(globs);
+        if (expanded) {
+                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+                _cleanup_free_ UnitInfo *unit_infos = NULL;
+                size_t allocated, n;
+
+                r = get_unit_list(bus, NULL, globs, &unit_infos, 0, &reply);
+                if (r < 0)
+                        return r;
+
+                n = strv_length(mangled);
+                allocated = n + 1;
+
+                for (i = 0; i < r; i++) {
+                        if (!GREEDY_REALLOC(mangled, allocated, n+2))
+                                return log_oom();
+
+                        mangled[n] = strdup(unit_infos[i].id);
+                        if (!mangled[n])
+                                return log_oom();
+
+                        mangled[++n] = NULL;
+                }
+        }
+
+        if (ret_expanded)
+                *ret_expanded = expanded;
+
+        *ret = TAKE_PTR(mangled);
+        return 0;
+}
+
 static int list_units(int argc, char *argv[], void *userdata) {
         _cleanup_free_ UnitInfo *unit_infos = NULL;
         _cleanup_(message_set_freep) Set *replies = NULL;
@@ -959,6 +1014,7 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
 static int list_sockets(int argc, char *argv[], void *userdata) {
         _cleanup_(message_set_freep) Set *replies = NULL;
         _cleanup_strv_free_ char **machines = NULL;
+        _cleanup_strv_free_ char **sockets_with_suffix = NULL;
         _cleanup_free_ UnitInfo *unit_infos = NULL;
         _cleanup_free_ struct socket_info *socket_infos = NULL;
         const UnitInfo *u;
@@ -974,49 +1030,55 @@ static int list_sockets(int argc, char *argv[], void *userdata) {
 
         (void) pager_open(arg_pager_flags);
 
-        n = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
-        if (n < 0)
-                return n;
+        r = expand_names(bus, strv_skip(argv, 1), ".socket", &sockets_with_suffix, NULL);
+        if (r < 0)
+                return r;
 
-        for (u = unit_infos; u < unit_infos + n; u++) {
-                _cleanup_strv_free_ char **listening = NULL, **triggered = NULL;
-                int i, c;
+        if (argc == 1 || sockets_with_suffix) {
+                n = get_unit_list_recursive(bus, sockets_with_suffix, &unit_infos, &replies, &machines);
+                if (n < 0)
+                        return n;
 
-                if (!endswith(u->id, ".socket"))
-                        continue;
+                for (u = unit_infos; u < unit_infos + n; u++) {
+                        _cleanup_strv_free_ char **listening = NULL, **triggered = NULL;
+                        int i, c;
 
-                r = get_triggered_units(bus, u->unit_path, &triggered);
-                if (r < 0)
-                        goto cleanup;
+                        if (!endswith(u->id, ".socket"))
+                                continue;
 
-                c = get_listening(bus, u->unit_path, &listening);
-                if (c < 0) {
-                        r = c;
-                        goto cleanup;
-                }
+                        r = get_triggered_units(bus, u->unit_path, &triggered);
+                        if (r < 0)
+                                goto cleanup;
 
-                if (!GREEDY_REALLOC(socket_infos, size, cs + c)) {
-                        r = log_oom();
-                        goto cleanup;
-                }
+                        c = get_listening(bus, u->unit_path, &listening);
+                        if (c < 0) {
+                                r = c;
+                                goto cleanup;
+                        }
 
-                for (i = 0; i < c; i++)
-                        socket_infos[cs + i] = (struct socket_info) {
-                                .machine = u->machine,
-                                .id = u->id,
-                                .type = listening[i*2],
-                                .path = listening[i*2 + 1],
-                                .triggered = triggered,
-                                .own_triggered = i==0,
-                        };
+                        if (!GREEDY_REALLOC(socket_infos, size, cs + c)) {
+                                r = log_oom();
+                                goto cleanup;
+                        }
 
-                /* from this point on we will cleanup those socket_infos */
-                cs += c;
-                free(listening);
-                listening = triggered = NULL; /* avoid cleanup */
-        }
+                        for (i = 0; i < c; i++)
+                                socket_infos[cs + i] = (struct socket_info) {
+                                        .machine = u->machine,
+                                        .id = u->id,
+                                        .type = listening[i*2],
+                                        .path = listening[i*2 + 1],
+                                        .triggered = triggered,
+                                        .own_triggered = i==0,
+                                };
+
+                        /* from this point on we will cleanup those socket_infos */
+                        cs += c;
+                        free(listening);
+                        listening = triggered = NULL; /* avoid cleanup */
+                }
 
-        typesafe_qsort(socket_infos, cs, socket_info_compare);
+                typesafe_qsort(socket_infos, cs, socket_info_compare);
+        }
 
         output_sockets_list(socket_infos, cs);
 
@@ -1263,6 +1325,7 @@ static usec_t calc_next_elapse(dual_timestamp *nw, dual_timestamp *next) {
 static int list_timers(int argc, char *argv[], void *userdata) {
         _cleanup_(message_set_freep) Set *replies = NULL;
         _cleanup_strv_free_ char **machines = NULL;
+        _cleanup_strv_free_ char **timers_with_suffix = NULL;
         _cleanup_free_ struct timer_info *timer_infos = NULL;
         _cleanup_free_ UnitInfo *unit_infos = NULL;
         struct timer_info *t;
@@ -1279,47 +1342,53 @@ static int list_timers(int argc, char *argv[], void *userdata) {
 
         (void) pager_open(arg_pager_flags);
 
-        n = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
-        if (n < 0)
-                return n;
+        r = expand_names(bus, strv_skip(argv, 1), ".timer", &timers_with_suffix, NULL);
+        if (r < 0)
+                return r;
 
-        dual_timestamp_get(&nw);
+        if (argc == 1 || timers_with_suffix) {
+                n = get_unit_list_recursive(bus, timers_with_suffix, &unit_infos, &replies, &machines);
+                if (n < 0)
+                        return n;
 
-        for (u = unit_infos; u < unit_infos + n; u++) {
-                _cleanup_strv_free_ char **triggered = NULL;
-                dual_timestamp next = DUAL_TIMESTAMP_NULL;
-                usec_t m, last = 0;
+                dual_timestamp_get(&nw);
 
-                if (!endswith(u->id, ".timer"))
-                        continue;
+                for (u = unit_infos; u < unit_infos + n; u++) {
+                        _cleanup_strv_free_ char **triggered = NULL;
+                        dual_timestamp next = DUAL_TIMESTAMP_NULL;
+                        usec_t m, last = 0;
 
-                r = get_triggered_units(bus, u->unit_path, &triggered);
-                if (r < 0)
-                        goto cleanup;
+                        if (!endswith(u->id, ".timer"))
+                                continue;
 
-                r = get_next_elapse(bus, u->unit_path, &next);
-                if (r < 0)
-                        goto cleanup;
+                        r = get_triggered_units(bus, u->unit_path, &triggered);
+                        if (r < 0)
+                                goto cleanup;
 
-                get_last_trigger(bus, u->unit_path, &last);
+                        r = get_next_elapse(bus, u->unit_path, &next);
+                        if (r < 0)
+                                goto cleanup;
 
-                if (!GREEDY_REALLOC(timer_infos, size, c+1)) {
-                        r = log_oom();
-                        goto cleanup;
-                }
+                        get_last_trigger(bus, u->unit_path, &last);
 
-                m = calc_next_elapse(&nw, &next);
+                        if (!GREEDY_REALLOC(timer_infos, size, c+1)) {
+                                r = log_oom();
+                                goto cleanup;
+                        }
 
-                timer_infos[c++] = (struct timer_info) {
-                        .machine = u->machine,
-                        .id = u->id,
-                        .next_elapse = m,
-                        .last_trigger = last,
-                        .triggered = TAKE_PTR(triggered),
-                };
-        }
+                        m = calc_next_elapse(&nw, &next);
+
+                        timer_infos[c++] = (struct timer_info) {
+                                .machine = u->machine,
+                                .id = u->id,
+                                .next_elapse = m,
+                                .last_trigger = last,
+                                .triggered = TAKE_PTR(triggered),
+                        };
+                }
 
-        typesafe_qsort(timer_infos, c, timer_info_compare);
+                typesafe_qsort(timer_infos, c, timer_info_compare);
+        }
 
         output_timers_list(timer_infos, c);
 
@@ -2106,7 +2175,9 @@ static int set_default(int argc, char *argv[], void *userdata) {
         assert(argc >= 2);
         assert(argv);
 
-        r = unit_name_mangle_with_suffix(argv[1], arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, ".target", &unit);
+        r = unit_name_mangle_with_suffix(argv[1], "set-default",
+                                         arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
+                                         ".target", &unit);
         if (r < 0)
                 return log_error_errno(r, "Failed to mangle unit name: %m");
 
@@ -2444,7 +2515,7 @@ static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **re
                 if (!path)
                         return log_oom();
 
-                r = chase_symlinks(path, arg_root, 0, &lpath);
+                r = chase_symlinks(path, arg_root, 0, &lpath, NULL);
                 if (r == -ENOENT)
                         continue;
                 if (r == -ENOMEM)
@@ -2926,63 +2997,6 @@ fail:
         return r;
 }
 
-static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***ret) {
-        _cleanup_strv_free_ char **mangled = NULL, **globs = NULL;
-        char **name;
-        int r, i;
-
-        assert(bus);
-        assert(ret);
-
-        STRV_FOREACH(name, names) {
-                char *t;
-                UnitNameMangle options = UNIT_NAME_MANGLE_GLOB | (arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN);
-
-                if (suffix)
-                        r = unit_name_mangle_with_suffix(*name, options, suffix, &t);
-                else
-                        r = unit_name_mangle(*name, options, &t);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to mangle name: %m");
-
-                if (string_is_glob(t))
-                        r = strv_consume(&globs, t);
-                else
-                        r = strv_consume(&mangled, t);
-                if (r < 0)
-                        return log_oom();
-        }
-
-        /* Query the manager only if any of the names are a glob, since
-         * this is fairly expensive */
-        if (!strv_isempty(globs)) {
-                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-                _cleanup_free_ UnitInfo *unit_infos = NULL;
-                size_t allocated, n;
-
-                r = get_unit_list(bus, NULL, globs, &unit_infos, 0, &reply);
-                if (r < 0)
-                        return r;
-
-                n = strv_length(mangled);
-                allocated = n + 1;
-
-                for (i = 0; i < r; i++) {
-                        if (!GREEDY_REALLOC(mangled, allocated, n+2))
-                                return log_oom();
-
-                        mangled[n] = strdup(unit_infos[i].id);
-                        if (!mangled[n])
-                                return log_oom();
-
-                        mangled[++n] = NULL;
-                }
-        }
-
-        *ret = TAKE_PTR(mangled);
-        return 0;
-}
-
 static const struct {
         const char *target;
         const char *verb;
@@ -3103,9 +3117,20 @@ static int start_unit(int argc, char *argv[], void *userdata) {
                 if (!names)
                         return log_oom();
         } else {
-                r = expand_names(bus, strv_skip(argv, 1), suffix, &names);
+                bool expanded;
+
+                r = expand_names(bus, strv_skip(argv, 1), suffix, &names, &expanded);
                 if (r < 0)
                         return log_error_errno(r, "Failed to expand names: %m");
+
+                if (!arg_all && expanded && streq(job_type, "start") && !arg_quiet) {
+                        log_warning("Warning: %ssystemctl start called with a glob pattern.%s",
+                                    ansi_highlight_red(),
+                                    ansi_normal());
+                        log_notice("Hint: unit globs expand to loaded units, so start will usually have no effect.\n"
+                                   "      Passing --all will also load units which are pulled in by other units.\n"
+                                   "      See systemctl(1) for more details.");
+                }
         }
 
         if (!arg_no_block) {
@@ -3713,7 +3738,7 @@ static int check_unit_generic(int code, const UnitActiveState good_states[], int
         if (r < 0)
                 return r;
 
-        r = expand_names(bus, args, NULL, &names);
+        r = expand_names(bus, args, NULL, &names, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to expand names: %m");
 
@@ -3772,7 +3797,7 @@ static int kill_unit(int argc, char *argv[], void *userdata) {
         if (streq(arg_job_mode, "fail"))
                 kill_who = strjoina(arg_kill_who, "-fail");
 
-        r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
+        r = expand_names(bus, strv_skip(argv, 1), NULL, &names, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to expand names: %m");
 
@@ -3817,7 +3842,7 @@ static int clean_unit(int argc, char *argv[], void *userdata) {
                         return log_oom();
         }
 
-        r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
+        r = expand_names(bus, strv_skip(argv, 1), NULL, &names, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to expand names: %m");
 
@@ -4025,6 +4050,9 @@ typedef struct UnitStatusInfo {
 
         char **dropin_paths;
 
+        char **triggered_by;
+        char **triggers;
+
         const char *load_error;
         const char *result;
 
@@ -4109,6 +4137,8 @@ static void unit_status_info_free(UnitStatusInfo *info) {
 
         strv_free(info->documentation);
         strv_free(info->dropin_paths);
+        strv_free(info->triggered_by);
+        strv_free(info->triggers);
         strv_free(info->listen);
 
         while ((c = info->conditions)) {
@@ -4122,6 +4152,17 @@ static void unit_status_info_free(UnitStatusInfo *info) {
         }
 }
 
+static void format_active_state(const char *active_state, const char **active_on, const char **active_off) {
+        if (streq_ptr(active_state, "failed")) {
+                *active_on = ansi_highlight_red();
+                *active_off = ansi_normal();
+        } else if (STRPTR_IN_SET(active_state, "active", "reloading")) {
+                *active_on = ansi_highlight_green();
+                *active_off = ansi_normal();
+        } else
+                *active_on = *active_off = "";
+}
+
 static void print_status_info(
                 sd_bus *bus,
                 UnitStatusInfo *i,
@@ -4141,14 +4182,7 @@ static void print_status_info(
         /* This shows pretty information about a unit. See
          * print_property() for a low-level property printer */
 
-        if (streq_ptr(i->active_state, "failed")) {
-                active_on = ansi_highlight_red();
-                active_off = ansi_normal();
-        } else if (STRPTR_IN_SET(i->active_state, "active", "reloading")) {
-                active_on = ansi_highlight_green();
-                active_off = ansi_normal();
-        } else
-                active_on = active_off = "";
+        format_active_state(i->active_state, &active_on, &active_off);
 
         printf("%s%s%s %s", active_on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), active_off, strna(i->id));
 
@@ -4171,24 +4205,24 @@ static void print_status_info(
                 path = formatted_path;
 
         if (!isempty(i->load_error))
-                printf("   Loaded: %s%s%s (Reason: %s)\n",
+                printf("     Loaded: %s%s%s (Reason: %s)\n",
                        on, strna(i->load_state), off, i->load_error);
         else if (path && !isempty(i->unit_file_state) && !isempty(i->unit_file_preset) &&
                  !STR_IN_SET(i->unit_file_state, "generated", "transient"))
-                printf("   Loaded: %s%s%s (%s; %s; vendor preset: %s)\n",
+                printf("     Loaded: %s%s%s (%s; %s; vendor preset: %s)\n",
                        on, strna(i->load_state), off, path, i->unit_file_state, i->unit_file_preset);
         else if (path && !isempty(i->unit_file_state))
-                printf("   Loaded: %s%s%s (%s; %s)\n",
+                printf("     Loaded: %s%s%s (%s; %s)\n",
                        on, strna(i->load_state), off, path, i->unit_file_state);
         else if (path)
-                printf("   Loaded: %s%s%s (%s)\n",
+                printf("     Loaded: %s%s%s (%s)\n",
                        on, strna(i->load_state), off, path);
         else
-                printf("   Loaded: %s%s%s\n",
+                printf("     Loaded: %s%s%s\n",
                        on, strna(i->load_state), off);
 
         if (i->transient)
-                printf("Transient: yes\n");
+                printf("  Transient: yes\n");
 
         if (!strv_isempty(i->dropin_paths)) {
                 _cleanup_free_ char *dir = NULL;
@@ -4200,8 +4234,8 @@ static void print_status_info(
                         const char *df;
 
                         if (!dir || last) {
-                                printf(dir ? "           " :
-                                             "  Drop-In: ");
+                                printf(dir ? "             " :
+                                             "    Drop-In: ");
 
                                 dir = mfree(dir);
 
@@ -4212,7 +4246,7 @@ static void print_status_info(
                                 }
 
                                 printf("%s\n"
-                                       "           %s", dir,
+                                       "             %s", dir,
                                        special_glyph(SPECIAL_GLYPH_TREE_RIGHT));
                         }
 
@@ -4229,10 +4263,10 @@ static void print_status_info(
 
         ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
         if (ss)
-                printf("   Active: %s%s (%s)%s",
+                printf("     Active: %s%s (%s)%s",
                        active_on, strna(i->active_state), ss, active_off);
         else
-                printf("   Active: %s%s%s",
+                printf("     Active: %s%s%s",
                        active_on, strna(i->active_state), active_off);
 
         if (!isempty(i->result) && !streq(i->result, "success"))
@@ -4253,6 +4287,18 @@ static void print_status_info(
         else
                 printf("\n");
 
+        STRV_FOREACH(t, i->triggered_by) {
+                UnitActiveState state = _UNIT_ACTIVE_STATE_INVALID;
+
+                (void) get_state_one_unit(bus, *t, &state);
+                format_active_state(unit_active_state_to_string(state), &on, &off);
+
+                printf("%s %s%s%s %s\n",
+                       t == i->triggered_by ? "TriggeredBy:" : "            ",
+                       on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off,
+                       *t);
+        }
+
         if (endswith(i->id, ".timer")) {
                 char tstamp1[FORMAT_TIMESTAMP_RELATIVE_MAX],
                      tstamp2[FORMAT_TIMESTAMP_MAX];
@@ -4261,7 +4307,7 @@ static void print_status_info(
                                            i->next_elapse_monotonic};
                 usec_t next_elapse;
 
-                printf("  Trigger: ");
+                printf("    Trigger: ");
 
                 dual_timestamp_get(&nw);
                 next_elapse = calc_next_elapse(&nw, &next);
@@ -4274,6 +4320,18 @@ static void print_status_info(
                         printf("n/a\n");
         }
 
+        STRV_FOREACH(t, i->triggers) {
+                UnitActiveState state = _UNIT_ACTIVE_STATE_INVALID;
+
+                (void) get_state_one_unit(bus, *t, &state);
+                format_active_state(unit_active_state_to_string(state), &on, &off);
+
+                printf("%s %s%s%s %s\n",
+                       t == i->triggers ? "   Triggers:" : "            ",
+                       on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off,
+                       *t);
+        }
+
         if (!i->condition_result && i->condition_timestamp > 0) {
                 UnitCondition *c;
                 int n = 0;
@@ -4281,7 +4339,7 @@ static void print_status_info(
                 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
                 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
 
-                printf("Condition: start %scondition failed%s at %s%s%s\n",
+                printf("  Condition: start %scondition failed%s at %s%s%s\n",
                        ansi_highlight_yellow(), ansi_normal(),
                        s2, s1 ? "; " : "", strempty(s1));
 
@@ -4291,7 +4349,7 @@ static void print_status_info(
 
                 LIST_FOREACH(conditions, c, i->conditions)
                         if (c->tristate < 0)
-                                printf("           %s %s=%s%s%s was not met\n",
+                                printf("             %s %s=%s%s%s was not met\n",
                                        --n ? special_glyph(SPECIAL_GLYPH_TREE_BRANCH) : special_glyph(SPECIAL_GLYPH_TREE_RIGHT),
                                        c->name,
                                        c->trigger ? "|" : "",
@@ -4303,24 +4361,24 @@ static void print_status_info(
                 s1 = format_timestamp_relative(since1, sizeof(since1), i->assert_timestamp);
                 s2 = format_timestamp(since2, sizeof(since2), i->assert_timestamp);
 
-                printf("   Assert: start %sassertion failed%s at %s%s%s\n",
+                printf("     Assert: start %sassertion failed%s at %s%s%s\n",
                        ansi_highlight_red(), ansi_normal(),
                        s2, s1 ? "; " : "", strempty(s1));
                 if (i->failed_assert_trigger)
-                        printf("           none of the trigger assertions were met\n");
+                        printf("             none of the trigger assertions were met\n");
                 else if (i->failed_assert)
-                        printf("           %s=%s%s was not met\n",
+                        printf("             %s=%s%s was not met\n",
                                i->failed_assert,
                                i->failed_assert_negate ? "!" : "",
                                i->failed_assert_parameter);
         }
 
         if (i->sysfs_path)
-                printf("   Device: %s\n", i->sysfs_path);
+                printf("     Device: %s\n", i->sysfs_path);
         if (i->where)
-                printf("    Where: %s\n", i->where);
+                printf("      Where: %s\n", i->where);
         if (i->what)
-                printf("     What: %s\n", i->what);
+                printf("       What: %s\n", i->what);
 
         STRV_FOREACH(t, i->documentation) {
                 _cleanup_free_ char *formatted = NULL;
@@ -4331,16 +4389,16 @@ static void print_status_info(
                 else
                         q = *t;
 
-                printf(" %*s %s\n", 9, t == i->documentation ? "Docs:" : "", q);
+                printf("   %*s %s\n", 9, t == i->documentation ? "Docs:" : "", q);
         }
 
         STRV_FOREACH_PAIR(t, t2, i->listen)
-                printf(" %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t);
+                printf("   %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t);
 
         if (i->accept) {
-                printf(" Accepted: %u; Connected: %u;", i->n_accepted, i->n_connections);
+                printf("   Accepted: %u; Connected: %u;", i->n_accepted, i->n_connections);
                 if (i->n_refused)
-                        printf(" Refused: %u", i->n_refused);
+                        printf("   Refused: %u", i->n_refused);
                 printf("\n");
         }
 
@@ -4358,7 +4416,7 @@ static void print_status_info(
                         continue;
 
                 argv = strv_join(p->argv, " ");
-                printf("  Process: "PID_FMT" %s=%s ", p->pid, p->name, strna(argv));
+                printf("    Process: "PID_FMT" %s=%s ", p->pid, p->name, strna(argv));
 
                 good = is_clean_exit(p->code, p->status, EXIT_CLEAN_DAEMON, NULL);
                 if (!good) {
@@ -4395,7 +4453,7 @@ static void print_status_info(
 
         if (i->main_pid > 0 || i->control_pid > 0) {
                 if (i->main_pid > 0) {
-                        printf(" Main PID: "PID_FMT, i->main_pid);
+                        printf("   Main PID: "PID_FMT, i->main_pid);
 
                         if (i->running) {
 
@@ -4447,14 +4505,14 @@ static void print_status_info(
         }
 
         if (i->status_text)
-                printf("   Status: \"%s\"\n", i->status_text);
+                printf("     Status: \"%s\"\n", i->status_text);
         if (i->status_errno > 0)
-                printf("    Error: %i (%s)\n", i->status_errno, strerror_safe(i->status_errno));
+                printf("      Error: %i (%s)\n", i->status_errno, strerror_safe(i->status_errno));
 
         if (i->ip_ingress_bytes != (uint64_t) -1 && i->ip_egress_bytes != (uint64_t) -1) {
                 char buf_in[FORMAT_BYTES_MAX], buf_out[FORMAT_BYTES_MAX];
 
-                printf("       IP: %s in, %s out\n",
+                printf("         IP: %s in, %s out\n",
                         format_bytes(buf_in, sizeof(buf_in), i->ip_ingress_bytes),
                         format_bytes(buf_out, sizeof(buf_out), i->ip_egress_bytes));
         }
@@ -4462,13 +4520,13 @@ static void print_status_info(
         if (i->io_read_bytes != UINT64_MAX && i->io_write_bytes != UINT64_MAX) {
                 char buf_in[FORMAT_BYTES_MAX], buf_out[FORMAT_BYTES_MAX];
 
-                printf("       IO: %s read, %s written\n",
+                printf("         IO: %s read, %s written\n",
                         format_bytes(buf_in, sizeof(buf_in), i->io_read_bytes),
                         format_bytes(buf_out, sizeof(buf_out), i->io_write_bytes));
         }
 
         if (i->tasks_current != (uint64_t) -1) {
-                printf("    Tasks: %" PRIu64, i->tasks_current);
+                printf("      Tasks: %" PRIu64, i->tasks_current);
 
                 if (i->tasks_max != (uint64_t) -1)
                         printf(" (limit: %" PRIu64 ")\n", i->tasks_max);
@@ -4479,7 +4537,7 @@ static void print_status_info(
         if (i->memory_current != (uint64_t) -1) {
                 char buf[FORMAT_BYTES_MAX];
 
-                printf("   Memory: %s", format_bytes(buf, sizeof(buf), i->memory_current));
+                printf("     Memory: %s", format_bytes(buf, sizeof(buf), i->memory_current));
 
                 if (i->memory_min > 0 || i->memory_low > 0 ||
                     i->memory_high != CGROUP_LIMIT_MAX || i->memory_max != CGROUP_LIMIT_MAX ||
@@ -4519,7 +4577,7 @@ static void print_status_info(
 
         if (i->cpu_usage_nsec != (uint64_t) -1) {
                 char buf[FORMAT_TIMESPAN_MAX];
-                printf("      CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
+                printf("        CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
         }
 
         if (i->control_group) {
@@ -4527,7 +4585,7 @@ static void print_status_info(
                 static const char prefix[] = "           ";
                 unsigned c;
 
-                printf("   CGroup: %s\n", i->control_group);
+                printf("     CGroup: %s\n", i->control_group);
 
                 c = columns();
                 if (c > sizeof(prefix) - 1)
@@ -5485,6 +5543,8 @@ static int show_one(
                 { "DropInPaths",                    "as",              NULL,           offsetof(UnitStatusInfo, dropin_paths)                      },
                 { "LoadError",                      "(ss)",            map_load_error, offsetof(UnitStatusInfo, load_error)                        },
                 { "Result",                         "s",               NULL,           offsetof(UnitStatusInfo, result)                            },
+                { "TriggeredBy",                    "as",              NULL,           offsetof(UnitStatusInfo, triggered_by)                      },
+                { "Triggers",                       "as",              NULL,           offsetof(UnitStatusInfo, triggers)                          },
                 { "InactiveExitTimestamp",          "t",               NULL,           offsetof(UnitStatusInfo, inactive_exit_timestamp)           },
                 { "InactiveExitTimestampMonotonic", "t",               NULL,           offsetof(UnitStatusInfo, inactive_exit_timestamp_monotonic) },
                 { "ActiveEnterTimestamp",           "t",               NULL,           offsetof(UnitStatusInfo, active_enter_timestamp)            },
@@ -5845,7 +5905,7 @@ static int show(int argc, char *argv[], void *userdata) {
                 if (!strv_isempty(patterns)) {
                         _cleanup_strv_free_ char **names = NULL;
 
-                        r = expand_names(bus, patterns, NULL, &names);
+                        r = expand_names(bus, patterns, NULL, &names, NULL);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to expand names: %m");
 
@@ -5895,7 +5955,7 @@ static int cat(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return r;
 
-        r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
+        r = expand_names(bus, strv_skip(argv, 1), NULL, &names, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to expand names: %m");
 
@@ -6126,7 +6186,7 @@ static int reset_failed(int argc, char *argv[], void *userdata) {
 
         polkit_agent_open_maybe();
 
-        r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
+        r = expand_names(bus, strv_skip(argv, 1), NULL, &names, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to expand names: %m");
 
@@ -6535,7 +6595,7 @@ static int enable_sysv_units(const char *verb, char **args) {
         return r;
 }
 
-static int mangle_names(char **original_names, char ***mangled_names) {
+static int mangle_names(const char *operation, char **original_names, char ***mangled_names) {
         char **i, **l, **name;
         int r;
 
@@ -6555,7 +6615,9 @@ static int mangle_names(char **original_names, char ***mangled_names) {
                                 return log_oom();
                         }
                 } else {
-                        r = unit_name_mangle(*name, arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, i);
+                        r = unit_name_mangle_with_suffix(*name, operation,
+                                                         arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
+                                                         ".service", i);
                         if (r < 0) {
                                 *i = NULL;
                                 strv_free(l);
@@ -6666,7 +6728,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
         if (!argv[1])
                 return 0;
 
-        r = mangle_names(strv_skip(argv, 1), &names);
+        r = mangle_names("to enable", strv_skip(argv, 1), &names);
         if (r < 0)
                 return r;
 
@@ -6893,11 +6955,13 @@ static int add_dependency(int argc, char *argv[], void *userdata) {
         if (!argv[1])
                 return 0;
 
-        r = unit_name_mangle_with_suffix(argv[1], arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, ".target", &target);
+        r = unit_name_mangle_with_suffix(argv[1], "as target",
+                                         arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
+                                         ".target", &target);
         if (r < 0)
                 return log_error_errno(r, "Failed to mangle unit name: %m");
 
-        r = mangle_names(strv_skip(argv, 2), &names);
+        r = mangle_names("as dependency", strv_skip(argv, 2), &names);
         if (r < 0)
                 return r;
 
@@ -7083,7 +7147,7 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) {
         char **name;
         int r;
 
-        r = mangle_names(strv_skip(argv, 1), &names);
+        r = mangle_names("to check", strv_skip(argv, 1), &names);
         if (r < 0)
                 return r;
 
@@ -7560,7 +7624,7 @@ static int edit(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return r;
 
-        r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
+        r = expand_names(bus, strv_skip(argv, 1), NULL, &names, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to expand names: %m");
 
@@ -7636,68 +7700,8 @@ static int systemctl_help(void) {
         if (r < 0)
                 return log_oom();
 
-        printf("%1$s [OPTIONS...] {COMMAND} ...\n\n"
-               "Query or send control commands to the systemd manager.\n\n"
-               "  -h --help           Show this help\n"
-               "     --version        Show package version\n"
-               "     --system         Connect to system manager\n"
-               "     --user           Connect to user service manager\n"
-               "  -H --host=[USER@]HOST\n"
-               "                      Operate on remote host\n"
-               "  -M --machine=CONTAINER\n"
-               "                      Operate on local container\n"
-               "  -t --type=TYPE      List units of a particular type\n"
-               "     --state=STATE    List units with particular LOAD or SUB or ACTIVE state\n"
-               "     --failed         Shorcut for --state=failed\n"
-               "  -p --property=NAME  Show only properties by this name\n"
-               "  -a --all            Show all properties/all units currently in memory,\n"
-               "                      including dead/empty ones. To list all units installed on\n"
-               "                      the system, use the 'list-unit-files' command instead.\n"
-               "  -l --full           Don't ellipsize unit names on output\n"
-               "  -r --recursive      Show unit list of host and local containers\n"
-               "     --reverse        Show reverse dependencies with 'list-dependencies'\n"
-               "     --job-mode=MODE  Specify how to deal with already queued jobs, when\n"
-               "                      queueing a new job\n"
-               "  -T --show-transaction\n"
-               "                      When enqueuing a unit job, show full transaction\n"
-               "     --show-types     When showing sockets, explicitly show their type\n"
-               "     --value          When showing properties, only print the value\n"
-               "  -i --ignore-inhibitors\n"
-               "                      When shutting down or sleeping, ignore inhibitors\n"
-               "     --kill-who=WHO   Who to send signal to\n"
-               "  -s --signal=SIGNAL  Which signal to send\n"
-               "     --what=RESOURCES Which types of resources to remove\n"
-               "     --now            Start or stop unit in addition to enabling or disabling it\n"
-               "     --dry-run        Only print what would be done\n"
-               "  -q --quiet          Suppress output\n"
-               "     --wait           For (re)start, wait until service stopped again\n"
-               "                      For is-system-running, wait until startup is completed\n"
-               "     --no-block       Do not wait until operation finished\n"
-               "     --no-wall        Don't send wall message before halt/power-off/reboot\n"
-               "     --no-reload      Don't reload daemon after en-/dis-abling unit files\n"
-               "     --no-legend      Do not print a legend (column headers and hints)\n"
-               "     --no-pager       Do not pipe output into a pager\n"
-               "     --no-ask-password\n"
-               "                      Do not ask for system passwords\n"
-               "     --global         Enable/disable/mask unit files globally\n"
-               "     --runtime        Enable/disable/mask unit files temporarily until next\n"
-               "                      reboot\n"
-               "  -f --force          When enabling unit files, override existing symlinks\n"
-               "                      When shutting down, execute action immediately\n"
-               "     --preset-mode=   Apply only enable, only disable, or all presets\n"
-               "     --root=PATH      Enable/disable/mask unit files in the specified root\n"
-               "                      directory\n"
-               "  -n --lines=INTEGER  Number of journal entries to show\n"
-               "  -o --output=STRING  Change journal output mode (short, short-precise,\n"
-               "                             short-iso, short-iso-precise, short-full,\n"
-               "                             short-monotonic, short-unix,\n"
-               "                             verbose, export, json, json-pretty, json-sse, cat)\n"
-               "     --firmware-setup Tell the firmware to show the setup menu on next boot\n"
-               "     --boot-loader-menu=TIME\n"
-               "                      Boot into boot loader menu on next boot\n"
-               "     --boot-loader-entry=NAME\n"
-               "                      Boot into a specific boot loader entry on next boot\n"
-               "     --plain          Print unit dependencies as a list instead of a tree\n\n"
+        printf("%5$s%1$s [OPTIONS...] {COMMAND} ...\n\n"
+               "Query or send control commands to the systemd manager.%6$s\n\n"
                "%3$sUnit Commands:%4$s\n"
                "  list-units [PATTERN...]             List units currently in memory\n"
                "  list-sockets [PATTERN...]           List socket units currently in memory,\n"
@@ -7782,10 +7786,72 @@ static int systemctl_help(void) {
                "  hybrid-sleep                        Hibernate and suspend the system\n"
                "  suspend-then-hibernate              Suspend the system, wake after a period of\n"
                "                                      time and put it into hibernate\n"
+               "\nOptions\n"
+               "  -h --help           Show this help\n"
+               "     --version        Show package version\n"
+               "     --system         Connect to system manager\n"
+               "     --user           Connect to user service manager\n"
+               "  -H --host=[USER@]HOST\n"
+               "                      Operate on remote host\n"
+               "  -M --machine=CONTAINER\n"
+               "                      Operate on local container\n"
+               "  -t --type=TYPE      List units of a particular type\n"
+               "     --state=STATE    List units with particular LOAD or SUB or ACTIVE state\n"
+               "     --failed         Shorcut for --state=failed\n"
+               "  -p --property=NAME  Show only properties by this name\n"
+               "  -a --all            Show all properties/all units currently in memory,\n"
+               "                      including dead/empty ones. To list all units installed on\n"
+               "                      the system, use the 'list-unit-files' command instead.\n"
+               "  -l --full           Don't ellipsize unit names on output\n"
+               "  -r --recursive      Show unit list of host and local containers\n"
+               "     --reverse        Show reverse dependencies with 'list-dependencies'\n"
+               "     --job-mode=MODE  Specify how to deal with already queued jobs, when\n"
+               "                      queueing a new job\n"
+               "  -T --show-transaction\n"
+               "                      When enqueuing a unit job, show full transaction\n"
+               "     --show-types     When showing sockets, explicitly show their type\n"
+               "     --value          When showing properties, only print the value\n"
+               "  -i --ignore-inhibitors\n"
+               "                      When shutting down or sleeping, ignore inhibitors\n"
+               "     --kill-who=WHO   Who to send signal to\n"
+               "  -s --signal=SIGNAL  Which signal to send\n"
+               "     --what=RESOURCES Which types of resources to remove\n"
+               "     --now            Start or stop unit in addition to enabling or disabling it\n"
+               "     --dry-run        Only print what would be done\n"
+               "  -q --quiet          Suppress output\n"
+               "     --wait           For (re)start, wait until service stopped again\n"
+               "                      For is-system-running, wait until startup is completed\n"
+               "     --no-block       Do not wait until operation finished\n"
+               "     --no-wall        Don't send wall message before halt/power-off/reboot\n"
+               "     --no-reload      Don't reload daemon after en-/dis-abling unit files\n"
+               "     --no-legend      Do not print a legend (column headers and hints)\n"
+               "     --no-pager       Do not pipe output into a pager\n"
+               "     --no-ask-password\n"
+               "                      Do not ask for system passwords\n"
+               "     --global         Enable/disable/mask unit files globally\n"
+               "     --runtime        Enable/disable/mask unit files temporarily until next\n"
+               "                      reboot\n"
+               "  -f --force          When enabling unit files, override existing symlinks\n"
+               "                      When shutting down, execute action immediately\n"
+               "     --preset-mode=   Apply only enable, only disable, or all presets\n"
+               "     --root=PATH      Enable/disable/mask unit files in the specified root\n"
+               "                      directory\n"
+               "  -n --lines=INTEGER  Number of journal entries to show\n"
+               "  -o --output=STRING  Change journal output mode (short, short-precise,\n"
+               "                             short-iso, short-iso-precise, short-full,\n"
+               "                             short-monotonic, short-unix,\n"
+               "                             verbose, export, json, json-pretty, json-sse, cat)\n"
+               "     --firmware-setup Tell the firmware to show the setup menu on next boot\n"
+               "     --boot-loader-menu=TIME\n"
+               "                      Boot into boot loader menu on next boot\n"
+               "     --boot-loader-entry=NAME\n"
+               "                      Boot into a specific boot loader entry on next boot\n"
+               "     --plain          Print unit dependencies as a list instead of a tree\n"
                "\nSee the %2$s for details.\n"
                , program_invocation_short_name
                , link
                , ansi_underline(), ansi_normal()
+               , ansi_highlight(), ansi_normal()
         );
 
         return 0;
@@ -7960,7 +8026,7 @@ static void help_states(void) {
 
 static int help_boot_loader_entry(void) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_free_ char **l = NULL;
+        _cleanup_strv_free_ char **l = NULL;
         sd_bus *bus;
         char **i;
         int r;