/* SPDX-License-Identifier: GPL-2.0 */ #include "shared/utils.h" #include "minecctl.h" #include "server.h" #include "misc-commands.h" #include "rcon-commands.h" #include "mc-commands.h" #include "shared/systemd.h" bool do_list(struct cfg *cfg) { struct server *server; /* server->scfg.filename check excludes servers created from cmdline */ list_for_each_entry(server, &cfg->servers, list) if (server->scfg.filename) info("• %s", server->name); return true; } static bool saddr_match(struct list_head *la, struct list_head *lb) { struct saddr *a, *b; list_for_each_entry(a, la, list) { list_for_each_entry(b, lb, list) { if (a->st.ss_family != b->st.ss_family) continue; switch (a->st.ss_family) { case AF_INET: if (memcmp(&a->in4.sin_addr, &b->in4.sin_addr, sizeof(a->in4.sin_addr))) continue; if (a->in4.sin_port != b->in4.sin_port) continue; return true; case AF_INET6: if (memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr))) continue; if (a->in6.sin6_port != b->in6.sin6_port) continue; return true; default: continue; } } } return false; } bool do_lint(struct cfg *cfg) { struct server *a, *b; unsigned ia, ib; bool rv = true; rv = server_read_all_configs(cfg, true); dump_config(cfg); ia = 0; list_for_each_entry(a, &cfg->servers, list) { ib = 0; list_for_each_entry(b, &cfg->servers, list) { if (ib <= ia) { ib++; continue; } if (a->scfg.announce_port != 0 && b->scfg.announce_port != 0 && a->scfg.announce_port == b->scfg.announce_port) info("%sNote:%s %s and %s appear to have the " "same announce port", ansi_red, ansi_normal, a->name, b->name); if (saddr_match(&a->scfg.locals, &b->scfg.locals)) info("%sNote:%s %s and %s appear to share at " "least one local address/port pair", ansi_red, ansi_normal, a->name, b->name); if (saddr_match(&a->scfg.remotes, &b->scfg.remotes)) info("%sNote:%s %s and %s appear to share at " "least one remote address/port pair", ansi_red, ansi_normal, a->name, b->name); if (saddr_match(&a->scfg.rcons, &b->scfg.rcons)) info("%sNote:%s %s and %s appear to share at " "least one rcon address/port pair", ansi_red, ansi_normal, a->name, b->name); ib++; } ia++; } return rv; } bool do_pcount(struct cfg *cfg) { unsigned online, max; struct server *server; const char *error; server = server_get_default(cfg); if (!server) { error("failed to get default server"); return false; } if (do_rcon_pcount(cfg, server, &online, &max, &error)) info("Rcon says %u/%u", online, max); if (do_mc_pcount(cfg, server, &online, &max, &error)) info("MC says %u/%u", online, max); return true; } static bool do_one_status(struct cfg *cfg, struct server *server) { unsigned online, max; const char *error; bool rv = true; info("• %s", server->name); if (list_empty(&server->scfg.rcons)) info(" rcon : not configured"); else if (do_rcon_pcount(cfg, server, &online, &max, &error)) info(" rcon : %sok%s", ansi_green, ansi_normal); else { info(" rcon : %sfail%s (%s)", ansi_red, ansi_normal, error); rv = false; } if (list_empty(&server->scfg.remotes)) info(" mc : not configured"); else if (do_mc_pcount(cfg, server, &online, &max, &error)) info(" mc : %sok%s", ansi_green, ansi_normal); else { info(" mc : %sfail%s (%s)", ansi_red, ansi_normal, error); rv = false; } if (!server->scfg.systemd_service || !server->scfg.systemd_obj) info(" systemd service : not configured"); else if (systemd_service_running(&server->scfg, &error)) info(" systemd service : %sactive%s", ansi_green, ansi_normal); else { info(" systemd service : %sfail%s (%s)", ansi_red, ansi_normal, error); rv = false; } return rv; } bool do_status(struct cfg *cfg) { struct server *server; if (cfg->default_set) { server = server_get_default(cfg); if (!server) { error("failed to get default server"); return false; } do_one_status(cfg, server); } else { server_read_all_configs(cfg, false); list_for_each_entry(server, &cfg->servers, list) do_one_status(cfg, server); } systemd_delete(); return true; }