summaryrefslogtreecommitdiffstats
path: root/src/systemctl/systemctl-list-machines.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2020-10-07 11:27:56 +0200
committerLennart Poettering <lennart@poettering.net>2020-10-07 23:12:15 +0200
commitdaf71ef61ce0d60f378e20169fb8ab252f54d104 (patch)
tree01968fc42d802652b13921ac6c14bf6d3f5b0728 /src/systemctl/systemctl-list-machines.c
parentsystemctl: move compare_unit_info() to bus-unit-util.[ch] (diff)
downloadsystemd-daf71ef61ce0d60f378e20169fb8ab252f54d104.tar.xz
systemd-daf71ef61ce0d60f378e20169fb8ab252f54d104.zip
systemctl: split up humungous systemctl.c file
This is just some refactoring: shifting around of code, not change in codeflow. This splits up the way too huge systemctl.c in multiple more easily digestable files. It roughly follows the rule that each family of verbs gets its own .c/.h file pair, and so do all the compat executable names we support. Plus three extra files for sysv compat (which existed before already, but I renamed slightly, to get the systemctl- prefix lik everything else), a -util file with generic stuff everything uses, and a -logind file with everything that talks directly to logind instead of PID1. systemctl is still a bit too complex for my taste, but I think this way itc omes in a more digestable bits at least. No change of behaviour, just reshuffling of some code.
Diffstat (limited to 'src/systemctl/systemctl-list-machines.c')
-rw-r--r--src/systemctl/systemctl-list-machines.c246
1 files changed, 246 insertions, 0 deletions
diff --git a/src/systemctl/systemctl-list-machines.c b/src/systemctl/systemctl-list-machines.c
new file mode 100644
index 0000000000..424778c803
--- /dev/null
+++ b/src/systemctl/systemctl-list-machines.c
@@ -0,0 +1,246 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <unistd.h>
+
+#include "sd-login.h"
+
+#include "bus-map-properties.h"
+#include "hostname-util.h"
+#include "locale-util.h"
+#include "memory-util.h"
+#include "sort-util.h"
+#include "systemctl-list-machines.h"
+#include "systemctl-util.h"
+#include "systemctl.h"
+#include "terminal-util.h"
+
+const struct bus_properties_map machine_info_property_map[] = {
+ { "SystemState", "s", NULL, offsetof(struct machine_info, state) },
+ { "NJobs", "u", NULL, offsetof(struct machine_info, n_jobs) },
+ { "NFailedUnits", "u", NULL, offsetof(struct machine_info, n_failed_units) },
+ { "ControlGroup", "s", NULL, offsetof(struct machine_info, control_group) },
+ { "UserspaceTimestamp", "t", NULL, offsetof(struct machine_info, timestamp) },
+ {}
+};
+
+void machine_info_clear(struct machine_info *info) {
+ assert(info);
+
+ free(info->name);
+ free(info->state);
+ free(info->control_group);
+ zero(*info);
+}
+
+static void free_machines_list(struct machine_info *machine_infos, int n) {
+ int i;
+
+ if (!machine_infos)
+ return;
+
+ for (i = 0; i < n; i++)
+ machine_info_clear(&machine_infos[i]);
+
+ free(machine_infos);
+}
+
+static int compare_machine_info(const struct machine_info *a, const struct machine_info *b) {
+ int r;
+
+ r = CMP(b->is_host, a->is_host);
+ if (r != 0)
+ return r;
+
+ return strcasecmp(a->name, b->name);
+}
+
+static int get_machine_properties(sd_bus *bus, struct machine_info *mi) {
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *container = NULL;
+ int r;
+
+ assert(mi);
+
+ if (!bus) {
+ r = sd_bus_open_system_machine(&container, mi->name);
+ if (r < 0)
+ return r;
+
+ bus = container;
+ }
+
+ r = bus_map_all_properties(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ machine_info_property_map,
+ BUS_MAP_STRDUP,
+ NULL,
+ NULL,
+ mi);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+static bool output_show_machine(const char *name, char **patterns) {
+ return strv_fnmatch_or_empty(patterns, name, FNM_NOESCAPE);
+}
+
+static int get_machine_list(
+ sd_bus *bus,
+ struct machine_info **_machine_infos,
+ char **patterns) {
+
+ struct machine_info *machine_infos = NULL;
+ _cleanup_strv_free_ char **m = NULL;
+ _cleanup_free_ char *hn = NULL;
+ size_t sz = 0;
+ char **i;
+ int c = 0, r;
+
+ hn = gethostname_malloc();
+ if (!hn)
+ return log_oom();
+
+ if (output_show_machine(hn, patterns)) {
+ if (!GREEDY_REALLOC0(machine_infos, sz, c+1))
+ return log_oom();
+
+ machine_infos[c].is_host = true;
+ machine_infos[c].name = TAKE_PTR(hn);
+
+ (void) get_machine_properties(bus, &machine_infos[c]);
+ c++;
+ }
+
+ r = sd_get_machine_names(&m);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get machine list: %m");
+
+ STRV_FOREACH(i, m) {
+ _cleanup_free_ char *class = NULL;
+
+ if (!output_show_machine(*i, patterns))
+ continue;
+
+ sd_machine_get_class(*i, &class);
+ if (!streq_ptr(class, "container"))
+ continue;
+
+ if (!GREEDY_REALLOC0(machine_infos, sz, c+1)) {
+ free_machines_list(machine_infos, c);
+ return log_oom();
+ }
+
+ machine_infos[c].is_host = false;
+ machine_infos[c].name = strdup(*i);
+ if (!machine_infos[c].name) {
+ free_machines_list(machine_infos, c);
+ return log_oom();
+ }
+
+ (void) get_machine_properties(NULL, &machine_infos[c]);
+ c++;
+ }
+
+ *_machine_infos = machine_infos;
+ return c;
+}
+
+static int output_machines_list(struct machine_info *machine_infos, unsigned n) {
+ _cleanup_(table_unrefp) Table *table = NULL;
+ struct machine_info *m;
+ bool state_missing = false;
+ int r;
+
+ assert(machine_infos || n == 0);
+
+ table = table_new("", "name", "state", "failed", "jobs");
+ if (!table)
+ return log_oom();
+
+ table_set_header(table, !arg_no_legend);
+ if (arg_plain) {
+ /* Hide the 'glyph' column when --plain is requested */
+ r = table_hide_column_from_display(table, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to hide column: %m");
+ }
+ if (arg_full)
+ table_set_width(table, 0);
+
+ (void) table_set_empty_string(table, "-");
+
+ for (m = machine_infos; m < machine_infos + n; m++) {
+ _cleanup_free_ char *mname = NULL;
+ const char *on_state = "", *on_failed = "";
+ bool circle = false;
+
+ if (streq_ptr(m->state, "degraded")) {
+ on_state = ansi_highlight_red();
+ circle = true;
+ } else if (!streq_ptr(m->state, "running")) {
+ on_state = ansi_highlight_yellow();
+ circle = true;
+ }
+
+ if (m->n_failed_units > 0)
+ on_failed = ansi_highlight_red();
+ else
+ on_failed = "";
+
+ if (!m->state)
+ state_missing = true;
+
+ if (m->is_host)
+ mname = strjoin(strna(m->name), " (host)");
+
+ r = table_add_many(table,
+ TABLE_STRING, circle ? special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE) : " ",
+ TABLE_SET_COLOR, on_state,
+ TABLE_STRING, m->is_host ? mname : strna(m->name),
+ TABLE_STRING, strna(m->state),
+ TABLE_SET_COLOR, on_state,
+ TABLE_UINT32, m->n_failed_units,
+ TABLE_SET_COLOR, on_failed,
+ TABLE_UINT32, m->n_jobs);
+ if (r < 0)
+ return table_log_add_error(r);
+ }
+
+ r = output_table(table);
+ if (r < 0)
+ return r;
+
+ if (!arg_no_legend) {
+ printf("\n");
+ if (state_missing && geteuid() != 0)
+ printf("Notice: some information only available to privileged users was not shown.\n");
+ printf("%u machines listed.\n", n);
+ }
+
+ return 0;
+}
+
+int list_machines(int argc, char *argv[], void *userdata) {
+ struct machine_info *machine_infos = NULL;
+ sd_bus *bus;
+ int r, rc;
+
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ r = get_machine_list(bus, &machine_infos, strv_skip(argv, 1));
+ if (r < 0)
+ return r;
+
+ (void) pager_open(arg_pager_flags);
+
+ typesafe_qsort(machine_infos, r, compare_machine_info);
+ rc = output_machines_list(machine_infos, r);
+ free_machines_list(machine_infos, r);
+
+ return rc;
+}