#include #include #include #include #include "shared/utils.h" #include "minecctl.h" #include "server.h" #include "misc.h" #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) { char buf[4096]; size_t off = 0; ssize_t r; int dfd; int fd; 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) INVALID("failed to open configuration directory"); fd = openat(dfd, server->scfg.filename, O_RDONLY | O_CLOEXEC); if (fd < 0) INVALID("failed to open configuration file"); close(dfd); while (true) { r = read(fd, buf + off, sizeof(buf) - off - 1); if (r < 0) INVALID("failed to read configuration file"); else if (r == 0) break; off += r; if (off == sizeof(buf) - 1) INVALID("invalid, file too large"); } buf[off] = '\0'; close(fd); if (!scfg_parse(&server->scfg, buf, NULL, lineno, error)) return false; if (!server->scfg.rcon_password) 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"); /* FIXME: error msg */ if (!server_read_config(cfg, server, &lineno, &error)) return NULL; return server; } bool server_set_default(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 server_load_all_known(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(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_all(struct cfg *cfg) { struct server *server, *tmp; list_for_each_entry_safe(server, tmp, &cfg->servers, list) server_free(server); } void server_free(struct server *server) { scfg_delete(&server->scfg); xfree(server->name); xfree(server); } struct server *server_new(const char *filename) { struct server *server; server = zmalloc(sizeof(*server)); scfg_init(&server->scfg, filename); INIT_LIST_HEAD(&server->list); return server; }