From 6057bbf9e852103c252bf3429146c5c1309bbc4a Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Wed, 1 Jul 2020 19:44:19 +0200 Subject: Improve the lint command further --- minecctl/misc-commands.c | 102 +++++++++++++++++++++++++++++++++++++++++++---- minecctl/rcon-commands.c | 14 ++++++- minecctl/server.c | 37 ++++++++++------- minecctl/server.h | 3 +- 4 files changed, 131 insertions(+), 25 deletions(-) (limited to 'minecctl') diff --git a/minecctl/misc-commands.c b/minecctl/misc-commands.c index 8dd6bd2..28d9e3a 100644 --- a/minecctl/misc-commands.c +++ b/minecctl/misc-commands.c @@ -12,31 +12,119 @@ bool do_list(struct cfg *cfg) /* 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); + 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 *server; + unsigned lineno; const char *error; bool rv = true; + struct server *a, *b; + unsigned ia, ib; /* server->scfg.filename check excludes servers created from cmdline */ list_for_each_entry(server, &cfg->servers, list) { if (!server->scfg.filename) continue; - info("• %s", server->name); + if (!server_read_config(cfg, server, &lineno, &error)) { + if (lineno != 0) + info("• %s: %sfail%s - line %u: %s", + server->name, ansi_red, ansi_normal, + lineno, error); + else + info("• %s: %sfail%s - %s", + server->name, ansi_red, ansi_normal, + error); + rv = false; + } else if (!scfg_validate(&server->scfg, &error)) { + info("• %s: %sfail%s - %s", + server->name, ansi_red, ansi_normal, + error); + rv = false; + } else { + info("• %s: %sok%s", server->name, ansi_green, + ansi_normal); + } + } - /* FIXME: should return bool */ - server_read_config(cfg, server); + info(""); - if (!scfg_validate(&server->scfg, &error)) { - error("%s: invalid (%s)", server->name, error); - rv = false; + 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; diff --git a/minecctl/rcon-commands.c b/minecctl/rcon-commands.c index fc5b932..dfe8647 100644 --- a/minecctl/rcon-commands.c +++ b/minecctl/rcon-commands.c @@ -371,13 +371,23 @@ bool do_stop(struct cfg *cfg) bool do_stop_all(struct cfg *cfg) { struct server *server; + unsigned lineno; + const char *error; + bool rv = true; list_for_each_entry(server, &cfg->servers, list) { - server_read_config(cfg, server); + if (!server_read_config(cfg, server, &lineno, &error)) { + info("• %s: %sfail%s - invalid configuration file " + "(line %u: %s)", + server->name, ansi_red, ansi_normal, + lineno, error); + rv = false; + } + /* FIXME: error checks */ stop_one_server(cfg, server); } - return true; + return rv; } bool do_rcon_pcount(struct cfg *cfg, unsigned *online, unsigned *max) diff --git a/minecctl/server.c b/minecctl/server.c index 93882f1..582c4fd 100644 --- a/minecctl/server.c +++ b/minecctl/server.c @@ -8,70 +8,77 @@ #include "server.h" #include "misc.h" -void server_read_config(struct cfg *cfg, struct server *server) +#define INVALID(msg) do { *error = (msg); return false; } while(0) + +bool server_read_config(struct cfg *cfg, struct server *server, + unsigned *lineno, const char **error) { - unsigned lineno; - const char *error; char buf[4096]; size_t off = 0; ssize_t r; int dfd; int fd; - if (!server || !server->scfg.filename || server->file_read) - return; + if (!server || !server->scfg.filename || server->file_read || + !lineno || !error) + return false; + *lineno = 0; server->file_read = true; dfd = open(cfg->cfgdir, O_DIRECTORY | O_PATH | O_CLOEXEC); if (dfd < 0) - die("Failed to open %s: %m", cfg->cfgdir); + INVALID("failed to open configuration directory"); fd = openat(dfd, server->scfg.filename, O_RDONLY | O_CLOEXEC); if (fd < 0) - die("Failed to open %s: %m", server->scfg.filename); + INVALID("failed to open configuration file"); close(dfd); while (true) { r = read(fd, buf + off, sizeof(buf) - off - 1); if (r < 0) - die("Failed to read %s: %m", server->scfg.filename); + INVALID("failed to read configuration file"); else if (r == 0) break; off += r; if (off == sizeof(buf) - 1) - die("Failed to read %s: file too large", - server->scfg.filename); + INVALID("invalid, file too large"); } buf[off] = '\0'; close(fd); - if (!scfg_parse(&server->scfg, buf, NULL, &lineno, &error)) - die("Unable to parse %s, line %u: %s", server->scfg.filename, - lineno, error); + if (!scfg_parse(&server->scfg, buf, NULL, lineno, error)) + return false; if (!server->scfg.rcon_password) - verbose("rcon password not found in %s", server->scfg.filename); + verbose("rcon password not set"); if (list_empty(&server->scfg.rcons)) verbose("rcon address not found in %s", server->scfg.filename); if (list_empty(&server->scfg.remotes)) verbose("mc server address not found in %s", server->scfg.filename); + + return true; } struct server *server_get_default(struct cfg *cfg) { struct server *server; + unsigned lineno; + const char *error; server = list_first_entry_or_null(&cfg->servers, struct server, list); if (!server) die("No servers defined"); - server_read_config(cfg, server); + /* FIXME: error msg */ + if (!server_read_config(cfg, server, &lineno, &error)) + return NULL; return server; } diff --git a/minecctl/server.h b/minecctl/server.h index 61eba5f..2bfb3e8 100644 --- a/minecctl/server.h +++ b/minecctl/server.h @@ -12,7 +12,8 @@ struct server { struct list_head list; }; -void server_read_config(struct cfg *cfg, struct server *server); +bool server_read_config(struct cfg *cfg, struct server *server, + unsigned *lineno, const char **error); struct server *server_get_default(struct cfg *cfg); -- cgit v1.2.3