parser.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /* Parses the interactive commands */
  2. #include <config.h>
  3. #include <string.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <netinet/in.h>
  8. #ifdef HAVE_READLINE_HISTORY_H
  9. #include <readline/history.h>
  10. #endif
  11. #include <corosync/coroapi.h>
  12. #include "vqsim.h"
  13. static void do_usage(void)
  14. {
  15. printf(" All node IDs in the cluster are unique and belong to a numbered 'partition' (default=0)\n");
  16. printf("\n");
  17. printf("up [<partition>:][<nodeid>[,<nodeid>] ...] [[<partition>:][<nodeid>...]] [...]\n");
  18. printf(" bring node(s) online in the specified partition(s)\n");
  19. printf("down <nodeid>,[<nodeid>...]\n");
  20. printf(" send nodes offline (shut them down)\n");
  21. printf("move/split [<partition>:][<nodeid>[,<nodeid>] ...] [[<partition>:][<nodeid>...]] [...]\n");
  22. printf(" Move nodes from one partition to another (netsplit)\n");
  23. printf(" <partition> here is the partition to move the nodes to\n");
  24. printf("join <partition> <partition> [<partition>] ... \n");
  25. printf(" Join partitions together (reverse of a netsplit)\n");
  26. printf("qdevice on|off [<partition>:][<nodeid>[,<nodeid>] ...] [[<partition>:][<nodeid>...]] [...]\n");
  27. printf(" Enable quorum device in specified nodes\n");
  28. printf("autofence on|off\n");
  29. printf(" automatically 'down' nodes on inquorate side on netsplit\n");
  30. printf("show Show current nodes status\n");
  31. printf("exit\n\n");
  32. }
  33. typedef void (*cmd_routine_t)(int argc, char **argv);
  34. static void run_up_cmd(int argc, char **argv);
  35. static void run_down_cmd(int argc, char **argv);
  36. static void run_join_cmd(int argc, char **argv);
  37. static void run_move_cmd(int argc, char **argv);
  38. static void run_exit_cmd(int argc, char **argv);
  39. static void run_show_cmd(int argc, char **argv);
  40. static void run_autofence_cmd(int argc, char **argv);
  41. static void run_qdevice_cmd(int argc, char **argv);
  42. static struct cmd_list_struct {
  43. const char *cmd;
  44. int min_args;
  45. cmd_routine_t cmd_runner;
  46. } cmd_list[] = {
  47. { "up", 1, run_up_cmd},
  48. { "down", 1, run_down_cmd},
  49. { "move", 2, run_move_cmd},
  50. { "split", 2, run_move_cmd},
  51. { "join", 2, run_join_cmd},
  52. { "autofence", 1, run_autofence_cmd},
  53. { "qdevice", 1, run_qdevice_cmd},
  54. { "show", 0, run_show_cmd},
  55. { "exit", 0, run_exit_cmd},
  56. { "quit", 0, run_exit_cmd},
  57. { "q", 0, run_exit_cmd},
  58. };
  59. static int num_cmds = (sizeof(cmd_list)) / sizeof(struct cmd_list_struct);
  60. #define MAX_ARGS 1024
  61. /* Takes a <partition>:[<node>[,<node>]...] list and return it
  62. as a partition and a list of nodes.
  63. Returns 0 if successful, -1 if not
  64. */
  65. static int parse_partition_nodelist(char *string, int *partition, int *num_nodes, int **retnodes)
  66. {
  67. int i;
  68. int nodecount;
  69. int len;
  70. int last_comma;
  71. char *nodeptr;
  72. int *nodes;
  73. char *colonptr = strchr(string, ':');
  74. if (colonptr) {
  75. *colonptr = '\0';
  76. nodeptr = colonptr+1;
  77. *partition = atoi(string);
  78. }
  79. else {
  80. /* Default to partition 0 */
  81. *partition = 0;
  82. nodeptr = string;
  83. }
  84. /* Count the number of commas and allocate space for the nodes */
  85. nodecount = 0;
  86. for (i=0; i<strlen(nodeptr); i++) {
  87. if (nodeptr[i] == ',') {
  88. nodecount++;
  89. }
  90. }
  91. nodecount++; /* The one between the last comma and the trailing NUL */
  92. if (nodecount < 1 || nodecount > MAX_NODES) {
  93. return -1;
  94. }
  95. nodes = malloc(sizeof(int) * nodecount);
  96. if (!nodes) {
  97. return -1;
  98. }
  99. nodecount = 0;
  100. last_comma = 0;
  101. len = strlen(nodeptr);
  102. for (i=0; i<=len; i++) {
  103. if (nodeptr[i] == ',' || nodeptr[i] == '\0') {
  104. nodeptr[i] = '\0';
  105. nodes[nodecount++] = atoi(&nodeptr[last_comma]);
  106. last_comma = i+1;
  107. }
  108. }
  109. *num_nodes = nodecount;
  110. *retnodes = nodes;
  111. return 0;
  112. }
  113. void parse_input_command(char *rl_cmd)
  114. {
  115. int i;
  116. int argc = 0;
  117. int valid_cmd = 0;
  118. char *argv[MAX_ARGS];
  119. int last_arg_start = 0;
  120. int last_was_space = 0;
  121. int len;
  122. char *cmd;
  123. /* ^D quits */
  124. if (rl_cmd == NULL) {
  125. run_exit_cmd(0, NULL);
  126. }
  127. cmd = strdup(rl_cmd);
  128. /* Split cmd up into args
  129. * destroying the original string mwahahahaha
  130. */
  131. len = strlen(cmd);
  132. /* Span leading spaces */
  133. for (i=0; cmd[i] == ' '; i++)
  134. ;
  135. last_arg_start = i;
  136. for (; i<=len; i++) {
  137. if (cmd[i] == ' ' || cmd[i] == '\0') {
  138. /* Allow multiple spaces */
  139. if (last_was_space) {
  140. continue;
  141. }
  142. cmd[i] = '\0';
  143. last_was_space = 1;
  144. argv[argc] = &cmd[last_arg_start];
  145. argc++;
  146. }
  147. else {
  148. if (last_was_space) {
  149. last_arg_start = i;
  150. }
  151. last_was_space = 0;
  152. }
  153. }
  154. /* Ignore null commands */
  155. if (strlen(argv[0]) == 0) {
  156. free(cmd);
  157. return;
  158. }
  159. #ifdef HAVE_READLINE_HISTORY_H
  160. add_history(rl_cmd);
  161. #endif
  162. /* Dispatch command */
  163. for (i=0; i<num_cmds; i++) {
  164. if (strcasecmp(argv[0], cmd_list[i].cmd) == 0) {
  165. if (argc < cmd_list[i].min_args) {
  166. break;
  167. }
  168. cmd_list[i].cmd_runner(argc, argv);
  169. valid_cmd = 1;
  170. }
  171. }
  172. if (!valid_cmd) {
  173. do_usage();
  174. }
  175. free(cmd);
  176. }
  177. static void run_up_cmd(int argc, char **argv)
  178. {
  179. int partition;
  180. int num_nodes;
  181. int *nodelist;
  182. int i,j;
  183. if (argc <= 1) {
  184. return;
  185. }
  186. for (i=1; i<argc; i++) {
  187. if (parse_partition_nodelist(argv[i], &partition, &num_nodes, &nodelist) == 0) {
  188. for (j=0; j<num_nodes; j++) {
  189. cmd_start_new_node(nodelist[j], partition);
  190. }
  191. free(nodelist);
  192. }
  193. }
  194. }
  195. static void run_down_cmd(int argc, char **argv)
  196. {
  197. int nodeid;
  198. int i;
  199. for (i=1; i<argc; i++) {
  200. nodeid = atoi(argv[1]);
  201. cmd_stop_node(nodeid);
  202. }
  203. }
  204. static void run_join_cmd(int argc, char **argv)
  205. {
  206. int i;
  207. if (argc < 2) {
  208. printf("join needs at least two partition numbers\n");
  209. return;
  210. }
  211. for (i=2; i<argc; i++) {
  212. cmd_join_partitions(atoi(argv[1]), atoi(argv[i]));
  213. }
  214. cmd_update_all_partitions(1);
  215. }
  216. static void run_move_cmd(int argc, char **argv)
  217. {
  218. int i;
  219. int partition;
  220. int num_nodes;
  221. int *nodelist;
  222. for (i=1; i<argc; i++) {
  223. if (parse_partition_nodelist(argv[i], &partition, &num_nodes, &nodelist) == 0) {
  224. cmd_move_nodes(partition, num_nodes, nodelist);
  225. free(nodelist);
  226. }
  227. }
  228. cmd_update_all_partitions(1);
  229. }
  230. static void run_autofence_cmd(int argc, char **argv)
  231. {
  232. int onoff = -1;
  233. if (strcasecmp(argv[1], "on") == 0) {
  234. onoff = 1;
  235. }
  236. if (strcasecmp(argv[1], "off") == 0) {
  237. onoff = 0;
  238. }
  239. if (onoff == -1) {
  240. fprintf(stderr, "ERR: autofence value must be 'on' or 'off'\n");
  241. }
  242. else {
  243. cmd_set_autofence(onoff);
  244. }
  245. }
  246. static void run_qdevice_cmd(int argc, char **argv)
  247. {
  248. int i,j;
  249. int partition;
  250. int num_nodes;
  251. int *nodelist;
  252. int onoff = -1;
  253. if (strcasecmp(argv[1], "on") == 0) {
  254. onoff = 1;
  255. }
  256. if (strcasecmp(argv[1], "off") == 0) {
  257. onoff = 0;
  258. }
  259. if (onoff == -1) {
  260. fprintf(stderr, "ERR: qdevice should be 'on' or 'off'\n");
  261. return;
  262. }
  263. for (i=2; i<argc; i++) {
  264. if (parse_partition_nodelist(argv[i], &partition, &num_nodes, &nodelist) == 0) {
  265. for (j=0; j<num_nodes; j++) {
  266. cmd_qdevice_poll(nodelist[j], onoff);
  267. }
  268. free(nodelist);
  269. }
  270. }
  271. cmd_update_all_partitions(0);
  272. }
  273. static void run_show_cmd(int argc, char **argv)
  274. {
  275. cmd_show_node_states();
  276. }
  277. static void run_exit_cmd(int argc, char **argv)
  278. {
  279. cmd_stop_all_nodes();
  280. exit(0);
  281. }