Esempio n. 1
0
gboolean
crm_is_peer_active(const crm_node_t * node)
{
    if(node == NULL) {
        return FALSE;
    }

    if (is_set(node->flags, crm_remote_node)) {
        /* remote nodes are never considered active members. This
         * guarantees they will never be considered for DC membership.*/
        return FALSE;
    }
#if SUPPORT_COROSYNC
    if (is_openais_cluster()) {
        return crm_is_corosync_peer_active(node);
    }
#endif
#if SUPPORT_HEARTBEAT
    if (is_heartbeat_cluster()) {
        return crm_is_heartbeat_peer_active(node);
    }
#endif
    crm_err("Unhandled cluster type: %s", name_for_cluster_type(get_cluster_type()));
    return FALSE;
}
Esempio n. 2
0
gboolean
crm_connect_corosync(crm_cluster_t * cluster)
{
    gboolean rc = FALSE;

    if (is_openais_cluster()) {
        crm_set_status_callback(&peer_update_callback);
        cluster->cpg.cpg_deliver_fn = crmd_cs_dispatch;
        cluster->cpg.cpg_confchg_fn = pcmk_cpg_membership;
        cluster->destroy = crmd_cs_destroy;

        rc = crm_cluster_connect(cluster);
    }

    if (rc && is_corosync_cluster()) {
        cluster_connect_quorum(crmd_cman_dispatch, crmd_quorum_destroy);
    }
#  if SUPPORT_CMAN
    if (rc && is_cman_cluster()) {
        init_cman_connection(crmd_cman_dispatch, crmd_cman_destroy);
        set_bit(fsa_input_register, R_MEMBERSHIP);
    }
#  endif
    return rc;
}
Esempio n. 3
0
static crm_node_t *crm_new_peer(unsigned int id, const char *uname)
{
    crm_node_t *node = NULL;
    CRM_CHECK(uname != NULL || id > 0, return NULL);

    crm_debug("Creating entry for node %s/%u", uname, id);
    
    crm_malloc0(node, sizeof(crm_node_t));
    node->state = crm_strdup("unknown");

    if(id > 0) {
	node->id = id;
	crm_info("Node %s now has id: %u", crm_str(uname), id);
	g_hash_table_replace(crm_peer_id_cache, GUINT_TO_POINTER(node->id), node);
    }
    
    if(uname) {
	node->uname = crm_strdup(uname);
	CRM_ASSERT(node->uname != NULL);
	crm_info("Node %u is now known as %s", id, node->uname);
	g_hash_table_replace(crm_peer_cache, node->uname, node);

	if(is_openais_cluster()) {
	    node->uuid = crm_strdup(node->uname);
	}

	if(crm_status_callback) {
	    crm_status_callback(crm_status_uname, node, NULL);
	}	
    }
    
    return node;
}
Esempio n. 4
0
gboolean
crm_cluster_connect(crm_cluster_t * cluster)
{
    enum cluster_type_e type = get_cluster_type();

    crm_notice("Connecting to cluster infrastructure: %s", name_for_cluster_type(type));
#if SUPPORT_COROSYNC
    if (is_openais_cluster()) {
        crm_peer_init();
        return init_cs_connection(cluster);
    }
#endif

#if SUPPORT_HEARTBEAT
    if (is_heartbeat_cluster()) {
        int rv;

        /* coverity[var_deref_op] False positive */
        if (cluster->hb_conn == NULL) {
            /* No object passed in, create a new one. */
            ll_cluster_t *(*new_cluster) (const char *llctype) =
                find_library_function(&hb_library, HEARTBEAT_LIBRARY, "ll_cluster_new", 1);

            cluster->hb_conn = (*new_cluster) ("heartbeat");
            /* dlclose(handle); */

        } else {
            /* Object passed in. Disconnect first, then reconnect below. */
            cluster->hb_conn->llc_ops->signoff(cluster->hb_conn, FALSE);
        }

        /* make sure we are disconnected first with the old object, if any. */
        if (heartbeat_cluster && heartbeat_cluster != cluster->hb_conn) {
            heartbeat_cluster->llc_ops->signoff(heartbeat_cluster, FALSE);
        }

        CRM_ASSERT(cluster->hb_conn != NULL);
        heartbeat_cluster = cluster->hb_conn;

        rv = register_heartbeat_conn(cluster);
        if (rv) {
            /* we'll benefit from a bigger queue length on heartbeat side.
             * Otherwise, if peers send messages faster than we can consume
             * them right now, heartbeat messaging layer will kick us out once
             * it's (small) default queue fills up :(
             * If we fail to adjust the sendq length, that's not yet fatal, though.
             */
            if (HA_OK != heartbeat_cluster->llc_ops->set_sendq_len(heartbeat_cluster, 1024)) {
                crm_warn("Cannot set sendq length: %s",
                         heartbeat_cluster->llc_ops->errmsg(heartbeat_cluster));
            }
        }
        return rv;
    }
#endif
    crm_info("Unsupported cluster stack: %s", getenv("HA_cluster_type"));
    return FALSE;
}
Esempio n. 5
0
gboolean
crm_is_peer_active(const crm_node_t * node)
{
#if SUPPORT_COROSYNC
    if(is_openais_cluster()) {
        return crm_is_corosync_peer_active(node);
    }
#endif
#if SUPPORT_HEARTBEAT
    if(is_heartbeat_cluster()) {
        return crm_is_heartbeat_peer_active(node);
    }
#endif
    crm_err("Unhandled cluster type: %s", name_for_cluster_type(get_cluster_type()));
    return FALSE;
}
Esempio n. 6
0
gboolean
send_cluster_message(crm_node_t * node, enum crm_ais_msg_types service, xmlNode * data,
                     gboolean ordered)
{

#if SUPPORT_COROSYNC
    if (is_openais_cluster()) {
        return send_cluster_message_cs(data, FALSE, node, service);
    }
#endif
#if SUPPORT_HEARTBEAT
    if (is_heartbeat_cluster()) {
        return send_ha_message(heartbeat_cluster, data, node ? node->uname : NULL, ordered);
    }
#endif
    return FALSE;
}
Esempio n. 7
0
gboolean
crm_connect_corosync(void)
{
    gboolean rc = FALSE;

    if (is_openais_cluster()) {
        crm_set_status_callback(&ais_status_callback);
        rc = crm_cluster_connect(&fsa_our_uname, &fsa_our_uuid, crmd_ais_dispatch, crmd_ais_destroy,
                                 NULL);
    }

    if (rc && is_corosync_cluster()) {
        init_quorum_connection(crmd_cman_dispatch, crmd_quorum_destroy);
    }

    if (rc && is_cman_cluster()) {
        init_cman_connection(crmd_cman_dispatch, crmd_cman_destroy);
        set_bit_inplace(fsa_input_register, R_CCM_DATA);
    }
    return rc;
}
Esempio n. 8
0
void
crm_cluster_disconnect(crm_cluster_t * cluster)
{
    enum cluster_type_e type = get_cluster_type();
    const char *type_str = name_for_cluster_type(type);

    crm_info("Disconnecting from cluster infrastructure: %s", type_str);
#if SUPPORT_COROSYNC
    if (is_openais_cluster()) {
        crm_peer_destroy();
        terminate_cs_connection(cluster);
        crm_info("Disconnected from %s", type_str);
        return;
    }
#endif

#if SUPPORT_HEARTBEAT
    if (is_heartbeat_cluster()) {
        if (cluster == NULL) {
            crm_info("No cluster connection");
            return;

        } else if (cluster->hb_conn) {
            cluster->hb_conn->llc_ops->signoff(cluster->hb_conn, TRUE);
            cluster->hb_conn = NULL;
            crm_info("Disconnected from %s", type_str);
            return;

        } else {
            crm_info("No %s connection", type_str);
            return;
        }
    }
#endif
    crm_info("Unsupported cluster stack: %s", getenv("HA_cluster_type"));
}
Esempio n. 9
0
crm_node_t *
crm_update_peer(const char *source, unsigned int id, uint64_t born, uint64_t seen, int32_t votes,
                uint32_t children, const char *uuid, const char *uname, const char *addr,
                const char *state)
{
#if SUPPORT_PLUGIN
    gboolean addr_changed = FALSE;
    gboolean votes_changed = FALSE;
#endif
    crm_node_t *node = NULL;

    id = get_corosync_id(id, uuid);
    node = crm_get_peer(id, uname);

    CRM_ASSERT(node != NULL);

    if (node->uuid == NULL) {
        if (is_openais_cluster()) {
            /* Yes, overrule whatever was passed in */
            crm_peer_uuid(node);

        } else if (uuid != NULL) {
            node->uuid = strdup(uuid);
        }
    }

    if (children > 0) {
        crm_update_peer_proc(source, node, children, state);
    }

    if (state != NULL) {
        crm_update_peer_state(source, node, state, seen);
    }
#if SUPPORT_HEARTBEAT
    if (born != 0) {
        node->born = born;
    }
#endif

#if SUPPORT_PLUGIN
    /* These were only used by the plugin */
    if (born != 0) {
        node->born = born;
    }

    if (votes > 0 && node->votes != votes) {
        votes_changed = TRUE;
        node->votes = votes;
    }

    if (addr != NULL) {
        if (node->addr == NULL || crm_str_eq(node->addr, addr, FALSE) == FALSE) {
            addr_changed = TRUE;
            free(node->addr);
            node->addr = strdup(addr);
        }
    }
    if (addr_changed || votes_changed) {
        crm_info("%s: Node %s: id=%u state=%s addr=%s%s votes=%d%s born=" U64T " seen=" U64T
                 " proc=%.32x", source, node->uname, node->id, node->state,
                 node->addr, addr_changed ? " (new)" : "", node->votes,
                 votes_changed ? " (new)" : "", node->born, node->last_seen, node->processes);
    }
#endif

    return node;
}
Esempio n. 10
0
gboolean
relay_message(xmlNode * msg, gboolean originated_locally)
{
    int dest = 1;
    int is_for_dc = 0;
    int is_for_dcib = 0;
    int is_for_te = 0;
    int is_for_crm = 0;
    int is_for_cib = 0;
    int is_local = 0;
    gboolean processing_complete = FALSE;
    const char *host_to = crm_element_value(msg, F_CRM_HOST_TO);
    const char *sys_to = crm_element_value(msg, F_CRM_SYS_TO);
    const char *sys_from = crm_element_value(msg, F_CRM_SYS_FROM);
    const char *type = crm_element_value(msg, F_TYPE);
    const char *msg_error = NULL;

    crm_trace("Routing message %s", crm_element_value(msg, XML_ATTR_REFERENCE));

    if (msg == NULL) {
        msg_error = "Cannot route empty message";

    } else if (safe_str_eq(CRM_OP_HELLO, crm_element_value(msg, F_CRM_TASK))) {
        /* quietly ignore */
        processing_complete = TRUE;

    } else if (safe_str_neq(type, T_CRM)) {
        msg_error = "Bad message type";

    } else if (sys_to == NULL) {
        msg_error = "Bad message destination: no subsystem";
    }

    if (msg_error != NULL) {
        processing_complete = TRUE;
        crm_err("%s", msg_error);
        crm_log_xml_warn(msg, "bad msg");
    }

    if (processing_complete) {
        return TRUE;
    }

    processing_complete = TRUE;

    is_for_dc = (strcasecmp(CRM_SYSTEM_DC, sys_to) == 0);
    is_for_dcib = (strcasecmp(CRM_SYSTEM_DCIB, sys_to) == 0);
    is_for_te = (strcasecmp(CRM_SYSTEM_TENGINE, sys_to) == 0);
    is_for_cib = (strcasecmp(CRM_SYSTEM_CIB, sys_to) == 0);
    is_for_crm = (strcasecmp(CRM_SYSTEM_CRMD, sys_to) == 0);

    is_local = 0;
    if (host_to == NULL || strlen(host_to) == 0) {
        if (is_for_dc || is_for_te) {
            is_local = 0;

        } else if (is_for_crm && originated_locally) {
            is_local = 0;

        } else {
            is_local = 1;
        }

    } else if (safe_str_eq(fsa_our_uname, host_to)) {
        is_local = 1;
    }

    if (is_for_dc || is_for_dcib || is_for_te) {
        if (AM_I_DC && is_for_te) {
            ROUTER_RESULT("Message result: Local relay");
            send_msg_via_ipc(msg, sys_to);

        } else if (AM_I_DC) {
            ROUTER_RESULT("Message result: DC/CRMd process");
            processing_complete = FALSE;        /* more to be done by caller */
        } else if (originated_locally && safe_str_neq(sys_from, CRM_SYSTEM_PENGINE)
                   && safe_str_neq(sys_from, CRM_SYSTEM_TENGINE)) {

            /* Neither the TE or PE should be sending messages
             *   to DC's on other nodes
             *
             * By definition, if we are no longer the DC, then
             *   the PE or TE's data should be discarded
             */

#if SUPPORT_COROSYNC
            if (is_openais_cluster()) {
                dest = text2msg_type(sys_to);
            }
#endif
            ROUTER_RESULT("Message result: External relay to DC");
            send_cluster_message(host_to ? crm_get_peer(0, host_to) : NULL, dest, msg, TRUE);

        } else {
            /* discard */
            ROUTER_RESULT("Message result: Discard, not DC");
        }

    } else if (is_local && (is_for_crm || is_for_cib)) {
        ROUTER_RESULT("Message result: CRMd process");
        processing_complete = FALSE;    /* more to be done by caller */

    } else if (is_local) {
        ROUTER_RESULT("Message result: Local relay");
        send_msg_via_ipc(msg, sys_to);

    } else {
#if SUPPORT_COROSYNC
        if (is_openais_cluster()) {
            dest = text2msg_type(sys_to);

            if (dest == crm_msg_none || dest > crm_msg_stonith_ng) {
                dest = crm_msg_crmd;
            }
        }
#endif
        ROUTER_RESULT("Message result: External relay");
        send_cluster_message(host_to ? crm_get_peer(0, host_to) : NULL, dest, msg, TRUE);
    }

    return processing_complete;
}
Esempio n. 11
0
crm_node_t *
crm_update_peer(const char *source, unsigned int id, uint64_t born, uint64_t seen, int32_t votes, uint32_t children,
                const char *uuid, const char *uname, const char *addr, const char *state)
{
    gboolean addr_changed = FALSE;
    gboolean state_changed = FALSE;
    gboolean procs_changed = FALSE;
    gboolean votes_changed = FALSE;

    crm_node_t *node = NULL;

    id = get_corosync_id(id, uuid);

    CRM_CHECK(uname != NULL || id > 0, return NULL);
    CRM_ASSERT(crm_peer_cache != NULL);
    CRM_ASSERT(crm_peer_id_cache != NULL);

    node = crm_get_peer(id, uname);
    if (node == NULL) {
        crm_trace("No node found for %d/%s", id, uname);
        node = crm_new_peer(id, uname);

        CRM_LOG_ASSERT(node != NULL);
        if (node == NULL) {
            crm_err("Insufficient information to create node %d/%s", id, uname);
            return NULL;
        }

        /* do it now so we don't get '(new)' everywhere */
        node->votes = votes;
        node->processes = children;
        if (addr) {
            node->addr = strdup(addr);
        }
    }

    if (votes > 0 && node->votes != votes) {
        votes_changed = TRUE;
        node->votes = votes;
    }

    if (node->uuid == NULL) {
        if (is_openais_cluster()) {
            /* Yes, overrule whatever was passed in */
            node->uuid = get_corosync_uuid(id, uname);

        } else if (uuid != NULL) {
            node->uuid = strdup(uuid);
        }
    }

    if (children > 0 && children != node->processes) {
        uint32_t last = node->processes;

        node->processes = children;
        procs_changed = TRUE;

        if (crm_status_callback) {
            crm_status_callback(crm_status_processes, node, &last);
        }
    }

    if (born != 0) {
        node->born = born;
    }

    if (state != NULL && safe_str_neq(node->state, state)) {
        char *last = node->state;

        node->state = strdup(state);
        state_changed = TRUE;

        if (crm_status_callback) {
            crm_status_callback(crm_status_nstate, node, last);
        }
        free(last);
    }

    if (seen != 0 && safe_str_eq(node->state, CRM_NODE_MEMBER)) {
        node->last_seen = seen;
    }

    if (addr != NULL) {
        if (node->addr == NULL || crm_str_eq(node->addr, addr, FALSE) == FALSE) {
            addr_changed = TRUE;
            free(node->addr);
            node->addr = strdup(addr);
        }
    }

    if (state_changed || addr_changed || votes_changed) {
        do_crm_log_unlikely(state_changed?LOG_NOTICE:LOG_INFO,
                   "%s: Node %s: id=%u state=%s%s addr=%s%s votes=%d%s born=" U64T " seen=" U64T
                   " proc=%.32x%s", source, node->uname, node->id, node->state, state_changed ? " (new)" : "",
                   node->addr, addr_changed ? " (new)" : "", node->votes,
                   votes_changed ? " (new)" : "", node->born, node->last_seen, node->processes,
                   procs_changed ? " (new)" : "");

    } else if (procs_changed) {
        crm_debug("%s: Node %s: id=%u seen=" U64T
                  " proc=%.32x (new)", source, node->uname, node->id, node->last_seen, node->processes);
    }

    return node;
}
/*
	DCノード開始処理
*/
void
do_dc_takeover(long long action,
	       enum crmd_fsa_cause cause,
	       enum crmd_fsa_state cur_state,
	       enum crmd_fsa_input current_input,
	       fsa_data_t *msg_data)
{
	int rc = cib_ok;
	xmlNode *cib = NULL;
	static const char *cluster_type = NULL;
	
	if(cluster_type == NULL) {
	    cluster_type = getenv("HA_cluster_type");
	}
	if(cluster_type == NULL) {
	    cluster_type = "Heartbeat";
	}
	
	crm_info("Taking over DC status for this partition");
	/* -------- ★★★★★★★★フラグ的な意味あいでの、DCノードはここでセット --------- */
	set_bit_inplace(fsa_input_register, R_THE_DC);

#if SUPPORT_AIS
	if(is_openais_cluster()) {
	    send_ais_text(crm_class_quorum, NULL, TRUE, NULL, crm_msg_ais);
	}
#endif
	
	if(voted != NULL) {
		/* votedハッシュテーブルを破棄する */
		crm_debug_2("Destroying voted hash");
		g_hash_table_destroy(voted);
		voted = NULL;
	}
	
	/* R_JOIN_OK, R_INVOKE_PEフラグセット */
	set_bit_inplace(fsa_input_register, R_JOIN_OK);
	set_bit_inplace(fsa_input_register, R_INVOKE_PE);
	
	/* CIBのset_master処理を実行する */
	fsa_cib_conn->cmds->set_master(fsa_cib_conn, cib_scope_local);
	
	/* 初期CIBのXMLを生成する */
	cib = create_xml_node(NULL, XML_TAG_CIB);
	/* 生成したXMLにCRM_FEATURE_SETをセットする */
	crm_xml_add(cib, XML_ATTR_CRM_VERSION, CRM_FEATURE_SET);
	/* CIBを生成した初期XMLで更新する */
	fsa_cib_update(XML_TAG_CIB, cib, cib_quorum_override, rc);
	/* 更新コールバックをセットする */
	add_cib_op_callback(fsa_cib_conn, rc, FALSE, NULL, feature_update_callback);

	/* CIBの"dc-version","cluster-infrastructure"属性を更新する */
	update_attr(fsa_cib_conn, cib_none, XML_CIB_TAG_CRMCONFIG,
		    NULL, NULL, NULL, "dc-version", VERSION"-"BUILD_VERSION, FALSE);

	update_attr(fsa_cib_conn, cib_none, XML_CIB_TAG_CRMCONFIG,
		    NULL, NULL, NULL, "cluster-infrastructure", cluster_type, FALSE);
	
	/* config_readトリガーを叩く */
	mainloop_set_trigger(config_read);
	
	free_xml(cib);
}
Esempio n. 13
0
const char *
crm_peer_uname(const char *uuid)
{
    GHashTableIter iter;
    crm_node_t *node = NULL;

    CRM_CHECK(uuid != NULL, return NULL);

    /* remote nodes have the same uname and uuid */
    if (g_hash_table_lookup(crm_remote_peer_cache, uuid)) {
        return uuid;
    }

    /* avoid blocking calls where possible */
    g_hash_table_iter_init(&iter, crm_peer_cache);
    while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
        if(node->uuid && strcasecmp(node->uuid, uuid) == 0) {
            if(node->uname) {
                return node->uname;
            }
            break;
        }
    }

