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
;
98 hn
= gethostname_malloc();
102 if (output_show_machine(hn
, patterns
)) {
103 if (!GREEDY_REALLOC0(machine_infos
, c
+1))
106 machine_infos
[c
].is_host
= true;
107 machine_infos
[c
].name
= TAKE_PTR(hn
);
109 (void) get_machine_properties(bus
, &machine_infos
[c
]);
113 r
= sd_get_machine_names(&m
);
115 return log_error_errno(r
, "Failed to get machine list: %m");
118 _cleanup_free_
char *class = NULL
;
120 if (!output_show_machine(*i
, patterns
))
123 sd_machine_get_class(*i
, &class);
124 if (!streq_ptr(class, "container"))
127 if (!GREEDY_REALLOC0(machine_infos
, c
+1)) {
128 free_machines_list(machine_infos
, c
);
132 machine_infos
[c
].is_host
= false;
133 machine_infos
[c
].name
= strdup(*i
);
134 if (!machine_infos
[c
].name
) {
135 free_machines_list(machine_infos
, c
);
139 (void) get_machine_properties(NULL
, &machine_infos
[c
]);
143 *_machine_infos
= machine_infos
;
147 static int output_machines_list(struct machine_info
*machine_infos
, unsigned n
) {
148 _cleanup_(table_unrefp
) Table
*table
= NULL
;
149 bool state_missing
= false;
152 assert(machine_infos
|| n
== 0);
154 table
= table_new("", "name", "state", "failed", "jobs");
158 table_set_header(table
, arg_legend
!= 0);
160 /* Hide the 'glyph' column when --plain is requested */
161 r
= table_hide_column_from_display(table
, 0);
163 return log_error_errno(r
, "Failed to hide column: %m");
166 table_set_width(table
, 0);
168 (void) table_set_empty_string(table
, "-");
170 for (struct machine_info
*m
= machine_infos
; m
< machine_infos
+ n
; m
++) {
171 _cleanup_free_
char *mname
= NULL
;
172 const char *on_state
= "", *on_failed
= "";
175 if (streq_ptr(m
->state
, "degraded")) {
176 on_state
= ansi_highlight_red();
178 } else if (!streq_ptr(m
->state
, "running")) {
179 on_state
= ansi_highlight_yellow();
183 if (m
->n_failed_units
> 0)
184 on_failed
= ansi_highlight_red();
189 state_missing
= true;
192 mname
= strjoin(strna(m
->name
), " (host)");
194 r
= table_add_many(table
,
195 TABLE_STRING
, circle
? special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE
) : " ",
196 TABLE_SET_COLOR
, on_state
,
197 TABLE_STRING
, m
->is_host
? mname
: strna(m
->name
),
198 TABLE_STRING
, strna(m
->state
),
199 TABLE_SET_COLOR
, on_state
,
200 TABLE_UINT32
, m
->n_failed_units
,
201 TABLE_SET_COLOR
, on_failed
,
202 TABLE_UINT32
, m
->n_jobs
);
204 return table_log_add_error(r
);
207 r
= output_table(table
);
211 if (arg_legend
!= 0) {
213 if (state_missing
&& geteuid() != 0)
214 printf("Notice: some information only available to privileged users was not shown.\n");
215 printf("%u machines listed.\n", n
);
221 int verb_list_machines(int argc
, char *argv
[], void *userdata
) {
222 struct machine_info
*machine_infos
= NULL
;
226 r
= acquire_bus(BUS_MANAGER
, &bus
);
230 r
= get_machine_list(bus
, &machine_infos
, strv_skip(argv
, 1));
234 pager_open(arg_pager_flags
);
236 typesafe_qsort(machine_infos
, r
, compare_machine_info
);
237 rc
= output_machines_list(machine_infos
, r
);
238 free_machines_list(machine_infos
, r
);