parser.c 8.8 KB

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