vqmain.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848
  1. #include <config.h>
  2. #include <stdio.h>
  3. #include <sys/types.h>
  4. #include <sys/wait.h>
  5. #include <qb/qblog.h>
  6. #include <qb/qbloop.h>
  7. #include <sys/poll.h>
  8. #include <netinet/in.h>
  9. #include <sys/queue.h>
  10. #ifdef HAVE_READLINE_READLINE_H
  11. #include <readline/readline.h>
  12. #else
  13. #include <unistd.h> /* isatty */
  14. #endif
  15. #include "../exec/votequorum.h"
  16. #include "../exec/service.h"
  17. #include <corosync/logsys.h>
  18. #include <corosync/coroapi.h>
  19. #include "icmap.h"
  20. #include "vqsim.h"
  21. /* Easier than including the config file with a ton of conflicting dependencies */
  22. extern int coroparse_configparse (icmap_map_t config_map, const char **error_string);
  23. extern int corosync_log_config_read (const char **error_string);
  24. static int stdin_read_fn(int32_t fd, int32_t revents, void *data);
  25. /* 'Keep the compiler happy' time */
  26. const char *corosync_get_config_file(void);
  27. /* One of these per partition */
  28. struct vq_partition {
  29. TAILQ_HEAD(, vq_node) nodelist;
  30. struct memb_ring_id ring_id;
  31. int num;
  32. };
  33. /* One of these per node */
  34. struct vq_node {
  35. vq_object_t instance;
  36. unsigned int nodeid;
  37. int fd;
  38. struct vq_partition *partition;
  39. TAILQ_ENTRY(vq_node) entries;
  40. /* Last status */
  41. int last_quorate;
  42. struct memb_ring_id last_ring_id;
  43. int last_view_list[MAX_NODES];
  44. int last_view_list_entries;
  45. };
  46. static struct vq_partition partitions[MAX_PARTITIONS];
  47. static qb_loop_t *poll_loop;
  48. static int autofence;
  49. static int check_for_quorum;
  50. static FILE *output_file;
  51. static int sync_cmds = 1;
  52. static qb_loop_timer_handle kb_timer;
  53. static int waiting_for_sync = 0;
  54. static int is_tty;
  55. static int assert_on_timeout;
  56. static uint64_t command_timeout = 250000000L;
  57. static struct vq_node *find_by_pid(pid_t pid);
  58. static void send_partition_to_nodes(struct vq_partition *partition, int newring);
  59. static void start_kb_input_timeout(void *data);
  60. static void finish_wait_timeout(void *data);
  61. #ifndef HAVE_READLINE_READLINE_H
  62. #define INPUT_BUF_SIZE 1024
  63. static char input_buf[INPUT_BUF_SIZE];
  64. static size_t input_buf_term = 0;
  65. #endif
  66. /* 'Keep the compiler happy' time */
  67. static char corosync_config_file[PATH_MAX + 1] = COROSYSCONFDIR "/corosync.conf";
  68. const char *corosync_get_config_file(void)
  69. {
  70. return (corosync_config_file);
  71. }
  72. /* Tell all non-quorate nodes to quit */
  73. static void force_fence(void)
  74. {
  75. int i;
  76. struct vq_node *vqn;
  77. for (i=0; i<MAX_PARTITIONS; i++) {
  78. TAILQ_FOREACH(vqn, &partitions[i].nodelist, entries) {
  79. vq_quit_if_inquorate(vqn->instance);
  80. }
  81. }
  82. }
  83. /* Save quorum state from the incoming message */
  84. static void save_quorum_state(struct vq_node *node, struct vqsim_quorum_msg *qmsg)
  85. {
  86. node->last_quorate = qmsg->quorate;
  87. memcpy(&node->last_ring_id, &qmsg->ring_id, sizeof(struct memb_ring_id));
  88. memcpy(node->last_view_list, qmsg->view_list, sizeof(int) * qmsg->view_list_entries);
  89. node->last_view_list_entries = qmsg->view_list_entries;
  90. /* If at least one node is quorate and autofence is enabled, then fence everyone who is not quorate */
  91. if (check_for_quorum && qmsg->quorate & autofence) {
  92. check_for_quorum = 0;
  93. force_fence();
  94. }
  95. }
  96. /* Print current node state */
  97. static void print_quorum_state(struct vq_node *node)
  98. {
  99. int i;
  100. if (node->last_quorate < 0) {
  101. fprintf(output_file, "%d:%02d: q=UNINITIALIZED\n",
  102. node->partition->num, node->nodeid);
  103. return;
  104. }
  105. fprintf(output_file, "%d:%02d: q=%d ring=[%d/%lld] ", node->partition->num, node->nodeid, node->last_quorate,
  106. node->last_ring_id.nodeid, node->last_ring_id.seq);
  107. fprintf(output_file, "nodes=[");
  108. for (i = 0; i < node->last_view_list_entries; i++) {
  109. if (i) {
  110. fprintf(output_file, " ");
  111. }
  112. fprintf(output_file, "%d", node->last_view_list[i]);
  113. }
  114. fprintf(output_file, "]\n");
  115. }
  116. static void propogate_vq_message(struct vq_node *vqn, const char *msg, int len)
  117. {
  118. struct vq_node *other_vqn;
  119. /* Send it to everyone in that node's partition (including itself) */
  120. TAILQ_FOREACH(other_vqn, &vqn->partition->nodelist, entries) {
  121. write(other_vqn->fd, msg, len);
  122. }
  123. }
  124. static void cmd_show_prompt_if_needed(void)
  125. {
  126. qb_loop_timer_del(poll_loop, kb_timer);
  127. if (is_tty) {
  128. printf("vqsim> ");
  129. fflush(stdout);
  130. } else {
  131. printf("#vqsim> ");
  132. fflush(stdout);
  133. }
  134. }
  135. void resume_kb_input(int show_status)
  136. {
  137. /* If running synchronously, we don't display
  138. the quorum messages as they come in. So run 'show' commamnd
  139. */
  140. if (show_status && waiting_for_sync) {
  141. cmd_show_node_states();
  142. }
  143. waiting_for_sync = 0;
  144. if (qb_loop_poll_add(poll_loop,
  145. QB_LOOP_MED,
  146. STDIN_FILENO,
  147. POLLIN | POLLERR,
  148. NULL,
  149. stdin_read_fn)) {
  150. if (errno != EEXIST) {
  151. perror("qb_loop_poll_add1 returned error");
  152. }
  153. }
  154. /* Always shows the prompt here, cos we cleared waiting_for_sync */
  155. cmd_show_prompt_if_needed();
  156. }
  157. /* Return true (1) if all nodes in each partition have the same ring id, false(0) otherwise */
  158. static int all_nodes_consistent(void)
  159. {
  160. int i;
  161. struct vq_node *vqn;
  162. struct memb_ring_id last_ring_id;
  163. for (i=0; i<MAX_PARTITIONS; i++) {
  164. memset(&last_ring_id, 0, sizeof(last_ring_id));
  165. TAILQ_FOREACH(vqn, &partitions[i].nodelist, entries) {
  166. if (last_ring_id.seq &&
  167. last_ring_id.seq != vqn->last_ring_id.seq) {
  168. return 0;
  169. }
  170. last_ring_id.seq = vqn->last_ring_id.seq;
  171. }
  172. }
  173. return 1;
  174. }
  175. static int vq_parent_read_fn(int32_t fd, int32_t revents, void *data)
  176. {
  177. char msgbuf[8192];
  178. int msglen;
  179. struct vqsim_msg_header *msg;
  180. struct vqsim_quorum_msg *qmsg;
  181. struct vq_node *vqn = data;
  182. if (revents == POLLIN) {
  183. msglen = read(fd, msgbuf, sizeof(msgbuf));
  184. if (msglen < 0) {
  185. perror("read failed");
  186. }
  187. if (msglen > 0) {
  188. msg = (void*)msgbuf;
  189. switch (msg->type) {
  190. case VQMSG_QUORUM:
  191. qmsg = (void*)msgbuf;
  192. save_quorum_state(vqn, qmsg);
  193. if (!sync_cmds) {
  194. print_quorum_state(vqn);
  195. }
  196. /* Have the partitions stabilised? */
  197. if (sync_cmds && waiting_for_sync &&
  198. all_nodes_consistent()) {
  199. qb_loop_timer_del(poll_loop, kb_timer);
  200. resume_kb_input(sync_cmds);
  201. }
  202. break;
  203. case VQMSG_EXEC:
  204. /* Message from votequorum, pass around the partition */
  205. propogate_vq_message(vqn, msgbuf, msglen);
  206. break;
  207. case VQMSG_QUIT:
  208. case VQMSG_SYNC:
  209. case VQMSG_QDEVICE:
  210. case VQMSG_QUORUMQUIT:
  211. /* not used here */
  212. break;
  213. }
  214. }
  215. }
  216. if (revents == POLLERR) {
  217. fprintf(stderr, "pollerr on %d\n", vqn->nodeid);
  218. }
  219. return 0;
  220. }
  221. static int read_corosync_conf(void)
  222. {
  223. int res;
  224. const char *error_string;
  225. int err = icmap_init();
  226. if (!err) {
  227. fprintf(stderr, "icmap_init failed\n");
  228. }
  229. /* Load corosync.conf */
  230. logsys_format_set(NULL);
  231. res = coroparse_configparse(icmap_get_global_map(), &error_string);
  232. if (res == -1) {
  233. log_printf (LOGSYS_LEVEL_INFO, "Error loading corosync.conf %s", error_string);
  234. return -1;
  235. }
  236. else {
  237. res = corosync_log_config_read (&error_string);
  238. if (res < 0) {
  239. log_printf (LOGSYS_LEVEL_INFO, "error reading log config %s", error_string);
  240. syslog (LOGSYS_LEVEL_INFO, "error reading log config %s", error_string);
  241. }
  242. else {
  243. logsys_config_apply();
  244. }
  245. }
  246. if (logsys_thread_start() != 0) {
  247. log_printf (LOGSYS_LEVEL_ERROR, "Can't initialize log thread");
  248. return -1;
  249. }
  250. return 0;
  251. }
  252. static void remove_node(struct vq_node *node)
  253. {
  254. struct vq_partition *part;
  255. part = node->partition;
  256. /* Remove from partition list */
  257. TAILQ_REMOVE(&part->nodelist, node, entries);
  258. free(node);
  259. /* Rebuild quorum */
  260. send_partition_to_nodes(part, 1);
  261. }
  262. static int32_t sigchld_handler(int32_t sig, void *data)
  263. {
  264. pid_t pid;
  265. int status;
  266. struct vq_node *vqn;
  267. const char *exit_status="";
  268. char text[132];
  269. pid = wait(&status);
  270. if (WIFEXITED(status)) {
  271. vqn = find_by_pid(pid);
  272. if (vqn) {
  273. switch (WEXITSTATUS(status)) {
  274. case 0:
  275. exit_status = "(on request)";
  276. break;
  277. case 1:
  278. exit_status = "(autofenced)";
  279. break;
  280. default:
  281. sprintf(text, "(exit code %d)", WEXITSTATUS(status));
  282. break;
  283. }
  284. printf("%d:%02d: Quit %s\n", vqn->partition->num, vqn->nodeid, exit_status);
  285. remove_node(vqn);
  286. }
  287. else {
  288. fprintf(stderr, "Unknown child %d exited with status %d\n", pid, WEXITSTATUS(status));
  289. }
  290. }
  291. if (WIFSIGNALED(status)) {
  292. vqn = find_by_pid(pid);
  293. if (vqn) {
  294. printf("%d:%02d exited on signal %d%s\n", vqn->partition->num, vqn->nodeid, WTERMSIG(status), WCOREDUMP(status)?" (core dumped)":"");
  295. remove_node(vqn);
  296. }
  297. else {
  298. fprintf(stderr, "Unknown child %d exited with status %d%s\n", pid, WTERMSIG(status), WCOREDUMP(status)?" (core dumped)":"");
  299. }
  300. }
  301. return 0;
  302. }
  303. static void send_partition_to_nodes(struct vq_partition *partition, int newring)
  304. {
  305. struct vq_node *vqn;
  306. int nodelist[MAX_NODES];
  307. int nodes = 0;
  308. int first = 1;
  309. if (newring) {
  310. /* Simulate corosync incrementing the seq by 4 for added authenticity */
  311. partition->ring_id.seq += 4;
  312. }
  313. /* Build the node list */
  314. TAILQ_FOREACH(vqn, &partition->nodelist, entries) {
  315. nodelist[nodes++] = vqn->nodeid;
  316. if (first) {
  317. partition->ring_id.nodeid = vqn->nodeid;
  318. first = 0;
  319. }
  320. }
  321. TAILQ_FOREACH(vqn, &partition->nodelist, entries) {
  322. vq_set_nodelist(vqn->instance, &partition->ring_id, nodelist, nodes);
  323. }
  324. }
  325. static void init_partitions(void)
  326. {
  327. int i;
  328. for (i=0; i<MAX_PARTITIONS; i++) {
  329. TAILQ_INIT(&partitions[i].nodelist);
  330. partitions[i].ring_id.nodeid = 1000+i;
  331. partitions[i].ring_id.seq = 0;
  332. partitions[i].num = i;
  333. }
  334. }
  335. static int nodes_in_partition(int part)
  336. {
  337. struct vq_node *vqn;
  338. int partnodes = 0;
  339. TAILQ_FOREACH(vqn, &partitions[part].nodelist, entries) {
  340. partnodes++;
  341. }
  342. return partnodes;
  343. }
  344. static pid_t create_node(int nodeid, int partno)
  345. {
  346. struct vq_node *newvq;
  347. newvq = malloc(sizeof(struct vq_node));
  348. if (newvq) {
  349. newvq->last_quorate = -1; /* mark "uninitialized" */
  350. newvq->instance = vq_create_instance(poll_loop, nodeid);
  351. if (!newvq->instance) {
  352. fprintf(stderr,
  353. "ERR: could not create vq instance nodeid %d\n",
  354. nodeid);
  355. return (pid_t) -1;
  356. }
  357. newvq->partition = &partitions[partno];
  358. newvq->nodeid = nodeid;
  359. newvq->fd = vq_get_parent_fd(newvq->instance);
  360. TAILQ_INSERT_TAIL(&partitions[partno].nodelist, newvq, entries);
  361. if (qb_loop_poll_add(poll_loop,
  362. QB_LOOP_MED,
  363. newvq->fd,
  364. POLLIN | POLLERR,
  365. newvq,
  366. vq_parent_read_fn)) {
  367. perror("qb_loop_poll_add returned error");
  368. return (pid_t) -1;
  369. }
  370. /* Send sync with all the nodes so far in it. */
  371. send_partition_to_nodes(&partitions[partno], 1);
  372. return vq_get_pid(newvq->instance);
  373. }
  374. return (pid_t) -1;
  375. }
  376. static size_t create_nodes_from_config(void)
  377. {
  378. icmap_iter_t iter;
  379. char tmp_key[ICMAP_KEYNAME_MAXLEN];
  380. uint32_t node_pos;
  381. uint32_t nodeid;
  382. const char *iter_key;
  383. int res;
  384. pid_t pid;
  385. size_t ret = 0;
  386. init_partitions();
  387. iter = icmap_iter_init("nodelist.node.");
  388. while ((iter_key = icmap_iter_next(iter, NULL, NULL)) != NULL) {
  389. res = sscanf(iter_key, "nodelist.node.%u.%s", &node_pos, tmp_key);
  390. if (res != 2) {
  391. continue;
  392. }
  393. if (strcmp(tmp_key, "ring0_addr") != 0) {
  394. continue;
  395. }
  396. snprintf(tmp_key, ICMAP_KEYNAME_MAXLEN, "nodelist.node.%u.nodeid", node_pos);
  397. if (icmap_get_uint32(tmp_key, &nodeid) == CS_OK) {
  398. pid = create_node(nodeid, 0);
  399. if (pid == (pid_t) -1) {
  400. fprintf(stderr,
  401. "ERR: nodeid %d could not be spawned\n",
  402. nodeid);
  403. exit(1);
  404. }
  405. ret++;
  406. }
  407. }
  408. icmap_iter_finalize(iter);
  409. return ret;
  410. }
  411. static struct vq_node *find_node(int nodeid)
  412. {
  413. int i;
  414. struct vq_node *vqn;
  415. for (i=0; i<MAX_PARTITIONS; i++) {
  416. TAILQ_FOREACH(vqn, &partitions[i].nodelist, entries) {
  417. if (vqn->nodeid == nodeid) {
  418. return vqn;
  419. }
  420. }
  421. }
  422. return NULL;
  423. }
  424. static struct vq_node *find_by_pid(pid_t pid)
  425. {
  426. int i;
  427. struct vq_node *vqn;
  428. for (i=0; i<MAX_PARTITIONS; i++) {
  429. TAILQ_FOREACH(vqn, &partitions[i].nodelist, entries) {
  430. if (vq_get_pid(vqn->instance) == pid) {
  431. return vqn;
  432. }
  433. }
  434. }
  435. return NULL;
  436. }
  437. /* Routines called from the parser */
  438. /*
  439. * The parser calls this before running a command where
  440. * we might have to wait for a result to come back.
  441. */
  442. void cmd_start_sync_command()
  443. {
  444. if (sync_cmds) {
  445. qb_loop_poll_del(poll_loop, STDIN_FILENO);
  446. qb_loop_timer_add(poll_loop,
  447. QB_LOOP_MED,
  448. command_timeout,
  449. NULL,
  450. finish_wait_timeout,
  451. &kb_timer);
  452. waiting_for_sync = 1;
  453. }
  454. }
  455. int cmd_start_new_node(int nodeid, int partition)
  456. {
  457. struct vq_node *node;
  458. node = find_node(nodeid);
  459. if (node) {
  460. fprintf(stderr, "ERR: nodeid %d already exists in partition %d\n", nodeid, node->partition->num);
  461. return -1;
  462. }
  463. if (create_node(nodeid, partition) == -1) {
  464. return -1;
  465. }
  466. return 0;
  467. }
  468. void cmd_stop_all_nodes()
  469. {
  470. int i;
  471. struct vq_node *vqn;
  472. for (i=0; i<MAX_PARTITIONS; i++) {
  473. TAILQ_FOREACH(vqn, &partitions[i].nodelist, entries) {
  474. vq_quit(vqn->instance);
  475. }
  476. }
  477. }
  478. void cmd_show_node_states()
  479. {
  480. int i;
  481. struct vq_node *vqn;
  482. for (i=0; i<MAX_PARTITIONS; i++) {
  483. TAILQ_FOREACH(vqn, &partitions[i].nodelist, entries) {
  484. print_quorum_state(vqn);
  485. }
  486. }
  487. fprintf(output_file, "#autofence: %s\n", autofence?"on":"off");
  488. }
  489. int cmd_stop_node(int nodeid)
  490. {
  491. struct vq_node *node;
  492. node = find_node(nodeid);
  493. if (!node) {
  494. fprintf(stderr, "ERR: nodeid %d is not up\n", nodeid);
  495. return -1;
  496. }
  497. /* Remove processor */
  498. vq_quit(node->instance);
  499. /* Node will be removed when the child process exits */
  500. return 0;
  501. }
  502. /* Move all nodes in 'nodelist' into partition 'partition' */
  503. void cmd_move_nodes(int partition, int num_nodes, int *nodelist)
  504. {
  505. int i;
  506. struct vq_node *node;
  507. struct vq_node *vqn;
  508. int total_nodes = num_nodes;
  509. /* Work out the number of nodes affected */
  510. TAILQ_FOREACH(vqn, &partitions[partition].nodelist, entries) {
  511. total_nodes++;
  512. }
  513. for (i=0; i<num_nodes; i++) {
  514. node = find_node(nodelist[i]);
  515. if (node) {
  516. /* Remove it from the current partition */
  517. TAILQ_REMOVE(&node->partition->nodelist, node, entries);
  518. /* Add it to the new partition */
  519. TAILQ_INSERT_TAIL(&partitions[partition].nodelist, node, entries);
  520. node->partition = &partitions[partition];
  521. }
  522. else {
  523. printf("ERR: node %d does not exist\n", nodelist[i]);
  524. }
  525. }
  526. }
  527. /* Take all the nodes in part2 and join them to part1 */
  528. void cmd_join_partitions(int part1, int part2)
  529. {
  530. struct vq_node *vqn;
  531. int total_nodes=0;
  532. /* Work out the number of nodes affected */
  533. total_nodes += nodes_in_partition(part1);
  534. total_nodes += nodes_in_partition(part2);
  535. /* TAILQ_FOREACH is not delete safe *sigh* */
  536. retry:
  537. TAILQ_FOREACH(vqn, &partitions[part2].nodelist, entries) {
  538. TAILQ_REMOVE(&vqn->partition->nodelist, vqn, entries);
  539. TAILQ_INSERT_TAIL(&partitions[part1].nodelist, vqn, entries);
  540. vqn->partition = &partitions[part1];
  541. goto retry;
  542. }
  543. }
  544. void cmd_set_autofence(int onoff)
  545. {
  546. autofence = onoff;
  547. fprintf(output_file, "#autofence: %s\n", onoff?"on":"off");
  548. }
  549. void cmd_set_sync(int onoff)
  550. {
  551. autofence = onoff;
  552. fprintf(output_file, "#sync: %s\n", onoff?"on":"off");
  553. sync_cmds = onoff;
  554. }
  555. void cmd_set_assert(int onoff)
  556. {
  557. assert_on_timeout = onoff;
  558. }
  559. void cmd_update_all_partitions(int newring)
  560. {
  561. int i;
  562. check_for_quorum = 1;
  563. for (i=0; i<MAX_PARTITIONS; i++) {
  564. send_partition_to_nodes(&partitions[i], newring);
  565. }
  566. }
  567. void cmd_qdevice_poll(int nodeid, int onoff)
  568. {
  569. struct vq_node *node;
  570. node = find_node(nodeid);
  571. if (node) {
  572. vq_set_qdevice(node->instance, &node->partition->ring_id, onoff);
  573. }
  574. }
  575. /* If we get called then a command has timed-out */
  576. static void finish_wait_timeout(void *data)
  577. {
  578. if (command_timeout) {
  579. fprintf(stderr, "ERR: Partition(s) not stable within timeout\n");
  580. if (assert_on_timeout) {
  581. exit(2);
  582. }
  583. }
  584. resume_kb_input(sync_cmds);
  585. }
  586. void cmd_set_timeout(uint64_t seconds)
  587. {
  588. command_timeout = seconds * QB_TIME_NS_IN_MSEC;
  589. }
  590. /* ---------------------------------- */
  591. #ifndef HAVE_READLINE_READLINE_H
  592. static void dummy_read_char(void);
  593. static void dummy_read_char()
  594. {
  595. int c, flush = 0;
  596. while (!flush) {
  597. c = getchar();
  598. if (++input_buf_term >= INPUT_BUF_SIZE) {
  599. if (c != '\n' && c != EOF)
  600. fprintf(stderr, "User input overflows the limit: %zu\n",
  601. (size_t) INPUT_BUF_SIZE);
  602. input_buf[INPUT_BUF_SIZE - 1] = '\0';
  603. flush = 1;
  604. } else if (c == '\n' || c == EOF) {
  605. input_buf[input_buf_term - 1] = '\0';
  606. flush = 1;
  607. } else {
  608. input_buf[input_buf_term - 1] = c;
  609. }
  610. }
  611. parse_input_command((c == EOF) ? NULL : input_buf);
  612. input_buf_term = 0;
  613. }
  614. #endif
  615. static int stdin_read_fn(int32_t fd, int32_t revents, void *data)
  616. {
  617. #ifdef HAVE_READLINE_READLINE_H
  618. /* Send it to readline */
  619. rl_callback_read_char();
  620. #else
  621. dummy_read_char();
  622. #endif
  623. return 0;
  624. }
  625. static void start_kb_input_timeout(void *data)
  626. {
  627. resume_kb_input(1);
  628. }
  629. static void usage(char *program)
  630. {
  631. printf("Usage:\n");
  632. printf("\n");
  633. printf("%s [-c <config-file>] [-o <output-file>]\n", program);
  634. printf("\n");
  635. printf(" -c config file. defaults to /etc/corosync/corosync.conf\n");
  636. printf(" -o output file. defaults to stdout\n");
  637. printf(" -n no synchronization (on adding a node)\n");
  638. printf(" -h display this help text\n");
  639. printf("\n");
  640. printf("%s always takes input from STDIN, but cannot use a file.\n", program);
  641. printf("If you want to script it then use\n cat | %s\n", program);
  642. printf("\n");
  643. }
  644. int main(int argc, char **argv)
  645. {
  646. qb_loop_signal_handle sigchld_qb_handle;
  647. int ch;
  648. char *output_file_name = NULL;
  649. while ((ch = getopt (argc, argv, "c:o:nh")) != EOF) {
  650. switch (ch) {
  651. case 'c':
  652. strncpy(corosync_config_file, optarg, sizeof(corosync_config_file));
  653. break;
  654. case 'o':
  655. output_file_name = optarg;
  656. break;
  657. case 'n':
  658. sync_cmds = 0;
  659. break;
  660. default:
  661. usage(argv[0]);
  662. exit(0);
  663. }
  664. }
  665. if (output_file_name) {
  666. output_file = fopen(output_file_name, "w");
  667. if (!output_file) {
  668. fprintf(stderr, "Unable to open %s for output: %s\n", output_file_name, strerror(errno));
  669. exit(-1);
  670. }
  671. }
  672. else {
  673. output_file = stdout;
  674. }
  675. is_tty = isatty(STDIN_FILENO);
  676. qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD,
  677. QB_LOG_FILTER_FUNCTION, "*", LOG_DEBUG);
  678. qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE);
  679. qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
  680. QB_LOG_FILTER_FUNCTION, "*", LOG_DEBUG);
  681. poll_loop = qb_loop_create();
  682. /* SIGCHLD handler to reap sub-processes and reconfigure the cluster */
  683. qb_loop_signal_add(poll_loop,
  684. QB_LOOP_MED,
  685. SIGCHLD,
  686. NULL,
  687. sigchld_handler,
  688. &sigchld_qb_handle);
  689. #ifdef HAVE_READLINE_READLINE_H
  690. /* Readline will deal with completed lines when they arrive */
  691. /*
  692. * For scripting add '#' to the start of the prompt so that
  693. * parsers can ignore input lines
  694. */
  695. rl_already_prompted = 1;
  696. if (is_tty) {
  697. rl_callback_handler_install("vqsim> ", parse_input_command);
  698. } else {
  699. rl_callback_handler_install("#vqsim> ", parse_input_command);
  700. }
  701. #endif
  702. /* Create a full cluster of nodes from corosync.conf */
  703. read_corosync_conf();
  704. if (create_nodes_from_config() && sync_cmds) {
  705. /* Delay kb input handling by 1 second when we've just
  706. added the nodes from corosync.conf; expect that
  707. the delay will be cancelled substantially earlier
  708. once they all have reported their quorum info
  709. (the delay is in fact a failsafe input enabler here) */
  710. qb_loop_timer_add(poll_loop,
  711. QB_LOOP_MED,
  712. 1000000000,
  713. NULL,
  714. start_kb_input_timeout,
  715. &kb_timer);
  716. waiting_for_sync = 1;
  717. } else {
  718. resume_kb_input(0);
  719. }
  720. qb_loop_run(poll_loop);
  721. return 0;
  722. }