#if SUPPORT_COROSYNC
    if (is_openais_cluster()) {
        if (uname_is_uuid() == FALSE && is_corosync_cluster()) {
            uint32_t id = crm_int_helper(uuid, NULL);
            if(id != 0) {
                node = crm_find_peer(id, NULL);
            } else {
                crm_err("Invalid node id: %s", uuid);
            }

        } else {
            node = crm_find_peer(0, uuid);
        }

        if (node) {
            crm_info("Setting uuid for node %s[%u] to '%s'", node->uname, node->id, uuid);
            node->uuid = strdup(uuid);
            if(node->uname) {
                return node->uname;
            }
        }
        return NULL;
    }
#endif

#if SUPPORT_HEARTBEAT
    if (is_heartbeat_cluster()) {
        if (heartbeat_cluster != NULL) {
            cl_uuid_t uuid_raw;
            char *uuid_copy = strdup(uuid);
            char *uname = malloc(MAX_NAME);

            cl_uuid_parse(uuid_copy, &uuid_raw);

            if (heartbeat_cluster->llc_ops->get_name_by_uuid(heartbeat_cluster, &uuid_raw, uname,
                                                             MAX_NAME) == HA_FAIL) {
                crm_err("Could not calculate uname for %s", uuid);
            } else {
                node = crm_get_peer(0, uname);
            }

            free(uuid_copy);
            free(uname);
        }

        if (node) {
            crm_info("Setting uuid for node %s to '%s'", node->uname, uuid);
            node->uuid = strdup(uuid);
            if(node->uname) {
                return node->uname;
            }
        }
        return NULL;
    }
