diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2023-02-23 21:38:13 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-02-23 21:38:13 +0900 |
commit | 500ecfd5130159b3b48b34e571b0c0220247bd78 (patch) | |
tree | 0c6de870698469d803ac06d7a76b00502d650c28 /src/systemctl | |
parent | e47c426b5cd99ca1b511958925cef63a47397545 (diff) | |
parent | 1b7b956a9be11b03271334df2db1a851aa543943 (diff) | |
download | systemd-500ecfd5130159b3b48b34e571b0c0220247bd78.tar.gz |
Merge pull request #26535 from yuwata/systemctl-list-cleanups
systemctl-list: several cleanups
Diffstat (limited to 'src/systemctl')
-rw-r--r-- | src/systemctl/systemctl-list-units.c | 584 | ||||
-rw-r--r-- | src/systemctl/systemctl-list-units.h | 2 |
2 files changed, 307 insertions, 279 deletions
diff --git a/src/systemctl/systemctl-list-units.c b/src/systemctl/systemctl-list-units.c index 193535e118..c52eaec554 100644 --- a/src/systemctl/systemctl-list-units.c +++ b/src/systemctl/systemctl-list-units.c @@ -22,18 +22,16 @@ static int get_unit_list_recursive( sd_bus *bus, char **patterns, UnitInfo **ret_unit_infos, - Set **ret_replies, - char ***ret_machines) { + Set **ret_replies) { _cleanup_free_ UnitInfo *unit_infos = NULL; _cleanup_(message_set_freep) Set *replies = NULL; - sd_bus_message *reply; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; int c, r; assert(bus); assert(ret_replies); assert(ret_unit_infos); - assert(ret_machines); replies = set_new(NULL); if (!replies) @@ -44,10 +42,9 @@ static int get_unit_list_recursive( return c; r = set_put(replies, reply); - if (r < 0) { - sd_bus_message_unref(reply); + if (r < 0) return log_oom(); - } + TAKE_PTR(reply); if (arg_recursive) { _cleanup_strv_free_ char **machines = NULL; @@ -73,15 +70,11 @@ static int get_unit_list_recursive( c = k; r = set_put(replies, reply); - if (r < 0) { - sd_bus_message_unref(reply); + if (r < 0) return log_oom(); - } + TAKE_PTR(reply); } - - *ret_machines = TAKE_PTR(machines); - } else - *ret_machines = NULL; + } *ret_unit_infos = TAKE_PTR(unit_infos); *ret_replies = TAKE_PTR(replies); @@ -239,7 +232,6 @@ static int output_units_list(const UnitInfo *unit_infos, size_t c) { int verb_list_units(int argc, char *argv[], void *userdata) { _cleanup_free_ UnitInfo *unit_infos = NULL; _cleanup_(message_set_freep) Set *replies = NULL; - _cleanup_strv_free_ char **machines = NULL; sd_bus *bus; int r; @@ -256,11 +248,11 @@ int verb_list_units(int argc, char *argv[], void *userdata) { if (r < 0) return r; - r = get_unit_list_recursive(bus, names, &unit_infos, &replies, &machines); + r = get_unit_list_recursive(bus, names, &unit_infos, &replies); if (r < 0) return r; } else { - r = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines); + r = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies); if (r < 0) return r; } @@ -295,20 +287,79 @@ static int get_triggered_units( return 0; } -static int get_listening( +typedef struct SocketInfo { + const char *machine; + const char* id; + + char* type; + char* path; /* absolute path or socket address */ + + /* Note: triggered is a list here, although it almost certainly will always be one + * unit. Nevertheless, dbus API allows for multiple values, so let's follow that. */ + char** triggered; +} SocketInfo; + +static void socket_info_array_free(SocketInfo *sockets, size_t n_sockets) { + assert(sockets || n_sockets == 0); + + for (SocketInfo *s = sockets; s < sockets + n_sockets; s++) { + free(s->type); + free(s->path); + strv_free(s->triggered); + } + + free(sockets); +} + +static int socket_info_compare(const SocketInfo *a, const SocketInfo *b) { + int r; + + assert(a); + assert(b); + + r = strcasecmp_ptr(a->machine, b->machine); + if (r != 0) + return r; + + r = CMP(path_is_absolute(a->path), path_is_absolute(b->path)); + if (r != 0) + return r; + + r = path_is_absolute(a->path) ? path_compare(a->path, b->path) : strcmp(a->path, b->path); + if (r != 0) + return r; + + return strcmp(a->type, b->type); +} + +static int socket_info_add( sd_bus *bus, - const char* unit_path, - char*** listening) { + const UnitInfo *u, + SocketInfo **sockets, + size_t *n_sockets) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_strv_free_ char **triggered = NULL; const char *type, *path; - int r, n = 0; + int r; + + assert(bus); + assert(u); + assert(sockets); + assert(n_sockets); + + if (!endswith(u->id, ".socket")) + return 0; + + r = get_triggered_units(bus, u->unit_path, &triggered); + if (r < 0) + return r; r = sd_bus_get_property( bus, "org.freedesktop.systemd1", - unit_path, + u->unit_path, "org.freedesktop.systemd1.Socket", "Listen", &error, @@ -322,16 +373,31 @@ static int get_listening( return bus_log_parse_error(r); while ((r = sd_bus_message_read(reply, "(ss)", &type, &path)) > 0) { + _cleanup_free_ char *type_dup = NULL, *path_dup = NULL; + _cleanup_strv_free_ char **triggered_dup = NULL; - r = strv_extend(listening, type); - if (r < 0) + type_dup = strdup(type); + if (!type_dup) return log_oom(); - r = strv_extend(listening, path); - if (r < 0) + path_dup = strdup(path); + if (!path_dup) + return log_oom(); + + triggered_dup = strv_copy(triggered); + if (!triggered_dup) return log_oom(); - n++; + if (!GREEDY_REALLOC(*sockets, *n_sockets + 1)) + return log_oom(); + + (*sockets)[(*n_sockets)++] = (SocketInfo) { + .machine = u->machine, + .id = u->id, + .type = TAKE_PTR(type_dup), + .path = TAKE_PTR(path_dup), + .triggered = TAKE_PTR(triggered_dup), + }; } if (r < 0) return bus_log_parse_error(r); @@ -340,46 +406,14 @@ static int get_listening( if (r < 0) return bus_log_parse_error(r); - return n; -} - -struct socket_info { - const char *machine; - const char* id; - - char* type; - char* path; - - /* Note: triggered is a list here, although it almost certainly will always be one - * unit. Nevertheless, dbus API allows for multiple values, so let's follow that. */ - char** triggered; - - /* The strv above is shared. free is set only in the first one. */ - bool own_triggered; -}; - -static int socket_info_compare(const struct socket_info *a, const struct socket_info *b) { - int r; - - assert(a); - assert(b); - - r = strcasecmp_ptr(a->machine, b->machine); - if (r != 0) - return r; - - r = strcmp(a->path, b->path); - if (r != 0) - return r; - - return strcmp(a->type, b->type); + return 0; } -static int output_sockets_list(struct socket_info *socket_infos, size_t cs) { +static int output_sockets_list(const SocketInfo *sockets, size_t n_sockets) { _cleanup_(table_unrefp) Table *table = NULL; int r; - assert(socket_infos || cs == 0); + assert(sockets || n_sockets == 0); table = table_new("listen", "type", "unit", "activates"); if (!table) @@ -398,7 +432,7 @@ static int output_sockets_list(struct socket_info *socket_infos, size_t cs) { table_set_ersatz_string(table, TABLE_ERSATZ_DASH); - for (struct socket_info *s = socket_infos; s < socket_infos + cs; s++) { + for (const SocketInfo *s = sockets; s < sockets + n_sockets; s++) { _cleanup_free_ char *unit = NULL; unit = format_unit_id(s->id, s->machine); @@ -406,9 +440,9 @@ static int output_sockets_list(struct socket_info *socket_infos, size_t cs) { return log_oom(); r = table_add_many(table, - TABLE_STRING, s->path, - TABLE_STRING, s->type, - TABLE_STRING, unit); + TABLE_STRING, s->path, + TABLE_STRING, s->type, + TABLE_STRING, unit); if (r < 0) return table_log_add_error(r); @@ -422,20 +456,21 @@ static int output_sockets_list(struct socket_info *socket_infos, size_t cs) { return r; if (arg_legend != 0) - output_legend("socket", cs); + output_legend("socket", n_sockets); return 0; } int verb_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; - size_t cs = 0; - int r, n; + SocketInfo *sockets = NULL; + size_t n_sockets = 0; sd_bus *bus; + int r; + + CLEANUP_ARRAY(sockets, n_sockets, socket_info_array_free); r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) @@ -448,63 +483,23 @@ int verb_list_sockets(int argc, char *argv[], void *userdata) { return r; if (argc == 1 || sockets_with_suffix) { - n = get_unit_list_recursive(bus, sockets_with_suffix, &unit_infos, &replies, &machines); + int n; + + n = get_unit_list_recursive(bus, sockets_with_suffix, &unit_infos, &replies); if (n < 0) return n; for (const UnitInfo *u = unit_infos; u < unit_infos + n; u++) { - _cleanup_strv_free_ char **listening = NULL, **triggered = NULL; - int c; - - if (!endswith(u->id, ".socket")) - continue; - - r = get_triggered_units(bus, u->unit_path, &triggered); + r = socket_info_add(bus, u, &sockets, &n_sockets); if (r < 0) - goto cleanup; - - c = get_listening(bus, u->unit_path, &listening); - if (c < 0) { - r = c; - goto cleanup; - } - - if (!GREEDY_REALLOC(socket_infos, cs + c)) { - r = log_oom(); - goto cleanup; - } - - for (int 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 */ + return r; } - - typesafe_qsort(socket_infos, cs, socket_info_compare); } - output_sockets_list(socket_infos, cs); - - cleanup: - assert(cs == 0 || socket_infos); - for (struct socket_info *s = socket_infos; s < socket_infos + cs; s++) { - free(s->type); - free(s->path); - if (s->own_triggered) - strv_free(s->triggered); - } + typesafe_qsort(sockets, n_sockets, socket_info_compare); + output_sockets_list(sockets, n_sockets); - return r; + return 0; } static int get_next_elapse( @@ -575,15 +570,24 @@ static int get_last_trigger( return 0; } -struct timer_info { +typedef struct TimerInfo { const char* machine; const char* id; usec_t next_elapse; usec_t last_trigger; - char** triggered; -}; + char **triggered; +} TimerInfo; + +static void timer_info_array_free(TimerInfo *timers, size_t n_timers) { + assert(timers || n_timers == 0); + + for (TimerInfo *t = timers; t < timers + n_timers; t++) + strv_free(t->triggered); + + free(timers); +} -static int timer_info_compare(const struct timer_info *a, const struct timer_info *b) { +static int timer_info_compare(const TimerInfo *a, const TimerInfo *b) { int r; assert(a); @@ -600,11 +604,11 @@ static int timer_info_compare(const struct timer_info *a, const struct timer_inf return strcmp(a->id, b->id); } -static int output_timers_list(struct timer_info *timer_infos, size_t n) { +static int output_timers_list(const TimerInfo *timers, size_t n_timers) { _cleanup_(table_unrefp) Table *table = NULL; int r; - assert(timer_infos || n == 0); + assert(timers || n_timers == 0); table = table_new("next", "left", "last", "passed", "unit", "activates"); if (!table) @@ -619,7 +623,7 @@ static int output_timers_list(struct timer_info *timer_infos, size_t n) { (void) table_set_align_percent(table, table_get_cell(table, 0, 1), 100); (void) table_set_align_percent(table, table_get_cell(table, 0, 3), 100); - for (struct timer_info *t = timer_infos; t < timer_infos + n; t++) { + for (const TimerInfo *t = timers; t < timers + n_timers; t++) { _cleanup_free_ char *unit = NULL; unit = format_unit_id(t->id, t->machine); @@ -645,12 +649,12 @@ static int output_timers_list(struct timer_info *timer_infos, size_t n) { return r; if (arg_legend != 0) - output_legend("timer", n); + output_legend("timer", n_timers); return 0; } -usec_t calc_next_elapse(dual_timestamp *nw, dual_timestamp *next) { +usec_t calc_next_elapse(const dual_timestamp *nw, const dual_timestamp *next) { usec_t next_elapse; assert(nw); @@ -675,16 +679,65 @@ usec_t calc_next_elapse(dual_timestamp *nw, dual_timestamp *next) { return next_elapse; } +static int add_timer_info( + sd_bus *bus, + const UnitInfo *u, + const dual_timestamp *nw, + TimerInfo **timers, + size_t *n_timers) { + + _cleanup_strv_free_ char **triggered = NULL; + dual_timestamp next = DUAL_TIMESTAMP_NULL; + usec_t m, last = 0; + int r; + + assert(bus); + assert(u); + assert(nw); + assert(timers); + assert(n_timers); + + if (!endswith(u->id, ".timer")) + return 0; + + r = get_triggered_units(bus, u->unit_path, &triggered); + if (r < 0) + return r; + + r = get_next_elapse(bus, u->unit_path, &next); + if (r < 0) + return r; + + r = get_last_trigger(bus, u->unit_path, &last); + if (r < 0) + return r; + + m = calc_next_elapse(nw, &next); + + if (!GREEDY_REALLOC(*timers, *n_timers + 1)) + return log_oom(); + + (*timers)[(*n_timers)++] = (TimerInfo) { + .machine = u->machine, + .id = u->id, + .next_elapse = m, + .last_trigger = last, + .triggered = TAKE_PTR(triggered), + }; + + return 0; +} + int verb_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; - dual_timestamp nw; - size_t c = 0; + TimerInfo *timers = NULL; + size_t n_timers = 0; sd_bus *bus; - int n, r; + int r; + + CLEANUP_ARRAY(timers, n_timers, timer_info_array_free); r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) @@ -697,68 +750,49 @@ int verb_list_timers(int argc, char *argv[], void *userdata) { return r; if (argc == 1 || timers_with_suffix) { - n = get_unit_list_recursive(bus, timers_with_suffix, &unit_infos, &replies, &machines); + dual_timestamp nw; + int n; + + n = get_unit_list_recursive(bus, timers_with_suffix, &unit_infos, &replies); if (n < 0) return n; dual_timestamp_get(&nw); for (const UnitInfo *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; - - if (!endswith(u->id, ".timer")) - continue; - - r = get_triggered_units(bus, u->unit_path, &triggered); + r = add_timer_info(bus, u, &nw, &timers, &n_timers); if (r < 0) - goto cleanup; - - r = get_next_elapse(bus, u->unit_path, &next); - if (r < 0) - goto cleanup; - - get_last_trigger(bus, u->unit_path, &last); - - if (!GREEDY_REALLOC(timer_infos, c+1)) { - r = log_oom(); - goto cleanup; - } - - 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), - }; + return r; } - - typesafe_qsort(timer_infos, c, timer_info_compare); } - output_timers_list(timer_infos, c); - - cleanup: - for (struct timer_info *t = timer_infos; t < timer_infos + c; t++) - strv_free(t->triggered); + typesafe_qsort(timers, n_timers, timer_info_compare); + output_timers_list(timers, n_timers); - return r; + return 0; } -struct automount_info { +typedef struct AutomountInfo { const char *machine; const char *id; char *what; char *where; usec_t timeout_idle_usec; bool mounted; -}; +} AutomountInfo; + +static void automount_info_array_free(AutomountInfo *automounts, size_t n_automounts) { + assert(automounts || n_automounts == 0); -static int automount_info_compare(const struct automount_info *a, const struct automount_info *b) { + for (AutomountInfo *i = automounts; i < automounts + n_automounts; i++) { + free(i->what); + free(i->where); + } + + free(automounts); +} + +static int automount_info_compare(const AutomountInfo *a, const AutomountInfo *b) { int r; assert(a); @@ -768,10 +802,15 @@ static int automount_info_compare(const struct automount_info *a, const struct a if (r != 0) return r; - return strcmp(a->where, b->where); + return path_compare(a->where, b->where); } -static int collect_automount_info(sd_bus* bus, const UnitInfo* info, struct automount_info *ret_info) { +static int automount_info_add( + sd_bus* bus, + const UnitInfo *info, + AutomountInfo **automounts, + size_t *n_automounts) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_free_ char *mount = NULL, *mount_path = NULL, *where = NULL, *what = NULL, *state = NULL; uint64_t timeout_idle_usec; @@ -780,7 +819,11 @@ static int collect_automount_info(sd_bus* bus, const UnitInfo* info, struct auto assert(bus); assert(info); - assert(ret_info); + assert(automounts); + assert(n_automounts); + + if (!endswith(info->id, ".automount")) + return 0; locator = (BusLocator) { .destination = "org.freedesktop.systemd1", @@ -817,7 +860,10 @@ static int collect_automount_info(sd_bus* bus, const UnitInfo* info, struct auto if (r < 0) return log_error_errno(r, "Failed to get mount state: %s", bus_error_message(&error, r)); - *ret_info = (struct automount_info) { + if (!GREEDY_REALLOC(*automounts, *n_automounts + 1)) + return log_oom(); + + (*automounts)[(*n_automounts)++] = (AutomountInfo) { .machine = info->machine, .id = info->id, .what = TAKE_PTR(what), @@ -829,7 +875,7 @@ static int collect_automount_info(sd_bus* bus, const UnitInfo* info, struct auto return 0; } -static int output_automounts_list(struct automount_info *infos, size_t n_infos) { +static int output_automounts_list(const AutomountInfo *infos, size_t n_infos) { _cleanup_(table_unrefp) Table *table = NULL; int r; @@ -845,7 +891,7 @@ static int output_automounts_list(struct automount_info *infos, size_t n_infos) table_set_ersatz_string(table, TABLE_ERSATZ_DASH); - for (struct automount_info *info = infos; info < infos + n_infos; info++) { + for (const AutomountInfo *info = infos; info < infos + n_infos; info++) { _cleanup_free_ char *unit = NULL; unit = format_unit_id(info->id, info->machine); @@ -883,12 +929,14 @@ static int output_automounts_list(struct automount_info *infos, size_t n_infos) int verb_list_automounts(int argc, char *argv[], void *userdata) { _cleanup_(message_set_freep) Set *replies = NULL; - _cleanup_strv_free_ char **machines = NULL, **automounts = NULL; + _cleanup_strv_free_ char **names = NULL; _cleanup_free_ UnitInfo *unit_infos = NULL; - _cleanup_free_ struct automount_info *automount_infos = NULL; - size_t c = 0; - int r, n; + AutomountInfo *automounts = NULL; + size_t n_automounts = 0; sd_bus *bus; + int r; + + CLEANUP_ARRAY(automounts, n_automounts, automount_info_array_free); r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) @@ -896,47 +944,32 @@ int verb_list_automounts(int argc, char *argv[], void *userdata) { pager_open(arg_pager_flags); - r = expand_unit_names(bus, strv_skip(argv, 1), ".automount", &automounts, NULL); + r = expand_unit_names(bus, strv_skip(argv, 1), ".automount", &names, NULL); if (r < 0) return r; if (argc == 1 || automounts) { - n = get_unit_list_recursive(bus, automounts, &unit_infos, &replies, &machines); + int n; + + n = get_unit_list_recursive(bus, names, &unit_infos, &replies); if (n < 0) return n; for (const UnitInfo *u = unit_infos; u < unit_infos + n; u++) { - if (!endswith(u->id, ".automount")) - continue; - - if (!GREEDY_REALLOC(automount_infos, c + 1)) { - r = log_oom(); - goto cleanup; - } - - r = collect_automount_info(bus, u, &automount_infos[c]); + r = automount_info_add(bus, u, &automounts, &n_automounts); if (r < 0) - goto cleanup; - - c++; + return r; } - typesafe_qsort(automount_infos, c, automount_info_compare); } - output_automounts_list(automount_infos, c); - - cleanup: - assert(c == 0 || automount_infos); - for (struct automount_info *info = automount_infos; info < automount_infos + c; info++) { - free(info->what); - free(info->where); - } + typesafe_qsort(automounts, n_automounts, automount_info_compare); + output_automounts_list(automounts, n_automounts); - return r; + return 0; } -struct path_info { +typedef struct PathInfo { const char *machine; const char *id; @@ -946,14 +979,9 @@ struct path_info { /* Note: triggered is a list here, although it almost certainly will always be one * unit. Nevertheless, dbus API allows for multiple values, so let's follow that. */ char** triggered; -}; - -struct path_infos { - size_t count; - struct path_info *items; -}; +} PathInfo; -static int path_info_compare(const struct path_info *a, const struct path_info *b) { +static int path_info_compare(const PathInfo *a, const PathInfo *b) { int r; assert(a); @@ -974,34 +1002,45 @@ static int path_info_compare(const struct path_info *a, const struct path_info * return strcasecmp_ptr(a->id, b->id); } -static void path_infos_done(struct path_infos *ps) { - assert(ps); - assert(ps->items || ps->count == 0); +static void path_info_array_free(PathInfo *paths, size_t n_paths) { + assert(paths || n_paths == 0); - for (struct path_info *p = ps->items; p < ps->items + ps->count; p++) { + for (PathInfo *p = paths; p < paths + n_paths; p++) { free(p->condition); free(p->path); strv_free(p->triggered); } - free(ps->items); + free(paths); } -static int get_paths(sd_bus *bus, const char *unit_path, char ***ret_conditions, char ***ret_paths) { +static int path_info_add( + sd_bus *bus, + const struct UnitInfo *u, + PathInfo **paths, + size_t *n_paths) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_strv_free_ char **conditions = NULL, **paths = NULL; + _cleanup_strv_free_ char **triggered = NULL; const char *condition, *path; - int r, n = 0; + int r; assert(bus); - assert(unit_path); - assert(ret_conditions); - assert(ret_paths); + assert(u); + assert(paths); + assert(n_paths); + + if (!endswith(u->id, ".path")) + return 0; + + r = get_triggered_units(bus, u->unit_path, &triggered); + if (r < 0) + return r; r = sd_bus_get_property(bus, "org.freedesktop.systemd1", - unit_path, + u->unit_path, "org.freedesktop.systemd1.Path", "Paths", &error, @@ -1015,13 +1054,31 @@ static int get_paths(sd_bus *bus, const char *unit_path, char ***ret_conditions, return bus_log_parse_error(r); while ((r = sd_bus_message_read(reply, "(ss)", &condition, &path)) > 0) { - if (strv_extend(&conditions, condition) < 0) + _cleanup_free_ char *condition_dup = NULL, *path_dup = NULL; + _cleanup_strv_free_ char **triggered_dup = NULL; + + condition_dup = strdup(condition); + if (!condition_dup) + return log_oom(); + + path_dup = strdup(path); + if (!path_dup) return log_oom(); - if (strv_extend(&paths, path) < 0) + triggered_dup = strv_copy(triggered); + if (!triggered_dup) return log_oom(); - n++; + if (!GREEDY_REALLOC(*paths, *n_paths + 1)) + return log_oom(); + + (*paths)[(*n_paths)++] = (PathInfo) { + .machine = u->machine, + .id = u->id, + .condition = TAKE_PTR(condition_dup), + .path = TAKE_PTR(path_dup), + .triggered = TAKE_PTR(triggered_dup), + }; } if (r < 0) return bus_log_parse_error(r); @@ -1030,18 +1087,14 @@ static int get_paths(sd_bus *bus, const char *unit_path, char ***ret_conditions, if (r < 0) return bus_log_parse_error(r); - *ret_conditions = TAKE_PTR(conditions); - *ret_paths = TAKE_PTR(paths); - - return n; + return 0; } -static int output_paths_list(struct path_infos *ps) { +static int output_paths_list(const PathInfo *paths, size_t n_paths) { _cleanup_(table_unrefp) Table *table = NULL; int r; - assert(ps); - assert(ps->items || ps->count == 0); + assert(paths || n_paths == 0); table = table_new("path", "condition", "unit", "activates"); if (!table) @@ -1053,7 +1106,7 @@ static int output_paths_list(struct path_infos *ps) { table_set_ersatz_string(table, TABLE_ERSATZ_DASH); - for (struct path_info *p = ps->items; p < ps->items + ps->count; p++) { + for (const PathInfo *p = paths; p < paths + n_paths; p++) { _cleanup_free_ char *unit = NULL; unit = format_unit_id(p->id, p->machine); @@ -1077,18 +1130,21 @@ static int output_paths_list(struct path_infos *ps) { return r; if (arg_legend != 0) - output_legend("path", ps->count); + output_legend("path", n_paths); return 0; } int verb_list_paths(int argc, char *argv[], void *userdata) { _cleanup_(message_set_freep) Set *replies = NULL; - _cleanup_strv_free_ char **machines = NULL, **units = NULL; + _cleanup_strv_free_ char **units = NULL; _cleanup_free_ UnitInfo *unit_infos = NULL; - _cleanup_(path_infos_done) struct path_infos path_infos = {}; - int r, n; + PathInfo *paths = NULL; + size_t n_paths = 0; sd_bus *bus; + int r; + + CLEANUP_ARRAY(paths, n_paths, path_info_array_free); r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) @@ -1101,49 +1157,21 @@ int verb_list_paths(int argc, char *argv[], void *userdata) { return r; if (argc == 1 || units) { - n = get_unit_list_recursive(bus, units, &unit_infos, &replies, &machines); + int n; + + n = get_unit_list_recursive(bus, units, &unit_infos, &replies); if (n < 0) return n; for (const UnitInfo *u = unit_infos; u < unit_infos + n; u++) { - _cleanup_strv_free_ char **conditions = NULL, **paths = NULL, **triggered = NULL; - int c; - - if (!endswith(u->id, ".path")) - continue; - - r = get_triggered_units(bus, u->unit_path, &triggered); + r = path_info_add(bus, u, &paths, &n_paths); if (r < 0) return r; - - c = get_paths(bus, u->unit_path, &conditions, &paths); - if (c < 0) - return c; - - if (!GREEDY_REALLOC(path_infos.items, path_infos.count + c)) - return log_oom(); - - for (int i = c - 1; i >= 0; i--) { - char **t; - - t = strv_copy(triggered); - if (!t) - return log_oom(); - - path_infos.items[path_infos.count++] = (struct path_info) { - .machine = u->machine, - .id = u->id, - .condition = TAKE_PTR(conditions[i]), - .path = TAKE_PTR(paths[i]), - .triggered = t, - }; - } } - - typesafe_qsort(path_infos.items, path_infos.count, path_info_compare); } - output_paths_list(&path_infos); + typesafe_qsort(paths, n_paths, path_info_compare); + output_paths_list(paths, n_paths); return 0; } diff --git a/src/systemctl/systemctl-list-units.h b/src/systemctl/systemctl-list-units.h index f7353d037e..cb190545e3 100644 --- a/src/systemctl/systemctl-list-units.h +++ b/src/systemctl/systemctl-list-units.h @@ -7,4 +7,4 @@ int verb_list_timers(int argc, char *argv[], void *userdata); int verb_list_automounts(int argc, char *argv[], void *userdata); int verb_list_paths(int argc, char *argv[], void *userdata); -usec_t calc_next_elapse(dual_timestamp *nw, dual_timestamp *next); +usec_t calc_next_elapse(const dual_timestamp *nw, const dual_timestamp *next); |