mirror of
https://github.com/clearlinux/systemd-stable.git
synced 2026-09-06 05:32:02 +00:00
systemctl add command list-dependencies
systemctl list-dependencies lists all unit's dependecies and recursively expands all subsidiary target units into a tree. Primary purpose for this command is to show all units which are enabled in specified target.
This commit is contained in:
committed by
Kay Sievers
parent
86ed7ec58b
commit
55c0b89c57
@@ -996,6 +996,17 @@
|
||||
ordering and requirement
|
||||
dependencies.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><command>list-dependencies [NAME]</command></term>
|
||||
|
||||
<listitem><para>
|
||||
Shows required and wanted units of given unit.
|
||||
Target units are recursively expanded.
|
||||
When <option>--all</option> is passed
|
||||
dependency tree is generated for all
|
||||
subsidiary units.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><command>snapshot [NAME]</command></term>
|
||||
|
||||
|
||||
@@ -5648,12 +5648,14 @@ const char *draw_special_char(DrawSpecialChar ch) {
|
||||
[DRAW_TREE_VERT] = "\342\224\202 ", /* │ */
|
||||
[DRAW_TREE_BRANCH] = "\342\224\234\342\224\200", /* ├─ */
|
||||
[DRAW_TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */
|
||||
[DRAW_TREE_SPACE] = " ", /* */
|
||||
[DRAW_TRIANGULAR_BULLET] = "\342\200\243 ", /* ‣ */
|
||||
},
|
||||
/* ASCII fallback */ {
|
||||
[DRAW_TREE_VERT] = "| ",
|
||||
[DRAW_TREE_BRANCH] = "|-",
|
||||
[DRAW_TREE_RIGHT] = "`-",
|
||||
[DRAW_TREE_SPACE] = " ",
|
||||
[DRAW_TRIANGULAR_BULLET] = "> ",
|
||||
}
|
||||
};
|
||||
|
||||
@@ -555,6 +555,7 @@ typedef enum DrawSpecialChar {
|
||||
DRAW_TREE_VERT,
|
||||
DRAW_TREE_BRANCH,
|
||||
DRAW_TREE_RIGHT,
|
||||
DRAW_TREE_SPACE,
|
||||
DRAW_TRIANGULAR_BULLET,
|
||||
_DRAW_SPECIAL_CHAR_MAX
|
||||
} DrawSpecialChar;
|
||||
|
||||
+225
-2
@@ -710,6 +710,226 @@ static int list_unit_files(DBusConnection *bus, char **args) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int list_dependencies_print(const char *name, int level, unsigned int branches, bool last) {
|
||||
int i;
|
||||
_cleanup_free_ char *n = NULL;
|
||||
size_t len = 0;
|
||||
size_t max_len = MAX(columns(),20);
|
||||
|
||||
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", draw_special_char(branches & (1 << i) ? DRAW_TREE_VERT : DRAW_TREE_SPACE));
|
||||
}
|
||||
len += 2;
|
||||
if(len > max_len - 3 && !arg_full) {
|
||||
printf("%s...\n",max_len % 2 ? "" : " ");
|
||||
return 0;
|
||||
}
|
||||
printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_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_get_dependencies(DBusConnection *bus, const char *name, char ***deps) {
|
||||
static const char * const dependencies[] = {
|
||||
"Requires",
|
||||
"RequiresOverridable",
|
||||
"Requisite",
|
||||
"RequisiteOverridable",
|
||||
"Wants"
|
||||
};
|
||||
|
||||
_cleanup_free_ char *path;
|
||||
const char *interface = "org.freedesktop.systemd1.Unit";
|
||||
|
||||
_cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
|
||||
DBusMessageIter iter, sub, sub2, sub3;
|
||||
|
||||
int r = 0;
|
||||
unsigned int i;
|
||||
|
||||
char **ret = NULL;
|
||||
char **c;
|
||||
|
||||
assert(bus);
|
||||
assert(name);
|
||||
assert(deps);
|
||||
|
||||
path = unit_dbus_path_from_name(name);
|
||||
if (path == NULL) {
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = bus_method_call_with_reply(
|
||||
bus,
|
||||
"org.freedesktop.systemd1",
|
||||
path,
|
||||
"org.freedesktop.DBus.Properties",
|
||||
"GetAll",
|
||||
&reply,
|
||||
NULL,
|
||||
DBUS_TYPE_STRING, &interface,
|
||||
DBUS_TYPE_INVALID);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
if (!dbus_message_iter_init(reply, &iter) ||
|
||||
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
|
||||
dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
|
||||
log_error("Failed to parse reply.");
|
||||
r = -EIO;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
dbus_message_iter_recurse(&iter, &sub);
|
||||
|
||||
while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
|
||||
const char *prop;
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
|
||||
log_error("Failed to parse reply.");
|
||||
r = -EIO;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
dbus_message_iter_recurse(&sub, &sub2);
|
||||
|
||||
if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0) {
|
||||
log_error("Failed to parse reply.");
|
||||
r = -EIO;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
|
||||
log_error("Failed to parse reply.");
|
||||
r = -EIO;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
dbus_message_iter_recurse(&sub2, &sub3);
|
||||
|
||||
dbus_message_iter_next(&sub);
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(dependencies); i++)
|
||||
if (streq(dependencies[i], prop)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == ELEMENTSOF(dependencies))
|
||||
continue;
|
||||
|
||||
if (dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_ARRAY) {
|
||||
if (dbus_message_iter_get_element_type(&sub3) == DBUS_TYPE_STRING) {
|
||||
DBusMessageIter sub4;
|
||||
dbus_message_iter_recurse(&sub3, &sub4);
|
||||
|
||||
while (dbus_message_iter_get_arg_type(&sub4) != DBUS_TYPE_INVALID) {
|
||||
const char *s;
|
||||
|
||||
assert(dbus_message_iter_get_arg_type(&sub4) == DBUS_TYPE_STRING);
|
||||
dbus_message_iter_get_basic(&sub4, &s);
|
||||
c = strv_append(ret, s);
|
||||
if (c == NULL) {
|
||||
r = log_oom();
|
||||
goto finish;
|
||||
}
|
||||
strv_free(ret);
|
||||
ret = c;
|
||||
dbus_message_iter_next(&sub4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finish:
|
||||
if (r < 0)
|
||||
strv_freep(&ret);
|
||||
*deps = ret;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int list_dependencies_compare(const void *_a, const void *_b) {
|
||||
const char **a = (const char**) _a, **b = (const char**) _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(DBusConnection *bus, const char *name, int level, char **units, unsigned int branches) {
|
||||
char **deps = NULL;
|
||||
char **c;
|
||||
char **u = NULL;
|
||||
int r = 0;
|
||||
|
||||
u = strv_append(units, name);
|
||||
if(!u)
|
||||
return log_oom();
|
||||
|
||||
r = list_dependencies_get_dependencies(bus, name, &deps);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
qsort(deps, strv_length(deps), sizeof (char*), list_dependencies_compare);
|
||||
|
||||
STRV_FOREACH(c, deps) {
|
||||
if (strv_contains(u, *c)) {
|
||||
r = list_dependencies_print("...", level + 1, (branches << 1) | (c[1] == NULL ? 0 : 1), 1);
|
||||
if(r < 0)
|
||||
goto finish;
|
||||
continue;
|
||||
}
|
||||
|
||||
r = list_dependencies_print(*c, level, branches, c[1] == NULL);
|
||||
if(r < 0)
|
||||
goto finish;
|
||||
|
||||
if (arg_all || unit_name_to_type(*c) == UNIT_TARGET) {
|
||||
r = list_dependencies_one(bus, *c, level + 1, u, (branches << 1) | (c[1] == NULL ? 0 : 1));
|
||||
if(r < 0)
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
r = 0;
|
||||
finish:
|
||||
strv_free(deps);
|
||||
strv_free(u);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int list_dependencies(DBusConnection *bus, char **args) {
|
||||
int r = 0;
|
||||
_cleanup_free_ char *unit = NULL;
|
||||
|
||||
assert(bus);
|
||||
assert(args[1]);
|
||||
|
||||
unit = unit_name_mangle(args[1]);
|
||||
if (!unit)
|
||||
return log_oom();
|
||||
|
||||
pager_open_if_enabled();
|
||||
printf("%s\n", unit);
|
||||
r = list_dependencies_one(bus, unit, 0, NULL, 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int dot_one_property(const char *name, const char *prop, DBusMessageIter *iter) {
|
||||
|
||||
static const char * const colors[] = {
|
||||
@@ -4063,7 +4283,7 @@ static int systemctl_help(void) {
|
||||
" status [NAME...|PID...] Show runtime status of one or more units\n"
|
||||
" show [NAME...|JOB...] Show properties of one or more\n"
|
||||
" units/jobs or the manager\n"
|
||||
" help [NAME...|PID...] Show manual for one or more units\n"
|
||||
" help [NAME...|PID...] Show manual for one or more units\n"
|
||||
" reset-failed [NAME...] Reset failed state for all, one, or more\n"
|
||||
" units\n"
|
||||
" set-cgroup [NAME] [CGROUP...] Add unit to a control group\n"
|
||||
@@ -4072,7 +4292,9 @@ static int systemctl_help(void) {
|
||||
" Set control group attribute\n"
|
||||
" unset-cgroup-attr [NAME] [ATTR...]\n"
|
||||
" Unset control group attribute\n"
|
||||
" load [NAME...] Load one or more units\n\n"
|
||||
" load [NAME...] Load one or more units\n"
|
||||
" list-dependencies [NAME] Recursively show units which are required\n"
|
||||
" or wanted by this unit\n\n"
|
||||
"Unit File Commands:\n"
|
||||
" list-unit-files List installed unit files\n"
|
||||
" enable [NAME...] Enable one or more unit files\n"
|
||||
@@ -5088,6 +5310,7 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
|
||||
{ "unmask", MORE, 2, enable_unit },
|
||||
{ "link", MORE, 2, enable_unit },
|
||||
{ "switch-root", MORE, 2, switch_root },
|
||||
{ "list-dependencies", EQUAL, 2, list_dependencies },
|
||||
};
|
||||
|
||||
int left;
|
||||
|
||||
Reference in New Issue
Block a user