|
@@ -25,6 +25,7 @@
|
|
|
/* Easier than including the config file with a ton of conflicting dependencies */
|
|
/* Easier than including the config file with a ton of conflicting dependencies */
|
|
|
extern int coroparse_configparse (icmap_map_t config_map, const char **error_string);
|
|
extern int coroparse_configparse (icmap_map_t config_map, const char **error_string);
|
|
|
extern int corosync_log_config_read (const char **error_string);
|
|
extern int corosync_log_config_read (const char **error_string);
|
|
|
|
|
+static int stdin_read_fn(int32_t fd, int32_t revents, void *data);
|
|
|
|
|
|
|
|
/* 'Keep the compiler happy' time */
|
|
/* 'Keep the compiler happy' time */
|
|
|
const char *corosync_get_config_file(void);
|
|
const char *corosync_get_config_file(void);
|
|
@@ -56,21 +57,22 @@ static qb_loop_t *poll_loop;
|
|
|
static int autofence;
|
|
static int autofence;
|
|
|
static int check_for_quorum;
|
|
static int check_for_quorum;
|
|
|
static FILE *output_file;
|
|
static FILE *output_file;
|
|
|
-static int nosync;
|
|
|
|
|
|
|
+static int sync_cmds = 1;
|
|
|
static qb_loop_timer_handle kb_timer;
|
|
static qb_loop_timer_handle kb_timer;
|
|
|
-static ssize_t wait_count;
|
|
|
|
|
-static ssize_t wait_count_to_unblock;
|
|
|
|
|
|
|
+static int waiting_for_sync = 0;
|
|
|
|
|
+static int is_tty;
|
|
|
|
|
+static int assert_on_timeout;
|
|
|
|
|
+static uint64_t command_timeout = 250000000L;
|
|
|
|
|
|
|
|
static struct vq_node *find_by_pid(pid_t pid);
|
|
static struct vq_node *find_by_pid(pid_t pid);
|
|
|
static void send_partition_to_nodes(struct vq_partition *partition, int newring);
|
|
static void send_partition_to_nodes(struct vq_partition *partition, int newring);
|
|
|
-static void start_kb_input(void);
|
|
|
|
|
static void start_kb_input_timeout(void *data);
|
|
static void start_kb_input_timeout(void *data);
|
|
|
|
|
+static void finish_wait_timeout(void *data);
|
|
|
|
|
|
|
|
#ifndef HAVE_READLINE_READLINE_H
|
|
#ifndef HAVE_READLINE_READLINE_H
|
|
|
#define INPUT_BUF_SIZE 1024
|
|
#define INPUT_BUF_SIZE 1024
|
|
|
static char input_buf[INPUT_BUF_SIZE];
|
|
static char input_buf[INPUT_BUF_SIZE];
|
|
|
static size_t input_buf_term = 0;
|
|
static size_t input_buf_term = 0;
|
|
|
-static int is_tty;
|
|
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
/* 'Keep the compiler happy' time */
|
|
/* 'Keep the compiler happy' time */
|
|
@@ -78,7 +80,6 @@ static char corosync_config_file[PATH_MAX + 1] = COROSYSCONFDIR "/corosync.conf"
|
|
|
|
|
|
|
|
const char *corosync_get_config_file(void)
|
|
const char *corosync_get_config_file(void)
|
|
|
{
|
|
{
|
|
|
-
|
|
|
|
|
return (corosync_config_file);
|
|
return (corosync_config_file);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -144,6 +145,65 @@ static void propogate_vq_message(struct vq_node *vqn, const char *msg, int len)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
|
+static void cmd_show_prompt_if_needed(void)
|
|
|
|
|
+{
|
|
|
|
|
+ qb_loop_timer_del(poll_loop, kb_timer);
|
|
|
|
|
+ if (is_tty) {
|
|
|
|
|
+ printf("vqsim> ");
|
|
|
|
|
+ fflush(stdout);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ printf("#vqsim> ");
|
|
|
|
|
+ fflush(stdout);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void resume_kb_input(int show_status)
|
|
|
|
|
+{
|
|
|
|
|
+ /* If running synchronously, we don't display
|
|
|
|
|
+ the quorum messages as they come in. So run 'show' commamnd
|
|
|
|
|
+ */
|
|
|
|
|
+ if (show_status && waiting_for_sync) {
|
|
|
|
|
+ cmd_show_node_states();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ waiting_for_sync = 0;
|
|
|
|
|
+
|
|
|
|
|
+ if (qb_loop_poll_add(poll_loop,
|
|
|
|
|
+ QB_LOOP_MED,
|
|
|
|
|
+ STDIN_FILENO,
|
|
|
|
|
+ POLLIN | POLLERR,
|
|
|
|
|
+ NULL,
|
|
|
|
|
+ stdin_read_fn)) {
|
|
|
|
|
+ if (errno != EEXIST) {
|
|
|
|
|
+ perror("qb_loop_poll_add1 returned error");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ /* Always shows the prompt here, cos we cleared waiting_for_sync */
|
|
|
|
|
+ cmd_show_prompt_if_needed();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* Return true (1) if all nodes in each partition have the same ring id, false(0) otherwise */
|
|
|
|
|
+static int all_nodes_consistent(void)
|
|
|
|
|
+{
|
|
|
|
|
+ int i;
|
|
|
|
|
+ struct vq_node *vqn;
|
|
|
|
|
+ struct memb_ring_id last_ring_id;
|
|
|
|
|
+
|
|
|
|
|
+ for (i=0; i<MAX_PARTITIONS; i++) {
|
|
|
|
|
+ memset(&last_ring_id, 0, sizeof(last_ring_id));
|
|
|
|
|
+ TAILQ_FOREACH(vqn, &partitions[i].nodelist, entries) {
|
|
|
|
|
+ if (last_ring_id.seq &&
|
|
|
|
|
+ last_ring_id.seq != vqn->last_ring_id.seq) {
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ last_ring_id.seq = vqn->last_ring_id.seq;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return 1;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
static int vq_parent_read_fn(int32_t fd, int32_t revents, void *data)
|
|
static int vq_parent_read_fn(int32_t fd, int32_t revents, void *data)
|
|
|
{
|
|
{
|
|
|
char msgbuf[8192];
|
|
char msgbuf[8192];
|
|
@@ -162,13 +222,18 @@ static int vq_parent_read_fn(int32_t fd, int32_t revents, void *data)
|
|
|
msg = (void*)msgbuf;
|
|
msg = (void*)msgbuf;
|
|
|
switch (msg->type) {
|
|
switch (msg->type) {
|
|
|
case VQMSG_QUORUM:
|
|
case VQMSG_QUORUM:
|
|
|
- if (!nosync && --wait_count_to_unblock <= 0)
|
|
|
|
|
- qb_loop_timer_del(poll_loop, kb_timer);
|
|
|
|
|
qmsg = (void*)msgbuf;
|
|
qmsg = (void*)msgbuf;
|
|
|
save_quorum_state(vqn, qmsg);
|
|
save_quorum_state(vqn, qmsg);
|
|
|
- print_quorum_state(vqn);
|
|
|
|
|
- if (!nosync && wait_count_to_unblock <= 0)
|
|
|
|
|
- start_kb_input();
|
|
|
|
|
|
|
+ if (!sync_cmds) {
|
|
|
|
|
+ print_quorum_state(vqn);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* Have the partitions stabilised? */
|
|
|
|
|
+ if (sync_cmds && waiting_for_sync &&
|
|
|
|
|
+ all_nodes_consistent()) {
|
|
|
|
|
+ qb_loop_timer_del(poll_loop, kb_timer);
|
|
|
|
|
+ resume_kb_input(sync_cmds);
|
|
|
|
|
+ }
|
|
|
break;
|
|
break;
|
|
|
case VQMSG_EXEC:
|
|
case VQMSG_EXEC:
|
|
|
/* Message from votequorum, pass around the partition */
|
|
/* Message from votequorum, pass around the partition */
|
|
@@ -204,7 +269,7 @@ static int read_corosync_conf(void)
|
|
|
logsys_format_set(NULL);
|
|
logsys_format_set(NULL);
|
|
|
res = coroparse_configparse(icmap_get_global_map(), &error_string);
|
|
res = coroparse_configparse(icmap_get_global_map(), &error_string);
|
|
|
if (res == -1) {
|
|
if (res == -1) {
|
|
|
- log_printf (LOGSYS_LEVEL_INFO, "Error loading corosyc.conf %s", error_string);
|
|
|
|
|
|
|
+ log_printf (LOGSYS_LEVEL_INFO, "Error loading corosync.conf %s", error_string);
|
|
|
return -1;
|
|
return -1;
|
|
|
}
|
|
}
|
|
|
else {
|
|
else {
|
|
@@ -234,8 +299,6 @@ static void remove_node(struct vq_node *node)
|
|
|
TAILQ_REMOVE(&part->nodelist, node, entries);
|
|
TAILQ_REMOVE(&part->nodelist, node, entries);
|
|
|
free(node);
|
|
free(node);
|
|
|
|
|
|
|
|
- wait_count--;
|
|
|
|
|
-
|
|
|
|
|
/* Rebuild quorum */
|
|
/* Rebuild quorum */
|
|
|
send_partition_to_nodes(part, 1);
|
|
send_partition_to_nodes(part, 1);
|
|
|
}
|
|
}
|
|
@@ -263,7 +326,7 @@ static int32_t sigchld_handler(int32_t sig, void *data)
|
|
|
sprintf(text, "(exit code %d)", WEXITSTATUS(status));
|
|
sprintf(text, "(exit code %d)", WEXITSTATUS(status));
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
- printf("%d:%02d Quit %s\n", vqn->partition->num, vqn->nodeid, exit_status);
|
|
|
|
|
|
|
+ printf("%d:%02d: Quit %s\n", vqn->partition->num, vqn->nodeid, exit_status);
|
|
|
|
|
|
|
|
remove_node(vqn);
|
|
remove_node(vqn);
|
|
|
}
|
|
}
|
|
@@ -322,20 +385,24 @@ static void init_partitions(void)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+static int nodes_in_partition(int part)
|
|
|
|
|
+{
|
|
|
|
|
+ struct vq_node *vqn;
|
|
|
|
|
+ int partnodes = 0;
|
|
|
|
|
+
|
|
|
|
|
+ TAILQ_FOREACH(vqn, &partitions[part].nodelist, entries) {
|
|
|
|
|
+ partnodes++;
|
|
|
|
|
+ }
|
|
|
|
|
+ return partnodes;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
static pid_t create_node(int nodeid, int partno)
|
|
static pid_t create_node(int nodeid, int partno)
|
|
|
{
|
|
{
|
|
|
struct vq_node *newvq;
|
|
struct vq_node *newvq;
|
|
|
|
|
|
|
|
newvq = malloc(sizeof(struct vq_node));
|
|
newvq = malloc(sizeof(struct vq_node));
|
|
|
if (newvq) {
|
|
if (newvq) {
|
|
|
- if (!nosync) {
|
|
|
|
|
- /* Number of expected "quorum" vq messages is a square
|
|
|
|
|
- of the total nodes count, so increment the node
|
|
|
|
|
- counter and set new square of this value as
|
|
|
|
|
- a "to observe" counter */
|
|
|
|
|
- wait_count++;
|
|
|
|
|
- wait_count_to_unblock = wait_count * wait_count;
|
|
|
|
|
- }
|
|
|
|
|
newvq->last_quorate = -1; /* mark "uninitialized" */
|
|
newvq->last_quorate = -1; /* mark "uninitialized" */
|
|
|
newvq->instance = vq_create_instance(poll_loop, nodeid);
|
|
newvq->instance = vq_create_instance(poll_loop, nodeid);
|
|
|
if (!newvq->instance) {
|
|
if (!newvq->instance) {
|
|
@@ -439,29 +506,39 @@ static struct vq_node *find_by_pid(pid_t pid)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* Routines called from the parser */
|
|
/* Routines called from the parser */
|
|
|
-void cmd_start_new_node(int nodeid, int partition)
|
|
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+/*
|
|
|
|
|
+ * The parser calls this before running a command where
|
|
|
|
|
+ * we might have to wait for a result to come back.
|
|
|
|
|
+ */
|
|
|
|
|
+void cmd_start_sync_command()
|
|
|
|
|
+{
|
|
|
|
|
+ if (sync_cmds) {
|
|
|
|
|
+ qb_loop_poll_del(poll_loop, STDIN_FILENO);
|
|
|
|
|
+ qb_loop_timer_add(poll_loop,
|
|
|
|
|
+ QB_LOOP_MED,
|
|
|
|
|
+ command_timeout,
|
|
|
|
|
+ NULL,
|
|
|
|
|
+ finish_wait_timeout,
|
|
|
|
|
+ &kb_timer);
|
|
|
|
|
+ waiting_for_sync = 1;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+int cmd_start_new_node(int nodeid, int partition)
|
|
|
{
|
|
{
|
|
|
struct vq_node *node;
|
|
struct vq_node *node;
|
|
|
|
|
|
|
|
node = find_node(nodeid);
|
|
node = find_node(nodeid);
|
|
|
if (node) {
|
|
if (node) {
|
|
|
fprintf(stderr, "ERR: nodeid %d already exists in partition %d\n", nodeid, node->partition->num);
|
|
fprintf(stderr, "ERR: nodeid %d already exists in partition %d\n", nodeid, node->partition->num);
|
|
|
- return;
|
|
|
|
|
|
|
+ return -1;
|
|
|
}
|
|
}
|
|
|
- qb_loop_poll_del(poll_loop, STDIN_FILENO);
|
|
|
|
|
- create_node(nodeid, partition);
|
|
|
|
|
- if (!nosync) {
|
|
|
|
|
- /* Delay kb input handling by 0.25 second when we've just
|
|
|
|
|
- added a node; expect that the delay will be cancelled
|
|
|
|
|
- substantially earlier once it has reported its quorum info
|
|
|
|
|
- (the delay is in fact a failsafe input enabler here) */
|
|
|
|
|
- qb_loop_timer_add(poll_loop,
|
|
|
|
|
- QB_LOOP_MED,
|
|
|
|
|
- 250000000,
|
|
|
|
|
- NULL,
|
|
|
|
|
- start_kb_input_timeout,
|
|
|
|
|
- &kb_timer);
|
|
|
|
|
|
|
+ if (create_node(nodeid, partition) == -1) {
|
|
|
|
|
+ return -1;
|
|
|
}
|
|
}
|
|
|
|
|
+ return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void cmd_stop_all_nodes()
|
|
void cmd_stop_all_nodes()
|
|
@@ -489,20 +566,21 @@ void cmd_show_node_states()
|
|
|
fprintf(output_file, "#autofence: %s\n", autofence?"on":"off");
|
|
fprintf(output_file, "#autofence: %s\n", autofence?"on":"off");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void cmd_stop_node(int nodeid)
|
|
|
|
|
|
|
+int cmd_stop_node(int nodeid)
|
|
|
{
|
|
{
|
|
|
struct vq_node *node;
|
|
struct vq_node *node;
|
|
|
|
|
|
|
|
node = find_node(nodeid);
|
|
node = find_node(nodeid);
|
|
|
if (!node) {
|
|
if (!node) {
|
|
|
fprintf(stderr, "ERR: nodeid %d is not up\n", nodeid);
|
|
fprintf(stderr, "ERR: nodeid %d is not up\n", nodeid);
|
|
|
- return;
|
|
|
|
|
|
|
+ return -1;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* Remove processor */
|
|
/* Remove processor */
|
|
|
vq_quit(node->instance);
|
|
vq_quit(node->instance);
|
|
|
|
|
|
|
|
/* Node will be removed when the child process exits */
|
|
/* Node will be removed when the child process exits */
|
|
|
|
|
+ return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* Move all nodes in 'nodelist' into partition 'partition' */
|
|
/* Move all nodes in 'nodelist' into partition 'partition' */
|
|
@@ -510,6 +588,13 @@ void cmd_move_nodes(int partition, int num_nodes, int *nodelist)
|
|
|
{
|
|
{
|
|
|
int i;
|
|
int i;
|
|
|
struct vq_node *node;
|
|
struct vq_node *node;
|
|
|
|
|
+ struct vq_node *vqn;
|
|
|
|
|
+ int total_nodes = num_nodes;
|
|
|
|
|
+
|
|
|
|
|
+ /* Work out the number of nodes affected */
|
|
|
|
|
+ TAILQ_FOREACH(vqn, &partitions[partition].nodelist, entries) {
|
|
|
|
|
+ total_nodes++;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
for (i=0; i<num_nodes; i++) {
|
|
for (i=0; i<num_nodes; i++) {
|
|
|
node = find_node(nodelist[i]);
|
|
node = find_node(nodelist[i]);
|
|
@@ -532,6 +617,11 @@ void cmd_move_nodes(int partition, int num_nodes, int *nodelist)
|
|
|
void cmd_join_partitions(int part1, int part2)
|
|
void cmd_join_partitions(int part1, int part2)
|
|
|
{
|
|
{
|
|
|
struct vq_node *vqn;
|
|
struct vq_node *vqn;
|
|
|
|
|
+ int total_nodes=0;
|
|
|
|
|
+
|
|
|
|
|
+ /* Work out the number of nodes affected */
|
|
|
|
|
+ total_nodes += nodes_in_partition(part1);
|
|
|
|
|
+ total_nodes += nodes_in_partition(part2);
|
|
|
|
|
|
|
|
/* TAILQ_FOREACH is not delete safe *sigh* */
|
|
/* TAILQ_FOREACH is not delete safe *sigh* */
|
|
|
retry:
|
|
retry:
|
|
@@ -551,6 +641,18 @@ void cmd_set_autofence(int onoff)
|
|
|
fprintf(output_file, "#autofence: %s\n", onoff?"on":"off");
|
|
fprintf(output_file, "#autofence: %s\n", onoff?"on":"off");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+void cmd_set_sync(int onoff)
|
|
|
|
|
+{
|
|
|
|
|
+ autofence = onoff;
|
|
|
|
|
+ fprintf(output_file, "#sync: %s\n", onoff?"on":"off");
|
|
|
|
|
+ sync_cmds = onoff;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void cmd_set_assert(int onoff)
|
|
|
|
|
+{
|
|
|
|
|
+ assert_on_timeout = onoff;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
void cmd_update_all_partitions(int newring)
|
|
void cmd_update_all_partitions(int newring)
|
|
|
{
|
|
{
|
|
|
int i;
|
|
int i;
|
|
@@ -571,6 +673,24 @@ void cmd_qdevice_poll(int nodeid, int onoff)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/* If we get called then a command has timed-out */
|
|
|
|
|
+static void finish_wait_timeout(void *data)
|
|
|
|
|
+{
|
|
|
|
|
+ if (command_timeout) {
|
|
|
|
|
+ fprintf(stderr, "ERR: Partition(s) not stable within timeout\n");
|
|
|
|
|
+ if (assert_on_timeout) {
|
|
|
|
|
+ exit(2);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ resume_kb_input(sync_cmds);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void cmd_set_timeout(uint64_t seconds)
|
|
|
|
|
+{
|
|
|
|
|
+ command_timeout = seconds * QB_TIME_NS_IN_MSEC;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/* ---------------------------------- */
|
|
/* ---------------------------------- */
|
|
|
|
|
|
|
|
#ifndef HAVE_READLINE_READLINE_H
|
|
#ifndef HAVE_READLINE_READLINE_H
|
|
@@ -598,11 +718,6 @@ static void dummy_read_char()
|
|
|
|
|
|
|
|
parse_input_command((c == EOF) ? NULL : input_buf);
|
|
parse_input_command((c == EOF) ? NULL : input_buf);
|
|
|
input_buf_term = 0;
|
|
input_buf_term = 0;
|
|
|
-
|
|
|
|
|
- if (is_tty) {
|
|
|
|
|
- printf("vqsim> ");
|
|
|
|
|
- fflush(stdout);
|
|
|
|
|
- }
|
|
|
|
|
}
|
|
}
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
@@ -617,50 +732,26 @@ static int stdin_read_fn(int32_t fd, int32_t revents, void *data)
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static void start_kb_input(void)
|
|
|
|
|
-{
|
|
|
|
|
- wait_count_to_unblock = 0;
|
|
|
|
|
-
|
|
|
|
|
-#ifdef HAVE_READLINE_READLINE_H
|
|
|
|
|
- /* Readline will deal with completed lines when they arrive */
|
|
|
|
|
- rl_callback_handler_install("vqsim> ", parse_input_command);
|
|
|
|
|
-#else
|
|
|
|
|
- if (is_tty) {
|
|
|
|
|
- printf("vqsim> ");
|
|
|
|
|
- fflush(stdout);
|
|
|
|
|
- }
|
|
|
|
|
-#endif
|
|
|
|
|
-
|
|
|
|
|
- /* Send stdin to readline */
|
|
|
|
|
- if (qb_loop_poll_add(poll_loop,
|
|
|
|
|
- QB_LOOP_MED,
|
|
|
|
|
- STDIN_FILENO,
|
|
|
|
|
- POLLIN | POLLERR,
|
|
|
|
|
- NULL,
|
|
|
|
|
- stdin_read_fn)) {
|
|
|
|
|
- if (errno != EEXIST) {
|
|
|
|
|
- perror("qb_loop_poll_add1 returned error");
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
static void start_kb_input_timeout(void *data)
|
|
static void start_kb_input_timeout(void *data)
|
|
|
{
|
|
{
|
|
|
-// fprintf(stderr, "Waiting for nodes to report status timed out\n");
|
|
|
|
|
- start_kb_input();
|
|
|
|
|
|
|
+ resume_kb_input(1);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void usage(char *program)
|
|
static void usage(char *program)
|
|
|
{
|
|
{
|
|
|
printf("Usage:\n");
|
|
printf("Usage:\n");
|
|
|
printf("\n");
|
|
printf("\n");
|
|
|
- printf("%s [-f <config-file>] [-o <output-file>]\n", program);
|
|
|
|
|
|
|
+ printf("%s [-c <config-file>] [-o <output-file>]\n", program);
|
|
|
printf("\n");
|
|
printf("\n");
|
|
|
- printf(" -f config file. defaults to /etc/corosync/corosync.conf\n");
|
|
|
|
|
|
|
+ printf(" -c config file. defaults to /etc/corosync/corosync.conf\n");
|
|
|
printf(" -o output file. defaults to stdout\n");
|
|
printf(" -o output file. defaults to stdout\n");
|
|
|
printf(" -n no synchronization (on adding a node)\n");
|
|
printf(" -n no synchronization (on adding a node)\n");
|
|
|
printf(" -h display this help text\n");
|
|
printf(" -h display this help text\n");
|
|
|
printf("\n");
|
|
printf("\n");
|
|
|
|
|
+ printf("%s always takes input from STDIN, but cannot use a file.\n", program);
|
|
|
|
|
+ printf("If you want to script it then use\n cat | %s\n", program);
|
|
|
|
|
+ printf("\n");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
int main(int argc, char **argv)
|
|
@@ -669,16 +760,16 @@ int main(int argc, char **argv)
|
|
|
int ch;
|
|
int ch;
|
|
|
char *output_file_name = NULL;
|
|
char *output_file_name = NULL;
|
|
|
|
|
|
|
|
- while ((ch = getopt (argc, argv, "f:o:nh")) != EOF) {
|
|
|
|
|
|
|
+ while ((ch = getopt (argc, argv, "c:o:nh")) != EOF) {
|
|
|
switch (ch) {
|
|
switch (ch) {
|
|
|
- case 'f':
|
|
|
|
|
|
|
+ case 'c':
|
|
|
strncpy(corosync_config_file, optarg, sizeof(corosync_config_file));
|
|
strncpy(corosync_config_file, optarg, sizeof(corosync_config_file));
|
|
|
break;
|
|
break;
|
|
|
case 'o':
|
|
case 'o':
|
|
|
output_file_name = optarg;
|
|
output_file_name = optarg;
|
|
|
break;
|
|
break;
|
|
|
case 'n':
|
|
case 'n':
|
|
|
- nosync = 1;
|
|
|
|
|
|
|
+ sync_cmds = 0;
|
|
|
break;
|
|
break;
|
|
|
default:
|
|
default:
|
|
|
usage(argv[0]);
|
|
usage(argv[0]);
|
|
@@ -696,9 +787,8 @@ int main(int argc, char **argv)
|
|
|
else {
|
|
else {
|
|
|
output_file = stdout;
|
|
output_file = stdout;
|
|
|
}
|
|
}
|
|
|
-#ifndef HAVE_READLINE_READLINE_H
|
|
|
|
|
|
|
+
|
|
|
is_tty = isatty(STDIN_FILENO);
|
|
is_tty = isatty(STDIN_FILENO);
|
|
|
-#endif
|
|
|
|
|
|
|
|
|
|
qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD,
|
|
qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD,
|
|
|
QB_LOG_FILTER_FUNCTION, "*", LOG_DEBUG);
|
|
QB_LOG_FILTER_FUNCTION, "*", LOG_DEBUG);
|
|
@@ -717,9 +807,26 @@ int main(int argc, char **argv)
|
|
|
sigchld_handler,
|
|
sigchld_handler,
|
|
|
&sigchld_qb_handle);
|
|
&sigchld_qb_handle);
|
|
|
|
|
|
|
|
- /* Create a full cluster of nodes from corosync.conf */
|
|
|
|
|
|
|
+
|
|
|
|
|
+#ifdef HAVE_READLINE_READLINE_H
|
|
|
|
|
+ /* Readline will deal with completed lines when they arrive */
|
|
|
|
|
+ /*
|
|
|
|
|
+ * For scripting add '#' to the start of the prompt so that
|
|
|
|
|
+ * parsers can ignore input lines
|
|
|
|
|
+ */
|
|
|
|
|
+ rl_already_prompted = 1;
|
|
|
|
|
+ if (is_tty) {
|
|
|
|
|
+ rl_callback_handler_install("vqsim> ", parse_input_command);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ rl_callback_handler_install("#vqsim> ", parse_input_command);
|
|
|
|
|
+ }
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+/* Create a full cluster of nodes from corosync.conf */
|
|
|
read_corosync_conf();
|
|
read_corosync_conf();
|
|
|
- if (create_nodes_from_config() && !nosync) {
|
|
|
|
|
|
|
+ if (create_nodes_from_config() && sync_cmds) {
|
|
|
/* Delay kb input handling by 1 second when we've just
|
|
/* Delay kb input handling by 1 second when we've just
|
|
|
added the nodes from corosync.conf; expect that
|
|
added the nodes from corosync.conf; expect that
|
|
|
the delay will be cancelled substantially earlier
|
|
the delay will be cancelled substantially earlier
|
|
@@ -731,8 +838,9 @@ int main(int argc, char **argv)
|
|
|
NULL,
|
|
NULL,
|
|
|
start_kb_input_timeout,
|
|
start_kb_input_timeout,
|
|
|
&kb_timer);
|
|
&kb_timer);
|
|
|
|
|
+ waiting_for_sync = 1;
|
|
|
} else {
|
|
} else {
|
|
|
- start_kb_input();
|
|
|
|
|
|
|
+ resume_kb_input(0);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
qb_loop_run(poll_loop);
|
|
qb_loop_run(poll_loop);
|