1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
7 #include "bus-map-properties.h"
8 #include "hostname-util.h"
9 #include "locale-util.h"
10 #include "memory-util.h"
11 #include "sort-util.h"
12 #include "systemctl-list-machines.h"
13 #include "systemctl-util.h"
14 #include "systemctl.h"
15 #include "terminal-util.h"
17 const struct bus_properties_map machine_info_property_map
[] = {
18 { "SystemState", "s", NULL
, offsetof(struct machine_info
, state
) },
19 { "NJobs", "u", NULL
, offsetof(struct machine_info
, n_jobs
) },
20 { "NFailedUnits", "u", NULL
, offsetof(struct machine_info
, n_failed_units
) },
21 { "ControlGroup", "s", NULL
, offsetof(struct machine_info
, control_group
) },
22 { "UserspaceTimestamp", "t", NULL
, offsetof(struct machine_info
, timestamp
) },
26 void machine_info_clear(struct machine_info
*info
) {
31 free(info
->control_group
);
35 static void free_machines_list(struct machine_info
*machine_infos
, int n
) {
39 for (int i
= 0; i
< n
; i
++)
40 machine_info_clear(&machine_infos
[i
]);
45 static int compare_machine_info(const struct machine_info
*a
, const struct machine_info
*b
) {
48 r
= CMP(b
->is_host
, a
->is_host
);
52 return strcasecmp(a
->name
, b
->name
);
55 static int get_machine_properties(sd_bus
*bus
, struct machine_info
*mi
) {
56 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*container
= NULL
;
62 r
= sd_bus_open_system_machine(&container
, mi
->name
);
69 r
= bus_map_all_properties(
71 "org.freedesktop.systemd1",
72 "/org/freedesktop/systemd1",
73 machine_info_property_map
,
84 static bool output_show_machine(const char *name
, char **patterns
) {
85 return strv_fnmatch_or_empty(patterns
, name
, FNM_NOESCAPE
);
88 static int get_machine_list(
90 struct machine_info
**_machine_infos
,
93 struct machine_info
*machine_infos
= NULL
;
94 _cleanup_strv_free_
char **m
= NULL
;
95 _cleanup_free_
char *hn
= NULL
;
100 hn
= gethostname_malloc();
104 if (output_show_machine(hn
, patterns
)) {
105 if (!GREEDY_REALLOC0(machine_infos
, sz
, c
+1))
108 machine_infos
[c
].is_host
= true;
109 machine_infos
[c
].name
= TAKE_PTR(hn
);
111 (void) get_machine_properties(bus
, &machine_infos
[c
]);
115 r
= sd_get_machine_names(&m
);
117 return log_error_errno(r
, "Failed to get machine list: %m");
120 _cleanup_free_
char *class = NULL
;
122 if (!output_show_machine(*i
, patterns
))
125 sd_machine_get_class(*i
, &class);
126 if (!streq_ptr(class, "container"))
129 if (!GREEDY_REALLOC0(machine_infos
, sz
, c
+1)) {
130 free_machines_list(machine_infos
, c
);
134 machine_infos
[c
].is_host
= false;
135 machine_infos
[c
].name
= strdup(*i
);
136 if (!machine_infos
[c
].name
) {
137 free_machines_list(machine_infos
, c
);
141 (void) get_machine_properties(NULL
, &machine_infos
[c
]);
145 *_machine_infos
= machine_infos
;
149 static int output_machines_list(struct machine_info
*machine_infos
, unsigned n
) {
150 _cleanup_(table_unrefp
) Table
*table
= NULL
;
151 bool state_missing
= false;
154 assert(machine_infos
|| n
== 0);
156 table
= table_new("", "name", "state", "failed", "jobs");
160 table_set_header(table
, arg_legend
!= 0);
162 /* Hide the 'glyph' column when --plain is requested */
163 r
= table_hide_column_from_display(table
, 0);
165 return log_error_errno(r
, "Failed to hide column: %m");
168 table_set_width(table
, 0);
170 (void) table_set_empty_string(table
, "-");
172 for (struct machine_info
*m
= machine_infos
; m
< machine_infos
+ n
; m
++) {
173 _cleanup_free_
char *mname
= NULL
;
174 const char *on_state
= "", *on_failed
= "";
177 if (streq_ptr(m
->state
, "degraded")) {
178 on_state
= ansi_highlight_red();
180 } else if (!streq_ptr(m
->state
, "running")) {
181 on_state
= ansi_highlight_yellow();
185 if (m
->n_failed_units
> 0)
186 on_failed
= ansi_highlight_red();
191 state_missing
= true;
194 mname
= strjoin(strna(m
->name
), " (host)");
196 r
= table_add_many(table
,
197 TABLE_STRING
, circle
? special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE
) : " ",
198 TABLE_SET_COLOR
, on_state
,
199 TABLE_STRING
, m
->is_host
? mname
: strna(m
->name
),
200 TABLE_STRING
, strna(m
->state
),
201 TABLE_SET_COLOR
, on_state
,
202 TABLE_UINT32
, m
->n_failed_units
,
203 TABLE_SET_COLOR
, on_failed
,
204 TABLE_UINT32
, m
->n_jobs
);
206 return table_log_add_error(r
);
209 r
= output_table(table
);
213 if (arg_legend
!= 0) {
215 if (state_missing
&& geteuid() != 0)
216 printf("Notice: some information only available to privileged users was not shown.\n");
217 printf("%u machines listed.\n", n
);
223 int list_machines(int argc
, char *argv
[], void *userdata
) {
224 struct machine_info
*machine_infos
= NULL
;
228 r
= acquire_bus(BUS_MANAGER
, &bus
);
232 r
= get_machine_list(bus
, &machine_infos
, strv_skip(argv
, 1));
236 (void) pager_open(arg_pager_flags
);
238 typesafe_qsort(machine_infos
, r
, compare_machine_info
);
239 rc
= output_machines_list(machine_infos
, r
);
240 free_machines_list(machine_infos
, r
);