summaryrefslogtreecommitdiff
path: root/minecctl/server.c
diff options
context:
space:
mode:
authorDavid Härdeman <david@hardeman.nu>2020-06-26 22:26:14 +0200
committerDavid Härdeman <david@hardeman.nu>2020-06-26 22:26:14 +0200
commit09d88fc3db9265732c7960ee52240b1196dcee71 (patch)
treef2324fc368f23baa379b2240bd044a6f1a7b06ab /minecctl/server.c
parent591b03bd3cfd52b33a5e8512fef466494cf329f6 (diff)
Split off all server functionality to a separate file
Diffstat (limited to 'minecctl/server.c')
-rw-r--r--minecctl/server.c198
1 files changed, 198 insertions, 0 deletions
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 <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#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;
+}
+