diff --git a/pengine/ptest.c b/pengine/ptest.c index a6afd02ae4..35da43193f 100644 --- a/pengine/ptest.c +++ b/pengine/ptest.c @@ -1,516 +1,479 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include -#define OPTARGS "V?XD:G:I:Lwx:d:aSs" - -#ifdef HAVE_GETOPT_H -# include -#endif #include #include #include #include #if HAVE_LIBXML2 # include #endif gboolean use_stdin = FALSE; gboolean do_simulation = FALSE; gboolean inhibit_exit = FALSE; gboolean all_actions = FALSE; extern xmlNode * do_calculations( pe_working_set_t *data_set, xmlNode *xml_input, ha_time_t *now); extern void cleanup_calculations(pe_working_set_t *data_set); char *use_date = NULL; FILE *dot_strm = NULL; #define DOT_PREFIX "PE_DOT: " /* #define DOT_PREFIX "" */ #define dot_write(fmt...) if(dot_strm != NULL) { \ fprintf(dot_strm, fmt); \ fprintf(dot_strm, "\n"); \ } else { \ crm_debug(DOT_PREFIX""fmt); \ } static void init_dotfile(void) { dot_write(" digraph \"g\" {"); /* dot_write(" size = \"30,30\""); */ /* dot_write(" graph ["); */ /* dot_write(" fontsize = \"12\""); */ /* dot_write(" fontname = \"Times-Roman\""); */ /* dot_write(" fontcolor = \"black\""); */ /* dot_write(" bb = \"0,0,398.922306,478.927856\""); */ /* dot_write(" color = \"black\""); */ /* dot_write(" ]"); */ /* dot_write(" node ["); */ /* dot_write(" fontsize = \"12\""); */ /* dot_write(" fontname = \"Times-Roman\""); */ /* dot_write(" fontcolor = \"black\""); */ /* dot_write(" shape = \"ellipse\""); */ /* dot_write(" color = \"black\""); */ /* dot_write(" ]"); */ /* dot_write(" edge ["); */ /* dot_write(" fontsize = \"12\""); */ /* dot_write(" fontname = \"Times-Roman\""); */ /* dot_write(" fontcolor = \"black\""); */ /* dot_write(" color = \"black\""); */ /* dot_write(" ]"); */ } -static void -usage(const char *cli, int exitcode) -{ - FILE *out = exitcode?stderr:stdout; - fprintf(out, "Usage: %s -(?|L|X|x) [-V] [-D] [-G] [-I]\n", cli); - fprintf(out, " --%s (-%c): This text\n\n", "help", '?'); - fprintf(out, " --%s (-%c): Increase verbosity (can be supplied multiple times)\n\n", "verbose", 'V'); - fprintf(out, " --%s (-%c): Connect to the CIB and use the current contents as input\n", "live-check", 'L'); - fprintf(out, " --%s (-%c): Display resource allocation scores\n", "show-scores", 's'); - - fprintf(out, " --%s (-%c): Retrieve XML from stdin\n", "xml-pipe", 'p'); - fprintf(out, " --%s (-%c)\t : Retrieve XML from the supplied string\n\n", "xml-text", 'X'); - fprintf(out, " --%s (-%c)\t : Retrieve XML from the named file\n\n", "xml-file", 'x'); - - fprintf(out, " --%s (-%c)\t : Save the transition graph to the named file\n", "save-graph", 'G'); - fprintf(out, " --%s (-%c)\t : Save the DOT formatted transition graph to the named file\n", "save-dotfile", 'D'); - fprintf(out, " --%s (-%c)\t : Save the input to the named file\n", "save-input", 'I'); - exit(exitcode); -} - static char * create_action_name(action_t *action) { char *action_name = NULL; const char *action_host = NULL; if(action->node) { action_host = action->node->details->uname; action_name = crm_concat(action->uuid, action_host, ' '); } else if(action->pseudo) { action_name = crm_strdup(action->uuid); } else { action_host = ""; action_name = crm_concat(action->uuid, action_host, ' '); } if(safe_str_eq(action->task, RSC_CANCEL)) { char *tmp_action_name = action_name; action_name = crm_concat("Cancel", tmp_action_name, ' '); crm_free(tmp_action_name); } return action_name; } gboolean USE_LIVE_CIB = FALSE; +static struct crm_option long_options[] = { + /* Top-level Options */ + {"help", 0, 0, '?', "This text"}, + {"version", 0, 0, 'v', "Version information" }, + {"verbose", 0, 0, 'V', "Increase debug output\n"}, + + {"show-scores", 0, 0, 's', "Display resource allocation scores"}, + {"simulate", 0, 0, 'S', "\tSimulate the transition's execution to find invalid graphs\n"}, + + {"live-check", 0, 0, 'L', "Connect to the CIB and use the current contents as input"}, + {"xml-text", 0, 0, 'X', "\tRetrieve XML from the supplied string"}, + {"xml-file", 1, 0, 'x', "Retrieve XML from the named file"}, + {"xml-pipe", 1, 0, 'p', "Retrieve XML from stdin\n"}, + + {"save-input", 1, 0, 'I', "\tSave the input to the named file"}, + {"save-graph", 1, 0, 'G', "\tSave the transition graph (XML format) to the named file"}, + {"save-dotfile",1, 0, 'D', "Save the transition graph (DOT format) to the named file\n"}, + + {0, 0, 0, 0} +}; int main(int argc, char **argv) { gboolean process = TRUE; gboolean all_good = TRUE; enum transition_status graph_rc = -1; crm_graph_t *transition = NULL; ha_time_t *a_date = NULL; cib_t * cib_conn = NULL; xmlNode * cib_object = NULL; int argerr = 0; int flag; char *msg_buffer = NULL; gboolean optional = FALSE; pe_working_set_t data_set; const char *source = NULL; const char *xml_file = NULL; const char *dot_file = NULL; const char *graph_file = NULL; const char *input_file = NULL; /* disable glib's fancy allocators that can't be free'd */ GMemVTable vtable; vtable.malloc = malloc; vtable.realloc = realloc; vtable.free = free; vtable.calloc = calloc; vtable.try_malloc = malloc; vtable.try_realloc = realloc; g_mem_set_vtable(&vtable); crm_log_init("ptest", LOG_CRIT, FALSE, FALSE, 0, NULL); + crm_set_options("V?vXD:G:I:Lwx:d:aSs", "[-?Vv] -[Xxp] {other options}", long_options, + "Calculate the cluster's response to the supplied cluster state\n"); cl_log_set_facility(LOG_USER); while (1) { -#ifdef HAVE_GETOPT_H int option_index = 0; - static struct option long_options[] = { - /* Top-level Options */ - {"help", 0, 0, '?'}, - {"verbose", 0, 0, 'V'}, - - {"live-check", 0, 0, 'L'}, - {"show-scores", 0, 0, 's'}, - {"xml-text", 0, 0, 'X'}, - {"xml-file", 1, 0, 'x'}, - {"xml-pipe", 1, 0, 'p'}, - - {"simulate", 0, 0, 'S'}, - {"save-graph", 1, 0, 'G'}, - {"save-dotfile",1, 0, 'D'}, - {"save-input", 1, 0, 'I'}, - - {0, 0, 0, 0} - }; -#endif - -#ifdef HAVE_GETOPT_H - flag = getopt_long(argc, argv, OPTARGS, - long_options, &option_index); -#else - flag = getopt(argc, argv, OPTARGS); -#endif + flag = crm_get_option(argc, argv, &option_index); if (flag == -1) break; switch(flag) { -#ifdef HAVE_GETOPT_H - case 0: - printf("option %s", long_options[option_index].name); - if (optarg) - printf(" with arg %s", optarg); - printf("\n"); - - break; -#endif case 'S': do_simulation = TRUE; break; case 'a': all_actions = TRUE; break; case 'w': inhibit_exit = TRUE; break; case 'X': use_stdin = TRUE; break; case 's': show_scores = TRUE; break; case 'x': xml_file = optarg; break; case 'd': use_date = optarg; break; case 'D': dot_file = optarg; break; case 'G': graph_file = optarg; break; case 'I': input_file = optarg; break; case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; case 'L': USE_LIVE_CIB = TRUE; break; + case 'v': case '?': - usage("ptest", 0); + crm_help(flag, 0); break; default: printf("?? getopt returned character code 0%o ??\n", flag); ++argerr; break; } } if (optind < argc) { printf("non-option ARGV-elements: "); while (optind < argc) { printf("%s ", argv[optind++]); } printf("\n"); } if (optind > argc) { ++argerr; } if (argerr) { crm_err("%d errors in option parsing", argerr); - usage("ptest", 1); + crm_help('?', 1); } if(USE_LIVE_CIB) { int rc = cib_ok; source = "live cib"; cib_conn = cib_new(); rc = cib_conn->cmds->signon(cib_conn, "ptest", cib_command); if(rc == cib_ok) { crm_info("Reading XML from: live cluster"); cib_object = get_cib_copy(cib_conn); } else { fprintf(stderr, "Live CIB query failed: %s\n", cib_error2string(rc)); return 3; } if(cib_object == NULL) { fprintf(stderr, "Live CIB query failed: empty result\n"); return 3; } } else if(xml_file != NULL) { source = xml_file; cib_object = filename2xml(xml_file); } else if(use_stdin) { source = "stdin"; cib_object = filename2xml(NULL); } if(cib_object == NULL && source) { fprintf(stderr, "Could not parse configuration input from: %s\n", source); return 4; } else if(cib_object == NULL) { fprintf(stderr, "Not configuration specified\n"); - usage("ptest", 1); + crm_help('?', 1); } if(cli_config_update(&cib_object, NULL) == FALSE) { free_xml(cib_object); return cib_STALE; } if(validate_xml(cib_object, NULL, FALSE) != TRUE) { free_xml(cib_object); return cib_dtd_validation; } if(input_file != NULL) { FILE *input_strm = fopen(input_file, "w"); if(input_strm == NULL) { crm_perror(LOG_ERR,"Could not open %s for writing", input_file); } else { msg_buffer = dump_xml_formatted(cib_object); if(fprintf(input_strm, "%s\n", msg_buffer) < 0) { crm_perror(LOG_ERR,"Write to %s failed", input_file); } fflush(input_strm); fclose(input_strm); crm_free(msg_buffer); } } if(use_date != NULL) { a_date = parse_date(&use_date); log_date(LOG_WARNING, "Set fake 'now' to", a_date, ha_log_date|ha_log_time); log_date(LOG_WARNING, "Set fake 'now' to (localtime)", a_date, ha_log_date|ha_log_time|ha_log_local); } if(process) { if(show_scores) { fprintf(stdout, "Allocation scores:\n"); } do_calculations(&data_set, cib_object, a_date); } msg_buffer = dump_xml_formatted(data_set.graph); if(safe_str_eq(graph_file, "-")) { fprintf(stdout, "%s\n", msg_buffer); fflush(stdout); } else if(graph_file != NULL) { FILE *graph_strm = fopen(graph_file, "w"); if(graph_strm == NULL) { crm_perror(LOG_ERR,"Could not open %s for writing", graph_file); } else { if(fprintf(graph_strm, "%s\n\n", msg_buffer) < 0) { crm_perror(LOG_ERR,"Write to %s failed", graph_file); } fflush(graph_strm); fclose(graph_strm); } } crm_free(msg_buffer); if(dot_file != NULL) { dot_strm = fopen(dot_file, "w"); if(dot_strm == NULL) { crm_perror(LOG_ERR,"Could not open %s for writing", dot_file); } } if(dot_strm == NULL) { goto simulate; } init_dotfile(); slist_iter( action, action_t, data_set.actions, lpc, const char *style = "filled"; const char *font = "black"; const char *color = "black"; const char *fill = NULL; char *action_name = create_action_name(action); crm_debug_3("Action %d: %p", action->id, action); if(action->pseudo) { font = "orange"; } style = "dashed"; if(action->dumped) { style = "bold"; color = "green"; } else if(action->rsc != NULL && is_not_set(action->rsc->flags, pe_rsc_managed)) { color = "purple"; if(all_actions == FALSE) { goto dont_write; } } else if(action->optional) { color = "blue"; if(all_actions == FALSE) { goto dont_write; } } else { color = "red"; CRM_CHECK(action->runnable == FALSE, ;); } action->dumped = TRUE; dot_write("\"%s\" [ style=%s color=\"%s\" fontcolor=\"%s\" %s%s]", action_name, style, color, font, fill?"fillcolor=":"", fill?fill:""); dont_write: crm_free(action_name); ); slist_iter( action, action_t, data_set.actions, lpc, slist_iter( before, action_wrapper_t, action->actions_before, lpc2, char *before_name = NULL; char *after_name = NULL; const char *style = "dashed"; optional = TRUE; if(before->state == pe_link_dumped) { optional = FALSE; style = "bold"; } else if(action->pseudo && (before->type & pe_order_stonith_stop)) { continue; } else if(before->state == pe_link_dup) { continue; } else if(action->dumped && before->action->dumped) { optional = FALSE; } if(all_actions || optional == FALSE) { before_name = create_action_name(before->action); after_name = create_action_name(action); dot_write("\"%s\" -> \"%s\" [ style = %s]", before_name, after_name, style); crm_free(before_name); crm_free(after_name); } ); ); dot_write("}"); if(dot_strm != NULL) { fflush(dot_strm); fclose(dot_strm); } simulate: if(do_simulation == FALSE) { goto cleanup; } transition = unpack_graph(data_set.graph, "ptest"); transition->batch_limit = 0; print_graph(LOG_DEBUG, transition); do { graph_rc = run_graph(transition); } while(graph_rc == transition_active); if(graph_rc != transition_complete) { crm_crit("Transition failed: %s", transition_status(graph_rc)); print_graph(LOG_ERR, transition); } destroy_graph(transition); CRM_CHECK(graph_rc == transition_complete, all_good = FALSE; crm_err("An invalid transition was produced")); cleanup: cleanup_alloc_calculations(&data_set); crm_log_deinit(); /* required for MallocDebug.app */ if(inhibit_exit) { GMainLoop* mainloop = g_main_new(FALSE); g_main_run(mainloop); } if(all_good) { return 0; } return 5; } diff --git a/tools/ccm_epoche.c b/tools/ccm_epoche.c index 92c4a24079..49bcedfb78 100644 --- a/tools/ccm_epoche.c +++ b/tools/ccm_epoche.c @@ -1,383 +1,357 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include -#ifdef HAVE_GETOPT_H -# include -#endif - #include /* for basename() */ - - - - #include #include #include int command = 0; - -#define OPTARGS "hVqepHR:" - int ccm_fd = 0; int try_hb = 1; int try_ais = 1; const char *uname = NULL; void usage(const char* cmd, int exit_status); void ais_membership_destroy(gpointer user_data); gboolean ais_membership_dispatch(AIS_Message *wrapper, char *data, int sender); #include <../lib/common/stack.h> #if SUPPORT_HEARTBEAT # include # include oc_ev_t *ccm_token = NULL; void oc_ev_special(const oc_ev_t *, oc_ev_class_t , int ); void ccm_age_callback( oc_ed_t event, void *cookie, size_t size, const void *data); gboolean ccm_age_connect(int *ccm_fd); #endif +static struct crm_option long_options[] = { + /* Top-level Options */ + {"help", 0, 0, '?', "This text"}, + {"version", 0, 0, 'v', "Version information" }, + {"verbose", 0, 0, 'V', "Increase debug output\n"}, + + {"openais", 0, 0, 'A', "Connect to an OpenAIS-based cluster"}, + {"heartbeat", 0, 0, 'H', "Connect to a Heartbeat-based cluster\n"}, + + {"epoch", 0, 0, 'e', "Display the epoch this node joined the partition"}, + {"quorum", 0, 0, 'q', "Display a 1 if our partition has quorum, 0 if not"}, + {"partition", 0, 0, 'p', "Display the members of this partition\n"}, + + {"remove", 1, 0, 'R', "Remove the (stopped) node with the specified nodeid from the cluster"}, + {"force", 0, 0, 'f'}, + + {0, 0, 0, 0} +}; + int main(int argc, char ** argv) { int flag = 0; int argerr = 0; gboolean force_flag = FALSE; gboolean dangerous_cmd = FALSE; -#ifdef HAVE_GETOPT_H int option_index = 0; - static struct option long_options[] = { - /* Top-level Options */ - - {"remove", 1, 0, 'R'}, - {"partition", 0, 0, 'p'}, - {"epoch", 0, 0, 'e'}, - {"quorum", 0, 0, 'q'}, - {"force", 0, 0, 'f'}, - {"verbose", 0, 0, 'V'}, - {"help", 0, 0, '?'}, - - {0, 0, 0, 0} - }; -#endif crm_peer_init(); crm_log_init(basename(argv[0]), LOG_WARNING, FALSE, FALSE, 0, NULL); - + crm_set_options("hVqepHR:", "[-?Vv] -[HA] -[peqR]", long_options, + "Tool for displaying node-level information"); + while (flag >= 0) { -#ifdef HAVE_GETOPT_H - flag = getopt_long(argc, argv, OPTARGS, - long_options, &option_index); -#else - flag = getopt(argc, argv, OPTARGS); -#endif + flag = crm_get_option(argc, argv, &option_index); switch(flag) { case -1: break; case 'V': cl_log_enable_stderr(TRUE); alter_debug(DEBUG_INC); break; - case 'h': /* Help message */ - usage(crm_system_name, LSB_EXIT_OK); + case 'v': + case '?': + crm_help(flag, LSB_EXIT_OK); break; case 'H': try_ais = 0; break; case 'A': try_hb = 0; break; case 'f': force_flag = TRUE; break; case 'R': dangerous_cmd = TRUE; command = flag; uname = optarg; break; case 'p': case 'e': case 'q': command = flag; break; default: ++argerr; break; } } if (optind > argc) { ++argerr; } if (argerr) { - usage(crm_system_name,LSB_EXIT_GENERIC); + crm_help('?', LSB_EXIT_GENERIC); } if(dangerous_cmd && force_flag == FALSE) { fprintf(stderr, "The supplied command is considered dangerous." " To prevent accidental destruction of the cluster," " the --force flag is required in order to proceed.\n"); fflush(stderr); exit(LSB_EXIT_GENERIC); } #if SUPPORT_AIS if(try_ais && init_ais_connection( ais_membership_dispatch, ais_membership_destroy, NULL, NULL, NULL)) { GMainLoop* amainloop = NULL; switch(command) { case 'R': send_ais_text(crm_class_rmpeer, uname, TRUE, NULL, crm_msg_ais); return 0; case 'e': /* Age makes no sense (yet) in an AIS cluster */ fprintf(stdout, "1\n"); return 0; case 'q': send_ais_text(crm_class_quorum, NULL, TRUE, NULL, crm_msg_ais); break; case 'p': crm_info("Requesting the list of configured nodes"); send_ais_text(crm_class_members, __FUNCTION__, TRUE, NULL, crm_msg_ais); break; default: fprintf(stderr, "Unknown option '%c'\n", command); - usage(crm_system_name, LSB_EXIT_GENERIC); + crm_help('?', LSB_EXIT_GENERIC); } amainloop = g_main_new(FALSE); g_main_run(amainloop); } #endif #if SUPPORT_HEARTBEAT if(try_hb && ccm_age_connect(&ccm_fd)) { int rc = 0; fd_set rset; oc_ev_t *ccm_token = NULL; while (1) { sleep(1); FD_ZERO(&rset); FD_SET(ccm_fd, &rset); errno = 0; rc = select(ccm_fd + 1, &rset, NULL,NULL,NULL); if(rc > 0 && oc_ev_handle_event(ccm_token) != 0) { crm_err("oc_ev_handle_event failed"); return 1; } else if(rc < 0 && errno != EINTR) { crm_perror(LOG_ERR, "select failed"); return 1; } } } #endif return(1); } - -void -usage(const char* cmd, int exit_status) -{ - FILE* stream; - - stream = exit_status ? stderr : stdout; - - fprintf(stream, "usage: %s [-V] [-p|-e|-q]\n", cmd); - fprintf(stream, "\t--%s (-%c)\tprint the members of this partition\n", "partition", 'p'); - fprintf(stream, "\t--%s (-%c)\tprint the epoch this node joined the partition\n", "epoch", 'e'); - fprintf(stream, "\t--%s (-%c)\tprint a 1 if our partition has quorum\n", "quorum", 'q'); - fflush(stream); - - exit(exit_status); -} - #if SUPPORT_HEARTBEAT gboolean ccm_age_connect(int *ccm_fd) { gboolean did_fail = FALSE; int ret = 0; crm_debug("Registering with CCM"); ret = oc_ev_register(&ccm_token); if (ret != 0) { crm_warn("CCM registration failed"); did_fail = TRUE; } if(did_fail == FALSE) { crm_debug("Setting up CCM callbacks"); ret = oc_ev_set_callback(ccm_token, OC_EV_MEMB_CLASS, ccm_age_callback, NULL); if (ret != 0) { crm_warn("CCM callback not set"); did_fail = TRUE; } } if(did_fail == FALSE) { oc_ev_special(ccm_token, OC_EV_MEMB_CLASS, 0/*don't care*/); crm_debug("Activating CCM token"); ret = oc_ev_activate(ccm_token, ccm_fd); if (ret != 0){ crm_warn("CCM Activation failed"); did_fail = TRUE; } } return !did_fail; } void ccm_age_callback(oc_ed_t event, void *cookie, size_t size, const void *data) { int lpc; int node_list_size; const oc_ev_membership_t *oc = (const oc_ev_membership_t *)data; node_list_size = oc->m_n_member; if(command == 'q') { crm_debug("Processing \"%s\" event.", event==OC_EV_MS_NEW_MEMBERSHIP?"NEW MEMBERSHIP": event==OC_EV_MS_NOT_PRIMARY?"NOT PRIMARY": event==OC_EV_MS_PRIMARY_RESTORED?"PRIMARY RESTORED": event==OC_EV_MS_EVICTED?"EVICTED": "NO QUORUM MEMBERSHIP"); if(ccm_have_quorum(event)) { fprintf(stdout, "1\n"); } else { fprintf(stdout, "0\n"); } } else if(command == 'e') { crm_debug("Searching %d members for our birth", oc->m_n_member); } for(lpc=0; lpcm_array[oc->m_memb_idx+lpc].node_uname); } else if(command == 'e') { if(oc_ev_is_my_nodeid(ccm_token, &(oc->m_array[lpc]))){ crm_debug("MATCH: nodeid=%d, uname=%s, born=%d", oc->m_array[oc->m_memb_idx+lpc].node_id, oc->m_array[oc->m_memb_idx+lpc].node_uname, oc->m_array[oc->m_memb_idx+lpc].node_born_on); fprintf(stdout, "%d\n", oc->m_array[oc->m_memb_idx+lpc].node_born_on); } } } oc_ev_callback_done(cookie); if(command == 'p') { fprintf(stdout, "\n"); } fflush(stdout); exit(0); } #endif #if SUPPORT_AIS void ais_membership_destroy(gpointer user_data) { crm_err("AIS connection terminated"); ais_fd_sync = -1; exit(1); } #endif static gint member_sort(gconstpointer a, gconstpointer b) { const crm_node_t *node_a = a; const crm_node_t *node_b = b; return strcmp(node_a->uname, node_b->uname); } static void crm_add_member( gpointer key, gpointer value, gpointer user_data) { GList **list = user_data; crm_node_t *node = value; if(node->uname != NULL) { *list = g_list_insert_sorted(*list, node, member_sort); } } gboolean ais_membership_dispatch(AIS_Message *wrapper, char *data, int sender) { switch(wrapper->header.id) { case crm_class_members: case crm_class_notify: case crm_class_quorum: break; default: return TRUE; break; } if(command == 'q') { if(crm_have_quorum) { fprintf(stdout, "1\n"); } else { fprintf(stdout, "0\n"); } } else if(command == 'p') { GList *nodes = NULL; g_hash_table_foreach(crm_peer_cache, crm_add_member, &nodes); slist_iter(node, crm_node_t, nodes, lpc, if(node->uname && crm_is_member_active(node)) { fprintf(stdout, "%s ", node->uname); } ); fprintf(stdout, "\n"); } exit(0); return TRUE; }