From f06ff46151c38b2259c5ee4ae83d38c6f6fc0c8c Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Sun, 12 Jul 2020 02:30:31 +0200 Subject: Teach minecctl to create proper mcserver files, auto-generate systemd service names as necessary --- examples/meson.build | 21 +++++--- minecctl/minecctl.c | 8 +-- minecctl/misc-commands.c | 118 +++++++++++++++++++++++++++------------------ minecctl/misc.c | 2 +- minecctl/rcon-commands.c | 26 +++++----- minecctl/server.c | 21 +++----- minecctl/server.h | 1 - minecproxy/server-config.c | 14 +++--- minecproxy/server-proxy.c | 36 +++++++------- minecproxy/server-rcon.c | 26 +++++----- minecproxy/server.c | 71 +++++++++++---------------- minecproxy/server.h | 1 - shared/config-parser.c | 71 +++++++++++++++++---------- shared/config-parser.h | 1 + shared/utils.c | 34 +++++++++++++ shared/utils.h | 2 + 16 files changed, 257 insertions(+), 196 deletions(-) diff --git a/examples/meson.build b/examples/meson.build index 5d3564b..7b525f6 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -1,8 +1,7 @@ # SPDX-License-Identifier: GPL-2 -example_files = [ +xxd_files = [ 'eula.txt', - 'example.mcserver', 'minecctl.conf', 'minecproxy.conf', 'minecproxy.service', @@ -14,16 +13,24 @@ xxd = find_program('xxd') xxd_cmd = [xxd, '-i', '@INPUT@', '@OUTPUT@'] -foreach example_file: example_files - example_output = example_file + '.h' +foreach xxd_file: xxd_files + xxd_output = xxd_file + '.h' file = custom_target( - example_output, - input: example_file, - output: example_output, + xxd_output, + input: xxd_file, + output: xxd_output, command: xxd_cmd, build_by_default: true, ) endforeach +install_files = [ + 'example.mcserver', + 'minecctl.conf', + 'minecproxy.conf', + 'minecproxy.service', + 'minecserver@.service', +] + diff --git a/minecctl/minecctl.c b/minecctl/minecctl.c index 4a6bf0f..c2d6c19 100644 --- a/minecctl/minecctl.c +++ b/minecctl/minecctl.c @@ -28,7 +28,7 @@ static void dump_server(struct server *server) info("│"); info("│ ▷ server"); info("│ ┌─────"); - info("│ │ name : %s", server->name); + info("│ │ name : %s", server->scfg.name); info("│ │ file_read : %s", server->file_read ? "yes" : "no"); info("│ │ filename : %s", server->scfg.filename); @@ -237,7 +237,7 @@ static bool create_server_from_cmdline_args(struct cfg *cfg) if (!str_to_addrs(cfg->rcon_addrstr, &server->scfg.rcons)) goto error; - server->name = cfg->rcon_addrstr; + server->scfg.name = cfg->rcon_addrstr; cfg->rcon_addrstr = NULL; } @@ -245,8 +245,8 @@ static bool create_server_from_cmdline_args(struct cfg *cfg) if (!str_to_addrs(cfg->mc_addrstr, &server->scfg.remotes)) goto error; - if (!server->name) - server->name = cfg->mc_addrstr; + if (!server->scfg.name) + server->scfg.name = cfg->mc_addrstr; else xfree(cfg->mc_addrstr); diff --git a/minecctl/misc-commands.c b/minecctl/misc-commands.c index 1133e55..34dd990 100644 --- a/minecctl/misc-commands.c +++ b/minecctl/misc-commands.c @@ -20,7 +20,6 @@ #include "misc.h" #include "examples/eula.txt.h" -#include "examples/example.mcserver.h" #include "examples/minecctl.conf.h" #include "examples/minecproxy.conf.h" #include "examples/minecproxy.service.h" @@ -142,10 +141,12 @@ static bool create_user_service(int xfd, const char *service, return true; } -static bool create_server_cfg(struct cfg *cfg, const char *name, - const char *filename, - const unsigned char *properties, - size_t properties_len) +static bool write_server_cfg(struct cfg *cfg, const char *name, + const char *filename, + const unsigned char *properties, + size_t properties_len, + const unsigned char *mcserver, + size_t mcserver_len) { _cleanup_close_ int sfd = -1; int cfd, dfd; @@ -156,17 +157,15 @@ static bool create_server_cfg(struct cfg *cfg, const char *name, cfd = dirfd(cfg->cfg_dir); dfd = dirfd(cfg->data_dir); - if (!write_cfg_file(cfd, filename, - ___examples_example_mcserver, - ___examples_example_mcserver_len)) - return false; - sfd = open_subdir(dfd, name, true); if (sfd < 0) { error("Failed to create server directory \"%s\"", name); return false; } + if (!write_cfg_file(cfd, filename, mcserver, mcserver_len)) + return false; + if (!write_cfg_file(sfd, "eula.txt", ___examples_eula_txt, ___examples_eula_txt_len)) return false; @@ -299,18 +298,37 @@ static bool generate_random_password(char *buf, size_t len) } *d = '\0'; - info("Hex = %s", buf); return true; } +static unsigned char *create_mc_server(const char *name, uint16_t local_port, + size_t *len) +{ + char *mcserver; + + /* FIXME: Add comments, commented out options */ + mcserver = xsprintf(len, + "[server]\n" + "type = proxy\n" + "name = %s\n" + "local = %" PRIu16 "\n" + "idle_timeout = 600\n" + "start_method = systemd\n" + "stop_method = systemd\n", + name, local_port); + if (!mcserver) + error("xsprintf: %m"); + + return (unsigned char *)mcserver; +} + static unsigned char *create_mc_properties(const char *name, uint16_t mc_port, uint16_t rcon_port, const char *rcon_password, size_t *len) { char hexrnd[16 + 1]; - char *properties; - int r; + char *prop; if (!rcon_password) { if (!generate_random_password(hexrnd, sizeof(hexrnd))) { @@ -319,27 +337,24 @@ static unsigned char *create_mc_properties(const char *name, uint16_t mc_port, } } - /* FIXME: server-ip= */ - r = asprintf(&properties, - "#Minecraft server properties\n" - "# This is a partial file, it will be replaced with a\n" - "# fleshed out version the first time the Minecraft\n" - "# server is executed.\n" - "motd=%s\n" - "server-port=%" PRIu16 "\n" - "enable-rcon=true\n" - "rcon.port=%" PRIu16 "\n" - "rcon.password=%s", - name, mc_port, rcon_port, - rcon_password ? rcon_password : hexrnd); - if (r < 0) { - error("asprintf failed: %m"); - return NULL; - } - - if (len) - *len = r; - return (unsigned char *)properties; + prop = xsprintf(len, + "#Minecraft server properties\n" + "# This is a partial file, it will be replaced with a\n" + "# fleshed out version the first time the Minecraft\n" + "# server is executed.\n" + "motd=%s\n" + "#maybe uncomment the next line if you use minecproxy\n" + "#server-ip=127.0.0.1\n" + "server-port=%" PRIu16 "\n" + "enable-rcon=true\n" + "rcon.port=%" PRIu16 "\n" + "rcon.password=%s\n", + name, mc_port, rcon_port, + rcon_password ? rcon_password : hexrnd); + if (!prop) + error("xsprintf: %m"); + + return (unsigned char *)prop; } static uint16_t get_port(struct list_head *list) @@ -461,10 +476,12 @@ bool do_new(struct cfg *cfg) const char *name = cfg->commands[0]; struct server *server; struct server *defserver = NULL; + uint16_t local_port = 0, mc_port = 0, rcon_port = 0; + const char *rcon_password = NULL; _cleanup_free_ unsigned char *properties = NULL; size_t properties_len; - uint16_t rcon_port = 0, mc_port = 0; - const char *rcon_password = NULL; + _cleanup_free_ unsigned char *mcserver = NULL; + size_t mcserver_len; if (!valid_name(name)) return false; @@ -494,7 +511,6 @@ bool do_new(struct cfg *cfg) } if (defserver) { - /* FIXME: check list empty and tailor error msg */ rcon_port = get_port(&defserver->scfg.rcons); mc_port = get_port(&defserver->scfg.remotes); rcon_password = defserver->scfg.rcon_password; @@ -503,8 +519,8 @@ bool do_new(struct cfg *cfg) dump_config(cfg); - if (!select_free_ports(cfg, NULL, &mc_port, &rcon_port)) { - error("Failed to find a free port"); + if (!select_free_ports(cfg, &local_port, &mc_port, &rcon_port)) { + error("Failed to find free port(s)"); return false; } @@ -513,10 +529,13 @@ bool do_new(struct cfg *cfg) if (!properties) return false; - error("Created config file (%zu):\n%s", properties_len, properties); + mcserver = create_mc_server(name, local_port, &mcserver_len); + if (!mcserver) + return false; - if (!create_server_cfg(cfg, name, filename, properties, - properties_len)) + if (!write_server_cfg(cfg, name, filename, + properties, properties_len, + mcserver, mcserver_len)) return false; info("Created server configuration %s", name); @@ -532,7 +551,7 @@ 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->scfg.name); return true; } @@ -598,22 +617,25 @@ bool do_lint(struct cfg *cfg) 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); + ansi_normal, a->scfg.name, b->scfg.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); + ansi_red, ansi_normal, a->scfg.name, + b->scfg.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); + ansi_red, ansi_normal, a->scfg.name, + b->scfg.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); + ansi_red, ansi_normal, a->scfg.name, + b->scfg.name); ib++; } @@ -648,7 +670,7 @@ static bool do_one_status(struct cfg *cfg, struct server *server) const char *error; bool rv = true; - info("• %s", server->name); + info("• %s", server->scfg.name); if (list_empty(&server->scfg.rcons)) info(" rcon : not configured"); diff --git a/minecctl/misc.c b/minecctl/misc.c index 26cbc86..90189dc 100644 --- a/minecctl/misc.c +++ b/minecctl/misc.c @@ -335,7 +335,7 @@ char *__xstrndup(const char *fn, int line, const char *s, size_t n) "invalid arguments"); ptr = strndup(s, n); - if (ptr) + if (!ptr) die("strdup: %m"); return ptr; } diff --git a/minecctl/rcon-commands.c b/minecctl/rcon-commands.c index cb6ea45..cdbf868 100644 --- a/minecctl/rcon-commands.c +++ b/minecctl/rcon-commands.c @@ -96,22 +96,22 @@ static int rcon_login(struct cfg *cfg, struct server *server) assert_die(cfg && server, "invalid arguments"); if (list_empty(&server->scfg.rcons)) { - error("%s: rcon address unknown", server->name); + error("%s: rcon address unknown", server->scfg.name); goto error; } fd = connect_any(&server->scfg.rcons, &saddr, &error); if (fd < 0) { - verbose("%s: unable to connect - %s", server->name, error); + verbose("%s: unable to connect - %s", server->scfg.name, error); goto error; } else - verbose("%s: connected to %s", server->name, saddr->addrstr); + verbose("%s: connected to %s", server->scfg.name, saddr->addrstr); if (!server->scfg.rcon_password) server->scfg.rcon_password = ask_password(); if (!server->scfg.rcon_password) { - error("%s: can't login - password missing", server->name); + error("%s: can't login - password missing", server->scfg.name); goto error; } @@ -123,10 +123,10 @@ static int rcon_login(struct cfg *cfg, struct server *server) if (!rcon_protocol_verify_response(1, 1, RCON_PACKET_LOGIN, rtype, &error)) { - error("%s: invalid response - %s", server->name, error); + error("%s: invalid response - %s", server->scfg.name, error); goto error; } else - verbose("%s: login ok", server->name); + verbose("%s: login ok", server->scfg.name); return fd; @@ -230,7 +230,7 @@ static bool do_one_info(struct cfg *cfg, struct server *server) if (fd < 0) return false; - info("• %s", server->name); + info("• %s", server->scfg.name); if (get_one_status(fd, buf, sizeof(buf), "seed", 1, "Seed : [ %[^]]]", &reply, tbuf)) info(" Seed: %s", tbuf); @@ -336,7 +336,7 @@ static bool stop_one_server(struct cfg *cfg, struct server *server) fd = rcon_login(cfg, server); if (fd < 0) { info("• %s: %sfail%s - unable to login", - server->name, ansi_red, ansi_normal); + server->scfg.name, ansi_red, ansi_normal); return false; } @@ -345,17 +345,17 @@ static bool stop_one_server(struct cfg *cfg, struct server *server) if (!get_player_count(fd, ¤t, NULL)) { info("• %s: %sfail%s - unable to get player count", - server->name, ansi_red, ansi_normal); + server->scfg.name, ansi_red, ansi_normal); return false; } else if (current > 0) { info("• %s: %sfail%s - has active players " "(use -f to force)", - server->name, ansi_red, ansi_normal); + server->scfg.name, ansi_red, ansi_normal); return false; } } - info("• %s: sending stop command", server->name); + info("• %s: sending stop command", server->scfg.name); rv = send_cmd(fd, "stop"); close(fd); @@ -419,9 +419,9 @@ bool do_console(struct cfg *cfg) return false; prompt = alloca(strlen(program_invocation_short_name) + STRLEN(" (") + - strlen(server->name) + STRLEN("): ") + 1); + strlen(server->scfg.name) + STRLEN("): ") + 1); sprintf(prompt, "%s (%s): ", program_invocation_short_name, - server->name); + server->scfg.name); while (true) { char *tmp; diff --git a/minecctl/server.c b/minecctl/server.c index 8bd7b51..3acc537 100644 --- a/minecctl/server.c +++ b/minecctl/server.c @@ -71,18 +71,12 @@ void server_load_all_known(struct cfg *cfg) while ((dent = readdir(cfg->cfg_dir))) { struct server *server; - char *suffix; if (!config_valid_server_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); } } @@ -153,7 +147,7 @@ bool server_read_config(struct cfg *cfg, struct server *server, return false; /* fill in missing parameters from server.properties */ - dfd = open_subdir(dirfd(cfg->data_dir), server->name, false); + dfd = open_subdir(dirfd(cfg->data_dir), server->scfg.name, false); if (dfd < 0) goto out; @@ -193,21 +187,21 @@ bool server_read_all_configs(struct cfg *cfg, bool print_results) if (!server_read_config(cfg, server, &lineno, &error)) { if (lineno != 0 && print_results) info("• %s: %sfail%s - line %u: %s", - server->name, ansi_red, ansi_normal, + server->scfg.name, ansi_red, ansi_normal, lineno, error); else if (print_results) info("• %s: %sfail%s - %s", - server->name, ansi_red, ansi_normal, + server->scfg.name, ansi_red, ansi_normal, error); rv = false; } else if (!scfg_validate(&server->scfg, &error) && print_results) { info("• %s: %sfail%s - %s", - server->name, ansi_red, ansi_normal, + server->scfg.name, ansi_red, ansi_normal, error); rv = false; } else if (print_results) { - info("• %s: %sok%s", server->name, ansi_green, + info("• %s: %sok%s", server->scfg.name, ansi_green, ansi_normal); } } @@ -226,7 +220,7 @@ struct server *server_get_default(struct cfg *cfg) die("No servers defined"); if (!server_read_config(cfg, server, &lineno, &error)) { - error("%s: server_read_config error - %s", server->name, error); + error("%s: server_read_config error - %s", server->scfg.name, error); return NULL; } @@ -242,7 +236,7 @@ bool server_set_default(struct cfg *cfg, const char *name) server_load_all_known(cfg); list_for_each_entry(server, &cfg->servers, list) { - if (streq(name, server->name)) { + if (streq(name, server->scfg.name)) { list_rotate_to_front(&server->list, &cfg->servers); cfg->default_set = true; return true; @@ -263,7 +257,6 @@ void server_free_all(struct cfg *cfg) void server_free(struct server *server) { scfg_delete(&server->scfg); - xfree(server->name); xfree(server); } diff --git a/minecctl/server.h b/minecctl/server.h index 4520d34..47682a5 100644 --- a/minecctl/server.h +++ b/minecctl/server.h @@ -8,7 +8,6 @@ struct server { bool file_read; - char *name; struct server_config scfg; struct list_head list; }; diff --git a/minecproxy/server-config.c b/minecproxy/server-config.c index 7009952..959f1d0 100644 --- a/minecproxy/server-config.c +++ b/minecproxy/server-config.c @@ -39,18 +39,18 @@ static void server_cfg_read_cb(struct uring_task *task, int res) assert_task_alive(DBG_CFG, task); if (res <= 0) { - error("error reading config file for %s: %s", server->name, + error("error reading config file for %s: %s", server->scfg.name, strerror(-res)); server_delete(server); } - debug(DBG_CFG, "%s: parsing cfg (%i bytes)", server->name, res); + debug(DBG_CFG, "%s: parsing cfg (%i bytes)", server->scfg.name, res); uring_task_close_fd(&server->task); if (!scfg_parse(&server->scfg, server->tbuf.buf, true, &lineno, &error)) { error("%s: failed to parse config file, line %u: %s", - server->name, lineno, error); + server->scfg.name, lineno, error); server_delete(server); return; } @@ -74,12 +74,12 @@ static void server_cfg_open_cb(struct uring_task *task, int res) assert_task_alive(DBG_CFG, task); if (res < 0) { - error("open(%s) failed: %s", server->name, strerror(-res)); + error("open(%s) failed: %s", server->scfg.name, strerror(-res)); server_delete(server); return; } - debug(DBG_CFG, "reading server cfg %s (fd %i)", server->name, res); + debug(DBG_CFG, "reading server cfg %s (fd %i)", server->scfg.name, res); uring_task_set_fd(&server->task, res); uring_tbuf_read_until_eof(&server->task, server_cfg_read_cb); } @@ -184,8 +184,8 @@ static void inotify_cb(struct uring_task *task, int res) (IN_MOVED_TO | IN_CREATE | IN_CLOSE_WRITE)) { server = server_new(event->name); verbose("New server config file detected: %s", - server->name); - uring_openat(&server->task, server->name, + event->name); + uring_openat(&server->task, event->name, server_cfg_open_cb); } else error("inotify: unknown event: 0x%08x", event->mask); diff --git a/minecproxy/server-proxy.c b/minecproxy/server-proxy.c index 9d7b59e..e486a73 100644 --- a/minecproxy/server-proxy.c +++ b/minecproxy/server-proxy.c @@ -70,7 +70,7 @@ static void proxy_free(struct uring_task *task) assert_return(task); - debug(DBG_PROXY, "server: %s, src: %s, dst: %s", proxy->server->name, + debug(DBG_PROXY, "server: %s, src: %s, dst: %s", proxy->server->scfg.name, proxy->client_conn.remote.addrstr, proxy->server_conn.remote.addrstr); @@ -82,7 +82,7 @@ static void proxy_free(struct uring_task *task) info("%s: proxy connection %s -> %s closed " "(CtS: %s, StC: %s), duration %s", - proxy->server->name, proxy->client_conn.remote.addrstr, + proxy->server->scfg.name, proxy->client_conn.remote.addrstr, proxy->server_conn.remote.addrstr, cts, stc, duration); } @@ -97,7 +97,7 @@ static void proxy_client_free(struct uring_task *task) assert_return(task); - debug(DBG_PROXY, "%s: client connection closed", proxy->server->name); + debug(DBG_PROXY, "%s: client connection closed", proxy->server->scfg.name); } static void proxy_server_free(struct uring_task *task) @@ -107,12 +107,12 @@ static void proxy_server_free(struct uring_task *task) assert_return(task); - debug(DBG_PROXY, "%s: server connection closed", proxy->server->name); + debug(DBG_PROXY, "%s: server connection closed", proxy->server->scfg.name); } void proxy_delete(struct server_proxy *proxy) { - debug(DBG_PROXY, "%s: shutting down proxy %p", proxy->server->name, + debug(DBG_PROXY, "%s: shutting down proxy %p", proxy->server->scfg.name, proxy); assert_return(proxy); @@ -147,7 +147,7 @@ static void proxy_client_written_out(struct uring_task *task, int res) assert_task_alive(DBG_PROXY, task); if (res <= 0) { - debug(DBG_PROXY, "%s: res: %i", proxy->server->name, res); + debug(DBG_PROXY, "%s: res: %i", proxy->server->scfg.name, res); proxy_delete(proxy); return; } @@ -166,7 +166,7 @@ static void proxy_client_read_in(struct uring_task *task, int res) assert_task_alive(DBG_PROXY, task); if (res <= 0) { - debug(DBG_PROXY, "%s: res: %i", proxy->server->name, res); + debug(DBG_PROXY, "%s: res: %i", proxy->server->scfg.name, res); proxy_delete(proxy); return; } @@ -186,7 +186,7 @@ static void proxy_server_written_out(struct uring_task *task, int res) assert_task_alive(DBG_PROXY, task); if (res <= 0) { - debug(DBG_PROXY, "%s: res: %i", proxy->server->name, res); + debug(DBG_PROXY, "%s: res: %i", proxy->server->scfg.name, res); proxy_delete(proxy); return; } @@ -205,7 +205,7 @@ static void proxy_server_read_in(struct uring_task *task, int res) assert_task_alive(DBG_PROXY, task); if (res <= 0) { - debug(DBG_PROXY, "%s: res: %i", proxy->server->name, res); + debug(DBG_PROXY, "%s: res: %i", proxy->server->scfg.name, res); proxy_delete(proxy); return; } @@ -228,7 +228,7 @@ static void proxy_client_spliced_out(struct uring_task *task, int res) assert_task_alive(DBG_PROXY, task); if (res <= 0) { - debug(DBG_PROXY, "%s: res: %i", proxy->server->name, res); + debug(DBG_PROXY, "%s: res: %i", proxy->server->scfg.name, res); proxy_delete(proxy); return; } @@ -247,7 +247,7 @@ static void proxy_client_spliced_in(struct uring_task *task, int res) assert_task_alive(DBG_PROXY, task); if (res <= 0) { - debug(DBG_PROXY, "%s: res: %i", proxy->server->name, res); + debug(DBG_PROXY, "%s: res: %i", proxy->server->scfg.name, res); proxy_delete(proxy); return; } @@ -267,7 +267,7 @@ static void proxy_server_spliced_out(struct uring_task *task, int res) assert_task_alive(DBG_PROXY, task); if (res <= 0) { - debug(DBG_PROXY, "%s: res: %i", proxy->server->name, res); + debug(DBG_PROXY, "%s: res: %i", proxy->server->scfg.name, res); proxy_delete(proxy); return; } @@ -286,7 +286,7 @@ static void proxy_server_spliced_in(struct uring_task *task, int res) assert_task_alive(DBG_PROXY, task); if (res <= 0) { - debug(DBG_PROXY, "%s: res: %i", proxy->server->name, res); + debug(DBG_PROXY, "%s: res: %i", proxy->server->scfg.name, res); proxy_delete(proxy); return; } @@ -307,7 +307,7 @@ static void proxy_connected_cb(struct connection *conn, bool connected) proxy->connecting = false; if (!connected) { error("%s: proxy connection to remote server failed", - proxy->server->name); + proxy->server->scfg.name); if (!proxy->ptask.active) proxy_delete(proxy); return; @@ -316,7 +316,7 @@ static void proxy_connected_cb(struct connection *conn, bool connected) ptimer_del_task(&proxy->ptask); proxy->sfd = proxy->servertask.fd; - verbose("%s: proxy connection %s -> %s opened", proxy->server->name, + verbose("%s: proxy connection %s -> %s opened", proxy->server->scfg.name, proxy->client_conn.remote.addrstr, proxy->server_conn.remote.addrstr); proxy->begin = time(NULL); @@ -439,7 +439,7 @@ static void local_accept(struct uring_task *task, int res) assert_return(task); assert_task_alive(DBG_PROXY, task); - debug(DBG_PROXY, "task %p, res %i, server %s", task, res, server->name); + debug(DBG_PROXY, "task %p, res %i, server %s", task, res, server->scfg.name); if (res < 0) { error("res: %i", res); @@ -448,7 +448,7 @@ static void local_accept(struct uring_task *task, int res) saddr_set_addrstr(&local->client); - verbose("%s: incoming proxy connection: %s -> %s", server->name, + verbose("%s: incoming proxy connection: %s -> %s", server->scfg.name, local->client.addrstr, local->local.addrstr); if (list_empty(&server->scfg.remotes)) { @@ -571,7 +571,7 @@ struct server_local *local_new(struct server *server, struct saddr *saddr) return NULL; } - debug(DBG_PROXY, "%s adding local: %s", server->name, saddr->addrstr); + debug(DBG_PROXY, "%s adding local: %s", server->scfg.name, saddr->addrstr); local->local = *saddr; local->server = server; uring_task_init(&local->task, "local", &server->task, local_free); diff --git a/minecproxy/server-rcon.c b/minecproxy/server-rcon.c index c8a91c3..a728bab 100644 --- a/minecproxy/server-rcon.c +++ b/minecproxy/server-rcon.c @@ -32,14 +32,14 @@ static bool rcon_check_reply(struct uring_task *task, int res, int32_t *id, const char *error; if (res < 0) { - error("rcon(%s): reading reply failed, res: %i", server->name, - res); + error("rcon(%s): reading reply failed, res: %i", + server->scfg.name, res); goto error; } if (!rcon_protocol_read_packet(task->tbuf->buf, task->tbuf->len, id, type, msg, &error)) { - error("rcon(%s): failed to parse packet: %s", server->name, + error("rcon(%s): failed to parse packet: %s", server->scfg.name, error); goto error; } @@ -66,10 +66,10 @@ static void rcon_stop_reply(struct uring_task *task, int res) if (!rcon_protocol_verify_response(2, id, RCON_PACKET_COMMAND, type, &error)) - error("rcon(%s): stop cmd failed - %s", server->name, error); + error("rcon(%s): stop cmd failed - %s", server->scfg.name, error); else verbose("rcon(%s): stop command sent, reply: %s", - server->name, msg); + server->scfg.name, msg); uring_task_close_fd(task); } @@ -83,12 +83,12 @@ static void rcon_stop_sent(struct uring_task *task, int res) if (res != task->tbuf->len) { error("rcon(%s): sending stop cmd failed, res: %i", - server->name, res); + server->scfg.name, res); uring_task_close_fd(task); return; } - debug(DBG_RCON, "rcon(%s): stop cmd sent", server->name); + debug(DBG_RCON, "rcon(%s): stop cmd sent", server->scfg.name); uring_tbuf_read_until(task, rcon_packet_complete, rcon_stop_reply); } @@ -107,11 +107,11 @@ static void rcon_login_reply(struct uring_task *task, int res) if (!rcon_protocol_verify_response(1, id, RCON_PACKET_LOGIN, type, &error)) { - error("rcon(%s): login failed - %s", server->name, error); + error("rcon(%s): login failed - %s", server->scfg.name, error); goto error; } - debug(DBG_RCON, "rcon(%s): login successful", server->name); + debug(DBG_RCON, "rcon(%s): login successful", server->scfg.name); rcon_protocol_create_packet(task->tbuf->buf, sizeof(task->tbuf->buf), &task->tbuf->len, 2, RCON_PACKET_COMMAND, "stop"); @@ -130,13 +130,13 @@ static void rcon_login_sent(struct uring_task *task, int res) assert_task_alive(DBG_RCON, task); if (res != task->tbuf->len) { - error("rcon(%s): sending login failed, res: %i", server->name, + error("rcon(%s): sending login failed, res: %i", server->scfg.name, res); uring_task_close_fd(task); return; } - debug(DBG_RCON, "rcon(%s): login sent", server->name); + debug(DBG_RCON, "rcon(%s): login sent", server->scfg.name); uring_tbuf_read_until(task, rcon_packet_complete, rcon_login_reply); } @@ -148,7 +148,7 @@ static void rcon_connected_cb(struct connection *conn, bool connected) assert_task_alive(DBG_RCON, &server->rcon_task); if (!connected) { - error("rcon (%s): connection failed", server->name); + error("rcon (%s): connection failed", server->scfg.name); return; } @@ -166,7 +166,7 @@ static void rcon_free(struct uring_task *task) assert_return(task); - debug(DBG_RCON, "task %p, server %s (%p)", task, server->name, server); + debug(DBG_RCON, "task %p, server %s (%p)", task, server->scfg.name, server); } void rcon_stop(struct server *server) diff --git a/minecproxy/server.c b/minecproxy/server.c index b1e9b05..7a992d1 100644 --- a/minecproxy/server.c +++ b/minecproxy/server.c @@ -46,9 +46,8 @@ static void server_free(struct uring_task *task) assert_return(task); - debug(DBG_SRV, "freeing server %s (%p)", server->name, server); + debug(DBG_SRV, "freeing server (%p)", server); list_del(&server->list); - xfree(server->name); xfree(server); } @@ -59,7 +58,7 @@ void server_delete(struct server *server) assert_return(server); - verbose("Removing server %s", server->name); + verbose("Removing server %s", server->scfg.name); server->state = SERVER_STATE_DEAD; rcon_delete(server); @@ -101,7 +100,7 @@ static void server_dump(struct server *server) assert_return(server); - verbose("Server %s:", server->name); + verbose("Server %s:", server->scfg.name); verbose(" * Filename: %s", server->scfg.filename); switch (server->scfg.type) { case SERVER_TYPE_ANNOUNCE: @@ -225,7 +224,7 @@ static bool server_check_running(struct server *server) /* FIXME: other methods, rcon? */ if (server->scfg.systemd_service) { verbose("%s: checking if systemd service is running", - server->name); + server->scfg.name); if (systemd_service_running(&server->scfg, &error)) { server->state = SERVER_STATE_RUNNING; return true; @@ -246,12 +245,12 @@ bool server_start(struct server *server) switch (server->scfg.start_method) { case SERVER_START_METHOD_EXEC: verbose("Starting server %s via external cmd", - server->name); + server->scfg.name); return server_exec(server, server->scfg.start_exec); case SERVER_START_METHOD_SYSTEMD: verbose("Starting server %s via systemd (%s)", - server->name, + server->scfg.name, server->scfg.systemd_service); if (systemd_service_start(&server->scfg)) { @@ -276,12 +275,12 @@ bool server_stop(struct server *server) switch (server->scfg.stop_method) { case SERVER_STOP_METHOD_EXEC: verbose("Stopping server %s via external cmd", - server->name); + server->scfg.name); return server_exec(server, server->scfg.stop_exec); case SERVER_STOP_METHOD_SYSTEMD: verbose("Stopping server %s via systemd (%s)", - server->name, + server->scfg.name, server->scfg.systemd_service); if (systemd_service_stop(&server->scfg)) { server->state = SERVER_STATE_STOPPED; @@ -290,7 +289,7 @@ bool server_stop(struct server *server) return server_check_running(server); case SERVER_STOP_METHOD_RCON: - verbose("Stopping server %s via rcon", server->name); + verbose("Stopping server %s via rcon", server->scfg.name); rcon_stop(server); return true; @@ -315,7 +314,7 @@ void server_update_active_players(struct server *server, int count) assert_task_alive(DBG_IDLE, &server->idle_task); debug(DBG_IDLE, "%s: currently %i active players", - server->name, count); + server->scfg.name, count); if (count < 0) return; @@ -327,7 +326,7 @@ void server_update_active_players(struct server *server, int count) server->idle_count++; if (server->idle_count > server->scfg.idle_timeout) { - verbose("stopping idle server %s", server->name); + verbose("stopping idle server %s", server->scfg.name); server_stop(server); } } @@ -342,7 +341,7 @@ static void server_idle_connected_cb(struct connection *conn, bool connected) if (!connected) { debug(DBG_IDLE, "idle check connection to remote server (%s) failed", - server->name); + server->scfg.name); server->idle_count = 0; server->state = SERVER_STATE_STOPPED; return; @@ -390,11 +389,11 @@ static void server_announce_cb(struct uring_task *task, int res) assert_return(task); if (res < 0) - error("%s: failure %i", server->name, res); + error("%s: failure %i", server->scfg.name, res); else if (res == server->ann_buf.len) - debug(DBG_ANN, "%s: ok (%i)", server->name, res); + debug(DBG_ANN, "%s: ok (%i)", server->scfg.name, res); else - debug(DBG_ANN, "%s: unexpected result: %i", server->name, res); + debug(DBG_ANN, "%s: unexpected result: %i", server->scfg.name, res); uring_task_set_fd(&server->ann_task, -1); } @@ -410,7 +409,7 @@ bool server_announce(struct server *server, int fd) server->state != SERVER_STATE_RUNNING)) return false; - debug(DBG_ANN, "announcing server: %s", server->name); + debug(DBG_ANN, "announcing server: %s", server->scfg.name); uring_task_set_fd(&server->ann_task, fd); uring_tbuf_sendmsg(&server->ann_task, server_announce_cb); return true; @@ -422,12 +421,12 @@ bool server_commit(struct server *server) struct saddr *saddr, *tmp; int r; - assert_return(server && server->name, false); + assert_return(server && server->scfg.name, false); assert_task_alive_or(DBG_SRV, &server->task, return false); if (!list_empty(&server->scfg.dnslookups)) { debug(DBG_SRV, "%s: called with pending DNS requests", - server->name); + server->scfg.name); return false; } @@ -437,23 +436,23 @@ bool server_commit(struct server *server) } if (!list_empty(&server->proxys)) { - error("%s: proxys not empty?", server->name); + error("%s: proxys not empty?", server->scfg.name); return false; } if (!scfg_validate(&server->scfg, &error)) { error("%s: failed to validate config file (%s)", - server->name, error); + server->scfg.name, error); server_delete(server); return false; } r = snprintf(server->ann_buf.buf, sizeof(server->ann_buf.buf), "[MOTD]%s[/MOTD][AD]%" PRIu16 "[/AD]", - server->scfg.pretty_name ? server->scfg.pretty_name : server->name, + server->scfg.pretty_name ? server->scfg.pretty_name : server->scfg.name, server->scfg.announce_port); if (r < 1 || r >= sizeof(server->ann_buf.buf)) { - error("%s: unable to create announce msg: %i\n", server->name, + error("%s: unable to create announce msg: %i\n", server->scfg.name, r); return false; } @@ -469,14 +468,14 @@ bool server_commit(struct server *server) local = local_new(server, saddr); if (!local) { error("%s: failed to create local listener", - server->name); + server->scfg.name); server_delete(server); return false; } list_add(&local->list, &server->listenings); if (!local_open(local)) { error("%s: failed to open listening port", - server->name); + server->scfg.name); server_delete(server); return false; } @@ -486,19 +485,18 @@ bool server_commit(struct server *server) server_check_running(server); - debug(DBG_SRV, "%s: success", server->name); + debug(DBG_SRV, "%s: success", server->scfg.name); return true; } struct server *server_new(const char *filename) { struct server *server; - const char *suffix; assert_return(!empty_str(filename), NULL); list_for_each_entry(server, &cfg->servers, list) { - if (!streq(filename, server->name)) + if (!streq(filename, server->scfg.filename)) continue; error("attempt to add duplicate server: %s", filename); return server; @@ -511,29 +509,14 @@ struct server *server_new(const char *filename) return NULL; } - suffix = strrchr(filename, '.'); - if (!suffix || suffix == filename) { - error("invalid filename: %s", filename); - xfree(server); - return NULL; - } - - server->name = xstrndup(filename, suffix - filename); - if (!server->name) { - error("failed to create server name: %s", filename); - xfree(server); - return NULL; - } - if (!scfg_init(&server->scfg, filename)) { - xfree(server->name); xfree(server); return NULL; } server->state = SERVER_STATE_INIT; - uring_task_init(&server->task, server->name, uring_parent(), + uring_task_init(&server->task, server->scfg.name, uring_parent(), server_free); uring_task_set_buf(&server->task, &server->tbuf); diff --git a/minecproxy/server.h b/minecproxy/server.h index 8058d42..41aaf41 100644 --- a/minecproxy/server.h +++ b/minecproxy/server.h @@ -15,7 +15,6 @@ enum server_state { /* clang-format on */ struct server { - char *name; struct server_config scfg; struct list_head listenings; struct list_head proxys; diff --git a/shared/config-parser.c b/shared/config-parser.c index 8ea6557..4dc446c 100644 --- a/shared/config-parser.c +++ b/shared/config-parser.c @@ -529,29 +529,17 @@ bool scfg_parse(struct server_config *scfg, char *buf, bool async, case SCFG_KEY_SYSTEMD_SERVICE: if (scfg->systemd_service) ERROR("systemd service defined multiple times"); - else { - const char *suffix; - char *tmp; - - suffix = strrchr(value.str, '.'); - if (!suffix || !streq(suffix, ".service")) { - tmp = zmalloc(strlen(value.str) + - STRLEN(".service") + 1); - if (tmp) - sprintf(tmp, "%s.service", - value.str); - } else - tmp = xstrdup(value.str); - - if (!tmp) - ERROR("malloc/strdup failure"); - - scfg->systemd_service = tmp; - scfg->systemd_obj = - systemd_object_path(scfg->systemd_service); - if (!scfg->systemd_obj) - ERROR("failed to create object_path"); - } + + const char *suffix = strrchr(value.str, '.'); + if (!suffix || !streq(suffix, ".service")) + scfg->systemd_service = xsprintf(NULL, + "%s.service", + value.str); + else + scfg->systemd_service = xstrdup(value.str); + + if (!scfg->systemd_service) + ERROR("malloc/strdup failure"); break; @@ -563,6 +551,22 @@ bool scfg_parse(struct server_config *scfg, char *buf, bool async, } } + if (!scfg->systemd_service && + (scfg->stop_method == SERVER_STOP_METHOD_SYSTEMD || + scfg->start_method == SERVER_START_METHOD_SYSTEMD)) { + scfg->systemd_service = xsprintf(NULL, + "minecserver@%s.service", + scfg->name); + if (!scfg->systemd_service) + ERROR("failed to create systemd_service string"); + } + + if (scfg->systemd_service && !scfg->systemd_obj) { + scfg->systemd_obj = systemd_object_path(scfg->systemd_service); + if (!scfg->systemd_obj) + ERROR("failed to create object_path"); + } + return true; } @@ -605,14 +609,31 @@ bool scfg_init(struct server_config *scfg, const char *filename) assert_return(scfg, false); if (filename) { + const char *suffix; + + suffix = strrchr(filename, '.'); + if (!suffix || suffix == filename) { + error("invalid filename: %s", filename); + return false; + } + + scfg->name = xstrndup(filename, suffix - filename); + if (!scfg->name) { + error("xstrndup: %m"); + return false; + } + scfg->filename = xstrdup(filename); - if (!scfg->filename) { error("strdup: %m"); + xfree(scfg->name); + scfg->name = NULL; return false; } - } else + } else { + scfg->name = NULL; scfg->filename = NULL; + } scfg->type = SERVER_TYPE_UNDEFINED; scfg->pretty_name = NULL; diff --git a/shared/config-parser.h b/shared/config-parser.h index da5250d..ad7e4b2 100644 --- a/shared/config-parser.h +++ b/shared/config-parser.h @@ -35,6 +35,7 @@ enum server_announce { }; struct server_config { + char *name; char *filename; enum server_type type; char *pretty_name; diff --git a/shared/utils.c b/shared/utils.c index 9bf8cd8..99fcaa3 100644 --- a/shared/utils.c +++ b/shared/utils.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "utils.h" @@ -218,3 +219,36 @@ int strtou16_strict(const char *str, uint16_t *result) *result = val; return 0; } + +char *xsprintf(size_t *rlen, const char *fmt, ...) +{ + va_list ap; + int len; + char *str; + + va_start(ap, fmt); + len = vsnprintf(NULL, 0, fmt, ap); + va_end(ap); + + if (len < 0) + return NULL; + + len++; + str = zmalloc(len); + if (!str) + return NULL; + + va_start(ap, fmt); + len = vsnprintf(str, len, fmt, ap); + va_end(ap); + + if (len < 0) { + xfree(str); + return NULL; + } + + if (rlen) + *rlen = len; + + return str; +} diff --git a/shared/utils.h b/shared/utils.h index bf1b63a..1291d21 100644 --- a/shared/utils.h +++ b/shared/utils.h @@ -89,6 +89,8 @@ void saddr_set_addrstr(struct saddr *saddr); int strtou16_strict(const char *str, uint16_t *result); +char *xsprintf(size_t *rlen, const char *fmt, ...) _printf_(2, 3); + static inline bool empty_str(const char *str) { if (!str || str[0] == '\0') -- cgit v1.2.3