tmp1 = create_xml_node(NULL, XML_CIB_TAG_NODE); set_xml_property_copy(tmp1, XML_ATTR_ID, join_from); set_xml_property_copy(tmp1, "uname", join_from); set_xml_property_copy(tmp1, XML_ATTR_TYPE, "member");  tmp2 = create_cib_fragment(tmp1, NULL);   invoke_local_cib(NULL, tmp2, CRM_OP_UPDATE);  free_xml(tmp2); free_xml(tmp1);
create_node_entry(join_from, join_from, "member");
do_process_welcome_ack(long long action,		    enum crmd_fsa_cause cause,		    enum crmd_fsa_state cur_state,		    enum crmd_fsa_input current_input,		    void *data){	xmlNodePtr tmp1;	xmlNodePtr tmp2;	xmlNodePtr cib_fragment;	xmlNodePtr msg_cib;	xmlNodePtr join_ack = (xmlNodePtr)data;	int size = 0;	gboolean is_a_member  = FALSE;	const char *join_from = xmlGetProp(join_ack, XML_ATTR_HOSTFROM);	const char *ref       = xmlGetProp(join_ack, XML_ATTR_REFERENCE);		gpointer join_node =		g_hash_table_lookup(fsa_membership_copy->members, join_from);	if(join_node != NULL) {		is_a_member = TRUE;	}		cib_fragment = find_xml_node(join_ack, XML_TAG_FRAGMENT);	if(is_a_member == FALSE) {		crm_err("Node %s is not known to us (ref %s)",		       join_from, ref);		/* make sure any information from this node is discarded,		 * it is invalid		 */		free_xml(cib_fragment);		return I_FAIL;	}	crm_debug("Welcoming node %s after ACK (ref %s)",	       join_from, ref);		/* add them to our list of CRMD_STATE_ACTIVE nodes	   TODO: still used?	*/	g_hash_table_insert(joined_nodes, strdup(join_from),strdup(join_from));	if(cib_fragment == NULL) {		crm_err("No status information was part of the"			" Welcome ACK from %s",			join_from);		return I_NULL;	}	/* make sure a node entry exists for the new node	 *	 * this will add anyone except the first ever node in the cluster	 *   since it will also be the DC which doesnt go through the	 *   join process (with itself).  We can include a special case	 *   later if desired.	 */	tmp1 = create_xml_node(NULL, XML_CIB_TAG_NODE);	set_xml_property_copy(tmp1, XML_ATTR_ID, join_from);	set_xml_property_copy(tmp1, "uname", join_from);	set_xml_property_copy(tmp1, XML_ATTR_TYPE, "member");		tmp2 = create_cib_fragment(tmp1, NULL);	/* do not forward this to the TE */	invoke_local_cib(NULL, tmp2, CRM_OP_UPDATE);		free_xml(tmp2);	free_xml(tmp1);		/* Make changes so that exp_state=active for this node when the update	 *  is processed by A_CIB_INVOKE	 */	msg_cib = find_xml_node(cib_fragment, XML_TAG_CIB);	tmp1 = get_object_root(XML_CIB_TAG_STATUS, msg_cib);	tmp2 = find_entity(tmp1, XML_CIB_TAG_STATE, join_from, FALSE);	if(tmp2 == NULL) {		crm_err("Status entry for %s not found in update, adding",			join_from);				tmp2 = create_xml_node(tmp1, XML_CIB_TAG_STATE);		set_xml_property_copy(tmp2, XML_ATTR_ID, join_from);	}		set_xml_property_copy(		tmp2, XML_CIB_ATTR_EXPSTATE, CRMD_STATE_ACTIVE);	set_xml_property_copy(		tmp2, XML_CIB_ATTR_JOINSTATE,CRMD_JOINSTATE_MEMBER);		if(g_hash_table_size(joined_nodes)	   == fsa_membership_copy->members_size) {		crm_info("That was the last outstanding join ack");		return I_SUCCESS;		/* The update isnt lost, the A_CIB_OP action is part of the		 *   matrix for S_INTEGRATION + I_SUCCESS.		 */	} else {		crm_debug("Still waiting on %d outstanding join acks", size);		/* dont waste time by invoking the pe yet */	}	return I_CIB_OP;}