1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "locale-util.h"
6 #include "systemctl-list-dependencies.h"
7 #include "systemctl-util.h"
9 #include "terminal-util.h"
11 static int list_dependencies_print(const char *name
, int level
, unsigned branches
, bool last
) {
12 _cleanup_free_
char *n
= NULL
;
13 size_t max_len
= MAX(columns(),20u);
18 for (int i
= level
- 1; i
>= 0; i
--) {
20 if (len
> max_len
- 3 && !arg_full
) {
21 printf("%s...\n",max_len
% 2 ? "" : " ");
24 printf("%s", special_glyph(branches
& (1 << i
) ? SPECIAL_GLYPH_TREE_VERTICAL
: SPECIAL_GLYPH_TREE_SPACE
));
28 if (len
> max_len
- 3 && !arg_full
) {
29 printf("%s...\n",max_len
% 2 ? "" : " ");
33 printf("%s", special_glyph(last
? SPECIAL_GLYPH_TREE_RIGHT
: SPECIAL_GLYPH_TREE_BRANCH
));
41 n
= ellipsize(name
, max_len
-len
, 100);
49 static int list_dependencies_compare(char * const *a
, char * const *b
) {
50 if (unit_name_to_type(*a
) == UNIT_TARGET
&& unit_name_to_type(*b
) != UNIT_TARGET
)
52 if (unit_name_to_type(*a
) != UNIT_TARGET
&& unit_name_to_type(*b
) == UNIT_TARGET
)
55 return strcasecmp(*a
, *b
);
58 static int list_dependencies_one(
65 _cleanup_strv_free_
char **deps
= NULL
;
72 r
= strv_extend(units
, name
);
76 r
= unit_get_dependencies(bus
, name
, &deps
);
80 typesafe_qsort(deps
, strv_length(deps
), list_dependencies_compare
);
82 STRV_FOREACH(c
, deps
) {
83 _cleanup_free_
char *load_state
= NULL
, *sub_state
= NULL
;
84 UnitActiveState active_state
;
86 if (strv_contains(*units
, *c
)) {
89 r
= list_dependencies_print("...", level
+ 1, (branches
<< 1) | (c
[1] == NULL
? 0 : 1), /* last = */ true);
96 if (arg_types
&& !strv_contains(arg_types
, unit_type_suffix(*c
)))
99 r
= get_state_one_unit(bus
, *c
, &active_state
);
104 r
= unit_load_state(bus
, *c
, &load_state
);
108 r
= get_sub_state_one_unit(bus
, *c
, &sub_state
);
112 if (!strv_overlap(arg_states
, STRV_MAKE(unit_active_state_to_string(active_state
), load_state
, sub_state
)))
121 switch (active_state
) {
124 case UNIT_ACTIVATING
:
125 on
= ansi_highlight_green();
129 case UNIT_DEACTIVATING
:
134 on
= ansi_highlight_red();
138 printf("%s%s%s ", on
, special_glyph(unit_active_state_to_glyph(active_state
)), ansi_normal());
141 r
= list_dependencies_print(*c
, level
, branches
, c
[1] == NULL
);
145 if (arg_all
|| unit_name_to_type(*c
) == UNIT_TARGET
) {
146 r
= list_dependencies_one(bus
, *c
, level
+ 1, units
, (branches
<< 1) | (c
[1] == NULL
? 0 : 1));
153 strv_remove(*units
, name
);
158 int verb_list_dependencies(int argc
, char *argv
[], void *userdata
) {
159 _cleanup_strv_free_
char **units
= NULL
, **done
= NULL
;
164 /* We won't be able to preserve the tree structure if --type= or --state= is used */
165 arg_plain
= arg_plain
|| arg_types
|| arg_states
;
167 r
= acquire_bus(BUS_MANAGER
, &bus
);
171 patterns
= strv_skip(argv
, 1);
172 if (strv_isempty(patterns
)) {
173 units
= strv_new(SPECIAL_DEFAULT_TARGET
);
177 r
= expand_unit_names(bus
, patterns
, NULL
, &units
, NULL
);
179 return log_error_errno(r
, "Failed to expand names: %m");
182 pager_open(arg_pager_flags
);
184 STRV_FOREACH(u
, units
) {
189 r
= list_dependencies_one(bus
, *u
, 0, &done
, 0);