diff options
Diffstat (limited to '')
-rw-r--r-- | vqsim/parser.c | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/vqsim/parser.c b/vqsim/parser.c new file mode 100644 index 0000000..2857184 --- /dev/null +++ b/vqsim/parser.c @@ -0,0 +1,418 @@ +/* Parses the interactive commands */ + +#include <config.h> + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <netinet/in.h> +#ifdef HAVE_READLINE_HISTORY_H +#include <readline/history.h> +#endif + +#include <corosync/coroapi.h> +#include "vqsim.h" + +static void do_usage(void) +{ + printf(" All node IDs in the cluster are unique and belong to a numbered 'partition' (default=0)\n"); + printf("\n"); + printf("up [<partition>:][<nodeid>[,<nodeid>] ...] [[<partition>:][<nodeid>...]] [...]\n"); + printf(" bring node(s) online in the specified partition(s)\n"); + printf("down <nodeid>,[<nodeid>...]\n"); + printf(" send nodes offline (shut them down)\n"); + printf("move/split [<partition>:][<nodeid>[,<nodeid>] ...] [[<partition>:][<nodeid>...]] [...]\n"); + printf(" Move nodes from one partition to another (netsplit)\n"); + printf(" <partition> here is the partition to move the nodes to\n"); + printf("join <partition> <partition> [<partition>] ... \n"); + printf(" Join partitions together (reverse of a netsplit)\n"); + printf("qdevice on|off [<partition>:][<nodeid>[,<nodeid>] ...] [[<partition>:][<nodeid>...]] [...]\n"); + printf(" Enable quorum device in specified nodes\n"); + printf("autofence on|off\n"); + printf(" automatically 'down' nodes on inquorate side on netsplit\n"); + printf("timeout <n> (default 250)\n"); + printf(" Wait a maximum of <n> milli-seconds for the next command to complete.\n"); + printf("sync on|off (default on)\n"); + printf(" enable/disable synchronous execution of commands (wait for completion)\n"); + printf("assert on|off (default off)\n"); + printf(" Abort the simulation run if a timeout expires\n"); + printf("show Show current nodes status\n"); + printf("exit\n\n"); +} + + +/* Commands return 0 if they return immediately, >1 if we are waiting for replies from nodes */ +typedef int (*cmd_routine_t)(int argc, char **argv); + +static int run_up_cmd(int argc, char **argv); +static int run_down_cmd(int argc, char **argv); +static int run_join_cmd(int argc, char **argv); +static int run_move_cmd(int argc, char **argv); +static int run_exit_cmd(int argc, char **argv); +static int run_show_cmd(int argc, char **argv); +static int run_timeout_cmd(int argc, char **argv); +static int run_assert_cmd(int argc, char **argv); +static int run_autofence_cmd(int argc, char **argv); +static int run_qdevice_cmd(int argc, char **argv); +static int run_sync_cmd(int argc, char **argv); + +static struct cmd_list_struct { + const char *cmd; + int min_args; + cmd_routine_t cmd_runner; +} cmd_list[] = { + { "up", 1, run_up_cmd}, + { "down", 1, run_down_cmd}, + { "move", 2, run_move_cmd}, + { "split", 2, run_move_cmd}, + { "join", 2, run_join_cmd}, + { "autofence", 1, run_autofence_cmd}, + { "qdevice", 1, run_qdevice_cmd}, + { "show", 0, run_show_cmd}, + { "timeout", 1, run_timeout_cmd}, + { "sync", 1, run_sync_cmd}, + { "assert", 1, run_assert_cmd}, + { "exit", 0, run_exit_cmd}, + { "quit", 0, run_exit_cmd}, + { "q", 0, run_exit_cmd}, +}; +static int num_cmds = (sizeof(cmd_list)) / sizeof(struct cmd_list_struct); +#define MAX_ARGS 1024 + +/* Takes a <partition>:[<node>[,<node>]...] list and return it + as a partition and a list of nodes. + Returns 0 if successful, -1 if not +*/ +static int parse_partition_nodelist(char *string, int *partition, int *num_nodes, int **retnodes) +{ + int i; + int nodecount; + int len; + int last_comma; + char *nodeptr; + int *nodes; + char *colonptr = strchr(string, ':'); + + if (colonptr) { + *colonptr = '\0'; + nodeptr = colonptr+1; + *partition = atoi(string); + } + else { + /* Default to partition 0 */ + *partition = 0; + nodeptr = string; + } + + /* Count the number of commas and allocate space for the nodes */ + nodecount = 0; + for (i=0; i<strlen(nodeptr); i++) { + if (nodeptr[i] == ',') { + nodecount++; + } + } + nodecount++; /* The one between the last comma and the trailing NUL */ + if (nodecount < 1 || nodecount > MAX_NODES) { + return -1; + } + + nodes = malloc(sizeof(int) * nodecount); + if (!nodes) { + return -1; + } + + nodecount = 0; + last_comma = 0; + len = strlen(nodeptr); + for (i=0; i<=len; i++) { + if (nodeptr[i] == ',' || nodeptr[i] == '\0') { + + nodeptr[i] = '\0'; + nodes[nodecount++] = atoi(&nodeptr[last_comma]); + last_comma = i+1; + } + } + + *num_nodes = nodecount; + *retnodes = nodes; + + return 0; +} + +void parse_input_command(char *rl_cmd) +{ + int i; + int argc = 0; + int valid_cmd = 0; + char *argv[MAX_ARGS]; + int last_arg_start = 0; + int last_was_space = 0; + int len; + int ret = 0; + char *cmd; + + /* ^D quits */ + if (rl_cmd == NULL) { + (void)run_exit_cmd(0, NULL); + } + /* '#' starts a comment */ + if (rl_cmd[0] == '#') { + return; + } + + cmd = strdup(rl_cmd); + + /* Split cmd up into args + * destroying the original string mwahahahaha + */ + + len = strlen(cmd); + + /* Span leading spaces */ + for (i=0; cmd[i] == ' '; i++) + ; + last_arg_start = i; + + for (; i<=len; i++) { + if (cmd[i] == ' ' || cmd[i] == '\0') { + + /* Allow multiple spaces */ + if (last_was_space) { + continue; + } + + cmd[i] = '\0'; + last_was_space = 1; + + argv[argc] = &cmd[last_arg_start]; + argc++; + } + else { + if (last_was_space) { + last_arg_start = i; + } + last_was_space = 0; + } + } + + /* Ignore null commands */ + if (argc < 1 || strlen(argv[0]) == 0) { + free(cmd); + resume_kb_input(0); + return; + } +#ifdef HAVE_READLINE_HISTORY_H + add_history(rl_cmd); +#endif + + /* Dispatch command */ + for (i=0; i<num_cmds; i++) { + if (strcasecmp(argv[0], cmd_list[i].cmd) == 0) { + + if (argc < cmd_list[i].min_args) { + break; + } + ret = cmd_list[i].cmd_runner(argc, argv); + valid_cmd = 1; + } + } + if (!valid_cmd) { + do_usage(); + } + free(cmd); + + /* ret==0 means we can return immediately to command-line input */ + if (ret == 0) { + resume_kb_input(ret); + } +} + + + +static int run_up_cmd(int argc, char **argv) +{ + int partition; + int num_nodes; + int *nodelist; + int i,j; + int succeeded = 0; + + if (argc <= 1) { + return 0; + } + + cmd_start_sync_command(); + + for (i=1; i<argc; i++) { + if (parse_partition_nodelist(argv[i], &partition, &num_nodes, &nodelist) == 0) { + for (j=0; j<num_nodes; j++) { + if (!cmd_start_new_node(nodelist[j], partition)) { + succeeded++; + } + } + free(nodelist); + } + } + return succeeded; +} + +static int run_down_cmd(int argc, char **argv) +{ + int nodeid; + int i; + int succeeded = 0; + + cmd_start_sync_command(); + + for (i=1; i<argc; i++) { + nodeid = atoi(argv[1]); + if (!cmd_stop_node(nodeid)) { + succeeded++; + } + } + return succeeded; +} + +static int run_join_cmd(int argc, char **argv) +{ + int i; + + if (argc < 2) { + printf("join needs at least two partition numbers\n"); + return 0; + } + + cmd_start_sync_command(); + + for (i=2; i<argc; i++) { + cmd_join_partitions(atoi(argv[1]), atoi(argv[i])); + } + cmd_update_all_partitions(1); + return 1; +} + +static int run_move_cmd(int argc, char **argv) +{ + int i; + int partition; + int num_nodes; + int *nodelist; + + cmd_start_sync_command(); + + for (i=1; i<argc; i++) { + if (parse_partition_nodelist(argv[i], &partition, &num_nodes, &nodelist) == 0) { + cmd_move_nodes(partition, num_nodes, nodelist); + free(nodelist); + } + } + cmd_update_all_partitions(1); + return 1; +} + +static int run_autofence_cmd(int argc, char **argv) +{ + int onoff = -1; + + if (strcasecmp(argv[1], "on") == 0) { + onoff = 1; + } + if (strcasecmp(argv[1], "off") == 0) { + onoff = 0; + } + if (onoff == -1) { + fprintf(stderr, "ERR: autofence value must be 'on' or 'off'\n"); + } + else { + cmd_set_autofence(onoff); + } + return 0; +} + +static int run_qdevice_cmd(int argc, char **argv) +{ + int i,j; + int partition; + int num_nodes; + int *nodelist; + int onoff = -1; + + if (strcasecmp(argv[1], "on") == 0) { + onoff = 1; + } + if (strcasecmp(argv[1], "off") == 0) { + onoff = 0; + } + + if (onoff == -1) { + fprintf(stderr, "ERR: qdevice should be 'on' or 'off'\n"); + return 0; + } + + for (i=2; i<argc; i++) { + if (parse_partition_nodelist(argv[i], &partition, &num_nodes, &nodelist) == 0) { + for (j=0; j<num_nodes; j++) { + cmd_qdevice_poll(nodelist[j], onoff); + } + free(nodelist); + } + } + cmd_update_all_partitions(0); + return 0; +} + +static int run_show_cmd(int argc, char **argv) +{ + cmd_show_node_states(); + return 0; +} + +static int run_timeout_cmd(int argc, char **argv) +{ + cmd_set_timeout(atol(argv[1])); + return 0; +} + +static int run_sync_cmd(int argc, char **argv) +{ + int onoff = -1; + + if (strcasecmp(argv[1], "on") == 0) { + onoff = 1; + } + if (strcasecmp(argv[1], "off") == 0) { + onoff = 0; + } + if (onoff == -1) { + fprintf(stderr, "ERR: sync value must be 'on' or 'off'\n"); + } + else { + cmd_set_sync(onoff); + } + return 0; +} + +static int run_assert_cmd(int argc, char **argv) +{ + int onoff = -1; + + if (strcasecmp(argv[1], "on") == 0) { + onoff = 1; + } + if (strcasecmp(argv[1], "off") == 0) { + onoff = 0; + } + if (onoff == -1) { + fprintf(stderr, "ERR: assert value must be 'on' or 'off'\n"); + } + else { + cmd_set_assert(onoff); + } + return 0; +} + +static int run_exit_cmd(int argc, char **argv) +{ + cmd_stop_all_nodes(); + exit(0); +} |