From 09d88fc3db9265732c7960ee52240b1196dcee71 Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Fri, 26 Jun 2020 22:26:14 +0200 Subject: Split off all server functionality to a separate file --- minecctl/server.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 minecctl/server.c (limited to 'minecctl/server.c') diff --git a/minecctl/server.c b/minecctl/server.c new file mode 100644 index 0000000..8a32486 --- /dev/null +++ b/minecctl/server.c @@ -0,0 +1,198 @@ +#include +#include +#include +#include + +#include "utils.h" +#include "minecctl.h" +#include "server.h" +#include "misc.h" +#include "config-parser.h" +#include "server-config-options.h" + +void +read_server_config(struct cfg *cfg, struct server *server) +{ + char buf[4096]; + size_t off = 0; + ssize_t r; + int dfd; + int fd; + char *pos = buf; + + if (!server || !server->filename || server->file_read) + return; + + 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); + + fd = openat(dfd, server->filename, O_RDONLY | O_CLOEXEC); + if (fd < 0) + die("Failed to open %s: %m", server->filename); + + close(dfd); + + while (true) { + r = read(fd, buf + off, sizeof(buf) - off - 1); + if (r < 0) + die("Failed to read %s: %m", server->filename); + else if (r == 0) + break; + + off += r; + if (off == sizeof(buf) - 1) + die("Failed to read %s: file too large", server->filename); + } + + buf[off] = '\0'; + close(fd); + + if (!config_parse_header(SERVER_CFG_HEADER, &pos)) + die("Unable to parse %s: invalid/missing header", + server->filename); + + /* FIXME: this will cause superflous DNS lookups of other cfg entries */ + while (true) { + int key; + const char *keyname; + struct cfg_value value; + + if (!config_parse_line(server->filename, &pos, scfg_key_map, + &key, &keyname, &value, false)) + break; + + switch (key) { + case SCFG_KEY_RCON: + if (!list_empty(&server->rcon_addrs)) + die("rcon address defined twice in %s", + server->filename); + list_replace(&value.saddrs, &server->rcon_addrs); + break; + case SCFG_KEY_RCON_PASSWORD: + if (server->rcon_password) + die("rcon password defined twice in %s", + server->filename); + server->rcon_password = xstrdup(value.str); + break; + case SCFG_KEY_REMOTE: + if (!list_empty(&server->mc_addrs)) + die("rcon address defined twice in %s", + server->filename); + list_replace(&value.saddrs, &server->mc_addrs); + default: + continue; + } + } + + if (!server->rcon_password) + verbose("rcon password not found in %s", server->filename); + + if (list_empty(&server->rcon_addrs)) + verbose("rcon address not found in %s", server->filename); + + if (list_empty(&server->mc_addrs)) + verbose("mc server address not found in %s", server->filename); +} + +struct server * +get_default_server(struct cfg *cfg) +{ + struct server *server; + + server = list_first_entry_or_null(&cfg->servers, struct server, list); + if (!server) + die("No servers defined"); + + read_server_config(cfg, server); + + return server; +} + +bool +set_default_server(struct cfg *cfg, const char *name) +{ + struct server *server; + + assert_die(cfg, "invalid arguments"); + + list_for_each_entry(server, &cfg->servers, list) { + if (streq(name, server->name)) { + list_rotate_to_front(&server->list, &cfg->servers); + return true; + } + } + + return false; +} + +void +get_servers(struct cfg *cfg) +{ + struct dirent *dent; + DIR *dir; + + dir = opendir(cfg->cfgdir); + if (!dir) { + info("Can't open config directory %s: %m", cfg->cfgdir); + return; + } + + while ((dent = readdir(dir))) { + struct server *server; + char *suffix; + + if (!is_valid_server_config_filename(dent, NULL)) + continue; + + server = server_new(); + server->filename = xstrdup(dent->d_name); + + suffix = strrchr(dent->d_name, '.'); + assert_die(suffix, "Error parsing filename"); + *suffix = '\0'; + server->name = xstrdup(dent->d_name); + + list_add(&server->list, &cfg->servers); + } + + closedir(dir); +} + +void +server_free(struct server *server) +{ + struct saddr *saddr, *tmp; + + xfree(server->name); + xfree(server->filename); + free_password(&server->rcon_password); + + list_for_each_entry_safe(saddr, tmp, &server->rcon_addrs, list) { + list_del(&saddr->list); + xfree(saddr); + } + + list_for_each_entry_safe(saddr, tmp, &server->mc_addrs, list) { + list_del(&saddr->list); + xfree(saddr); + } + + xfree(server); +} + +struct server * +server_new() +{ + struct server *server; + + server = zmalloc(sizeof(*server)); + INIT_LIST_HEAD(&server->rcon_addrs); + INIT_LIST_HEAD(&server->mc_addrs); + INIT_LIST_HEAD(&server->list); + + return server; +} + -- cgit v1.2.3