]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/systemctl/systemctl-list-dependencies.c
Merge pull request #25168 from valentindavid/valentindavid/umount-move-recursive...
[thirdparty/systemd.git] / src / systemctl / systemctl-list-dependencies.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "locale-util.h"
4 #include "sort-util.h"
5 #include "special.h"
6 #include "systemctl-list-dependencies.h"
7 #include "systemctl-util.h"
8 #include "systemctl.h"
9 #include "terminal-util.h"
10
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);
14 size_t len = 0;
15
16 if (!arg_plain) {
17
18 for (int i = level - 1; i >= 0; i--) {
19 len += 2;
20 if (len > max_len - 3 && !arg_full) {
21 printf("%s...\n",max_len % 2 ? "" : " ");
22 return 0;
23 }
24 printf("%s", special_glyph(branches & (1 << i) ? SPECIAL_GLYPH_TREE_VERTICAL : SPECIAL_GLYPH_TREE_SPACE));
25 }
26 len += 2;
27
28 if (len > max_len - 3 && !arg_full) {
29 printf("%s...\n",max_len % 2 ? "" : " ");
30 return 0;
31 }
32
33 printf("%s", special_glyph(last ? SPECIAL_GLYPH_TREE_RIGHT : SPECIAL_GLYPH_TREE_BRANCH));
34 }
35
36 if (arg_full) {
37 printf("%s\n", name);
38 return 0;
39 }
40
41 n = ellipsize(name, max_len-len, 100);
42 if (!n)
43 return log_oom();
44
45 printf("%s\n", n);
46 return 0;
47 }
48
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)
51 return 1;
52 if (unit_name_to_type(*a) != UNIT_TARGET && unit_name_to_type(*b) == UNIT_TARGET)
53 return -1;
54
55 return strcasecmp(*a, *b);
56 }
57
58 static int list_dependencies_one(
59 sd_bus *bus,
60 const char *name,
61 int level,
62 char ***units,
63 unsigned branches) {
64
65 _cleanup_strv_free_ char **deps = NULL;
66 int r;
67
68 assert(bus);
69 assert(name);
70 assert(units);
71
72 r = strv_extend(units, name);
73 if (r < 0)
74 return log_oom();
75
76 r = unit_get_dependencies(bus, name, &deps);
77 if (r < 0)
78 return r;
79
80 typesafe_qsort(deps, strv_length(deps), list_dependencies_compare);
81
82 STRV_FOREACH(c, deps) {
83 _cleanup_free_ char *load_state = NULL, *sub_state = NULL;
84 UnitActiveState active_state;
85
86 if (strv_contains(*units, *c)) {
87 if (!arg_plain) {
88 printf(" ");
89 r = list_dependencies_print("...", level + 1, (branches << 1) | (c[1] == NULL ? 0 : 1), /* last = */ true);
90 if (r < 0)
91 return r;
92 }
93 continue;
94 }
95
96 if (arg_types && !strv_contains(arg_types, unit_type_suffix(*c)))
97 continue;
98
99 r = get_state_one_unit(bus, *c, &active_state);
100 if (r < 0)
101 return r;
102
103 if (arg_states) {
104 r = unit_load_state(bus, *c, &load_state);
105 if (r < 0)
106 return r;
107
108 r = get_sub_state_one_unit(bus, *c, &sub_state);
109 if (r < 0)
110 return r;
111
112 if (!strv_overlap(arg_states, STRV_MAKE(unit_active_state_to_string(active_state), load_state, sub_state)))
113 continue;
114 }
115
116 if (arg_plain)
117 printf(" ");
118 else {
119 const char *on;
120
121 switch (active_state) {
122 case UNIT_ACTIVE:
123 case UNIT_RELOADING:
124 case UNIT_ACTIVATING:
125 on = ansi_highlight_green();
126 break;
127
128 case UNIT_INACTIVE:
129 case UNIT_DEACTIVATING:
130 on = ansi_normal();
131 break;
132
133 default:
134 on = ansi_highlight_red();
135 break;
136 }
137
138 printf("%s%s%s ", on, special_glyph(unit_active_state_to_glyph(active_state)), ansi_normal());
139 }
140
141 r = list_dependencies_print(*c, level, branches, c[1] == NULL);
142 if (r < 0)
143 return r;
144
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));
147 if (r < 0)
148 return r;
149 }
150 }
151
152 if (!arg_plain)
153 strv_remove(*units, name);
154
155 return 0;
156 }
157
158 int verb_list_dependencies(int argc, char *argv[], void *userdata) {
159 _cleanup_strv_free_ char **units = NULL, **done = NULL;
160 char **patterns;
161 sd_bus *bus;
162 int r;
163
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;
166
167 r = acquire_bus(BUS_MANAGER, &bus);
168 if (r < 0)
169 return r;
170
171 patterns = strv_skip(argv, 1);
172 if (strv_isempty(patterns)) {
173 units = strv_new(SPECIAL_DEFAULT_TARGET);
174 if (!units)
175 return log_oom();
176 } else {
177 r = expand_unit_names(bus, patterns, NULL, &units, NULL);
178 if (r < 0)
179 return log_error_errno(r, "Failed to expand names: %m");
180 }
181
182 pager_open(arg_pager_flags);
183
184 STRV_FOREACH(u, units) {
185 if (u != units)
186 puts("");
187
188 puts(*u);
189 r = list_dependencies_one(bus, *u, 0, &done, 0);
190 if (r < 0)
191 return r;
192 }
193
194 return 0;
195 }