Merge pull request #14293 from keur/systemctl_with_dependencies

systemctl: Add --with-dependencies switch
This commit is contained in:
Lennart Poettering 2020-01-13 17:42:55 +01:00 committed by GitHub
commit 0b9da3d9e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 165 additions and 80 deletions

View File

@ -1592,6 +1592,22 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
</listitem>
</varlistentry>
<varlistentry>
<term><option>--with-dependencies</option></term>
<listitem>
<para>When used with <command>status</command>,
<command>cat</command>, <command>list-units</command>, and
<command>list-unit-files</command>, those commands print all
specified units and the dependencies of those units.</para>
<para>Options <option>--reverse</option>,
<option>--after</option>, <option>--before</option>
may be used to change what types of dependencies
are shown.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-l</option></term>
<term><option>--full</option></term>

View File

@ -1127,7 +1127,7 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, unsigne
if (r < 0)
return r;
return strv_free_and_replace(*p, l);
return strv_extend_strv(p, l, false);
}
case SD_BUS_TYPE_BOOLEAN: {

View File

@ -117,6 +117,7 @@ static bool arg_dry_run = false;
static bool arg_quiet = false;
static bool arg_full = false;
static bool arg_recursive = false;
static bool arg_with_dependencies = false;
static bool arg_show_transaction = false;
static int arg_force = 0;
static bool arg_ask_password = false;
@ -799,6 +800,107 @@ static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***r
return 0;
}
static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, char ***ret) {
_cleanup_strv_free_ char **deps = NULL;
static const struct bus_properties_map map[_DEPENDENCY_MAX][6] = {
[DEPENDENCY_FORWARD] = {
{ "Requires", "as", NULL, 0 },
{ "Requisite", "as", NULL, 0 },
{ "Wants", "as", NULL, 0 },
{ "ConsistsOf", "as", NULL, 0 },
{ "BindsTo", "as", NULL, 0 },
{}
},
[DEPENDENCY_REVERSE] = {
{ "RequiredBy", "as", NULL, 0 },
{ "RequisiteOf", "as", NULL, 0 },
{ "WantedBy", "as", NULL, 0 },
{ "PartOf", "as", NULL, 0 },
{ "BoundBy", "as", NULL, 0 },
{}
},
[DEPENDENCY_AFTER] = {
{ "After", "as", NULL, 0 },
{}
},
[DEPENDENCY_BEFORE] = {
{ "Before", "as", NULL, 0 },
{}
},
};
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ char *dbus_path = NULL;
int r;
assert(bus);
assert(name);
assert(ret);
dbus_path = unit_dbus_path_from_name(name);
if (!dbus_path)
return log_oom();
r = bus_map_all_properties(bus,
"org.freedesktop.systemd1",
dbus_path,
map[arg_dependency],
BUS_MAP_STRDUP,
&error,
NULL,
&deps);
if (r < 0)
return log_error_errno(r, "Failed to get properties of %s: %s", name, bus_error_message(&error, r));
*ret = TAKE_PTR(deps);
return 0;
}
static int append_unit_dependencies(sd_bus *bus, char **names, char ***ret) {
_cleanup_strv_free_ char **with_deps = NULL;
char **name;
assert(bus);
assert(ret);
STRV_FOREACH(name, names) {
_cleanup_strv_free_ char **deps = NULL;
if (strv_extend(&with_deps, *name) < 0)
return log_oom();
(void) list_dependencies_get_dependencies(bus, *name, &deps);
if (strv_extend_strv(&with_deps, deps, true) < 0)
return log_oom();
}
*ret = TAKE_PTR(with_deps);
return 0;
}
static int maybe_extend_with_unit_dependencies(sd_bus *bus, char ***list) {
assert(bus);
assert(list);
if (arg_with_dependencies) {
int r;
_cleanup_strv_free_ char **list_with_deps = NULL;
r = append_unit_dependencies(bus, *list, &list_with_deps);
if (r < 0)
return log_error_errno(r, "Failed to append unit dependencies: %m");
strv_free(*list);
*list = TAKE_PTR(list_with_deps);
}
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;
@ -812,9 +914,21 @@ static int list_units(int argc, char *argv[], void *userdata) {
(void) pager_open(arg_pager_flags);
r = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
if (r < 0)
return r;
if (arg_with_dependencies) {
_cleanup_strv_free_ char **names = NULL;
r = append_unit_dependencies(bus, strv_skip(argv, 1), &names);
if (r < 0)
return r;
r = get_unit_list_recursive(bus, names, &unit_infos, &replies, &machines);
if (r < 0)
return r;
} else {
r = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
if (r < 0)
return r;
}
typesafe_qsort(unit_infos, r, compare_unit_info);
return output_units_list(unit_infos, r);
@ -1588,9 +1702,21 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append_strv(m, strv_skip(argv, 1));
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)) {
@ -1694,79 +1820,6 @@ static int list_dependencies_print(const char *name, int level, unsigned branche
return 0;
}
static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, char ***deps) {
struct DependencyStatusInfo {
char **dep[5];
} info = {};
static const struct bus_properties_map map[_DEPENDENCY_MAX][6] = {
[DEPENDENCY_FORWARD] = {
{ "Requires", "as", NULL, offsetof(struct DependencyStatusInfo, dep[0]) },
{ "Requisite", "as", NULL, offsetof(struct DependencyStatusInfo, dep[1]) },
{ "Wants", "as", NULL, offsetof(struct DependencyStatusInfo, dep[2]) },
{ "ConsistsOf", "as", NULL, offsetof(struct DependencyStatusInfo, dep[3]) },
{ "BindsTo", "as", NULL, offsetof(struct DependencyStatusInfo, dep[4]) },
{}
},
[DEPENDENCY_REVERSE] = {
{ "RequiredBy", "as", NULL, offsetof(struct DependencyStatusInfo, dep[0]) },
{ "RequisiteOf", "as", NULL, offsetof(struct DependencyStatusInfo, dep[1]) },
{ "WantedBy", "as", NULL, offsetof(struct DependencyStatusInfo, dep[2]) },
{ "PartOf", "as", NULL, offsetof(struct DependencyStatusInfo, dep[3]) },
{ "BoundBy", "as", NULL, offsetof(struct DependencyStatusInfo, dep[4]) },
{}
},
[DEPENDENCY_AFTER] = {
{ "After", "as", NULL, offsetof(struct DependencyStatusInfo, dep[0]) },
{}
},
[DEPENDENCY_BEFORE] = {
{ "Before", "as", NULL, offsetof(struct DependencyStatusInfo, dep[0]) },
{}
},
};
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_strv_free_ char **ret = NULL;
_cleanup_free_ char *dbus_path = NULL;
int i, r;
assert(bus);
assert(name);
assert(deps);
dbus_path = unit_dbus_path_from_name(name);
if (!dbus_path)
return log_oom();
r = bus_map_all_properties(bus,
"org.freedesktop.systemd1",
dbus_path,
map[arg_dependency],
BUS_MAP_STRDUP,
&error,
NULL,
&info);
if (r < 0)
return log_error_errno(r, "Failed to get properties of %s: %s", name, bus_error_message(&error, r));
if (IN_SET(arg_dependency, DEPENDENCY_AFTER, DEPENDENCY_BEFORE)) {
*deps = info.dep[0];
return 0;
}
for (i = 0; i < 5; i++) {
r = strv_extend_strv(&ret, info.dep[i], true);
if (r < 0)
return log_oom();
info.dep[i] = strv_free(info.dep[i]);
}
*deps = TAKE_PTR(ret);
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;
@ -5926,6 +5979,10 @@ static int show(int argc, char *argv[], void *userdata) {
if (r < 0)
return log_error_errno(r, "Failed to expand names: %m");
r = maybe_extend_with_unit_dependencies(bus, &names);
if (r < 0)
return r;
STRV_FOREACH(name, names) {
_cleanup_free_ char *path;
@ -5976,6 +6033,10 @@ static int cat(int argc, char *argv[], void *userdata) {
if (r < 0)
return log_error_errno(r, "Failed to expand names: %m");
r = maybe_extend_with_unit_dependencies(bus, &names);
if (r < 0)
return r;
(void) pager_open(arg_pager_flags);
STRV_FOREACH(name, names) {
@ -7966,6 +8027,8 @@ static int systemctl_help(void) {
" -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"
" --with-dependencies Show unit dependencies with 'status', 'cat',\n"
" 'list-units', and 'list-unit-files'.\n"
" --job-mode=MODE Specify how to deal with already queued jobs, when\n"
" queueing a new job\n"
" -T --show-transaction When enqueuing a unit job, show full transaction\n"
@ -8259,6 +8322,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
ARG_BOOT_LOADER_ENTRY,
ARG_NOW,
ARG_MESSAGE,
ARG_WITH_DEPENDENCIES,
ARG_WAIT,
ARG_WHAT,
};
@ -8305,6 +8369,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
{ "plain", no_argument, NULL, ARG_PLAIN },
{ "state", required_argument, NULL, ARG_STATE },
{ "recursive", no_argument, NULL, 'r' },
{ "with-dependencies", no_argument, NULL, ARG_WITH_DEPENDENCIES },
{ "preset-mode", required_argument, NULL, ARG_PRESET_MODE },
{ "firmware-setup", no_argument, NULL, ARG_FIRMWARE_SETUP },
{ "boot-loader-menu", required_argument, NULL, ARG_BOOT_LOADER_MENU },
@ -8665,6 +8730,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
arg_show_transaction = true;
break;
case ARG_WITH_DEPENDENCIES:
arg_with_dependencies = true;
break;
case ARG_WHAT: {
const char *p;