From: Amitay Isaacs Date: Tue, 24 Apr 2018 13:17:18 +0000 (+1000) Subject: ctdb-common: Add command line processing abstraction X-Git-Tag: ldb-1.4.0~273 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=356dacc6d701b6d4ffa91f20f208e0d09a4136e6;p=thirdparty%2Fsamba.git ctdb-common: Add command line processing abstraction Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke --- diff --git a/ctdb/common/cmdline.c b/ctdb/common/cmdline.c new file mode 100644 index 00000000000..2540ce546ae --- /dev/null +++ b/ctdb/common/cmdline.c @@ -0,0 +1,517 @@ +/* + Command line processing + + Copyright (C) Amitay Isaacs 2018 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include "replace.h" + +#include +#include +#include + +#include "lib/util/debug.h" + +#include "common/cmdline.h" + +#define CMDLINE_MAX_LEN 80 + +struct cmdline_context { + const char *prog; + struct poptOption *options; + struct cmdline_command *commands; + int max_len; + poptContext pc; + int argc, arg0; + const char **argv; + struct cmdline_command *match_cmd; +}; + +static bool cmdline_show_help = false; + +static void cmdline_popt_help(poptContext pc, + enum poptCallbackReason reason, + struct poptOption *key, + const char *arg, + void *data) +{ + if (key->shortName == 'h') { + cmdline_show_help = true; + } +} + +struct poptOption cmdline_help_options[] = { + { NULL, '\0', POPT_ARG_CALLBACK, cmdline_popt_help, 0, NULL, NULL }, + { "help", 'h', 0, NULL, 'h', "Show this help message", NULL }, + POPT_TABLEEND +}; + +#define CMDLINE_HELP_OPTIONS \ + { NULL, '\0', POPT_ARG_INCLUDE_TABLE, cmdline_help_options, \ + 0, "Help Options:", NULL } + +static bool cmdline_option_check(struct poptOption *option) +{ + if (option->longName == NULL) { + D_ERR("Option has no long name\n"); + return false; + } + + if (option->argInfo != POPT_ARG_STRING && + option->argInfo != POPT_ARG_INT && + option->argInfo != POPT_ARG_LONG && + option->argInfo != POPT_ARG_VAL && + option->argInfo != POPT_ARG_FLOAT && + option->argInfo != POPT_ARG_DOUBLE) { + D_ERR("Option '%s' has unsupported type\n", option->longName); + return false; + } + + if (option->arg == NULL) { + D_ERR("Option '%s' has invalid arg\n", option->longName); + return false; + } + + if (option->descrip == NULL) { + D_ERR("Option '%s' has no help msg\n", option->longName); + return false; + } + + return true; +} + +static bool cmdline_options_check(struct poptOption *options) +{ + int i; + bool ok; + + if (options == NULL) { + return true; + } + + i = 0; + while (options[i].longName != NULL || options[i].shortName != '\0') { + ok = cmdline_option_check(&options[i]); + if (!ok) { + return false; + } + i++; + } + + return true; +} + +static int cmdline_options_define(TALLOC_CTX *mem_ctx, + struct poptOption *user_options, + struct poptOption **result) +{ + struct poptOption *options; + int count, i; + + count = (user_options == NULL ? 2 : 3); + + options = talloc_array(mem_ctx, struct poptOption, count); + if (options == NULL) { + return ENOMEM; + } + + i = 0; + options[i++] = (struct poptOption) CMDLINE_HELP_OPTIONS; + if (user_options != NULL) { + options[i++] = (struct poptOption) { + .argInfo = POPT_ARG_INCLUDE_TABLE, + .arg = user_options, + .descrip = "Options:", + }; + } + options[i++] = (struct poptOption) POPT_TABLEEND; + + *result = options; + return 0; +} + +static bool cmdline_command_check(struct cmdline_command *cmd, int *max_len) +{ + size_t len; + + if (cmd->name == NULL) { + return false; + } + + if (cmd->fn == NULL) { + D_ERR("Command '%s' has no implementation function\n", + cmd->name); + return false; + } + + if (cmd->msg_help == NULL) { + D_ERR("Command '%s' has no help msg\n", cmd->name); + return false; + } + + len = strlen(cmd->name); + if (cmd->msg_args != NULL) { + len += strlen(cmd->msg_args); + } + if (len > CMDLINE_MAX_LEN) { + D_ERR("Command '%s' is too long (%zu)\n", cmd->name, len); + return false; + } + + if (len > *max_len) { + *max_len = (int)len; + } + + len = strlen(cmd->msg_help); + if (len > CMDLINE_MAX_LEN) { + D_ERR("Command '%s' help too long (%zu)\n", cmd->name, len); + return false; + } + + return true; +} + +static bool cmdline_commands_check(struct cmdline_command *commands, + int *max_len) +{ + int i; + bool ok; + + if (commands == NULL) { + return false; + } + + for (i=0; commands[i].name != NULL; i++) { + ok = cmdline_command_check(&commands[i], max_len); + if (!ok) { + return false; + } + } + + return true; +} + +static int cmdline_context_destructor(struct cmdline_context *cmdline); + +int cmdline_init(TALLOC_CTX *mem_ctx, + const char *prog, + struct poptOption *options, + struct cmdline_command *commands, + struct cmdline_context **result) +{ + struct cmdline_context *cmdline; + int ret, max_len = 0; + bool ok; + + if (prog == NULL) { + return EINVAL; + } + + ok = cmdline_options_check(options); + if (!ok) { + return EINVAL; + } + + ok = cmdline_commands_check(commands, &max_len); + if (!ok) { + return EINVAL; + } + + cmdline = talloc_zero(mem_ctx, struct cmdline_context); + if (cmdline == NULL) { + return ENOMEM; + } + + cmdline->prog = talloc_strdup(cmdline, prog); + if (cmdline->prog == NULL) { + talloc_free(cmdline); + return ENOMEM; + } + + ret = cmdline_options_define(cmdline, options, &cmdline->options); + if (ret != 0) { + talloc_free(cmdline); + return ret; + } + cmdline->commands = commands; + cmdline->max_len = max_len; + + cmdline->argc = 1; + cmdline->argv = talloc_array(cmdline, const char *, 2); + if (cmdline->argv == NULL) { + talloc_free(cmdline); + return ENOMEM; + } + cmdline->argv[0] = cmdline->prog; + cmdline->argv[1] = NULL; + + /* Dummy popt context for generating help */ + cmdline->pc = poptGetContext(cmdline->prog, + cmdline->argc, + cmdline->argv, + cmdline->options, + 0); + if (cmdline->pc == NULL) { + talloc_free(cmdline); + return ENOMEM; + } + + talloc_set_destructor(cmdline, cmdline_context_destructor); + + *result = cmdline; + return 0; +} + +static int cmdline_context_destructor(struct cmdline_context *cmdline) +{ + if (cmdline->pc != NULL) { + poptFreeContext(cmdline->pc); + } + + return 0; +} + +static int cmdline_parse_options(struct cmdline_context *cmdline, + int argc, + const char **argv) +{ + int opt; + + if (cmdline->pc != NULL) { + poptFreeContext(cmdline->pc); + } + + cmdline->pc = poptGetContext(cmdline->prog, + argc, + argv, + cmdline->options, + 0); + if (cmdline->pc == NULL) { + return ENOMEM; + } + + while ((opt = poptGetNextOpt(cmdline->pc)) != -1) { + D_ERR("Invalid option %s: %s\n", + poptBadOption(cmdline->pc, 0), + poptStrerror(opt)); + return EINVAL; + } + + /* Set up remaining arguments for commands */ + cmdline->argc = 0; + cmdline->argv = poptGetArgs(cmdline->pc); + if (cmdline->argv != NULL) { + while (cmdline->argv[cmdline->argc] != NULL) { + cmdline->argc++; + } + } + + return 0; +} + +static int cmdline_match(struct cmdline_context *cmdline) +{ + int i; + + if (cmdline->argc == 0 || cmdline->argv == NULL) { + cmdline->match_cmd = NULL; + return EINVAL; + } + + for (i=0; cmdline->commands[i].name != NULL; i++) { + struct cmdline_command *cmd; + char name[CMDLINE_MAX_LEN+1]; + size_t len; + char *t, *str; + int n = 0; + bool match; + + cmd = &cmdline->commands[i]; + len = strlcpy(name, cmd->name, sizeof(name)); + if (len >= sizeof(name)) { + D_ERR("Skipping long command '%s'\n", cmd->name); + continue; + } + + str = name; + while ((t = strtok(str, " ")) != NULL) { + if (n >= cmdline->argc) { + match = false; + break; + } + if (cmdline->argv[n] == NULL) { + match = false; + break; + } + if (strcmp(cmdline->argv[n], t) == 0) { + match = true; + cmdline->arg0 = n+1; + } else { + match = false; + break; + } + + n += 1; + str = NULL; + } + + if (match) { + cmdline->match_cmd = cmd; + return 0; + } + } + + cmdline->match_cmd = NULL; + return ENOENT; +} + +int cmdline_parse(struct cmdline_context *cmdline, + int argc, + const char **argv, + bool parse_options) +{ + int ret; + + if (argc < 2) { + return EINVAL; + } + + cmdline_show_help = false; + + if (parse_options) { + ret = cmdline_parse_options(cmdline, argc, argv); + if (ret != 0) { + return ret; + } + } else { + cmdline->argc = argc; + cmdline->argv = argv; + } + + ret = cmdline_match(cmdline); + if (!cmdline_show_help && ret != 0) { + return ret; + } + + return 0; +} + +static void cmdline_usage_command(struct cmdline_context *cmdline, + struct cmdline_command *cmd, + bool print_all) +{ + int len; + + len = (int)strlen(cmd->name); + + printf(" %s ", cmd->name); + if (print_all) { + printf("%-*s", + cmdline->max_len-len, + cmd->msg_args == NULL ? "" : cmd->msg_args); + } else { + printf("%s", cmd->msg_args == NULL ? "" : cmd->msg_args); + } + printf(" %s\n", cmd->msg_help); +} + +static void cmdline_usage_full(struct cmdline_context *cmdline) +{ + int i; + + poptSetOtherOptionHelp(cmdline->pc, "[] []"); + poptPrintHelp(cmdline->pc, stdout, 0); + + printf("\nCommands:\n"); + for (i=0; cmdline->commands[i].name != NULL; i++) { + cmdline_usage_command(cmdline, &cmdline->commands[i], true); + + } +} + +void cmdline_usage(struct cmdline_context *cmdline, const char *cmd_name) +{ + struct cmdline_command *cmd = NULL; + int i; + + if (cmd_name == NULL) { + cmdline_usage_full(cmdline); + return; + } + + for (i=0; cmdline->commands[i].name != NULL; i++) { + if (strcmp(cmdline->commands[i].name, cmd_name) == 0) { + cmd = &cmdline->commands[i]; + break; + } + } + + if (cmd == NULL) { + cmdline_usage_full(cmdline); + return; + } + + poptSetOtherOptionHelp(cmdline->pc, " []"); + poptPrintUsage(cmdline->pc, stdout, 0); + + printf("\n"); + cmdline_usage_command(cmdline, cmd, false); +} + +int cmdline_run(struct cmdline_context *cmdline, + void *private_data, + int *result) +{ + struct cmdline_command *cmd = cmdline->match_cmd; + TALLOC_CTX *tmp_ctx; + int ret; + + if (cmdline_show_help) { + const char *name = NULL; + + if (cmd != NULL) { + name = cmdline->match_cmd->name; + } + + cmdline_usage(cmdline, name); + + if (result != NULL) { + *result = 0; + } + return EAGAIN; + } + + if (cmd == NULL) { + return ENOENT; + } + + tmp_ctx = talloc_new(cmdline); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + ret = cmd->fn(tmp_ctx, + cmdline->argc - cmdline->arg0, + &cmdline->argv[cmdline->arg0], + private_data); + + talloc_free(tmp_ctx); + + if (result != NULL) { + *result = ret; + } + return 0; +} diff --git a/ctdb/common/cmdline.h b/ctdb/common/cmdline.h new file mode 100644 index 00000000000..1e11c66c76e --- /dev/null +++ b/ctdb/common/cmdline.h @@ -0,0 +1,148 @@ +/* + Command line processing + + Copyright (C) Amitay Isaacs 2018 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#ifndef __CTDB_CMDLINE_H__ +#define __CTDB_CMDLINE_H__ + +#include +#include + +/** + * @file cmdline.h + * + * @brief Command-line handling with options and commands + * + * This abstraction encapsulates the boiler-plate for parsing options, + * commands and arguments on command-line. + * + * Options handling is done using popt. + */ + +/** + * @brief Abstract data structure holding command-line configuration + */ +struct cmdline_context; + +/** + * @brief A command definition structure + * + * @name is the name of the command + * @fn is the implementation of the command + * @msg_help is the help message describing command + * @msg_args is the help message describing arguments + * + * A command name can be a single word or multiple words separated with spaces. + * + * An implementation function should return 0 on success and non-zero value + * on failure. This value is returned as result in @cmdline_run. + */ +struct cmdline_command { + const char *name; + int (*fn)(TALLOC_CTX *mem_ctx, + int argc, + const char **argv, + void *private_data); + const char *msg_help; + const char *msg_args; +}; + +/** + * @brief convinience macro to define the end of commands list + * + * Here is an example of defining commands list. + * + * struct cmdline_command commands[] = { + * { "command1", command1_func, "Run command1", NULL }, + * { "command2", command2_func, "Run command2", "" }, + * CMDLINE_TABLEEND + * }; + */ +#define CMDLINE_TABLEEND { NULL, NULL, NULL, NULL } + +/** + * @brief Initialize cmdline abstraction + * + * If there are no options, options can be NULL. + * + * Help options (--help, -h) are automatically added to the options. + * + * @param[in] mem_ctx Talloc memory context + * @param[in] prog Program name + * @param[in] options Command-line options + * @param[in] commands Commands array + * @param[out] result New cmdline context + * @return 0 on success, errno on failure + * + * Freeing cmdline context will free up all the resources. + */ +int cmdline_init(TALLOC_CTX *mem_ctx, + const char *prog, + struct poptOption *options, + struct cmdline_command *commands, + struct cmdline_context **result); + +/** + * @brief Parse command line options and commands/arguments + * + * This function parses the arguments to process options and commands. + * + * This function should be passed the arguments to main() and parse_options + * should be set to true. If cmdline is used for handling second-level + * commands, then parse_options should be set to false. + * + * If argv does not match any command, then ENOENT is returned. + * + * @param[in] cmdline Cmdline context + * @param[in] argc Number of arguments + * @param[in] argv Arguments array + * @param[in] parse_options Whether to parse for options + * @return 0 on success, errno on failure + */ +int cmdline_parse(struct cmdline_context *cmdline, + int argc, + const char **argv, + bool parse_options); + +/** + * @brief Excecute the function for the command matched by @cmdline_parse + * + * @param[in] cmdline Cmdline context + * @param[in] private_data Private data for implementation function + * @param[out] result Return value from the implementation function + * @return 0 on success, errno on failure + * + * If help options are specified, then detailed help will be printed and + * the return value will be EAGAIN. + */ +int cmdline_run(struct cmdline_context *cmdline, + void *private_data, + int *result); + +/** + * @brief Print usage help message to stdout + * + * @param[in] cmdline Cmdline context + * @param[in] command Command string + * + * If command is NULL, then full help is printed. + * If command is specified, then compact help is printed. + */ +void cmdline_usage(struct cmdline_context *cmdline, const char *command); + +#endif /* __CTDB_CMDLINE_H__ */ diff --git a/ctdb/tests/cunit/cmdline_test_001.sh b/ctdb/tests/cunit/cmdline_test_001.sh new file mode 100755 index 00000000000..527b1143e7e --- /dev/null +++ b/ctdb/tests/cunit/cmdline_test_001.sh @@ -0,0 +1,58 @@ +#!/bin/sh + +. "${TEST_SCRIPTS_DIR}/unit.sh" + +ok_null +unit_test cmdline_test 1 + +ok <] [] + +Help Options: + -h, --help Show this help message + +Options: + -c, --count=INT Option help of length thirty. + -v, --value=Value help of length 23 Short description + +Commands: + A really really long command This is a really long help message + short command short msg for short command +Usage: test4 [-h] [-h|--help] [-c|--count=INT] + [-v|--value=Value help of length 23] [] + + short command short msg for short command +EOF +unit_test cmdline_test 4 + +ok <] [] + +Help Options: + -h, --help Show this help message + +Commands: + action one action one help + action two action two help +EOF +unit_test cmdline_test 5 + +ok <. +*/ + +#include "replace.h" + +#include +#include + +#include + +#include "common/cmdline.c" + +static int dummy_func(TALLOC_CTX *mem_ctx, + int argc, + const char **argv, + void *private_data) +{ + return 0; +} + +static struct poptOption dummy_options[] = { + POPT_TABLEEND +}; + +static struct cmdline_command dummy_commands[] = { + CMDLINE_TABLEEND +}; + +static void test1(void) +{ + TALLOC_CTX *mem_ctx; + struct cmdline_context *cmdline; + int ret; + + mem_ctx = talloc_new(NULL); + assert(mem_ctx != NULL); + + ret = cmdline_init(mem_ctx, NULL, NULL, NULL, &cmdline); + assert(ret == EINVAL); + + ret = cmdline_init(mem_ctx, "test1", NULL, NULL, &cmdline); + assert(ret == EINVAL); + + ret = cmdline_init(mem_ctx, "test1", dummy_options, NULL, &cmdline); + assert(ret == EINVAL); + + talloc_free(mem_ctx); +} + +static struct cmdline_command test2_nofunc[] = { + { "nofunc", NULL, NULL, NULL }, + CMDLINE_TABLEEND +}; + +static struct cmdline_command test2_nohelp[] = { + { "nohelp", dummy_func, NULL, NULL }, + CMDLINE_TABLEEND +}; + +static struct cmdline_command test2_long[] = { + { "really really long command with lots of words", + dummy_func, "long command help", + "" }, + CMDLINE_TABLEEND +}; + +static struct cmdline_command test2_longhelp[] = { + { "longhelp", dummy_func, + "this is a really really really long help message" \ + "with lots of words and lots of description", + NULL }, + CMDLINE_TABLEEND +}; + +static struct cmdline_command test2_twowords[] = { + { "multiple words", dummy_func, "multiple words help", NULL }, + CMDLINE_TABLEEND +}; + +static void test2(void) +{ + TALLOC_CTX *mem_ctx; + struct cmdline_context *cmdline; + int ret; + + mem_ctx = talloc_new(NULL); + assert(mem_ctx != NULL); + + ret = cmdline_init(mem_ctx, "test2", NULL, test2_nofunc, &cmdline); + assert(ret == EINVAL); + + ret = cmdline_init(mem_ctx, "test2", NULL, test2_nohelp, &cmdline); + assert(ret == EINVAL); + + ret = cmdline_init(mem_ctx, "test2", NULL, test2_long, &cmdline); + assert(ret == EINVAL); + + ret = cmdline_init(mem_ctx, "test2", NULL, test2_longhelp, &cmdline); + assert(ret == EINVAL); + + ret = cmdline_init(mem_ctx, "test2", NULL, test2_twowords, &cmdline); + assert(ret == 0); + + talloc_free(mem_ctx); +} + +struct { + const char *str; +} test3_data; + +static struct poptOption test3_noname[] = { + { NULL, 'o', POPT_ARG_STRING, &test3_data.str, 0, + "Noname option", NULL }, + POPT_TABLEEND +}; + +static struct poptOption test3_notype[] = { + { "debug", 'd', POPT_ARG_NONE, NULL, 0, + "No argument option", NULL }, + POPT_TABLEEND +}; + +static struct poptOption test3_noarg[] = { + { "debug", 'd', POPT_ARG_STRING, NULL, 0, + "No argument option", NULL }, + POPT_TABLEEND +}; + +static void test3(void) +{ + TALLOC_CTX *mem_ctx; + struct cmdline_context *cmdline; + int ret; + + mem_ctx = talloc_new(NULL); + assert(mem_ctx != NULL); + + ret = cmdline_init(mem_ctx, + "test3", + test3_noname, + dummy_commands, + &cmdline); + assert(ret == EINVAL); + + ret = cmdline_init(mem_ctx, + "test3", + test3_notype, + dummy_commands, + &cmdline); + assert(ret == EINVAL); + + ret = cmdline_init(mem_ctx, + "test3", + test3_noarg, + dummy_commands, + &cmdline); + assert(ret == EINVAL); + + talloc_free(mem_ctx); +} + +static int test4_count; +static int test4_value; + +static struct poptOption test4_options[] = { + { "count", 'c', POPT_ARG_INT, &test4_count, 0, + "Option help of length thirty.", NULL }, + { "value", 'v', POPT_ARG_INT, &test4_value, 0, + "Short description", "Value help of length 23" }, + POPT_TABLEEND +}; + +static struct cmdline_command test4_commands[] = { + { "A really really long command", dummy_func, + "This is a really long help message", + "" }, + { "short command", dummy_func, + "short msg for short command", "" }, + CMDLINE_TABLEEND +}; + +static void test4(void) +{ + TALLOC_CTX *mem_ctx; + struct cmdline_context *cmdline; + int ret; + + mem_ctx = talloc_new(NULL); + assert(mem_ctx != NULL); + + ret = cmdline_init(mem_ctx, + "test4", + test4_options, + test4_commands, + &cmdline); + assert(ret == 0); + + cmdline_usage(cmdline, NULL); + cmdline_usage(cmdline, "short command"); + + talloc_free(mem_ctx); +} + +static int action_func(TALLOC_CTX *mem_ctx, + int argc, + const char **argv, + void *private_data) +{ + if (argc != 1) { + return 100; + } + + printf("%s\n", argv[0]); + return 200; +} + +static struct cmdline_command action_commands[] = { + { "action one", dummy_func, "action one help", NULL }, + { "action two", action_func, "action two help", NULL }, + CMDLINE_TABLEEND +}; + +static void test5(void) +{ + TALLOC_CTX *mem_ctx; + struct cmdline_context *cmdline; + const char *argv1[] = { "test5", "--help" }; + const char *argv2[] = { "test5", "action" }; + const char *argv3[] = { "test5", "action", "--help" }; + const char *argv4[] = { "test5", "action", "one" }; + int ret, result; + + mem_ctx = talloc_new(NULL); + assert(mem_ctx != NULL); + + ret = cmdline_init(mem_ctx, "test5", NULL, action_commands, &cmdline); + assert(ret == 0); + + ret = cmdline_parse(cmdline, 2, argv1, true); + assert(ret == 0); + + ret = cmdline_run(cmdline, NULL, &result); + assert(ret == EAGAIN); + assert(result == 0); + + ret = cmdline_parse(cmdline, 2, argv2, true); + assert(ret == ENOENT); + + ret = cmdline_parse(cmdline, 3, argv3, true); + assert(ret == 0); + + ret = cmdline_parse(cmdline, 3, argv4, true); + assert(ret == 0); + + talloc_free(mem_ctx); +} + +static void test6(void) +{ + TALLOC_CTX *mem_ctx; + struct cmdline_context *cmdline; + const char *argv1[] = { "action", "two" }; + const char *argv2[] = { "action", "two", "arg1" }; + const char *argv3[] = { "action", "two", "arg1", "arg2" }; + int ret, result; + + mem_ctx = talloc_new(NULL); + assert(mem_ctx != NULL); + + ret = cmdline_init(mem_ctx, "test6", NULL, action_commands, &cmdline); + assert(ret == 0); + + ret = cmdline_parse(cmdline, 2, argv1, false); + assert(ret == 0); + + ret = cmdline_run(cmdline, NULL, &result); + assert(ret == 0); + assert(result == 100); + + ret = cmdline_parse(cmdline, 3, argv2, false); + assert(ret == 0); + + ret = cmdline_run(cmdline, NULL, &result); + assert(ret == 0); + assert(result == 200); + + ret = cmdline_parse(cmdline, 4, argv3, false); + assert(ret == 0); + + ret = cmdline_run(cmdline, NULL, &result); + assert(ret == 0); + assert(result == 100); + + talloc_free(mem_ctx); +} + +int main(int argc, const char **argv) +{ + int num; + + if (argc < 2) { + fprintf(stderr, "Usage %s \n", argv[0]); + exit(1); + } + + num = atoi(argv[1]); + + switch (num) { + case 1: + test1(); + break; + + case 2: + test2(); + break; + + case 3: + test3(); + break; + + case 4: + test4(); + break; + + case 5: + test5(); + break; + + case 6: + test6(); + break; + } + + return 0; +} diff --git a/ctdb/wscript b/ctdb/wscript index 89020c5d122..c1a3dad2870 100644 --- a/ctdb/wscript +++ b/ctdb/wscript @@ -399,9 +399,11 @@ def build(bld): logging.c rb_tree.c tunable.c pidfile.c run_proc.c hash_count.c run_event.c - sock_client.c version.c'''), + sock_client.c version.c + cmdline.c + '''), deps='''samba-util sys_rw tevent-util - replace talloc tevent tdb''') + replace talloc tevent tdb popt''') bld.SAMBA_SUBSYSTEM('ctdb-protocol', source=bld.SUBDIR('protocol', @@ -748,6 +750,7 @@ def build(bld): 'sock_io_test', 'hash_count_test', 'run_event_test', + 'cmdline_test' ] for target in ctdb_unit_tests: @@ -755,7 +758,7 @@ def build(bld): bld.SAMBA_BINARY(target, source=src, - deps='''talloc tevent tdb tevent-util + deps='''talloc tevent tdb tevent-util popt LIBASYNC_REQ samba-util sys_rw''', install_path='${CTDB_TEST_LIBEXECDIR}')