]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl-list-unit-files.c
systemctl: reduce scope of iterator variables
[thirdparty/systemd.git] / src / systemctl / systemctl-list-unit-files.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
daf71ef6
LP
2
3#include "bus-error.h"
4#include "bus-locator.h"
5#include "sort-util.h"
6#include "systemctl-list-unit-files.h"
7#include "systemctl-util.h"
8#include "systemctl.h"
9#include "terminal-util.h"
10
11static int compare_unit_file_list(const UnitFileList *a, const UnitFileList *b) {
12 const char *d1, *d2;
13
14 d1 = strrchr(a->path, '.');
15 d2 = strrchr(b->path, '.');
16
17 if (d1 && d2) {
18 int r;
19
20 r = strcasecmp(d1, d2);
21 if (r != 0)
22 return r;
23 }
24
25 return strcasecmp(basename(a->path), basename(b->path));
26}
27
28static bool output_show_unit_file(const UnitFileList *u, char **states, char **patterns) {
29 assert(u);
30
31 if (!strv_fnmatch_or_empty(patterns, basename(u->path), FNM_NOESCAPE))
32 return false;
33
34 if (!strv_isempty(arg_types)) {
35 const char *dot;
36
37 dot = strrchr(u->path, '.');
38 if (!dot)
39 return false;
40
41 if (!strv_find(arg_types, dot+1))
42 return false;
43 }
44
45 if (!strv_isempty(states) &&
46 !strv_find(states, unit_file_state_to_string(u->state)))
47 return false;
48
49 return true;
50}
51
52static int output_unit_file_list(const UnitFileList *units, unsigned c) {
53 _cleanup_(table_unrefp) Table *table = NULL;
54 _cleanup_(unit_file_presets_freep) UnitFilePresets presets = {};
55 int r;
56
57 table = table_new("unit file", "state", "vendor preset");
58 if (!table)
59 return log_oom();
60
61 table_set_header(table, !arg_no_legend);
62 if (arg_full)
63 table_set_width(table, 0);
64
65 (void) table_set_empty_string(table, "-");
66
67 for (const UnitFileList *u = units; u < units + c; u++) {
68 const char *on_underline = NULL, *on_unit_color = NULL, *id;
69 bool underline;
70
71 underline = u + 1 < units + c &&
72 !streq(unit_type_suffix(u->path), unit_type_suffix((u + 1)->path));
73
74 if (underline)
75 on_underline = ansi_underline();
76
77 if (IN_SET(u->state,
78 UNIT_FILE_MASKED,
79 UNIT_FILE_MASKED_RUNTIME,
80 UNIT_FILE_DISABLED,
81 UNIT_FILE_BAD))
82 on_unit_color = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
83 else if (IN_SET(u->state,
84 UNIT_FILE_ENABLED,
85 UNIT_FILE_ALIAS))
86 on_unit_color = underline ? ansi_highlight_green_underline() : ansi_highlight_green();
87 else
88 on_unit_color = on_underline;
89
90 id = basename(u->path);
91
92 r = table_add_many(table,
93 TABLE_STRING, id,
94 TABLE_SET_BOTH_COLORS, strempty(on_underline),
95 TABLE_STRING, unit_file_state_to_string(u->state),
96 TABLE_SET_BOTH_COLORS, strempty(on_unit_color));
97 if (r < 0)
98 return table_log_add_error(r);
99
100 if (show_preset_for_state(u->state)) {
101 const char *unit_preset_str, *on_preset_color;
102
103 r = unit_file_query_preset(arg_scope, arg_root, id, &presets);
104 if (r < 0) {
105 unit_preset_str = "n/a";
106 on_preset_color = underline ? on_underline : ansi_normal();
107 } else if (r == 0) {
108 unit_preset_str = "disabled";
109 on_preset_color = underline ? ansi_highlight_red_underline() : ansi_highlight_red();
110 } else {
111 unit_preset_str = "enabled";
112 on_preset_color = underline ? ansi_highlight_green_underline() : ansi_highlight_green();
113 }
114
115 r = table_add_many(table,
116 TABLE_STRING, unit_preset_str,
117 TABLE_SET_BOTH_COLORS, strempty(on_preset_color));
118 } else
119 r = table_add_many(table,
120 TABLE_EMPTY,
121 TABLE_SET_BOTH_COLORS, underline ? ansi_grey_underline() : ansi_grey());
122 if (r < 0)
123 return table_log_add_error(r);
124 }
125
126 r = output_table(table);
127 if (r < 0)
128 return r;
129
130 if (!arg_no_legend)
131 printf("\n%u unit files listed.\n", c);
132
133 return 0;
134}
135
136int list_unit_files(int argc, char *argv[], void *userdata) {
137 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
138 _cleanup_free_ UnitFileList *units = NULL;
daf71ef6
LP
139 size_t size = 0;
140 unsigned c = 0;
141 const char *state;
142 char *path;
143 int r;
144 bool fallback = false;
145
146 if (install_client_side()) {
147 Hashmap *h;
148 UnitFileList *u;
149 unsigned n_units;
150
151 h = hashmap_new(&string_hash_ops);
152 if (!h)
153 return log_oom();
154
155 r = unit_file_get_list(arg_scope, arg_root, h, arg_states, strv_skip(argv, 1));
156 if (r < 0) {
157 unit_file_list_free(h);
158 return log_error_errno(r, "Failed to get unit file list: %m");
159 }
160
161 n_units = hashmap_size(h);
162
163 units = new(UnitFileList, n_units ?: 1); /* avoid malloc(0) */
164 if (!units) {
165 unit_file_list_free(h);
166 return log_oom();
167 }
168
169 HASHMAP_FOREACH(u, h) {
170 if (!output_show_unit_file(u, NULL, NULL))
171 continue;
172
173 units[c++] = *u;
174 free(u);
175 }
176
177 assert(c <= n_units);
178 hashmap_free(h);
179
180 r = 0;
181 } else {
182 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
183 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
184 sd_bus *bus;
185
186 r = acquire_bus(BUS_MANAGER, &bus);
187 if (r < 0)
188 return r;
189
190 r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "ListUnitFilesByPatterns");
191 if (r < 0)
192 return bus_log_create_error(r);
193
194 r = sd_bus_message_append_strv(m, arg_states);
195 if (r < 0)
196 return bus_log_create_error(r);
197
198 if (arg_with_dependencies) {
199 _cleanup_strv_free_ char **names_with_deps = NULL;
200
201 r = append_unit_dependencies(bus, strv_skip(argv, 1), &names_with_deps);
202 if (r < 0)
203 return log_error_errno(r, "Failed to append unit dependencies: %m");
204
205 r = sd_bus_message_append_strv(m, names_with_deps);
206 if (r < 0)
207 return bus_log_create_error(r);
208 } else {
209 r = sd_bus_message_append_strv(m, strv_skip(argv, 1));
210 if (r < 0)
211 return bus_log_create_error(r);
212 }
213
214 r = sd_bus_call(bus, m, 0, &error, &reply);
215 if (r < 0 && sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
216 /* Fallback to legacy ListUnitFiles method */
217 fallback = true;
218 log_debug_errno(r, "Failed to list unit files: %s Falling back to ListUnitsFiles method.", bus_error_message(&error, r));
219 m = sd_bus_message_unref(m);
220 sd_bus_error_free(&error);
221
222 r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "ListUnitFiles");
223 if (r < 0)
224 return bus_log_create_error(r);
225
226 r = sd_bus_call(bus, m, 0, &error, &reply);
227 }
228 if (r < 0)
229 return log_error_errno(r, "Failed to list unit files: %s", bus_error_message(&error, r));
230
231 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ss)");
232 if (r < 0)
233 return bus_log_parse_error(r);
234
235 while ((r = sd_bus_message_read(reply, "(ss)", &path, &state)) > 0) {
236
237 if (!GREEDY_REALLOC(units, size, c + 1))
238 return log_oom();
239
240 units[c] = (struct UnitFileList) {
241 path,
242 unit_file_state_from_string(state)
243 };
244
245 if (output_show_unit_file(&units[c],
246 fallback ? arg_states : NULL,
247 fallback ? strv_skip(argv, 1) : NULL))
248 c++;
249
250 }
251 if (r < 0)
252 return bus_log_parse_error(r);
253
254 r = sd_bus_message_exit_container(reply);
255 if (r < 0)
256 return bus_log_parse_error(r);
257 }
258
259 (void) pager_open(arg_pager_flags);
260
261 typesafe_qsort(units, c, compare_unit_file_list);
262 r = output_unit_file_list(units, c);
263 if (r < 0)
264 return r;
265
266 if (install_client_side())
deaf4b86 267 for (UnitFileList *unit = units; unit < units + c; unit++)
daf71ef6
LP
268 free(unit->path);
269
270 if (c == 0)
271 return -ENOENT;
272
273 return 0;
274}