From 8f29a4d23dd13a80aa26951b17e2a71f4e651cb1 Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Sun, 28 Jun 2020 19:25:20 +0200 Subject: Introduce the possibility of specifying serveral commands in one go --- minecctl/minecctl-commands.h | 5 +++ minecctl/minecctl.c | 23 +++++++++---- minecctl/minecctl.h | 5 +-- minecctl/misc.c | 77 ++++++++++++++++++++++++++++++++++++++------ minecctl/misc.h | 6 ++++ minecctl/rcon-commands.c | 20 ++++++++++-- minecctl/rcon-commands.h | 2 +- 7 files changed, 114 insertions(+), 24 deletions(-) (limited to 'minecctl') diff --git a/minecctl/minecctl-commands.h b/minecctl/minecctl-commands.h index 2805a51..e8bb132 100644 --- a/minecctl/minecctl-commands.h +++ b/minecctl/minecctl-commands.h @@ -10,6 +10,7 @@ enum commands { CMD_STOPALL, CMD_PCOUNT, CMD_COMMAND, + CMD_COMMANDS, CMD_CONSOLE, }; @@ -44,6 +45,10 @@ static struct command_list { .name = "cmd", .cmd = CMD_COMMAND, }, + { + .name = "cmds", + .cmd = CMD_COMMANDS, + }, { .name = "console", .cmd = CMD_CONSOLE, diff --git a/minecctl/minecctl.c b/minecctl/minecctl.c index 5ac3942..3d21ae6 100644 --- a/minecctl/minecctl.c +++ b/minecctl/minecctl.c @@ -34,7 +34,10 @@ static void dump_config(struct cfg *cfg) info("rcon_password : %s", cfg->rcon_password); info("rcon_addrstr : %s", cfg->rcon_addrstr); info("mc_addrstr : %s", cfg->mc_addrstr); - info("cmdstr : %s", cfg->cmdstr); + if (cfg->commands) { + for (char *const *cmd = cfg->commands; *cmd; cmd++) + info("command : %s", *cmd); + } info("cmd : %p", cfg->cmd); info("force stop : %s", cfg->force_stop ? "yes" : "no"); @@ -81,6 +84,7 @@ _noreturn_ static void usage(bool no_error) " pcount [SERVER] get player count for SERVER\n" " console [SERVER] interactive command line for SERVER\n" " cmd [SERVER] CMD send CMD to SERVER\n" + " cmds [SERVER] CMDS... send multiple CMDS to SERVER\n" " [SERVER] CMD shorthand for \"cmd [SERVER] CMD\"\n" " [SERVER] shorthand for \"console [SERVER]\"\n" "\n" @@ -249,6 +253,8 @@ static void parse_command(struct cfg *cfg, char *const *argv) cfg->cmd = do_console; break; case CMD_COMMAND: + _fallthrough_; + case CMD_COMMANDS: get_optional_server_arg(cfg, &argv, true); if (!*argv) { @@ -256,8 +262,11 @@ static void parse_command(struct cfg *cfg, char *const *argv) usage(false); } - cfg->cmdstr = strv_join(argv); - cfg->cmd = do_command; + if (cmd == CMD_COMMANDS) + cfg->commands = strv_copy(argv); + else + cfg->commands = strv_from_strs(strv_join(argv), NULL); + cfg->cmd = do_commands; break; case CMD_INVALID: /* shorthand notation */ @@ -268,8 +277,8 @@ static void parse_command(struct cfg *cfg, char *const *argv) cfg->cmd = do_console; } else { /* CMD... */ - cfg->cmdstr = strv_join(argv); - cfg->cmd = do_command; + cfg->commands = strv_from_strs(strv_join(argv), NULL); + cfg->cmd = do_commands; } break; default: @@ -360,7 +369,7 @@ static void parse_cmdline(struct cfg *cfg, int argc, char *const *argv) } } -int main(int argc, char **argv) +int main(int argc, char *const *argv) { struct cfg cfg = { .servers = LIST_HEAD_INIT(cfg.servers), @@ -393,8 +402,8 @@ int main(int argc, char **argv) out: server_free_all(&cfg); free_password(&cfg.rcon_password); + strv_free(cfg.commands); xfree(cfg.rcon_addrstr); xfree(cfg.mc_addrstr); - xfree(cfg.cmdstr); exit(success ? EXIT_SUCCESS : EXIT_FAILURE); } diff --git a/minecctl/minecctl.h b/minecctl/minecctl.h index 259ac52..898a93f 100644 --- a/minecctl/minecctl.h +++ b/minecctl/minecctl.h @@ -2,15 +2,12 @@ #define foominecctlhfoo struct cfg { - /* command line arguments */ const char *cfgdir; char *rcon_password; char *rcon_addrstr; char *mc_addrstr; - char *cmdstr; + char **commands; bool force_stop; - - /* bookkeeping */ bool (*cmd)(struct cfg *cfg); struct list_head servers; }; diff --git a/minecctl/misc.c b/minecctl/misc.c index 8f0761f..e2d6b02 100644 --- a/minecctl/misc.c +++ b/minecctl/misc.c @@ -36,27 +36,86 @@ void set_use_colors() use_colors = true; } +char **strv_copy(char *const *strv) +{ + size_t len = 1; + char **rv; + char **to; + + for (char *const *str = strv; *str; str++) + len++; + + rv = zmalloc(len * sizeof(char *)); + to = rv; + + for (char *const *str = strv; *str; str++) + *(to++) = xstrdup(*str); + + return rv; +} + +char **strv_from_strs(const char *first, ...) +{ + size_t len = 1; + va_list ap; + char **rv, **to; + + if (first) { + va_start(ap, first); + while (va_arg(ap, const char *)) + len++; + va_end(ap); + } + + rv = zmalloc(len * sizeof(char *)); + to = rv; + *(to++) = first ? xstrdup(first) : NULL; + + if (first) { + const char *str; + + va_start(ap, first); + while ((str = va_arg(ap, const char *))) + *(to++) = xstrdup(str); + va_end(ap); + *to = NULL; + } + + return rv; +} + char *strv_join(char *const *strv) { size_t len = 0; - char *r, *to; + char *rv, *to; - for (unsigned i = 0; strv[i]; i++) - len += strlen(strv[i]) + 1; + for (char *const *str = strv; *str; str++) + len += strlen(*str) + 1; if (len == 0) return NULL; - r = zmalloc(len); - to = r; + rv = zmalloc(len); + to = rv; - for (unsigned i = 0; strv[i]; i++) { - if (i > 0) + for (char *const *str = strv; *str; str++) { + if (str != strv) *(to++) = ' '; - to = stpcpy(to, strv[i]); + to = stpcpy(to, *str); } - return r; + return rv; +} + +void strv_free(char **strv) +{ + if (!strv) + return; + + for (char **str = strv; *str; str++) + xfree(*str); + + xfree(strv); } int connect_any(struct list_head *addrs, bool may_fail) diff --git a/minecctl/misc.h b/minecctl/misc.h index 6abed5e..c8254df 100644 --- a/minecctl/misc.h +++ b/minecctl/misc.h @@ -5,8 +5,14 @@ extern bool use_colors; void set_use_colors(); +char **strv_copy(char *const *strv); + +char **strv_from_strs(const char *first, ...); + char *strv_join(char *const *strv); +void strv_free(char **strv); + int connect_any(struct list_head *addrs, bool may_fail); char *ask_password(); diff --git a/minecctl/rcon-commands.c b/minecctl/rcon-commands.c index b6a216f..5f98b72 100644 --- a/minecctl/rcon-commands.c +++ b/minecctl/rcon-commands.c @@ -449,15 +449,29 @@ bool do_console(struct cfg *cfg) return true; } -bool do_command(struct cfg *cfg) +bool do_commands(struct cfg *cfg) { - int fd; struct server *server; + bool rv = true; + int fd; + + if (!cfg->commands) { + error("No commands to send"); + return false; + } server = server_get_default(cfg); fd = rcon_login(cfg, server); if (fd < 0) return false; - return send_cmd(fd, cfg->cmdstr); + for (char *const *cmd = cfg->commands; *cmd; cmd++) { + if (!send_cmd(fd, *cmd)) { + rv = false; + break; + } + } + + close(fd); + return rv; } diff --git a/minecctl/rcon-commands.h b/minecctl/rcon-commands.h index 1714dd5..c77e6fe 100644 --- a/minecctl/rcon-commands.h +++ b/minecctl/rcon-commands.h @@ -13,6 +13,6 @@ bool do_rcon_pcount(struct cfg *cfg, unsigned *online, unsigned *max); bool do_console(struct cfg *cfg); -bool do_command(struct cfg *cfg); +bool do_commands(struct cfg *cfg); #endif -- cgit v1.2.3