#endif

    return NULL;
}
Esempio n. 14
0
crm_node_t *crm_update_peer(
    unsigned int id, uint64_t born, uint64_t seen, int32_t votes, uint32_t children,
    const char *uuid, const char *uname, const char *addr, const char *state) 
{
    gboolean state_changed = FALSE;
    gboolean addr_changed = FALSE;
    gboolean procs_changed = FALSE;
    gboolean votes_changed = FALSE;
    
    crm_node_t *node = NULL;
    CRM_CHECK(uname != NULL || id > 0, return NULL);
    CRM_ASSERT(crm_peer_cache != NULL);
    CRM_ASSERT(crm_peer_id_cache != NULL);

    node = crm_get_peer(id, uname);
    if(node == NULL) {
	node = crm_new_peer(id, uname);

	/* do it now so we don't get '(new)' everywhere */
	node->votes = votes;
	node->processes = children;
	if(addr) {
	    node->addr = crm_strdup(addr);
	}
    }

    if(votes > 0 && node->votes != votes) {
	votes_changed = TRUE;
	node->votes = votes;
    }
    
    if(node->uuid == NULL) {
	if(uuid != NULL) {
	    node->uuid = crm_strdup(uuid);
	    
	} else if(node->uname != NULL && is_openais_cluster()) {
	    node->uuid = crm_strdup(node->uname);
	}
    }

    if(children > 0 && children != node->processes) {
	uint32_t last = node->processes;
	node->processes = children;
	procs_changed = TRUE;

	if(crm_status_callback) {
	    crm_status_callback(crm_status_processes, node, &last);
	}
    }

    if(born != 0) {
	node->born = born;
    }

    if(state != NULL && safe_str_neq(node->state, state)) {
	char *last = node->state;
	node->state = crm_strdup(state);
	state_changed = TRUE;

	if(crm_status_callback) {
	    crm_status_callback(crm_status_nstate, node, last);
	}
	crm_free(last);
    }

    if(seen != 0 && crm_is_member_active(node)) {
	node->last_seen = seen;
    }
    
    if(addr != NULL) {
	if(node->addr == NULL || crm_str_eq(node->addr, addr, FALSE) == FALSE) {
	    addr_changed = TRUE;
	    crm_free(node->addr);
	    node->addr = crm_strdup(addr);
	}
    }

    if(state_changed || addr_changed || votes_changed || procs_changed) {
	crm_info("Node %s: id=%u state=%s%s addr=%s%s votes=%d%s born="U64T" seen="U64T" proc=%.32x%s",
		 node->uname, node->id, 
		 node->state, state_changed?" (new)":"",
		 node->addr, addr_changed?" (new)":"",
		 node->votes, votes_changed?" (new)":"",
		 node->born, node->last_seen,
		 node->processes, procs_changed?" (new)":""
	);
    }
    
    return node;
}
Esempio n. 15
0
int
servant_pcmk(const char *diskname, int mode, const void* argp)
{
	int exit_code = 0;
	crm_cluster_t crm_cluster;

	cl_log(LOG_INFO, "Monitoring Pacemaker health");
	set_proc_title("sbd: watcher: Pacemaker");
        setenv("PCMK_watchdog", "true", 1);

        if(debug == 0) {
            /* We don't want any noisy crm messages */
            set_crm_log_level(LOG_CRIT);
        }

#ifdef SUPPORT_PLUGIN
	cluster_stack = get_cluster_type();

	if (cluster_stack != pcmk_cluster_classic_ais) {
		check_ais = 0;
	} else {
		check_ais = 1;
		cl_log(LOG_INFO, "Legacy plug-in detected, AIS quorum check enabled");
		if(is_openais_cluster()) {
		    crm_cluster.destroy = ais_membership_destroy;
		    crm_cluster.cpg.cpg_deliver_fn = ais_membership_dispatch;
		    /* crm_cluster.cpg.cpg_confchg_fn = pcmk_cpg_membership; TODO? */
		    crm_cluster.cpg.cpg_confchg_fn = NULL;
		}

		while (!crm_cluster_connect(&crm_cluster)) {
			cl_log(LOG_INFO, "Waiting to sign in with cluster ...");
			sleep(reconnect_msec / 1000);
		}
	}
#endif

	if (current_cib == NULL) {
		cib = cib_new();

		do {
			exit_code = cib_connect(TRUE);

			if (exit_code != 0) {
				sleep(reconnect_msec / 1000);
			}
		} while (exit_code == -ENOTCONN);

		if (exit_code != 0) {
			clean_up(-exit_code);
		}
	}

	mainloop = g_main_new(FALSE);

	mainloop_add_signal(SIGTERM, mon_shutdown);
	mainloop_add_signal(SIGINT, mon_shutdown);
	timer_id_notify = g_timeout_add(timeout_loop * 1000, mon_timer_notify, NULL);
#ifdef SUPPORT_PLUGIN
	if (check_ais) {
		timer_id_ais = g_timeout_add(timeout_loop * 1000, mon_timer_ais, NULL);
	}
#endif

	g_main_run(mainloop);
	g_main_destroy(mainloop);

	clean_up(0);
	return 0;                   /* never reached */
}