summaryrefslogtreecommitdiffstats
path: root/vqsim/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'vqsim/parser.c')
-rw-r--r--vqsim/parser.c418
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);
+}