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
list_dependencies_print(const char * name,int level,unsigned branches,bool last)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
list_dependencies_compare(char * const * a,char * const * b)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
list_dependencies_one(sd_bus * bus,const char * name,int level,char *** units,unsigned branches)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 if (strv_contains(*units, *c)) {
84 if (!arg_plain) {
85 printf(" ");
86 r = list_dependencies_print("...", level + 1, (branches << 1) | (c[1] == NULL ? 0 : 1), 1);
87 if (r < 0)
88 return r;
89 }
90 continue;
91 }
92
93 if (arg_plain)
94 printf(" ");
95 else {
96 UnitActiveState active_state = _UNIT_ACTIVE_STATE_INVALID;
97 const char *on;
98
99 (void) get_state_one_unit(bus, *c, &active_state);
100
101 switch (active_state) {
102 case UNIT_ACTIVE:
103 case UNIT_RELOADING:
104 case UNIT_ACTIVATING:
105 on = ansi_highlight_green();
106 break;
107
108 case UNIT_INACTIVE:
109 case UNIT_DEACTIVATING:
110 on = ansi_normal();
111 break;
112
113 default:
114 on = ansi_highlight_red();
115 break;
116 }
117
118 printf("%s%s%s ", on, special_glyph(unit_active_state_to_glyph(active_state)), ansi_normal());
119 }
120
121 r = list_dependencies_print(*c, level, branches, c[1] == NULL);
122 if (r < 0)
123 return r;
124
125 if (arg_all || unit_name_to_type(*c) == UNIT_TARGET) {
126 r = list_dependencies_one(bus, *c, level + 1, units, (branches << 1) | (c[1] == NULL ? 0 : 1));
127 if (r < 0)
128 return r;
129 }
130 }
131
132 if (!arg_plain)
133 strv_remove(*units, name);
134
135 return 0;
136 }
137
verb_list_dependencies(int argc,char * argv[],void * userdata)138 int verb_list_dependencies(int argc, char *argv[], void *userdata) {
139 _cleanup_strv_free_ char **units = NULL, **done = NULL;
140 char **patterns;
141 sd_bus *bus;
142 int r;
143
144 r = acquire_bus(BUS_MANAGER, &bus);
145 if (r < 0)
146 return r;
147
148 patterns = strv_skip(argv, 1);
149 if (strv_isempty(patterns)) {
150 units = strv_new(SPECIAL_DEFAULT_TARGET);
151 if (!units)
152 return log_oom();
153 } else {
154 r = expand_unit_names(bus, patterns, NULL, &units, NULL);
155 if (r < 0)
156 return log_error_errno(r, "Failed to expand names: %m");
157 }
158
159 pager_open(arg_pager_flags);
160
161 STRV_FOREACH(u, units) {
162 if (u != units)
163 puts("");
164
165 puts(*u);
166 r = list_dependencies_one(bus, *u, 0, &done, 0);
167 if (r < 0)
168 return r;
169 }
170
171 return 0;
172 }
173