parser.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  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. /* Check the partition number is within range. Returns 0 if it is, -1 if not */
  74. static int parse_partition_number(const char *string, int *partition)
  75. {
  76. *partition = atoi(string);
  77. if (*partition < 0 || *partition >= MAX_PARTITIONS) {
  78. fprintf(stderr, "ERR: partition number must be in range 0..%u\n",
  79. MAX_PARTITIONS - 1);
  80. return -1;
  81. }
  82. return 0;
  83. }
  84. /* Takes a <partition>:[<node>[,<node>]...] list and return it
  85. as a partition and a list of nodes.
  86. Returns 0 if successful, -1 if not
  87. */
  88. static int parse_partition_nodelist(char *string, int *partition, int *num_nodes, int **retnodes)
  89. {
  90. int i;
  91. int nodecount;
  92. int len;
  93. int last_comma;
  94. char *nodeptr;
  95. int *nodes;
  96. char *colonptr = strchr(string, ':');
  97. if (colonptr) {
  98. *colonptr = '\0';
  99. nodeptr = colonptr+1;
  100. if (parse_partition_number(string, partition) != 0) {
  101. return -1;
  102. }
  103. }
  104. else {
  105. /* Default to partition 0 */
  106. *partition = 0;
  107. nodeptr = string;
  108. }
  109. /* Count the number of commas and allocate space for the nodes */
  110. nodecount = 0;
  111. for (i=0; i<strlen(nodeptr); i++) {
  112. if (nodeptr[i] == ',') {
  113. nodecount++;
  114. }
  115. }
  116. nodecount++; /* The one between the last comma and the trailing NUL */
  117. if (nodecount < 1 || nodecount > MAX_NODES) {
  118. return -1;
  119. }
  120. nodes = malloc(sizeof(int) * nodecount);
  121. if (!nodes) {
  122. return -1;
  123. }
  124. nodecount = 0;
  125. last_comma = 0;
  126. len = strlen(nodeptr);
  127. for (i=0; i<=len; i++) {
  128. if (nodeptr[i] == ',' || nodeptr[i] == '\0') {
  129. nodeptr[i] = '\0';
  130. nodes[nodecount++] = atoi(&nodeptr[last_comma]);
  131. last_comma = i+1;
  132. }
  133. }
  134. *num_nodes = nodecount;
  135. *retnodes = nodes;
  136. return 0;
  137. }
  138. void parse_input_command(char *rl_cmd)
  139. {
  140. int i;
  141. int argc = 0;
  142. int valid_cmd = 0;
  143. char *argv[MAX_ARGS];
  144. int last_arg_start = 0;
  145. int last_was_space = 0;
  146. int len;
  147. int ret = 0;
  148. char *cmd;
  149. /* ^D quits */
  150. if (rl_cmd == NULL) {
  151. (void)run_exit_cmd(0, NULL);
  152. }
  153. /* '#' starts a comment */
  154. if (rl_cmd[0] == '#') {
  155. return;
  156. }
  157. cmd = strdup(rl_cmd);
  158. /* Split cmd up into args
  159. * destroying the original string mwahahahaha
  160. */
  161. len = strlen(cmd);
  162. /* Span leading spaces */
  163. for (i=0; cmd[i] == ' '; i++)
  164. ;
  165. last_arg_start = i;
  166. for (; i<=len; i++) {
  167. if (cmd[i] == ' ' || cmd[i] == '\0') {
  168. /* Allow multiple spaces */
  169. if (last_was_space) {
  170. continue;
  171. }
  172. cmd[i] = '\0';
  173. last_was_space = 1;
  174. argv[argc] = &cmd[last_arg_start];
  175. argc++;
  176. }
  177. else {
  178. if (last_was_space) {
  179. last_arg_start = i;
  180. }
  181. last_was_space = 0;
  182. }
  183. }
  184. /* Ignore null commands */
  185. if (argc < 1 || strlen(argv[0]) == 0) {
  186. free(cmd);
  187. resume_kb_input(0);
  188. return;
  189. }
  190. #ifdef HAVE_READLINE_HISTORY_H
  191. add_history(rl_cmd);
  192. #endif
  193. /* Dispatch command */
  194. for (i=0; i<num_cmds; i++) {
  195. if (strcasecmp(argv[0], cmd_list[i].cmd) == 0) {
  196. if (argc < cmd_list[i].min_args) {
  197. break;
  198. }
  199. ret = cmd_list[i].cmd_runner(argc, argv);
  200. valid_cmd = 1;
  201. }
  202. }
  203. if (!valid_cmd) {
  204. do_usage();
  205. }
  206. free(cmd);
  207. /* ret==0 means we can return immediately to command-line input */
  208. if (ret == 0) {
  209. resume_kb_input(ret);
  210. }
  211. }
  212. static int run_up_cmd(int argc, char **argv)
  213. {
  214. int partition;
  215. int num_nodes;
  216. int *nodelist;
  217. int i,j;
  218. int succeeded = 0;
  219. if (argc <= 1) {
  220. return 0;
  221. }
  222. cmd_start_sync_command();
  223. for (i=1; i<argc; i++) {
  224. if (parse_partition_nodelist(argv[i], &partition, &num_nodes, &nodelist) == 0) {
  225. for (j=0; j<num_nodes; j++) {
  226. if (!cmd_start_new_node(nodelist[j], partition)) {
  227. succeeded++;
  228. }
  229. }
  230. free(nodelist);
  231. }
  232. }
  233. return succeeded;
  234. }
  235. static int run_down_cmd(int argc, char **argv)
  236. {
  237. int nodeid;
  238. int i;
  239. int succeeded = 0;
  240. cmd_start_sync_command();
  241. for (i=1; i<argc; i++) {
  242. nodeid = atoi(argv[1]);
  243. if (!cmd_stop_node(nodeid)) {
  244. succeeded++;
  245. }
  246. }
  247. return succeeded;
  248. }
  249. static int run_join_cmd(int argc, char **argv)
  250. {
  251. int i;
  252. int part1;
  253. int part2;
  254. if (argc < 2) {
  255. printf("join needs at least two partition numbers\n");
  256. return 0;
  257. }
  258. cmd_start_sync_command();
  259. for (i=2; i<argc; i++) {
  260. if (parse_partition_number(argv[1], &part1) == 0 &&
  261. parse_partition_number(argv[i], &part2) == 0) {
  262. cmd_join_partitions(part1, part2);
  263. }
  264. }
  265. cmd_update_all_partitions(1);
  266. return 1;
  267. }
  268. static int run_move_cmd(int argc, char **argv)
  269. {
  270. int i;
  271. int partition;
  272. int num_nodes;
  273. int *nodelist;
  274. cmd_start_sync_command();
  275. for (i=1; i<argc; i++) {
  276. if (parse_partition_nodelist(argv[i], &partition, &num_nodes, &nodelist) == 0) {
  277. cmd_move_nodes(partition, num_nodes, nodelist);
  278. free(nodelist);
  279. }
  280. }
  281. cmd_update_all_partitions(1);
  282. return 1;
  283. }
  284. static int run_autofence_cmd(int argc, char **argv)
  285. {
  286. int onoff = -1;
  287. if (strcasecmp(argv[1], "on") == 0) {
  288. onoff = 1;
  289. }
  290. if (strcasecmp(argv[1], "off") == 0) {
  291. onoff = 0;
  292. }
  293. if (onoff == -1) {
  294. fprintf(stderr, "ERR: autofence value must be 'on' or 'off'\n");
  295. }
  296. else {
  297. cmd_set_autofence(onoff);
  298. }
  299. return 0;
  300. }
  301. static int run_qdevice_cmd(int argc, char **argv)
  302. {
  303. int i,j;
  304. int partition;
  305. int num_nodes;
  306. int *nodelist;
  307. int onoff = -1;
  308. if (strcasecmp(argv[1], "on") == 0) {
  309. onoff = 1;
  310. }
  311. if (strcasecmp(argv[1], "off") == 0) {
  312. onoff = 0;
  313. }
  314. if (onoff == -1) {
  315. fprintf(stderr, "ERR: qdevice should be 'on' or 'off'\n");
  316. return 0;
  317. }
  318. for (i=2; i<argc; i++) {
  319. if (parse_partition_nodelist(argv[i], &partition, &num_nodes, &nodelist) == 0) {
  320. for (j=0; j<num_nodes; j++) {
  321. cmd_qdevice_poll(nodelist[j], onoff);
  322. }
  323. free(nodelist);
  324. }
  325. }
  326. cmd_update_all_partitions(0);
  327. return 0;
  328. }
  329. static int run_show_cmd(int argc, char **argv)
  330. {
  331. cmd_show_node_states();
  332. return 0;
  333. }
  334. static int run_timeout_cmd(int argc, char **argv)
  335. {
  336. cmd_set_timeout(atol(argv[1]));
  337. return 0;
  338. }
  339. static int run_sync_cmd(int argc, char **argv)
  340. {
  341. int onoff = -1;
  342. if (strcasecmp(argv[1], "on") == 0) {
  343. onoff = 1;
  344. }
  345. if (strcasecmp(argv[1], "off") == 0) {
  346. onoff = 0;
  347. }
  348. if (onoff == -1) {
  349. fprintf(stderr, "ERR: sync value must be 'on' or 'off'\n");
  350. }
  351. else {
  352. cmd_set_sync(onoff);
  353. }
  354. return 0;
  355. }
  356. static int run_assert_cmd(int argc, char **argv)
  357. {
  358. int onoff = -1;
  359. if (strcasecmp(argv[1], "on") == 0) {
  360. onoff = 1;
  361. }
  362. if (strcasecmp(argv[1], "off") == 0) {
  363. onoff = 0;
  364. }
  365. if (onoff == -1) {
  366. fprintf(stderr, "ERR: assert value must be 'on' or 'off'\n");
  367. }
  368. else {
  369. cmd_set_assert(onoff);
  370. }
  371. return 0;
  372. }
  373. static int run_exit_cmd(int argc, char **argv)
  374. {
  375. cmd_stop_all_nodes();
  376. exit(0);
  377. }