daf71ef61c
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.
175 lines
5.4 KiB
C
175 lines
5.4 KiB
C
/* SPDX-License-Identifier: LGPL-2.1+ */
|
|
|
|
#include "locale-util.h"
|
|
#include "sort-util.h"
|
|
#include "special.h"
|
|
#include "systemctl-list-dependencies.h"
|
|
#include "systemctl-util.h"
|
|
#include "systemctl.h"
|
|
#include "terminal-util.h"
|
|
|
|
static int list_dependencies_print(const char *name, int level, unsigned branches, bool last) {
|
|
_cleanup_free_ char *n = NULL;
|
|
size_t max_len = MAX(columns(),20u);
|
|
size_t len = 0;
|
|
int i;
|
|
|
|
if (!arg_plain) {
|
|
|
|
for (i = level - 1; i >= 0; i--) {
|
|
len += 2;
|
|
if (len > max_len - 3 && !arg_full) {
|
|
printf("%s...\n",max_len % 2 ? "" : " ");
|
|
return 0;
|
|
}
|
|
printf("%s", special_glyph(branches & (1 << i) ? SPECIAL_GLYPH_TREE_VERTICAL : SPECIAL_GLYPH_TREE_SPACE));
|
|
}
|
|
len += 2;
|
|
|
|
if (len > max_len - 3 && !arg_full) {
|
|
printf("%s...\n",max_len % 2 ? "" : " ");
|
|
return 0;
|
|
}
|
|
|
|
printf("%s", special_glyph(last ? SPECIAL_GLYPH_TREE_RIGHT : SPECIAL_GLYPH_TREE_BRANCH));
|
|
}
|
|
|
|
if (arg_full) {
|
|
printf("%s\n", name);
|
|
return 0;
|
|
}
|
|
|
|
n = ellipsize(name, max_len-len, 100);
|
|
if (!n)
|
|
return log_oom();
|
|
|
|
printf("%s\n", n);
|
|
return 0;
|
|
}
|
|
|
|
static int list_dependencies_compare(char * const *a, char * const *b) {
|
|
if (unit_name_to_type(*a) == UNIT_TARGET && unit_name_to_type(*b) != UNIT_TARGET)
|
|
return 1;
|
|
if (unit_name_to_type(*a) != UNIT_TARGET && unit_name_to_type(*b) == UNIT_TARGET)
|
|
return -1;
|
|
|
|
return strcasecmp(*a, *b);
|
|
}
|
|
|
|
static int list_dependencies_one(
|
|
sd_bus *bus,
|
|
const char *name,
|
|
int level,
|
|
char ***units,
|
|
unsigned branches) {
|
|
|
|
_cleanup_strv_free_ char **deps = NULL;
|
|
char **c;
|
|
int r;
|
|
|
|
assert(bus);
|
|
assert(name);
|
|
assert(units);
|
|
|
|
r = strv_extend(units, name);
|
|
if (r < 0)
|
|
return log_oom();
|
|
|
|
r = unit_get_dependencies(bus, name, &deps);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
typesafe_qsort(deps, strv_length(deps), list_dependencies_compare);
|
|
|
|
STRV_FOREACH(c, deps) {
|
|
if (strv_contains(*units, *c)) {
|
|
if (!arg_plain) {
|
|
printf(" ");
|
|
r = list_dependencies_print("...", level + 1, (branches << 1) | (c[1] == NULL ? 0 : 1), 1);
|
|
if (r < 0)
|
|
return r;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (arg_plain)
|
|
printf(" ");
|
|
else {
|
|
UnitActiveState active_state = _UNIT_ACTIVE_STATE_INVALID;
|
|
const char *on;
|
|
|
|
(void) get_state_one_unit(bus, *c, &active_state);
|
|
|
|
switch (active_state) {
|
|
case UNIT_ACTIVE:
|
|
case UNIT_RELOADING:
|
|
case UNIT_ACTIVATING:
|
|
on = ansi_highlight_green();
|
|
break;
|
|
|
|
case UNIT_INACTIVE:
|
|
case UNIT_DEACTIVATING:
|
|
on = ansi_normal();
|
|
break;
|
|
|
|
default:
|
|
on = ansi_highlight_red();
|
|
break;
|
|
}
|
|
|
|
printf("%s%s%s ", on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), ansi_normal());
|
|
}
|
|
|
|
r = list_dependencies_print(*c, level, branches, c[1] == NULL);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
if (arg_all || unit_name_to_type(*c) == UNIT_TARGET) {
|
|
r = list_dependencies_one(bus, *c, level + 1, units, (branches << 1) | (c[1] == NULL ? 0 : 1));
|
|
if (r < 0)
|
|
return r;
|
|
}
|
|
}
|
|
|
|
if (!arg_plain)
|
|
strv_remove(*units, name);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int list_dependencies(int argc, char *argv[], void *userdata) {
|
|
_cleanup_strv_free_ char **units = NULL, **done = NULL;
|
|
char **u, **patterns;
|
|
sd_bus *bus;
|
|
int r;
|
|
|
|
r = acquire_bus(BUS_MANAGER, &bus);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
patterns = strv_skip(argv, 1);
|
|
if (strv_isempty(patterns)) {
|
|
units = strv_new(SPECIAL_DEFAULT_TARGET);
|
|
if (!units)
|
|
return log_oom();
|
|
} else {
|
|
r = expand_unit_names(bus, patterns, NULL, &units, NULL);
|
|
if (r < 0)
|
|
return log_error_errno(r, "Failed to expand names: %m");
|
|
}
|
|
|
|
(void) pager_open(arg_pager_flags);
|
|
|
|
STRV_FOREACH(u, units) {
|
|
if (u != units)
|
|
puts("");
|
|
|
|
puts(*u);
|
|
r = list_dependencies_one(bus, *u, 0, &done, 0);
|
|
if (r < 0)
|
|
return r;
|
|
}
|
|
|
|
return 0;
|
|
}
|