Systemd/src/systemctl/systemctl-list-unit-files.c
Lennart Poettering daf71ef61c systemctl: split up humungous systemctl.c file
This is just some refactoring: shifting around of code, not change in
codeflow.

This splits up the way too huge systemctl.c in multiple more easily
digestable files. It roughly follows the rule that each family of verbs
gets its own .c/.h file pair, and so do all the compat executable names
we support. Plus three extra files for sysv compat (which existed before
already, but I renamed slightly, to get the systemctl- prefix lik
everything else), a -util file with generic stuff everything uses, and a
-logind file with everything that talks directly to logind instead of
PID1.

systemctl is still a bit too complex for my taste, but I think this way
itc omes in a more digestable bits at least.

No change of behaviour, just reshuffling of some code.
2020-10-07 23:12:15 +02:00

276 lines
10 KiB
C

/* SPDX-License-Identifier: LGPL-2.1+ */
#include "bus-error.h"
#include "bus-locator.h"
#include "sort-util.h"
#include "systemctl-list-unit-files.h"
#include "systemctl-util.h"
#include "systemctl.h"
#include "terminal-util.h"
static int compare_unit_file_list(const UnitFileList *a, const UnitFileList *b) {
const char *d1, *d2;
d1 = strrchr(a->path, '.');
d2 = strrchr(b->path, '.');
if (d1 && d2) {
int r;
r = strcasecmp(d1, d2);
if (r != 0)
return r;
}
return strcasecmp(basename(a->path), basename(b->path));
}
static bool output_show_unit_file(const UnitFileList *u, char **states, char **patterns) {
assert(u);
if (!strv_fnmatch_or_empty(patterns, basename(u->path), FNM_NOESCAPE))
return false;
if (!strv_isempty(arg_types)) {
const char *dot;
dot = strrchr(u->path, '.');
if (!dot)
return false;
if (!strv_find(arg_types, dot+1))
return false;
}
if (!strv_isempty(states) &&
!strv_find(states, unit_file_state_to_string(u->state)))
return false;
return true;
}
static int output_unit_file_list(const UnitFileList *units, unsigned c) {
_cleanup_(table_unrefp) Table *table = NULL;
_cleanup_(unit_file_presets_freep) UnitFilePresets presets = {};
int r;
table = table_new("unit file", "state", "vendor preset");
if (!table)
return log_oom();
table_set_header(table, !arg_no_legend);
if (arg_full)
table_set_width(table, 0);
(void) table_set_empty_string(table, "-");
for (const UnitFileList *u = units; u < units + c; u++) {
const char *on_underline = NULL, *on_unit_color = NULL, *id;
bool underline;
underline = u + 1 < units + c &&
!streq(unit_type_suffix(u->path), unit_type_suffix((u + 1)->path));
if (underline)
on_underline = ansi_underline();
if (IN_SET(u->state,
UNIT_FILE_MASKED,
UNIT_FILE_MASKED_RUNTIME,
UNIT_FILE_DISABLED,
UNIT_FILE_BAD))
on_unit_color = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
else if (IN_SET(u->state,
UNIT_FILE_ENABLED,
UNIT_FILE_ALIAS))
on_unit_color = underline ? ansi_highlight_green_underline() : ansi_highlight_green();
else
on_unit_color = on_underline;
id = basename(u->path);
r = table_add_many(table,
TABLE_STRING, id,
TABLE_SET_BOTH_COLORS, strempty(on_underline),
TABLE_STRING, unit_file_state_to_string(u->state),
TABLE_SET_BOTH_COLORS, strempty(on_unit_color));
if (r < 0)
return table_log_add_error(r);
if (show_preset_for_state(u->state)) {
const char *unit_preset_str, *on_preset_color;
r = unit_file_query_preset(arg_scope, arg_root, id, &presets);
if (r < 0) {
unit_preset_str = "n/a";
on_preset_color = underline ? on_underline : ansi_normal();
} else if (r == 0) {
unit_preset_str = "disabled";
on_preset_color = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
} else {
unit_preset_str = "enabled";
on_preset_color = underline ? ansi_highlight_green_underline() : ansi_highlight_green();
}
r = table_add_many(table,
TABLE_STRING, unit_preset_str,
TABLE_SET_BOTH_COLORS, strempty(on_preset_color));
} else
r = table_add_many(table,
TABLE_EMPTY,
TABLE_SET_BOTH_COLORS, underline ? ansi_grey_underline() : ansi_grey());
if (r < 0)
return table_log_add_error(r);
}
r = output_table(table);
if (r < 0)
return r;
if (!arg_no_legend)
printf("\n%u unit files listed.\n", c);
return 0;
}
int list_unit_files(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_free_ UnitFileList *units = NULL;
UnitFileList *unit;
size_t size = 0;
unsigned c = 0;
const char *state;
char *path;
int r;
bool fallback = false;
if (install_client_side()) {
Hashmap *h;
UnitFileList *u;
unsigned n_units;
h = hashmap_new(&string_hash_ops);
if (!h)
return log_oom();
r = unit_file_get_list(arg_scope, arg_root, h, arg_states, strv_skip(argv, 1));
if (r < 0) {
unit_file_list_free(h);
return log_error_errno(r, "Failed to get unit file list: %m");
}
n_units = hashmap_size(h);
units = new(UnitFileList, n_units ?: 1); /* avoid malloc(0) */
if (!units) {
unit_file_list_free(h);
return log_oom();
}
HASHMAP_FOREACH(u, h) {
if (!output_show_unit_file(u, NULL, NULL))
continue;
units[c++] = *u;
free(u);
}
assert(c <= n_units);
hashmap_free(h);
r = 0;
} else {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus;
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "ListUnitFilesByPatterns");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append_strv(m, arg_states);
if (r < 0)
return bus_log_create_error(r);
if (arg_with_dependencies) {
_cleanup_strv_free_ char **names_with_deps = NULL;
r = append_unit_dependencies(bus, strv_skip(argv, 1), &names_with_deps);
if (r < 0)
return log_error_errno(r, "Failed to append unit dependencies: %m");
r = sd_bus_message_append_strv(m, names_with_deps);
if (r < 0)
return bus_log_create_error(r);
} else {
r = sd_bus_message_append_strv(m, strv_skip(argv, 1));
if (r < 0)
return bus_log_create_error(r);
}
r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0 && sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
/* Fallback to legacy ListUnitFiles method */
fallback = true;
log_debug_errno(r, "Failed to list unit files: %s Falling back to ListUnitsFiles method.", bus_error_message(&error, r));
m = sd_bus_message_unref(m);
sd_bus_error_free(&error);
r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "ListUnitFiles");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_call(bus, m, 0, &error, &reply);
}
if (r < 0)
return log_error_errno(r, "Failed to list unit files: %s", bus_error_message(&error, r));
r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ss)");
if (r < 0)
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(reply, "(ss)", &path, &state)) > 0) {
if (!GREEDY_REALLOC(units, size, c + 1))
return log_oom();
units[c] = (struct UnitFileList) {
path,
unit_file_state_from_string(state)
};
if (output_show_unit_file(&units[c],
fallback ? arg_states : NULL,
fallback ? strv_skip(argv, 1) : NULL))
c++;
}
if (r < 0)
return bus_log_parse_error(r);
r = sd_bus_message_exit_container(reply);
if (r < 0)
return bus_log_parse_error(r);
}
(void) pager_open(arg_pager_flags);
typesafe_qsort(units, c, compare_unit_file_list);
r = output_unit_file_list(units, c);
if (r < 0)
return r;
if (install_client_side())
for (unit = units; unit < units + c; unit++)
free(unit->path);
if (c == 0)
return -ENOENT;
return 0;
}