1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 #include "bus-locator.h"
6 #include "systemctl-list-unit-files.h"
7 #include "systemctl-util.h"
9 #include "terminal-util.h"
11 static int compare_unit_file_list(const UnitFileList
*a
, const UnitFileList
*b
) {
14 d1
= strrchr(a
->path
, '.');
15 d2
= strrchr(b
->path
, '.');
20 r
= strcasecmp(d1
, d2
);
25 return strcasecmp(basename(a
->path
), basename(b
->path
));
28 static bool output_show_unit_file(const UnitFileList
*u
, char **states
, char **patterns
) {
31 if (!strv_fnmatch_or_empty(patterns
, basename(u
->path
), FNM_NOESCAPE
))
34 if (!strv_isempty(arg_types
)) {
37 dot
= strrchr(u
->path
, '.');
41 if (!strv_find(arg_types
, dot
+1))
45 if (!strv_isempty(states
) &&
46 !strv_find(states
, unit_file_state_to_string(u
->state
)))
52 static 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
= {};
57 table
= table_new("unit file", "state", "vendor preset");
61 table_set_header(table
, !arg_no_legend
);
63 table_set_width(table
, 0);
65 (void) table_set_empty_string(table
, "-");
67 for (const UnitFileList
*u
= units
; u
< units
+ c
; u
++) {
68 const char *on_underline
= NULL
, *on_unit_color
= NULL
, *id
;
71 underline
= u
+ 1 < units
+ c
&&
72 !streq(unit_type_suffix(u
->path
), unit_type_suffix((u
+ 1)->path
));
75 on_underline
= ansi_underline();
79 UNIT_FILE_MASKED_RUNTIME
,
82 on_unit_color
= underline
? ansi_highlight_red_underline() : ansi_highlight_red();
83 else if (IN_SET(u
->state
,
86 on_unit_color
= underline
? ansi_highlight_green_underline() : ansi_highlight_green();
88 on_unit_color
= on_underline
;
90 id
= basename(u
->path
);
92 r
= table_add_many(table
,
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
));
98 return table_log_add_error(r
);
100 if (show_preset_for_state(u
->state
)) {
101 const char *unit_preset_str
, *on_preset_color
;
103 r
= unit_file_query_preset(arg_scope
, arg_root
, id
, &presets
);
105 unit_preset_str
= "n/a";
106 on_preset_color
= underline
? on_underline
: ansi_normal();
108 unit_preset_str
= "disabled";
109 on_preset_color
= underline
? ansi_highlight_red_underline() : ansi_highlight_red();
111 unit_preset_str
= "enabled";
112 on_preset_color
= underline
? ansi_highlight_green_underline() : ansi_highlight_green();
115 r
= table_add_many(table
,
116 TABLE_STRING
, unit_preset_str
,
117 TABLE_SET_BOTH_COLORS
, strempty(on_preset_color
));
119 r
= table_add_many(table
,
121 TABLE_SET_BOTH_COLORS
, underline
? ansi_grey_underline() : ansi_grey());
123 return table_log_add_error(r
);
126 r
= output_table(table
);
131 printf("\n%u unit files listed.\n", c
);
136 int 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
;
145 bool fallback
= false;
147 if (install_client_side()) {
152 h
= hashmap_new(&string_hash_ops
);
156 r
= unit_file_get_list(arg_scope
, arg_root
, h
, arg_states
, strv_skip(argv
, 1));
158 unit_file_list_free(h
);
159 return log_error_errno(r
, "Failed to get unit file list: %m");
162 n_units
= hashmap_size(h
);
164 units
= new(UnitFileList
, n_units
?: 1); /* avoid malloc(0) */
166 unit_file_list_free(h
);
170 HASHMAP_FOREACH(u
, h
) {
171 if (!output_show_unit_file(u
, NULL
, NULL
))
178 assert(c
<= n_units
);
183 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
184 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
187 r
= acquire_bus(BUS_MANAGER
, &bus
);
191 r
= bus_message_new_method_call(bus
, &m
, bus_systemd_mgr
, "ListUnitFilesByPatterns");
193 return bus_log_create_error(r
);
195 r
= sd_bus_message_append_strv(m
, arg_states
);
197 return bus_log_create_error(r
);
199 if (arg_with_dependencies
) {
200 _cleanup_strv_free_
char **names_with_deps
= NULL
;
202 r
= append_unit_dependencies(bus
, strv_skip(argv
, 1), &names_with_deps
);
204 return log_error_errno(r
, "Failed to append unit dependencies: %m");
206 r
= sd_bus_message_append_strv(m
, names_with_deps
);
208 return bus_log_create_error(r
);
210 r
= sd_bus_message_append_strv(m
, strv_skip(argv
, 1));
212 return bus_log_create_error(r
);
215 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
216 if (r
< 0 && sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_METHOD
)) {
217 /* Fallback to legacy ListUnitFiles method */
219 log_debug_errno(r
, "Failed to list unit files: %s Falling back to ListUnitsFiles method.", bus_error_message(&error
, r
));
220 m
= sd_bus_message_unref(m
);
221 sd_bus_error_free(&error
);
223 r
= bus_message_new_method_call(bus
, &m
, bus_systemd_mgr
, "ListUnitFiles");
225 return bus_log_create_error(r
);
227 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
230 return log_error_errno(r
, "Failed to list unit files: %s", bus_error_message(&error
, r
));
232 r
= sd_bus_message_enter_container(reply
, SD_BUS_TYPE_ARRAY
, "(ss)");
234 return bus_log_parse_error(r
);
236 while ((r
= sd_bus_message_read(reply
, "(ss)", &path
, &state
)) > 0) {
238 if (!GREEDY_REALLOC(units
, size
, c
+ 1))
241 units
[c
] = (struct UnitFileList
) {
243 unit_file_state_from_string(state
)
246 if (output_show_unit_file(&units
[c
],
247 fallback
? arg_states
: NULL
,
248 fallback
? strv_skip(argv
, 1) : NULL
))
253 return bus_log_parse_error(r
);
255 r
= sd_bus_message_exit_container(reply
);
257 return bus_log_parse_error(r
);
260 (void) pager_open(arg_pager_flags
);
262 typesafe_qsort(units
, c
, compare_unit_file_list
);
263 r
= output_unit_file_list(units
, c
);
267 if (install_client_side())
268 for (unit
= units
; unit
< units
+ c
; unit
++)